diff --git a/tool/书源整理工具/BookSourceMgr.dpr b/tool/书源整理工具/BookSourceMgr.dpr new file mode 100644 index 000000000..6e3280e73 --- /dev/null +++ b/tool/书源整理工具/BookSourceMgr.dpr @@ -0,0 +1,22 @@ +program BookSourceMgr; + +uses + Forms, + uFrmMain in 'uFrmMain.pas' {Form1}, + Themes, + Styles, + uFrmWait in 'uFrmWait.pas' {Form2}, + uBookSourceBean in 'uBookSourceBean.pas', + uFrmEditSource in 'uFrmEditSource.pas' {frmEditSource}, + uFrmReplaceGroup in 'uFrmReplaceGroup.pas' {frmReplaceGroup}, + uBookSourceBean20 in 'uBookSourceBean20.pas'; + +{$R *.res} + +begin + Application.Initialize; + Application.MainFormOnTaskbar := True; + Application.Title := 'ĶԴ'; + Application.CreateForm(TForm1, Form1); + Application.Run; +end. diff --git a/tool/书源整理工具/BookSourceMgr.dproj b/tool/书源整理工具/BookSourceMgr.dproj new file mode 100644 index 000000000..446dc3461 --- /dev/null +++ b/tool/书源整理工具/BookSourceMgr.dproj @@ -0,0 +1,654 @@ + + + {b1648034-9a9f-40d4-a355-b3335a5a9446} + Debug + DCC32 + bin\BookSourceMgr.exe + BookSourceMgr.dpr + VCL + 18.3 + True + Debug + Win64 + 3 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + true + Cfg_2 + true + true + + + BookSourceMgr + Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;Winapi;$(DCC_Namespace) + 2052 + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + D:\Documents\Desktop\delphi\SynEdit\Source;D:\Documents\Desktop\delphi\YxdJson\source;D:\Documents\Desktop\delphi\YxdIocp\YxdIocp\source\IOCP;D:\Documents\Desktop\delphi\YxdWorker\YxdWorker\source;E:\Projects\Delphi\YxdIocp\source\IOCP;E:\Projects\Delphi\YxdJson\source;E:\Projects\Delphi\YxdWorker\source;\\Mac\Home\Desktop\Project\SynEdit\SynEdit\Source;$(DCC_UnitSearchPath) + + + System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + Debug + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName) + 1033 + $(BDS)\bin\default_app.manifest + doc\Main.ico + true + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + true + + + $(BDS)\bin\default_app.manifest + BookSourceMgr_Icon1.ico + true + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png + $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png + System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) + Debug + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 1033 + + + 7.0 + 0 + False + 0 + RELEASE;$(DCC_Define) + + + true + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName) + true + 1033 + + + true + true + + + 7.0 + DEBUG;$(DCC_Define) + .\bin + .\dcu + .\dcu + .\dcu + D:\Documents\Desktop\YxdJson\source;D:\Documents\Desktop\YxdIocp\YxdIocp\source\IOCP;D:\Documents\Desktop\YxdWorker\YxdWorker\source;$(DCC_ResourcePath) + D:\Documents\Desktop\YxdJson\source;D:\Documents\Desktop\YxdIocp\YxdIocp\source\IOCP;D:\Documents\Desktop\YxdWorker\YxdWorker\source;$(DCC_ObjPath) + D:\Documents\Desktop\YxdJson\source;D:\Documents\Desktop\YxdIocp\YxdIocp\source\IOCP;D:\Documents\Desktop\YxdWorker\YxdWorker\source;$(DCC_IncludePath) + + + true + true + CompanyName=YangYxd;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=阅读书源管理工具;ProgramID=com.embarcadero.$(MSBuildProjectName) + true + 1033 + true + + + true + true + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + true + 1033 + doc\Main.ico + + + Delphi.Personality.12 + + + + + False + True + False + + + False + False + 1 + 0 + 0 + 0 + False + False + False + False + False + 2052 + 936 + + + + + 1.0.0.0 + + + + + + 1.0.0.0 + + + + Embarcadero Git Integration + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + BookSourceMgr.dpr + + + + True + True + + + + + BookSourceMgr.exe + true + + + + + 1 + + + Contents\MacOS + 1 + + + Contents\MacOS + 0 + + + + + classes + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\armeabi + 1 + + + + + library\lib\mips + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable + 1 + + + + + res\values + 1 + + + + + res\drawable + 1 + + + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-ldpi + 1 + + + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + + + res\drawable-small + 1 + + + + + res\drawable-normal + 1 + + + + + res\drawable-large + 1 + + + + + res\drawable-xlarge + 1 + + + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + Contents\MacOS + 1 + .framework + + + 0 + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .dll;.bpl + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 0 + .bpl + + + + + 0 + + + 0 + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + 1 + + + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\ + 1 + + + + + Contents + 1 + + + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + Contents\MacOS + 1 + + + 0 + + + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + + + + + + + + + 12 + + + + MainSource + + +
Form1
+
+ +
Form2
+ dfm +
+ + +
frmEditSource
+ dfm +
+ +
frmReplaceGroup
+ dfm +
+ + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ + + + + +
diff --git a/tool/书源整理工具/BookSourceMgr.otares b/tool/书源整理工具/BookSourceMgr.otares new file mode 100644 index 000000000..75c11775b Binary files /dev/null and b/tool/书源整理工具/BookSourceMgr.otares differ diff --git a/tool/书源整理工具/BookSourceMgr.res b/tool/书源整理工具/BookSourceMgr.res new file mode 100644 index 000000000..bd2e810df Binary files /dev/null and b/tool/书源整理工具/BookSourceMgr.res differ diff --git a/tool/书源整理工具/ReadMe.txt b/tool/书源整理工具/ReadMe.txt new file mode 100644 index 000000000..5388a7775 --- /dev/null +++ b/tool/书源整理工具/ReadMe.txt @@ -0,0 +1,3 @@ +õ SynEdit + +https://github.com/SynEdit/SynEdit \ No newline at end of file diff --git a/tool/书源整理工具/doc/Main.ico b/tool/书源整理工具/doc/Main.ico new file mode 100644 index 000000000..3ddcecd74 Binary files /dev/null and b/tool/书源整理工具/doc/Main.ico differ diff --git a/tool/书源整理工具/uBookSourceBean.pas b/tool/书源整理工具/uBookSourceBean.pas new file mode 100644 index 000000000..d73ae620d --- /dev/null +++ b/tool/书源整理工具/uBookSourceBean.pas @@ -0,0 +1,361 @@ +unit uBookSourceBean; + +interface + +uses + YxdJson, Classes, SysUtils, Math; + +type + TBookSourceItem = class(JSONObject) + private + function GetIndexValue(const Index: Integer): string; + procedure SetIndexValue(const Index: Integer; const Value: string); + function GetEnable: Boolean; + function GetSerialNumber: Integer; + function GetWeight: Integer; + procedure SetEnable(const Value: Boolean); + procedure SetSerialNumber(const Value: Integer); + procedure SetWeight(const Value: Integer); + function GetLastUpdateTime: Int64; + procedure SetLastUpdateTime(const Value: Int64); + function GetScore: Integer; + procedure SetScore(const Value: Integer); + function GetEnabledExplore: Boolean; + procedure SetEnabledExplore(const Value: Boolean); + function GetBookSourceType: Integer; + procedure SetBookSourceType(const Value: Integer); + public + procedure AddGroup(const Name: string); + procedure RemoveGroup(const Name: string); + procedure ReplaceGroup(const Name, NewName: string); + function GetGroupList(): TArray; + + procedure SetStrValue(const AKey, Value: string); + function GetStr(const AKey: string): string; + + property bookSourceType: Integer read GetBookSourceType write SetBookSourceType; // Դ + property bookSourceGroup: string index 0 read GetIndexValue write SetIndexValue; // Դ + property bookSourceName: string index 1 read GetIndexValue write SetIndexValue; // Դ + property bookSourceUrl: string index 2 read GetIndexValue write SetIndexValue; // ԴURL + property bookUrlPattern: string index 45 read GetIndexValue write SetIndexValue; // ֤ + property header: string index 3 read GetIndexValue write SetIndexValue; // ͷ + property loginUrl: string index 4 read GetIndexValue write SetIndexValue; // ¼URL + property searchUrl: string index 6 read GetIndexValue write SetIndexValue; // ַ + property exploreUrl: string index 7 read GetIndexValue write SetIndexValue; // ֵַ + + property ruleSearch_bookList: string index 8 read GetIndexValue write SetIndexValue; + property ruleSearch_name: string index 9 read GetIndexValue write SetIndexValue; + property ruleSearch_author: string index 10 read GetIndexValue write SetIndexValue; + property ruleSearch_kind: string index 11 read GetIndexValue write SetIndexValue; + property ruleSearch_wordCount: string index 12 read GetIndexValue write SetIndexValue; + property ruleSearch_lastChapter: string index 13 read GetIndexValue write SetIndexValue; + property ruleSearch_intro: string index 14 read GetIndexValue write SetIndexValue; + property ruleSearch_coverUrl: string index 15 read GetIndexValue write SetIndexValue; + property ruleSearch_bookUrl: string index 16 read GetIndexValue write SetIndexValue; + + property ruleExplore_bookList: string index 17 read GetIndexValue write SetIndexValue; + property ruleExplore_name: string index 18 read GetIndexValue write SetIndexValue; + property ruleExplore_author: string index 19 read GetIndexValue write SetIndexValue; + property ruleExplore_kind: string index 20 read GetIndexValue write SetIndexValue; + property ruleExplore_wordCount: string index 21 read GetIndexValue write SetIndexValue; + property ruleExplore_lastChapter: string index 22 read GetIndexValue write SetIndexValue; + property ruleExplore_intro: string index 23 read GetIndexValue write SetIndexValue; + property ruleExplore_coverUrl: string index 24 read GetIndexValue write SetIndexValue; + property ruleExplore_bookUrl: string index 25 read GetIndexValue write SetIndexValue; + + property ruleBookInfo_init: string index 26 read GetIndexValue write SetIndexValue; + property ruleBookInfo_name: string index 27 read GetIndexValue write SetIndexValue; + property ruleBookInfo_author: string index 28 read GetIndexValue write SetIndexValue; + property ruleBookInfo_kind: string index 29 read GetIndexValue write SetIndexValue; + property ruleBookInfo_wordCount: string index 30 read GetIndexValue write SetIndexValue; + property ruleBookInfo_lastChapter: string index 31 read GetIndexValue write SetIndexValue; + property ruleBookInfo_intro: string index 32 read GetIndexValue write SetIndexValue; + property ruleBookInfo_coverUrl: string index 33 read GetIndexValue write SetIndexValue; + property ruleBookInfo_tocUrl: string index 34 read GetIndexValue write SetIndexValue; + + property ruleToc_chapterList: string index 35 read GetIndexValue write SetIndexValue; + property ruleToc_chapterName: string index 36 read GetIndexValue write SetIndexValue; + property ruleToc_chapterUrl: string index 37 read GetIndexValue write SetIndexValue; + property ruleToc_isVip: string index 38 read GetIndexValue write SetIndexValue; + property ruleToc_updateTime: string index 39 read GetIndexValue write SetIndexValue; + property ruleToc_nextTocUrl: string index 40 read GetIndexValue write SetIndexValue; + + property ruleContent_content: string index 41 read GetIndexValue write SetIndexValue; + property ruleContent_nextContentUrl: string index 42 read GetIndexValue write SetIndexValue; + property ruleContent_webJs: string index 43 read GetIndexValue write SetIndexValue; + property ruleContent_sourceRegex: string index 44 read GetIndexValue write SetIndexValue; + + property lastUpdateTime: Int64 read GetLastUpdateTime write SetLastUpdateTime; // ʱ + property enable: Boolean read GetEnable write SetEnable; + property enabledExplore: Boolean read GetEnabledExplore write SetEnabledExplore; + property customOrder: Integer read GetSerialNumber write SetSerialNumber; + property weight: Integer read GetWeight write SetWeight; + property score: Integer read GetScore write SetScore; // + end; + +implementation + +{ TBookSourceItem } + +const + SKeyArray: array [0..45] of string = ( + 'bookSourceGroup', + 'bookSourceName', + 'bookSourceUrl', + 'header', + 'loginUrl', + 'bookSourceType', + 'searchUrl', + 'exploreUrl', + + 'ruleSearch_bookList', + 'ruleSearch_name', + 'ruleSearch_author', + 'ruleSearch_kind', + 'ruleSearch_wordCount', + 'ruleSearch_lastChapter', + 'ruleSearch_intro', + 'ruleSearch_coverUrl', + 'ruleSearch_bookUrl', + + 'ruleExplore_bookList', + 'ruleExplore_name', + 'ruleExplore_author', + 'ruleExplore_kind', + 'ruleExplore_wordCount', + 'ruleExplore_lastChapter', + 'ruleExplore_intro', + 'ruleExplore_coverUrl', + 'ruleExplore_bookUrl', + + 'ruleBookInfo_init', + 'ruleBookInfo_name', + 'ruleBookInfo_author', + 'ruleBookInfo_kind', + 'ruleBookInfo_wordCount', + 'ruleBookInfo_lastChapter', + 'ruleBookInfo_intro', + 'ruleBookInfo_coverUrl', + 'ruleBookInfo_tocUrl', + + 'ruleToc_chapterList', + 'ruleToc_chapterName', + 'ruleToc_chapterUrl', + 'ruleToc_isVip', + 'ruleToc_updateTime', + 'ruleToc_nextTocUrl', + + 'ruleContent_content', + 'ruleContent_nextContentUrl', + 'ruleContent_webJs', + 'ruleContent_sourceRegex', + + 'bookUrlPattern' + ); + SEnabled = 'enable'; + SEnabledExplore = 'enabledExplore'; + SSerialNumber = 'customOrder'; + SWeight = 'weight'; + +procedure TBookSourceItem.AddGroup(const Name: string); +var + S: string; + List: TArray; + I: Integer; +begin + S := Trim(bookSourceGroup); + if S = '' then + bookSourceGroup := Name + else begin + List := GetGroupList(); + for I := Low(List) to High(List) do begin + if Trim(List[I]) = Name then + Exit; + end; + bookSourceGroup := bookSourceGroup + '; ' + Name; + end; +end; + +function TBookSourceItem.GetBookSourceType: Integer; +begin + Result := Self.I[SKeyArray[5]]; +end; + +function TBookSourceItem.GetEnable: Boolean; +begin + Result := Self.B[SEnabled]; +end; + +function TBookSourceItem.GetEnabledExplore: Boolean; +begin + Result := Self.B[SEnabledExplore]; +end; + +function TBookSourceItem.GetGroupList: TArray; +var + S: string; +begin + S := Trim(bookSourceGroup); + Result := S.Split([',', ';', ':', '', '']); +end; + +function TBookSourceItem.GetIndexValue(const Index: Integer): string; +begin + Result := GetStr(SKeyArray[Index]); +end; + +function TBookSourceItem.GetLastUpdateTime: Int64; +begin + Result := Self.I['lastUpdateTime']; +end; + +function TBookSourceItem.GetScore: Integer; +begin + Result := Self.I['score']; +end; + +function TBookSourceItem.GetSerialNumber: Integer; +begin + Result := Self.I[SSerialNumber]; +end; + +function TBookSourceItem.GetStr(const AKey: string): string; +var + Key, PKey: string; + J: Integer; + Json: JSONObject; +begin + Key := AKey; + J := Key.IndexOf('_'); + if J > 0 then begin + PKey := Key.Substring(0, J); + Json := Self.O[PKey]; + if Json = nil then + Result := '' + else begin + Key := Key.Substring(J + 1); + Result := Json.S[Key]; + end; + end else + Result := Self.S[Key]; +end; + +function TBookSourceItem.GetWeight: Integer; +begin + Result := SElf.I[SWeight]; +end; + +procedure TBookSourceItem.RemoveGroup(const Name: string); +var + S: string; + List: TArray; + I, J: Integer; + SB: TStringBuilder; +begin + S := Trim(bookSourceGroup); + if S <> '' then begin + J := 0; + List := GetGroupList(); + SB := TStringBuilder.Create(Length(bookSourceGroup) * 2); + for I := Low(List) to High(List) do begin + if Trim(List[I]) <> Name then begin + if J > 0 then + SB.Append('; '); + SB.Append(Trim(List[I])); + Inc(J); + end; + end; + bookSourceGroup := SB.ToString; + end; +end; + +procedure TBookSourceItem.ReplaceGroup(const Name, NewName: string); +var + S: string; + List: TArray; + I, J: Integer; + SB: TStringBuilder; +begin + S := Trim(bookSourceGroup); + if S <> '' then begin + J := 0; + List := GetGroupList(); + SB := TStringBuilder.Create(Length(bookSourceGroup) * 2); + for I := Low(List) to High(List) do begin + if Trim(List[I]) <> Name then begin + if J > 0 then + SB.Append('; '); + SB.Append(Trim(List[I])); + Inc(J); + end else if NewName <> '' then begin + if J > 0 then + SB.Append('; '); + SB.Append(Trim(NewName)); + Inc(J); + end; + end; + bookSourceGroup := SB.ToString; + end; +end; + +procedure TBookSourceItem.SetBookSourceType(const Value: Integer); +begin + Self.I[SKeyArray[5]] := Value; +end; + +procedure TBookSourceItem.SetEnable(const Value: Boolean); +begin + Self.B[SEnabled] := Value; +end; + +procedure TBookSourceItem.SetEnabledExplore(const Value: Boolean); +begin + Self.B[SEnabledExplore] := Value; +end; + +procedure TBookSourceItem.SetIndexValue(const Index: Integer; + const Value: string); +begin + SetStrValue(SKeyArray[Index], Value); +end; + +procedure TBookSourceItem.SetStrValue(const AKey, Value: string); +var + Key, PKey: string; + J: Integer; + Json: JSONObject; +begin + Key := AKey; + J := Key.IndexOf('_'); + if J > 0 then begin + PKey := Key.Substring(0, J); + Json := Self.O[PKey]; + if Json = nil then + Json := Self.AddChildObject(PKey); + Key := Key.Substring(J + 1); + Json.S[Key] := Value; + end else + Self.S[Key] := Value; +end; + +procedure TBookSourceItem.SetLastUpdateTime(const Value: Int64); +begin + Self.I['lastUpdateTime'] := Value; +end; + +procedure TBookSourceItem.SetScore(const Value: Integer); +begin + Self.I['score'] := Value; +end; + +procedure TBookSourceItem.SetSerialNumber(const Value: Integer); +begin + Self.I[SSerialNumber] := Value; +end; + +procedure TBookSourceItem.SetWeight(const Value: Integer); +begin + Self.I[SWeight] := Value; +end; + +end. diff --git a/tool/书源整理工具/uBookSourceBean20.pas b/tool/书源整理工具/uBookSourceBean20.pas new file mode 100644 index 000000000..21ec57d59 --- /dev/null +++ b/tool/书源整理工具/uBookSourceBean20.pas @@ -0,0 +1,247 @@ +unit uBookSourceBean20; + +interface + +uses + YxdJson, Classes, SysUtils, Math; + +type + TBookSource20Item = class(JSONObject) + private + function GetIndexValue(const Index: Integer): string; + procedure SetIndexValue(const Index: Integer; const Value: string); + function GetEnable: Boolean; + function GetSerialNumber: Integer; + function GetWeight: Integer; + procedure SetEnable(const Value: Boolean); + procedure SetSerialNumber(const Value: Integer); + procedure SetWeight(const Value: Integer); + function GetLastUpdateTime: Int64; + procedure SetLastUpdateTime(const Value: Int64); + function GetScore: Integer; + procedure SetScore(const Value: Integer); + public + procedure AddGroup(const Name: string); + procedure RemoveGroup(const Name: string); + procedure ReplaceGroup(const Name, NewName: string); + function GetGroupList(): TArray; + + property bookSourceType: string index 28 read GetIndexValue write SetIndexValue; // Դ + property bookSourceGroup: string index 0 read GetIndexValue write SetIndexValue; // Դ + property bookSourceName: string index 1 read GetIndexValue write SetIndexValue; // Դ + property bookSourceUrl: string index 2 read GetIndexValue write SetIndexValue; // ԴURL + property httpUserAgent: string index 3 read GetIndexValue write SetIndexValue; // HttpUserAgent + property loginUrl: string index 4 read GetIndexValue write SetIndexValue; // ¼URL + property ruleBookAuthor: string index 5 read GetIndexValue write SetIndexValue; // ߹ + property ruleBookContent: string index 6 read GetIndexValue write SetIndexValue; // Ĺ + property ruleBookKind: string index 7 read GetIndexValue write SetIndexValue; // + property ruleBookLastChapter: string index 8 read GetIndexValue write SetIndexValue; // ½ڹ + property ruleBookName: string index 9 read GetIndexValue write SetIndexValue; // + property ruleBookUrlPattern: string index 10 read GetIndexValue write SetIndexValue; // 鼮URL + property ruleChapterList: string index 11 read GetIndexValue write SetIndexValue; // Ŀ¼б + property ruleChapterName: string index 12 read GetIndexValue write SetIndexValue; // ½ƹ + property ruleChapterUrl: string index 13 read GetIndexValue write SetIndexValue; // Ŀ¼URL + property ruleChapterUrlNext: string index 14 read GetIndexValue write SetIndexValue; // Ŀ¼һҳUrl + property ruleContentUrl: string index 15 read GetIndexValue write SetIndexValue; // ½URL + property ruleContentUrlNext: string index 16 read GetIndexValue write SetIndexValue; // һҳURL + property ruleCoverUrl: string index 17 read GetIndexValue write SetIndexValue; // + property ruleFindUrl: string index 18 read GetIndexValue write SetIndexValue; // ֹ + property ruleIntroduce: string index 19 read GetIndexValue write SetIndexValue; // + property ruleSearchAuthor: string index 20 read GetIndexValue write SetIndexValue; // ߹ + property ruleSearchCoverUrl: string index 21 read GetIndexValue write SetIndexValue; // + property ruleSearchKind: string index 22 read GetIndexValue write SetIndexValue; // + property ruleSearchLastChapter: string index 23 read GetIndexValue write SetIndexValue; // ½ڹ + property ruleSearchList: string index 24 read GetIndexValue write SetIndexValue; // б + property ruleSearchName: string index 25 read GetIndexValue write SetIndexValue; // + property ruleSearchNoteUrl: string index 26 read GetIndexValue write SetIndexValue; // 鼮URL + property ruleSearchUrl: string index 27 read GetIndexValue write SetIndexValue; // ַ + + property lastUpdateTime: Int64 read GetLastUpdateTime write SetLastUpdateTime; // ʱ + property enable: Boolean read GetEnable write SetEnable; + property serialNumber: Integer read GetSerialNumber write SetSerialNumber; + property weight: Integer read GetWeight write SetWeight; + property score: Integer read GetScore write SetScore; // + end; + +implementation + +{ TBookSourceItem } + +const + SKeyArray: array [0..28] of string = ( + 'bookSourceGroup', + 'bookSourceName', + 'bookSourceUrl', + 'httpUserAgent', + 'loginUrl', + 'ruleBookAuthor', + 'ruleBookContent', + 'ruleBookKind', + 'ruleBookLastChapter', + 'ruleBookName', + 'ruleBookUrlPattern', + 'ruleChapterList', + 'ruleChapterName', + 'ruleChapterUrl', + 'ruleChapterUrlNext', + 'ruleContentUrl', + 'ruleContentUrlNext', + 'ruleCoverUrl', + 'ruleFindUrl', + 'ruleIntroduce', + 'ruleSearchAuthor', + 'ruleSearchCoverUrl', + 'ruleSearchKind', + 'ruleSearchLastChapter', + 'ruleSearchList', + 'ruleSearchName', + 'ruleSearchNoteUrl', + 'ruleSearchUrl', + 'bookSourceType' + ); + SEnabled = 'enable'; + SSerialNumber = 'serialNumber'; + SWeight = 'weight'; + +procedure TBookSource20Item.AddGroup(const Name: string); +var + S: string; + List: TArray; + I: Integer; +begin + S := Trim(bookSourceGroup); + if S = '' then + bookSourceGroup := Name + else begin + List := GetGroupList(); + for I := Low(List) to High(List) do begin + if Trim(List[I]) = Name then + Exit; + end; + bookSourceGroup := bookSourceGroup + '; ' + Name; + end; +end; + +function TBookSource20Item.GetEnable: Boolean; +begin + Result := Self.B[SEnabled]; +end; + +function TBookSource20Item.GetGroupList: TArray; +var + S: string; +begin + S := Trim(bookSourceGroup); + Result := S.Split([',', ';', ':', '', '']); +end; + +function TBookSource20Item.GetIndexValue(const Index: Integer): string; +begin + Result := Self.S[SKeyArray[Index]]; +end; + +function TBookSource20Item.GetLastUpdateTime: Int64; +begin + Result := Self.I['lastUpdateTime']; +end; + +function TBookSource20Item.GetScore: Integer; +begin + Result := Self.I['score']; +end; + +function TBookSource20Item.GetSerialNumber: Integer; +begin + Result := Self.I[SSerialNumber]; +end; + +function TBookSource20Item.GetWeight: Integer; +begin + Result := SElf.I[SWeight]; +end; + +procedure TBookSource20Item.RemoveGroup(const Name: string); +var + S: string; + List: TArray; + I, J: Integer; + SB: TStringBuilder; +begin + S := Trim(bookSourceGroup); + if S <> '' then begin + J := 0; + List := GetGroupList(); + SB := TStringBuilder.Create(Length(bookSourceGroup) * 2); + for I := Low(List) to High(List) do begin + if Trim(List[I]) <> Name then begin + if J > 0 then + SB.Append('; '); + SB.Append(Trim(List[I])); + Inc(J); + end; + end; + bookSourceGroup := SB.ToString; + end; +end; + +procedure TBookSource20Item.ReplaceGroup(const Name, NewName: string); +var + S: string; + List: TArray; + I, J: Integer; + SB: TStringBuilder; +begin + S := Trim(bookSourceGroup); + if S <> '' then begin + J := 0; + List := GetGroupList(); + SB := TStringBuilder.Create(Length(bookSourceGroup) * 2); + for I := Low(List) to High(List) do begin + if Trim(List[I]) <> Name then begin + if J > 0 then + SB.Append('; '); + SB.Append(Trim(List[I])); + Inc(J); + end else if NewName <> '' then begin + if J > 0 then + SB.Append('; '); + SB.Append(Trim(NewName)); + Inc(J); + end; + end; + bookSourceGroup := SB.ToString; + end; +end; + +procedure TBookSource20Item.SetEnable(const Value: Boolean); +begin + Self.B[SEnabled] := Value; +end; + +procedure TBookSource20Item.SetIndexValue(const Index: Integer; + const Value: string); +begin + Self.S[SKeyArray[Index]] := Value; +end; + +procedure TBookSource20Item.SetLastUpdateTime(const Value: Int64); +begin + Self.I['lastUpdateTime'] := Value; +end; + +procedure TBookSource20Item.SetScore(const Value: Integer); +begin + Self.I['score'] := Value; +end; + +procedure TBookSource20Item.SetSerialNumber(const Value: Integer); +begin + Self.I[SSerialNumber] := Value; +end; + +procedure TBookSource20Item.SetWeight(const Value: Integer); +begin + Self.I[SWeight] := Value; +end; + +end. diff --git a/tool/书源整理工具/uFrmEditSource.dfm b/tool/书源整理工具/uFrmEditSource.dfm new file mode 100644 index 000000000..21a757976 --- /dev/null +++ b/tool/书源整理工具/uFrmEditSource.dfm @@ -0,0 +1,1397 @@ +object frmEditSource: TfrmEditSource + Left = 0 + Top = 0 + BorderIcons = [biSystemMenu] + Caption = #32534#36753#20070#28304 + ClientHeight = 743 + ClientWidth = 1198 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -12 + Font.Name = 'Courier New' + Font.Style = [] + OldCreateOrder = False + Position = poScreenCenter + OnClose = FormClose + OnCreate = FormCreate + OnMouseWheel = FormMouseWheel + OnResize = FormResize + OnShow = FormShow + PixelsPerInch = 96 + TextHeight = 15 + object Panel1: TPanel + Left = 0 + Top = 700 + Width = 1198 + Height = 43 + Align = alBottom + BevelOuter = bvNone + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [] + ParentFont = False + ShowCaption = False + TabOrder = 0 + DesignSize = ( + 1198 + 43) + object Label29: TLabel + Left = 413 + Top = 19 + Width = 60 + Height = 12 + Caption = #25628#32034#26435#37325#65306 + Font.Charset = DEFAULT_CHARSET + Font.Color = clTeal + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [] + ParentFont = False + end + object Label30: TLabel + Left = 564 + Top = 19 + Width = 60 + Height = 12 + Caption = #25490#24207#32534#21495#65306 + Font.Charset = DEFAULT_CHARSET + Font.Color = clTeal + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [] + ParentFont = False + end + object Button1: TButton + Left = 1098 + Top = 10 + Width = 88 + Height = 25 + Anchors = [akTop, akRight] + Caption = #30830#23450'(&O)' + Default = True + TabOrder = 0 + OnClick = Button1Click + end + object Button2: TButton + Left = 995 + Top = 10 + Width = 88 + Height = 25 + Anchors = [akTop, akRight] + Cancel = True + Caption = #21462#28040'(&C)' + ModalResult = 2 + TabOrder = 1 + OnClick = Button2Click + end + object CheckBox1: TCheckBox + Left = 12 + Top = 16 + Width = 113 + Height = 17 + Caption = #21551#29992#20070#28304 + TabOrder = 2 + end + object Edit27: TEdit + Left = 477 + Top = 14 + Width = 76 + Height = 20 + Hint = 'weight' + NumbersOnly = True + ParentShowHint = False + ShowHint = True + TabOrder = 3 + Text = '0' + end + object Edit28: TEdit + Left = 627 + Top = 14 + Width = 87 + Height = 20 + Hint = 'weight' + NumbersOnly = True + ParentShowHint = False + ShowHint = True + TabOrder = 4 + Text = '0' + end + object Button3: TButton + Left = 793 + Top = 10 + Width = 107 + Height = 25 + Anchors = [akTop, akRight] + Caption = #27979#35797#20070#28304'(&T)' + ModalResult = 2 + TabOrder = 5 + OnClick = Button3Click + end + object CheckBox2: TCheckBox + Left = 268 + Top = 16 + Width = 80 + Height = 17 + Caption = #38899#39057#28304 + TabOrder = 6 + OnClick = CheckBox2Click + end + object CheckBox3: TCheckBox + Left = 333 + Top = 16 + Width = 80 + Height = 17 + Caption = #22270#28304 + TabOrder = 7 + OnClick = CheckBox3Click + end + object CheckBox4: TCheckBox + Left = 90 + Top = 12 + Width = 87 + Height = 25 + Caption = #21551#29992#21457#29616 + TabOrder = 8 + end + object CheckBox5: TCheckBox + Left = 169 + Top = 12 + Width = 87 + Height = 25 + Caption = #21551#29992#25628#32034 + TabOrder = 9 + end + end + object ScrollBox1: TScrollBox + AlignWithMargins = True + Left = 3 + Top = 3 + Width = 1192 + Height = 694 + HorzScrollBar.Smooth = True + HorzScrollBar.Style = ssFlat + VertScrollBar.Smooth = True + VertScrollBar.Style = ssFlat + VertScrollBar.Tracking = True + Align = alClient + BevelInner = bvNone + BevelOuter = bvNone + BorderStyle = bsNone + Color = clWindow + Padding.Bottom = 8 + ParentColor = False + TabOrder = 1 + object Panel2: TPanel + Left = 0 + Top = 175 + Width = 1175 + Height = 295 + Hint = 'ruleSearch' + Align = alTop + BevelOuter = bvNone + Caption = 'Panel2' + ShowCaption = False + TabOrder = 1 + DesignSize = ( + 1175 + 295) + object Label33: TLabel + Left = 9 + Top = 7 + Width = 151 + Height = 16 + Caption = #25628#32034' - ruleSearch' + Font.Charset = DEFAULT_CHARSET + Font.Color = clBlack + Font.Height = -16 + Font.Name = #40657#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label6: TLabel + Left = 24 + Top = 38 + Width = 142 + Height = 12 + Caption = #25628#32034#22320#22336#65306'(searchUrl)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label7: TLabel + Left = 24 + Top = 64 + Width = 135 + Height = 12 + Caption = #21015#34920#35268#21017#65306'(bookList)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label8: TLabel + Left = 24 + Top = 89 + Width = 107 + Height = 12 + Caption = #20070#21517#35268#21017#65306'(name)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label9: TLabel + Left = 24 + Top = 115 + Width = 121 + Height = 12 + Caption = #20316#32773#35268#21017#65306'(author)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label10: TLabel + Left = 24 + Top = 140 + Width = 107 + Height = 12 + Caption = #20998#31867#35268#21017#65306'(kind)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label34: TLabel + Left = 24 + Top = 165 + Width = 142 + Height = 12 + Caption = #23383#25968#35268#21017#65306'(wordCount)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label11: TLabel + Left = 24 + Top = 190 + Width = 162 + Height = 12 + Caption = #26368#26032#31456#33410#35268#21017#65306'(lastChapter)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [] + ParentFont = False + end + object Label12: TLabel + Left = 24 + Top = 215 + Width = 135 + Height = 12 + Caption = #23553#38754#35268#21017#65306'(coverUrl)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label13: TLabel + Left = 24 + Top = 241 + Width = 128 + Height = 12 + Caption = #35814#24773#22320#22336#65306'(bookUrl)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label20: TLabel + Left = 24 + Top = 267 + Width = 114 + Height = 12 + Caption = #31616#20171#35268#21017#65306'(intro)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Edit18: TEdit + Left = 280 + Top = 236 + Width = 890 + Height = 23 + Hint = 'ruleSearch_bookUrl' + Anchors = [akLeft, akTop, akRight] + TabOrder = 8 + TextHint = #36873#25321#33410#28857#20070#31821#35814#24773#39029#32593#22336 + end + object Edit11: TEdit + Left = 280 + Top = 262 + Width = 890 + Height = 23 + Hint = 'ruleSearch_intro' + Anchors = [akLeft, akTop, akRight] + TabOrder = 9 + TextHint = #36873#25321#20070#31821#31616#20171 + end + object Edit10: TEdit + Left = 280 + Top = 210 + Width = 890 + Height = 23 + Hint = 'ruleSearch_coverUrl' + Anchors = [akLeft, akTop, akRight] + TabOrder = 7 + TextHint = #36873#25321#33410#28857#20070#31821#23553#38754 + end + object Edit9: TEdit + Left = 280 + Top = 185 + Width = 890 + Height = 23 + Hint = 'ruleSearch_lastChapter' + Anchors = [akLeft, akTop, akRight] + TabOrder = 6 + TextHint = #36873#25321#33410#28857#26368#26032#31456#33410 + end + object Edit30: TEdit + Left = 280 + Top = 160 + Width = 890 + Height = 23 + Hint = 'ruleSearch_wordCount' + Anchors = [akLeft, akTop, akRight] + TabOrder = 5 + TextHint = #36873#25321#33410#28857#23383#25968#20449#24687 + end + object Edit8: TEdit + Left = 280 + Top = 135 + Width = 890 + Height = 23 + Hint = 'ruleSearch_kind' + Anchors = [akLeft, akTop, akRight] + TabOrder = 4 + TextHint = #36873#25321#33410#28857#20998#31867#20449#24687 + end + object Edit7: TEdit + Left = 280 + Top = 110 + Width = 890 + Height = 23 + Hint = 'ruleSearch_author' + Anchors = [akLeft, akTop, akRight] + TabOrder = 3 + TextHint = #36873#25321#33410#28857#20316#32773 + end + object Edit6: TEdit + Left = 280 + Top = 85 + Width = 890 + Height = 23 + Hint = 'ruleSearch_name' + Anchors = [akLeft, akTop, akRight] + TabOrder = 2 + TextHint = #36873#25321#33410#28857#20070#21517 + end + object Edit5: TEdit + Left = 280 + Top = 59 + Width = 890 + Height = 23 + Hint = 'ruleSearch_bookList' + Anchors = [akLeft, akTop, akRight] + TabOrder = 1 + TextHint = #36873#25321#20070#31821#33410#28857 + end + object Edit4: TEdit + Left = 280 + Top = 33 + Width = 890 + Height = 23 + Hint = 'searchUrl' + Anchors = [akLeft, akTop, akRight] + TabOrder = 0 + TextHint = '['#22495#21517#21487#30465#30053'] /search.php@kw={{key}}' + end + end + object Panel3: TPanel + Left = 0 + Top = 470 + Width = 1175 + Height = 385 + Hint = 'ruleExplore' + Align = alTop + BevelOuter = bvNone + Caption = 'Panel2' + ShowCaption = False + TabOrder = 2 + DesignSize = ( + 1175 + 385) + object Label14: TLabel + Left = 9 + Top = 7 + Width = 160 + Height = 16 + Caption = #21457#29616' - ruleExplore' + Font.Charset = DEFAULT_CHARSET + Font.Color = clBlack + Font.Height = -16 + Font.Name = #40657#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label15: TLabel + Left = 24 + Top = 38 + Width = 149 + Height = 12 + Caption = #21457#29616#22320#22336#65306'(exploreUrl)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label16: TLabel + Left = 24 + Top = 156 + Width = 135 + Height = 12 + Caption = #21015#34920#35268#21017#65306'(bookList)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label17: TLabel + Left = 24 + Top = 181 + Width = 107 + Height = 12 + Caption = #20070#21517#35268#21017#65306'(name)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label18: TLabel + Left = 24 + Top = 207 + Width = 121 + Height = 12 + Caption = #20316#32773#35268#21017#65306'(author)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label19: TLabel + Left = 24 + Top = 232 + Width = 107 + Height = 12 + Caption = #20998#31867#35268#21017#65306'(kind)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label21: TLabel + Left = 24 + Top = 257 + Width = 142 + Height = 12 + Caption = #23383#25968#35268#21017#65306'(wordCount)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label22: TLabel + Left = 24 + Top = 282 + Width = 162 + Height = 12 + Caption = #26368#26032#31456#33410#35268#21017#65306'(lastChapter)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [] + ParentFont = False + end + object Label23: TLabel + Left = 24 + Top = 307 + Width = 135 + Height = 12 + Caption = #23553#38754#35268#21017#65306'(coverUrl)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label24: TLabel + Left = 24 + Top = 333 + Width = 128 + Height = 12 + Caption = #35814#24773#22320#22336#65306'(bookUrl)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label25: TLabel + Left = 24 + Top = 359 + Width = 114 + Height = 12 + Caption = #31616#20171#35268#21017#65306'(intro)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label2: TLabel + Left = 32 + Top = 70 + Width = 240 + Height = 60 + Caption = + #20869#23481#33021#26174#31034#22312#21457#29616#33756#21333#13#10#27599#34892#19968#26465#21457#29616#20998#31867#65288#32593#22336#22495#21517#21487#30465#30053#65289#65292#20363#65306#13#10#21517#31216'1::'#32593#22336'(Url)1'#13#10#21517#31216'2::'#32593#22336'(Url)2'#13#10 + + '...' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGray + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [] + ParentFont = False + end + object Edit12: TEdit + Left = 280 + Top = 328 + Width = 890 + Height = 23 + Hint = 'ruleExplore_bookUrl' + Anchors = [akLeft, akTop, akRight] + TabOrder = 8 + TextHint = #36873#25321#33410#28857#20070#31821#35814#24773#39029#32593#22336 + end + object Edit13: TEdit + Left = 280 + Top = 354 + Width = 890 + Height = 23 + Hint = 'ruleExplore_intro' + Anchors = [akLeft, akTop, akRight] + TabOrder = 9 + TextHint = #36873#25321#20070#31821#31616#20171 + end + object Edit14: TEdit + Left = 280 + Top = 302 + Width = 890 + Height = 23 + Hint = 'ruleExplore_coverUrl' + Anchors = [akLeft, akTop, akRight] + TabOrder = 7 + TextHint = #36873#25321#33410#28857#20070#31821#23553#38754 + end + object Edit15: TEdit + Left = 280 + Top = 277 + Width = 890 + Height = 23 + Hint = 'ruleExplore_lastChapter' + Anchors = [akLeft, akTop, akRight] + TabOrder = 6 + TextHint = #36873#25321#33410#28857#26368#26032#31456#33410 + end + object Edit16: TEdit + Left = 280 + Top = 252 + Width = 890 + Height = 23 + Hint = 'ruleExplore_wordCount' + Anchors = [akLeft, akTop, akRight] + TabOrder = 5 + TextHint = #36873#25321#33410#28857#23383#25968#20449#24687 + end + object Edit17: TEdit + Left = 280 + Top = 227 + Width = 890 + Height = 23 + Hint = 'ruleExplore_kind' + Anchors = [akLeft, akTop, akRight] + TabOrder = 4 + TextHint = #36873#25321#33410#28857#20998#31867#20449#24687 + end + object Edit19: TEdit + Left = 280 + Top = 202 + Width = 890 + Height = 23 + Hint = 'ruleExplore_author' + Anchors = [akLeft, akTop, akRight] + TabOrder = 3 + TextHint = #36873#25321#33410#28857#20316#32773 + end + object Edit20: TEdit + Left = 280 + Top = 176 + Width = 890 + Height = 23 + Hint = 'ruleExplore_name' + Anchors = [akLeft, akTop, akRight] + TabOrder = 2 + TextHint = #36873#25321#33410#28857#20070#21517 + end + object Edit21: TEdit + Left = 280 + Top = 151 + Width = 890 + Height = 23 + Hint = 'ruleExplore_bookList' + Anchors = [akLeft, akTop, akRight] + TabOrder = 1 + TextHint = #36873#25321#20070#31821#33410#28857 + end + object Memo1: TMemo + Left = 280 + Top = 33 + Width = 890 + Height = 115 + Hint = 'exploreUrl' + Margins.Bottom = 8 + Anchors = [akLeft, akTop, akRight] + ScrollBars = ssVertical + TabOrder = 0 + end + end + object Panel4: TPanel + Left = 0 + Top = 855 + Width = 1175 + Height = 270 + Hint = 'ruleSearch' + Align = alTop + BevelOuter = bvNone + Caption = 'Panel2' + ShowCaption = False + TabOrder = 3 + DesignSize = ( + 1175 + 270) + object Label26: TLabel + Left = 9 + Top = 7 + Width = 169 + Height = 16 + Caption = #35814#24773' - ruleBookInfo' + Font.Charset = DEFAULT_CHARSET + Font.Color = clBlack + Font.Height = -16 + Font.Name = #40657#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label27: TLabel + Left = 24 + Top = 38 + Width = 120 + Height = 12 + Caption = #39044#22788#29702#35268#21017#65306'(init)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label35: TLabel + Left = 24 + Top = 64 + Width = 107 + Height = 12 + Caption = #20070#21517#35268#21017#65306'(name)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label36: TLabel + Left = 24 + Top = 90 + Width = 121 + Height = 12 + Caption = #20316#32773#35268#21017#65306'(author)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label37: TLabel + Left = 24 + Top = 115 + Width = 107 + Height = 12 + Caption = #20998#31867#35268#21017#65306'(kind)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label38: TLabel + Left = 24 + Top = 140 + Width = 142 + Height = 12 + Caption = #23383#25968#35268#21017#65306'(wordCount)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label39: TLabel + Left = 24 + Top = 165 + Width = 162 + Height = 12 + Caption = #26368#26032#31456#33410#35268#21017#65306'(lastChapter)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [] + ParentFont = False + end + object Label40: TLabel + Left = 24 + Top = 190 + Width = 135 + Height = 12 + Caption = #23553#38754#35268#21017#65306'(coverUrl)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label41: TLabel + Left = 24 + Top = 216 + Width = 121 + Height = 12 + Caption = #30446#24405#22320#22336#65306'(tocUrl)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label42: TLabel + Left = 24 + Top = 242 + Width = 114 + Height = 12 + Caption = #31616#20171#35268#21017#65306'(intro)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Edit22: TEdit + Left = 280 + Top = 211 + Width = 890 + Height = 23 + Hint = 'ruleBookInfo_tocUrl' + Anchors = [akLeft, akTop, akRight] + TabOrder = 7 + TextHint = #36873#25321#33410#28857#20070#31821#30446#24405#21015#34920#22320#22336 + end + object Edit23: TEdit + Left = 280 + Top = 237 + Width = 890 + Height = 23 + Hint = 'ruleBookInfo_intro' + Anchors = [akLeft, akTop, akRight] + TabOrder = 8 + TextHint = #36873#25321#20070#31821#31616#20171 + end + object Edit24: TEdit + Left = 280 + Top = 185 + Width = 890 + Height = 23 + Hint = 'ruleBookInfo_coverUrl' + Anchors = [akLeft, akTop, akRight] + TabOrder = 6 + TextHint = #36873#25321#33410#28857#20070#31821#23553#38754 + end + object Edit25: TEdit + Left = 280 + Top = 160 + Width = 890 + Height = 23 + Hint = 'ruleBookInfo_lastChapter' + Anchors = [akLeft, akTop, akRight] + TabOrder = 5 + TextHint = #36873#25321#33410#28857#26368#26032#31456#33410 + end + object Edit26: TEdit + Left = 280 + Top = 135 + Width = 890 + Height = 23 + Hint = 'ruleBookInfo_wordCount' + Anchors = [akLeft, akTop, akRight] + TabOrder = 4 + TextHint = #36873#25321#33410#28857#23383#25968#20449#24687 + end + object Edit31: TEdit + Left = 280 + Top = 110 + Width = 890 + Height = 23 + Hint = 'ruleBookInfo_kind' + Anchors = [akLeft, akTop, akRight] + TabOrder = 3 + TextHint = #36873#25321#33410#28857#20998#31867#20449#24687 + end + object Edit32: TEdit + Left = 280 + Top = 85 + Width = 890 + Height = 23 + Hint = 'ruleBookInfo_author' + Anchors = [akLeft, akTop, akRight] + TabOrder = 2 + TextHint = #36873#25321#33410#28857#20316#32773 + end + object Edit33: TEdit + Left = 280 + Top = 59 + Width = 890 + Height = 23 + Hint = 'ruleBookInfo_name' + Anchors = [akLeft, akTop, akRight] + TabOrder = 1 + TextHint = #36873#25321#33410#28857#20070#21517 + end + object Edit35: TEdit + Left = 280 + Top = 33 + Width = 890 + Height = 23 + Hint = 'ruleBookInfo_init' + Anchors = [akLeft, akTop, akRight] + TabOrder = 0 + TextHint = #29992#20110#21152#36895#35814#24773#20449#24687#26816#32034#65292#21482#25903#25345'AllInOne'#35268#21017 + end + end + object Panel6: TPanel + Left = 0 + Top = 0 + Width = 1175 + Height = 175 + Align = alTop + BevelOuter = bvNone + ShowCaption = False + TabOrder = 0 + DesignSize = ( + 1175 + 175) + object Label32: TLabel + Left = 8 + Top = 121 + Width = 222 + Height = 12 + Caption = #35831#27714#22836#65306'(header) '#65288#33258#23450#20041#23458#25143#31471#26631#35782#65289 + Font.Charset = DEFAULT_CHARSET + Font.Color = clTeal + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [] + ParentFont = False + end + object Label5: TLabel + Left = 8 + Top = 94 + Width = 114 + Height = 12 + Caption = #30331#24405'URL'#65306'(loginUrl)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clTeal + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [] + ParentFont = False + end + object Label31: TLabel + Left = 8 + Top = 67 + Width = 174 + Height = 12 + Caption = #20070#31821'URL'#27491#21017#65306'(bookUrlPattern)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clTeal + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [] + ParentFont = False + end + object Label4: TLabel + Left = 8 + Top = 40 + Width = 165 + Height = 12 + Caption = #20070#28304'URL'#65306'(bookSourceUrl)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clRed + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label3: TLabel + Left = 8 + Top = 13 + Width = 177 + Height = 12 + Caption = #20070#28304#21517#31216#65306'(bookSourceName)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clRed + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label1: TLabel + Left = 588 + Top = 13 + Width = 184 + Height = 12 + Caption = #20998#32452#21517#31216#65306'(bookSourceGroup)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Memo2: TMemo + Left = 280 + Top = 116 + Width = 890 + Height = 53 + Hint = 'header' + Margins.Bottom = 8 + Anchors = [akLeft, akTop, akRight] + ParentShowHint = False + ScrollBars = ssVertical + ShowHint = False + TabOrder = 4 + end + object Edit3: TEdit + Left = 280 + Top = 89 + Width = 890 + Height = 23 + Hint = 'loginUrl' + Anchors = [akLeft, akTop, akRight] + TabOrder = 3 + TextHint = #22635#20889#32593#31449#30331#24405#32593#22336#65292#20165#22312#38656#35201#30331#24405#30340#20070#28304#26377#29992 + end + object Edit2: TEdit + Left = 280 + Top = 35 + Width = 890 + Height = 23 + Hint = 'bookSourceUrl' + Anchors = [akLeft, akTop, akRight] + TabOrder = 1 + TextHint = #65288#24517#22635#65289#36890#24120#22635#20889#32593#31449#20027#39029 + end + object Edit1: TEdit + Left = 280 + Top = 8 + Width = 290 + Height = 23 + Hint = 'bookSourceName' + TabOrder = 0 + TextHint = #65288#24517#22635#65289#26174#31034#22312#20070#28304#21015#34920 + end + object ComboBox1: TComboBox + Left = 778 + Top = 8 + Width = 392 + Height = 23 + Hint = 'bookSourceGroup' + Anchors = [akLeft, akTop, akRight] + DropDownCount = 20 + TabOrder = 5 + end + object Edit29: TEdit + Left = 280 + Top = 62 + Width = 890 + Height = 23 + Hint = 'bookUrlPattern' + Anchors = [akLeft, akTop, akRight] + TabOrder = 2 + TextHint = #24403#35814#24773#39029'URL'#19982#28304'URL'#30340#22495#21517#19981#19968#33268#26102#26377#25928#65292#29992#20110#28155#21152#32593#22336 + end + end + object Panel5: TPanel + Left = 0 + Top = 1315 + Width = 1175 + Height = 195 + Hint = 'ruleSearch' + Align = alTop + BevelOuter = bvNone + Caption = 'Panel2' + ShowCaption = False + TabOrder = 5 + DesignSize = ( + 1175 + 195) + object Label28: TLabel + Left = 9 + Top = 7 + Width = 160 + Height = 16 + Caption = #27491#25991' - ruleContent' + Font.Charset = DEFAULT_CHARSET + Font.Color = clBlack + Font.Height = -16 + Font.Name = #40657#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label43: TLabel + Left = 24 + Top = 38 + Width = 128 + Height = 12 + Caption = #27491#25991#35268#21017#65306'(content)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label44: TLabel + Left = 24 + Top = 64 + Width = 177 + Height = 12 + Caption = #32763#39029#35268#21017#65306'(nextContentUrl)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label45: TLabel + Left = 24 + Top = 90 + Width = 156 + Height = 12 + Caption = #36164#28304#27491#21017#65306'(sourceRegex)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label46: TLabel + Left = 24 + Top = 115 + Width = 114 + Height = 12 + Caption = #33050#26412#27880#20837#65306'(webJs)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Edit41: TEdit + Left = 280 + Top = 85 + Width = 890 + Height = 23 + Hint = 'ruleContent_sourceRegex' + Anchors = [akLeft, akTop, akRight] + TabOrder = 2 + TextHint = #21305#37197#36164#28304#30340'URL'#29305#24449#65292#29992#20110#21957#25506 + end + object Edit42: TEdit + Left = 280 + Top = 59 + Width = 890 + Height = 23 + Hint = 'ruleContent_nextContentUrl' + Anchors = [akLeft, akTop, akRight] + TabOrder = 1 + TextHint = #36873#25321#19979#19968#20998#39029#65288#19981#26159#19979#19968#31456#65289#38142#25509#65288#35268#21017#32467#26524#20026'String'#31867#22411#30340'Url)' + end + object Edit43: TEdit + Left = 280 + Top = 33 + Width = 890 + Height = 23 + Hint = 'ruleContent_content' + Anchors = [akLeft, akTop, akRight] + TabOrder = 0 + TextHint = #36873#25321#27491#25991#20869#23481 + end + object Memo3: TMemo + Left = 280 + Top = 112 + Width = 890 + Height = 53 + Hint = 'ruleContent_webJs' + Margins.Bottom = 8 + Anchors = [akLeft, akTop, akRight] + ParentShowHint = False + ScrollBars = ssVertical + ShowHint = False + TabOrder = 3 + end + end + object Panel7: TPanel + Left = 0 + Top = 1125 + Width = 1175 + Height = 190 + Hint = 'ruleSearch' + Align = alTop + BevelOuter = bvNone + Caption = 'Panel2' + ShowCaption = False + TabOrder = 4 + DesignSize = ( + 1175 + 190) + object Label48: TLabel + Left = 9 + Top = 7 + Width = 124 + Height = 16 + Caption = #30446#24405' - ruleToc' + Font.Charset = DEFAULT_CHARSET + Font.Color = clBlack + Font.Height = -16 + Font.Name = #40657#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label49: TLabel + Left = 24 + Top = 38 + Width = 156 + Height = 12 + Caption = #21015#34920#35268#21017#65306'(chapterList)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label50: TLabel + Left = 24 + Top = 64 + Width = 156 + Height = 12 + Caption = #31456#33410#21517#31216#65306'(chapterName)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label51: TLabel + Left = 24 + Top = 90 + Width = 149 + Height = 12 + Caption = #31456#33410#22320#22336#65306'(chapterUrl)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label52: TLabel + Left = 24 + Top = 115 + Width = 114 + Height = 12 + Caption = #25910#36153#26631#35782#65306'(isVip)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label53: TLabel + Left = 24 + Top = 140 + Width = 149 + Height = 12 + Caption = #32763#39029#35268#21017#65306'(nextTocUrl)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Label47: TLabel + Left = 24 + Top = 166 + Width = 149 + Height = 12 + Caption = #31456#33410#20449#24687#65306'(updateTime)' + Font.Charset = DEFAULT_CHARSET + Font.Color = clGreen + Font.Height = -12 + Font.Name = #23435#20307 + Font.Style = [fsBold] + ParentFont = False + end + object Edit34: TEdit + Left = 280 + Top = 135 + Width = 890 + Height = 23 + Hint = 'ruleToc_nextTocUrl' + Anchors = [akLeft, akTop, akRight] + TabOrder = 4 + TextHint = #36873#25321#30446#24405#19979#19968#39029#30340#38142#25509#65288#35268#21017#32467#26524#20026' List '#25110' String'#65289 + end + object Edit36: TEdit + Left = 280 + Top = 110 + Width = 890 + Height = 23 + Hint = 'ruleToc_isVip' + Anchors = [akLeft, akTop, akRight] + TabOrder = 3 + TextHint = #31456#33410#26159#21542#20026'VIP'#31456#33410#65288#35268#21017#32467#26524#20026'Bool'#65289 + end + object Edit37: TEdit + Left = 280 + Top = 84 + Width = 890 + Height = 23 + Hint = 'ruleToc_chapterUrl' + Anchors = [akLeft, akTop, akRight] + TabOrder = 2 + TextHint = #36873#25321#31456#33410#38142#25509 + end + object Edit38: TEdit + Left = 280 + Top = 59 + Width = 890 + Height = 23 + Hint = 'ruleToc_chapterName' + Anchors = [akLeft, akTop, akRight] + TabOrder = 1 + TextHint = #36873#25321#31456#33410#21517#31216 + end + object Edit44: TEdit + Left = 280 + Top = 33 + Width = 890 + Height = 23 + Hint = 'ruleToc_chapterList' + Anchors = [akLeft, akTop, akRight] + TabOrder = 0 + TextHint = #36873#25321#30446#24405#21015#34920#30340#31456#33410#33410#28857#65288#35268#21017#32467#26524#20026'List'#65289 + end + object Edit39: TEdit + Left = 280 + Top = 161 + Width = 890 + Height = 23 + Hint = 'ruleToc_updateTime' + Anchors = [akLeft, akTop, akRight] + TabOrder = 5 + TextHint = #36873#25321#31456#33410#20449#24687 + end + end + end +end diff --git a/tool/书源整理工具/uFrmEditSource.pas b/tool/书源整理工具/uFrmEditSource.pas new file mode 100644 index 000000000..28b2e8846 --- /dev/null +++ b/tool/书源整理工具/uFrmEditSource.pas @@ -0,0 +1,668 @@ +unit uFrmEditSource; + +interface + +uses + uBookSourceBean, YxdJson, RegularExpressions, + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls; + +type + TNotifyEventA = reference to procedure (Item: TBookSourceItem); + + TfrmEditSource = class(TForm) + Panel1: TPanel; + Button1: TButton; + Button2: TButton; + CheckBox1: TCheckBox; + Label29: TLabel; + Edit27: TEdit; + Label30: TLabel; + Edit28: TEdit; + Button3: TButton; + CheckBox2: TCheckBox; + CheckBox3: TCheckBox; + ScrollBox1: TScrollBox; + Panel2: TPanel; + Label33: TLabel; + Label6: TLabel; + Label7: TLabel; + Label8: TLabel; + Label9: TLabel; + Label10: TLabel; + Label34: TLabel; + Label11: TLabel; + Label12: TLabel; + Label13: TLabel; + Label20: TLabel; + Edit18: TEdit; + Edit11: TEdit; + Edit10: TEdit; + Edit9: TEdit; + Edit30: TEdit; + Edit8: TEdit; + Edit7: TEdit; + Edit6: TEdit; + Edit5: TEdit; + Edit4: TEdit; + Panel3: TPanel; + Label14: TLabel; + Label15: TLabel; + Label16: TLabel; + Label17: TLabel; + Label18: TLabel; + Label19: TLabel; + Label21: TLabel; + Label22: TLabel; + Label23: TLabel; + Label24: TLabel; + Label25: TLabel; + Label2: TLabel; + Edit12: TEdit; + Edit13: TEdit; + Edit14: TEdit; + Edit15: TEdit; + Edit16: TEdit; + Edit17: TEdit; + Edit19: TEdit; + Edit20: TEdit; + Edit21: TEdit; + Memo1: TMemo; + Panel4: TPanel; + Label26: TLabel; + Label27: TLabel; + Label35: TLabel; + Label36: TLabel; + Label37: TLabel; + Label38: TLabel; + Label39: TLabel; + Label40: TLabel; + Label41: TLabel; + Label42: TLabel; + Edit22: TEdit; + Edit23: TEdit; + Edit24: TEdit; + Edit25: TEdit; + Edit26: TEdit; + Edit31: TEdit; + Edit32: TEdit; + Edit33: TEdit; + Edit35: TEdit; + Panel6: TPanel; + Label32: TLabel; + Label5: TLabel; + Label31: TLabel; + Label4: TLabel; + Label3: TLabel; + Label1: TLabel; + Memo2: TMemo; + Edit3: TEdit; + Edit2: TEdit; + Edit1: TEdit; + ComboBox1: TComboBox; + Edit29: TEdit; + Panel5: TPanel; + Label28: TLabel; + Label43: TLabel; + Label44: TLabel; + Label45: TLabel; + Label46: TLabel; + Edit41: TEdit; + Edit42: TEdit; + Edit43: TEdit; + Memo3: TMemo; + Panel7: TPanel; + Label48: TLabel; + Label49: TLabel; + Label50: TLabel; + Label51: TLabel; + Label52: TLabel; + Label53: TLabel; + Edit34: TEdit; + Edit36: TEdit; + Edit37: TEdit; + Edit38: TEdit; + Edit44: TEdit; + CheckBox4: TCheckBox; + CheckBox5: TCheckBox; + Label47: TLabel; + Edit39: TEdit; + procedure FormShow(Sender: TObject); + procedure Button1Click(Sender: TObject); + procedure FormResize(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure Button2Click(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure Button3Click(Sender: TObject); + procedure FormMouseWheel(Sender: TObject; Shift: TShiftState; + WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); + procedure CheckBox2Click(Sender: TObject); + procedure CheckBox3Click(Sender: TObject); + private + { Private declarations } + FDisableChange: Boolean; + public + { Public declarations } + Data: TBookSourceItem; + CallBack: TNotifyEventA; + + procedure ApplayEdit(Data: TBookSourceItem); + end; + +var + frmEditSource: TfrmEditSource; + +procedure ShowEditSource(Item: TBookSourceItem; CallBack: TNotifyEventA = nil); +function Is20Source(Item: JSONObject): Boolean; +procedure ConvertToNewFormat(Item: TBookSourceItem); + +implementation + +{$R *.dfm} + +uses + uFrmMain, Math, uBookSourceBean20; + +var + LastW, LastH: Integer; + +procedure ShowEditSource(Item: TBookSourceItem; CallBack: TNotifyEventA); +var + F: TfrmEditSource; +begin + F := TfrmEditSource.Create(Application); + F.Data := Item; + F.CallBack := CallBack; + + if Is20Source(Item) then + ConvertToNewFormat(F.Data); + + F.Show; +end; + +function Is20Source(Item: JSONObject): Boolean; +begin + Result := Item.Contains('ruleSearchUrl') and (not Item.Contains('ruleSearch')) +end; + +type + RegCallback = reference to procedure(const value: string); + +procedure ConvertToNewFormat(Item: TBookSourceItem); +var + Data: TBookSource20Item; + NewData: TBookSourceItem; + Tmp: JSONObject; + S: string; + + function RegMatchs(const pattern, txt: string; callback: RegCallback; all: Boolean = False): string; + var + match : TMatch; + groups: TGroupCollection; + group: TGroup; + begin + match := TRegEx.Match(txt, pattern, [roIgnoreCase]); + groups := match.Groups; + if groups.Count = 0 then Exit; + if all then begin + for group in groups do begin + if Assigned(callback) then + callback(group.Value); + end; + end else if Assigned(callback) then + callback(groups[0].Value); + end; + + function toNewRule(oldRule: string): string; + var + reverse: Boolean; + allinone: Boolean; + I: Integer; + list: TArray; + begin + if oldRule = '' then begin + Result := ''; + Exit; + end; + reverse := False; + allinone := False; + Result := oldRule; + if (Result.StartsWith('-')) then begin + reverse := True; + Result := Result.Substring(1); + end; + if Result.StartsWith('+') then begin + allinone := True; + Result := Result.Substring(1); + end; + if (not Result.StartsWith('@CSS:', True)) and + (not Result.StartsWith('@XPath:', True)) and + (not Result.StartsWith('//')) and + (not Result.StartsWith('##')) and + (not Result.StartsWith(':')) and + (not Result.StartsWith('@js:', True)) and + (not Result.StartsWith('', True)) + then begin + if Result.Contains('#') and (not Result.Contains('##')) then begin + Result := Result.Replace('#', '##'); + end; + if Result.Contains('|') and (not Result.Contains('||')) then begin + if (Result.Contains('##')) then begin + list := result.Split(['##']); + if (list[0].Contains('|')) then begin + result := list[0].Replace('|', '||'); + for I := 0 to High(list) do + Result := Result + '##' + list[i]; + end; + end else begin + Result := Result.Replace('|', '||'); + end; + end; + + if Result.Contains('&') and + (not Result.Contains('&&')) and + (not Result.Contains('http')) and + (not Result.Contains('/')) then begin + result := result.Replace('&', '&&'); + end; + + end; + + if allinone = true then + Result := '+' + Result; + + if reverse = true then + Result := '-' + Result; + end; + + function toNewUrl(oldUrl: string): string; + var + url: string; + list: TArray; + jsList: TStrings; + map: JSONObject; + mather: Boolean; + I: Integer; + begin + if oldUrl = '' then begin + Result := ''; + Exit; + end; + url := oldUrl; + if (oldUrl.startsWith('', true)) then begin + Result := url.replace('=searchKey', '={{key}}') + .replace('=searchPage', '={{page}}'); + Exit; + end; + map := JSONObject.Create; + jsList := TStringList.Create; + try + RegMatchs('@Header:\{.+?\}', url, + procedure (const value: string) begin + url := url.Replace(value, ''); + map.S['headers'] := value; + end + ); + + list := url.Split(['|']); + url := list[0]; + if Length(list) > 1 then begin + list := list[1].Split(['=']); + if Length(list) > 1 then + map.S['charset'] := list[1]; + end; + + jsList.Clear; + RegMatchs('\{\{.+?\}\}', url, + procedure (const value: string) begin + jsList.Add(value); + url := url.Replace(value, '$${' + IntToStr(jsList.Count - 1) + '}'); + end + ); + + url := url.replace('{', '<').replace('}', '>'); + url := url.replace('searchKey', '{{key}}'); + + url := TRegEx.Replace(url, '', '{{page$1}}', [roIgnoreCase]); + url := TRegEx.Replace(url, 'searchPage([-+]1)', '{{page$1}}', [roIgnoreCase]); + url := url.replace('searchPage', '{{page}}'); + + for I := 0 to jsList.Count - 1 do begin + url := url.replace('$' + IntToStr(i), jsList[i].Replace('searchKey', 'key').Replace('searchPage', 'page')); + end; + + list := url.Split(['@']); + url := list[0]; + if (Length(list) > 1) then begin + map.S['method'] := 'POST'; + map.S['body'] := list[1]; + end; + + if map.Count > 0 then + url := Url + ',' + map.ToString; + + Result := url; + finally + FreeAndNil(jsList); + FreeAndNil(map); + end; + end; + + function toNewUrls(const oldUrls: string): string; + var + urls: TArray; + i: Integer; + begin + if oldUrls = '' then begin + Result := ''; + Exit; + end; + if (not oldUrls.Contains(#13)) and (not oldUrls.Contains('&&')) then begin + Result := toNewUrl(oldUrls); + Exit; + end; + Result := ''; + urls := oldurls.Split(['&&', sLineBreak, #13]); + for I := 0 to High(urls) do begin + if Trim(urls[i]) = '' then Continue; + Result := Result + toNewUrl(urls[i]).Replace(sLineBreak, '').Replace(#13, '') + sLineBreak; + end; + end; + + procedure SyncItem(const NewKey, LastKey: string; IsURL: Boolean = False; IsURLs: boolean = false); + var + v: string; + begin + v := Data.S[LastKey]; + if (v = '') then Exit; + if IsURL then + v := toNewUrl(v) + else if IsURLs then + v := toNewUrls(v) + else + v := toNewRule(v); + NewData.SetStrValue(NewKey, v); + end; + +begin + Tmp := JSONObject.Create(); + try + Data := TBookSource20Item(Item); + NewData := TBookSourceItem.Create(); + NewData.enable := data.enable; + if (data.bookSourceType = 'AUDIO') then + NewData.bookSourceType := 1 + else if (data.bookSourceType = 'IMAGE') then + NewData.bookSourceType := 2 + else + NewData.bookSourceType := 0; + NewData.bookSourceGroup := data.bookSourceGroup; + NewData.bookSourceUrl := data.bookSourceUrl; + NewData.bookUrlPattern := data.ruleBookUrlPattern; + NewData.bookSourceName := data.bookSourceName; + NewData.customOrder := data.serialNumber; + NewData.weight := data.weight; + NewData.score := data.score; + NewData.loginUrl := data.loginUrl; + if (Data.httpUserAgent <> '') then begin + Tmp.s['User-Agent'] := Data.httpUserAgent; + NewData.header := tmp.ToString; + end; + SyncItem('ruleBookInfo_author', 'ruleBookAuthor'); + SyncItem('searchUrl', 'ruleSearchUrl', True); + SyncItem('exploreUrl', 'ruleFindUrl', False, True); + + SyncItem('ruleSearch_bookList', 'ruleSearchList'); + SyncItem('ruleSearch_name', 'ruleSearchName'); + SyncItem('ruleSearch_author', 'ruleSearchAuthor'); + SyncItem('ruleSearch_kind', 'ruleSearchKind'); + SyncItem('ruleSearch_intro', 'ruleSearchIntroduce'); + SyncItem('ruleSearch_bookUrl', 'ruleSearchNoteUrl'); + SyncItem('ruleSearch_coverUrl', 'ruleSearchCoverUrl'); + SyncItem('ruleSearch_lastChapter', 'ruleSearchLastChapter'); + + SyncItem('ruleExplore_bookList', 'ruleFindList'); + SyncItem('ruleExplore_name', 'ruleFindName'); + SyncItem('ruleExplore_author', 'ruleFindAuthor'); + SyncItem('ruleExplore_intro', 'ruleFindIntroduce'); + SyncItem('ruleExplore_kind', 'ruleFindKind'); + SyncItem('ruleExplore_bookUrl', 'ruleFindNoteUrl'); + SyncItem('ruleExplore_coverUrl', 'ruleFindCoverUrl'); + SyncItem('ruleExplore_lastChapter', 'ruleFindLastChapter'); + + SyncItem('ruleBookInfo_init', 'ruleBookInfoInit'); + SyncItem('ruleBookInfo_name', 'ruleBookName'); + SyncItem('ruleBookInfo_author', 'ruleBookAuthor'); + SyncItem('ruleBookInfo_intro', 'ruleIntroduce'); + SyncItem('ruleBookInfo_kind', 'ruleBookKind'); + SyncItem('ruleBookInfo_coverUrl', 'ruleCoverUrl'); + SyncItem('ruleBookInfo_lastChapter', 'ruleBookLastChapter'); + SyncItem('ruleBookInfo_tocUrl', 'ruleChapterUrl'); + + SyncItem('ruleToc_chapterList', 'ruleChapterList'); + SyncItem('ruleToc_chapterName', 'ruleChapterName'); + SyncItem('ruleToc_chapterUrl', 'ruleContentUrl'); + SyncItem('ruleToc_nextTocUrl', 'ruleChapterUrlNext'); + + S := Data.S['ruleBookContent']; + if S.StartsWith('$') and (not S.StartsWith('$.')) then + S := S.Substring(1); + NewData.SetStrValue('ruleContent_content', S); + SyncItem('ruleContent_nextContentUrl', 'ruleContentUrlNext'); + + Item.Clear; + Item.Assign(NewData); + finally + FreeAndNil(tmp); + end; +end; + +procedure TfrmEditSource.ApplayEdit(Data: TBookSourceItem); + + procedure SetEditValue(Parent: TWinControl); + var + I, J: Integer; + Item: TControl; + Json: JSONObject; + Key, PKey, Value: string; + begin + for I := 0 to Parent.ControlCount - 1 do begin + Item := Parent.Controls[I]; + if not Item.Visible then Continue; + + if Item is TPanel then begin + SetEditValue(TWinControl(Item)); + Continue; + end; + + Key := Item.Hint; + if Key = '' then Continue; + + Json := Data; + J := Key.IndexOf('_'); + if J > 0 then begin + PKey := Key.Substring(0, J); + Json := Data.O[PKey]; + if Json = nil then + Json := Data.AddChildObject(PKey); + Key := Key.Substring(J + 1); + end; + + Value := ''; + if Item is TEdit then + Value := TEdit(Item).Text + else if Item is TComboBox then + Value := TComboBox(Item).Text + else if Item is TMemo then + Value := TMemo(Item).Text; + + Json.S[Key] := Value; + continue; + if Value <> '' then + Json.S[Key] := Value + else + Json.Delete(Key); + end; + end; + +begin + Data.enable := CheckBox1.Checked; + if CheckBox2.Checked then + Data.bookSourceType := 1 + else if CheckBox3.Checked then + Data.bookSourceType := 2 + else + Data.bookSourceType := 0; + Data.weight := StrToIntDef(Edit27.Text, Data.weight); + Data.customOrder := StrToIntDef(Edit28.Text, Data.customOrder); + SetEditValue(ScrollBox1); +end; + +procedure TfrmEditSource.Button1Click(Sender: TObject); +begin + FDisableChange := True; + try + ApplayEdit(Data); + finally + FDisableChange := False; + end; + + if Assigned(CallBack) then + CallBack(Data); + Close; +end; + +procedure TfrmEditSource.Button2Click(Sender: TObject); +begin + Close; +end; + +procedure TfrmEditSource.Button3Click(Sender: TObject); +var + Item: TBookSourceItem; + Msg: TStrings; +begin + Msg := TStringList.Create; + Item := TBookSourceItem(JSONObject.Create); + try + Item.Parse(Data.ToString()); + ApplayEdit(Item); + if Form1.CheckBookSourceItem(Item, True, Msg) then + MessageBox(Handle, PChar(Msg.Text), 'ϲ, ͨ!', 64) + else + MessageBox(Handle, PChar(Msg.Text), 'Դ쳣', 48) + finally + FreeAndNil(Item); + FreeAndNil(Msg); + end; +end; + +procedure TfrmEditSource.CheckBox2Click(Sender: TObject); +begin + if CheckBox2.Checked then + CheckBox3.Checked := False; +end; + +procedure TfrmEditSource.CheckBox3Click(Sender: TObject); +begin + if CheckBox3.Checked then + CheckBox2.Checked := False; +end; + +procedure TfrmEditSource.FormClose(Sender: TObject; var Action: TCloseAction); +begin + Action := caFree; +end; + +procedure TfrmEditSource.FormCreate(Sender: TObject); +begin + if LastW <= 0 then LastW := Self.Width; + if LastH <= 0 then LastH := Self.Height; + Self.SetBounds(Left, Top, LastW, LastH); +end; + +procedure TfrmEditSource.FormMouseWheel(Sender: TObject; Shift: TShiftState; + WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean); +begin + if WheelDelta < 0 then + ScrollBox1.Perform(WM_VSCROLL,SB_LINEDOWN,0) + else + ScrollBox1.Perform(WM_VSCROLL,SB_LINEUP,0); +end; + +procedure TfrmEditSource.FormResize(Sender: TObject); +begin + LastW := Width; + LastH := Height; +end; + +procedure TfrmEditSource.FormShow(Sender: TObject); + + procedure SetEditValue(Parent: TWinControl); + var + I, J: Integer; + Item: TControl; + Json: JSONObject; + Key, PKey, Value: string; + begin + for I := 0 to Parent.ControlCount - 1 do begin + Item := Parent.Controls[I]; + if not Item.Visible then Continue; + + if Item is TPanel then begin + SetEditValue(TWinControl(Item)); + Continue; + end; + + Key := Item.Hint; + if Key = '' then Continue; + + Value := ''; + Json := Data; + J := Key.IndexOf('_'); + if J > 0 then begin + PKey := Key.Substring(0, J); + Json := Data.O[PKey]; + if Json <> nil then begin + Key := Key.Substring(J + 1); + Value := Json.S[Key]; + end; + end else + Value := Json.S[Key]; + + + if Item is TEdit then + TEdit(Item).Text := Value + else if Item is TComboBox then + TComboBox(Item).Text := Value + else if Item is TMemo then + TMemo(Item).Text := Value + end; + end; + +begin + ComboBox1.Items := Form1.bookGroupList.Items; + + if Assigned(Data) then begin + FDisableChange := True; + try + CheckBox1.Checked := Data.enable; + CheckBox2.Checked := False; + CheckBox3.Checked := False; + + if Data.bookSourceType = 1 then + CheckBox2.Checked := True; + if Data.bookSourceType = 2 then + CheckBox3.Checked := True; + + Edit27.Text := IntToStr(Data.weight); + Edit28.Text := IntToStr(Data.customOrder); + SetEditValue(ScrollBox1); + + finally + FDisableChange := False; + end; + end; +end; + +end. diff --git a/tool/书源整理工具/uFrmMain.dfm b/tool/书源整理工具/uFrmMain.dfm new file mode 100644 index 000000000..ab83e431f --- /dev/null +++ b/tool/书源整理工具/uFrmMain.dfm @@ -0,0 +1,780 @@ +object Form1: TForm1 + Left = 0 + Top = 0 + Caption = #38405#35835#20070#28304#25972#29702#24037#20855 + ClientHeight = 362 + ClientWidth = 1145 + Color = 15921906 + DoubleBuffered = True + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Pitch = fpFixed + Font.Style = [] + Menu = MainMenu1 + OldCreateOrder = False + OnCreate = FormCreate + OnDestroy = FormDestroy + OnShow = FormShow + PixelsPerInch = 96 + TextHeight = 13 + object Splitter1: TSplitter + AlignWithMargins = True + Left = 313 + Top = 0 + Width = 4 + Height = 331 + Margins.Left = 0 + Margins.Top = 0 + Margins.Right = 0 + Margins.Bottom = 0 + Color = clSilver + ParentColor = False + ExplicitLeft = 257 + ExplicitHeight = 697 + end + object Panel1: TPanel + Left = 0 + Top = 0 + Width = 313 + Height = 331 + Align = alLeft + BevelOuter = bvNone + Padding.Left = 4 + Padding.Top = 4 + Padding.Bottom = 4 + TabOrder = 1 + object SrcList: TListBox + AlignWithMargins = True + Left = 4 + Top = 59 + Width = 309 + Height = 238 + Hint = #23558#20070#28304#25991#20214#25302#20837#27492#22788 + Margins.Left = 0 + Margins.Top = 2 + Margins.Right = 0 + Margins.Bottom = 0 + Style = lbVirtual + Align = alClient + BorderStyle = bsNone + DoubleBuffered = True + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -12 + Font.Name = #23435#20307 + Font.Pitch = fpFixed + Font.Style = [] + ItemHeight = 18 + MultiSelect = True + ParentDoubleBuffered = False + ParentFont = False + ParentShowHint = False + PopupMenu = PopupMenu1 + ShowHint = True + TabOrder = 0 + OnClick = SrcListClick + OnData = SrcListData + OnDblClick = SrcListDblClick + OnKeyDown = SrcListKeyDown + end + object Panel4: TPanel + Left = 4 + Top = 4 + Width = 309 + Height = 53 + Align = alTop + BevelOuter = bvNone + DoubleBuffered = True + ParentDoubleBuffered = False + TabOrder = 1 + DesignSize = ( + 309 + 53) + object lbCount: TLabel + Left = 0 + Top = 7 + Width = 60 + Height = 13 + Caption = #20070#28304#21015#34920#65306 + Transparent = False + end + object bookGroupList: TComboBox + Left = 80 + Top = 3 + Width = 223 + Height = 21 + Anchors = [akLeft, akTop, akRight] + DropDownCount = 24 + Font.Charset = GB2312_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Pitch = fpFixed + Font.Style = [] + ParentFont = False + TabOrder = 0 + OnChange = bookGroupListChange + OnClick = bookGroupListChange + end + object RadioButton1: TRadioButton + Left = 3 + Top = 30 + Width = 57 + Height = 17 + Caption = #20840#37096 + Checked = True + TabOrder = 1 + TabStop = True + OnClick = RadioButton1Click + end + object RadioButton2: TRadioButton + Left = 59 + Top = 30 + Width = 57 + Height = 17 + Caption = #25991#26412 + TabOrder = 2 + OnClick = RadioButton2Click + end + object RadioButton3: TRadioButton + Left = 122 + Top = 29 + Width = 57 + Height = 20 + Caption = #38899#39057 + TabOrder = 3 + OnClick = RadioButton3Click + end + object RadioButton4: TRadioButton + Left = 182 + Top = 29 + Width = 57 + Height = 20 + Caption = #22270#28304 + TabOrder = 4 + OnClick = RadioButton4Click + end + end + object StaticText1: TStaticText + AlignWithMargins = True + Left = 7 + Top = 87 + Width = 303 + Height = 207 + Margins.Top = 30 + Align = alClient + Alignment = taCenter + Caption = #40736#26631#25302#20837#20070#28304#25991#20214#21040#27492#22788 + Color = clWindow + Font.Charset = DEFAULT_CHARSET + Font.Color = 6736896 + Font.Height = -16 + Font.Name = #24494#36719#38597#40657 + Font.Pitch = fpFixed + Font.Style = [] + ParentColor = False + ParentFont = False + PopupMenu = PopupMenu1 + TabOrder = 2 + Transparent = False + end + object Panel6: TPanel + Left = 4 + Top = 297 + Width = 309 + Height = 30 + Align = alBottom + BevelOuter = bvNone + Color = clWindow + ParentBackground = False + ShowCaption = False + TabOrder = 3 + object Shape1: TShape + Left = 0 + Top = 0 + Width = 309 + Height = 1 + Align = alTop + Pen.Color = clSilver + end + object Button2: TButton + Left = 3 + Top = 4 + Width = 57 + Height = 25 + Caption = #32622#39030'(&T)' + TabOrder = 0 + OnClick = Button2Click + end + object Button3: TButton + Left = 64 + Top = 4 + Width = 57 + Height = 25 + Caption = #19978#31227'(&U)' + TabOrder = 1 + OnClick = Button3Click + end + object Button4: TButton + Left = 125 + Top = 4 + Width = 57 + Height = 25 + Caption = #19979#31227'(&N)' + TabOrder = 2 + OnClick = Button4Click + end + object Button5: TButton + Left = 185 + Top = 4 + Width = 57 + Height = 25 + Caption = #32622#24213'(&B)' + TabOrder = 3 + OnClick = Button5Click + end + end + end + object Panel2: TPanel + Left = 317 + Top = 0 + Width = 828 + Height = 331 + Align = alClient + BevelOuter = bvNone + ParentBackground = False + ParentColor = True + TabOrder = 0 + object Splitter2: TSplitter + Left = 0 + Top = 186 + Width = 828 + Height = 4 + Cursor = crVSplit + Align = alBottom + Color = clSilver + ParentColor = False + ExplicitTop = 373 + end + object Panel3: TPanel + Left = 0 + Top = 0 + Width = 828 + Height = 36 + Align = alTop + BevelOuter = bvNone + TabOrder = 1 + object Label1: TLabel + Left = 144 + Top = 10 + Width = 64 + Height = 13 + Caption = #24037#20316#32447#31243#25968':' + Transparent = False + end + object Button1: TButton + Left = 6 + Top = 6 + Width = 128 + Height = 24 + Caption = #24320#22987#22788#29702'(&B)' + TabOrder = 0 + OnClick = Button1Click + end + object Edit1: TEdit + Left = 212 + Top = 7 + Width = 35 + Height = 21 + Alignment = taCenter + NumbersOnly = True + TabOrder = 1 + Text = '60' + end + object CheckBox1: TCheckBox + Left = 264 + Top = 9 + Width = 97 + Height = 17 + Caption = #21435#38500#37325#22797 + Checked = True + State = cbChecked + TabOrder = 2 + end + object CheckBox3: TCheckBox + Left = 344 + Top = 9 + Width = 97 + Height = 17 + Hint = #21435#37325#26102#19981#26816#27979#20070#28304#21517#31216#21644#20998#32452 + Caption = #30495#23454#21435#37325 + Checked = True + State = cbChecked + TabOrder = 4 + end + object CheckBox2: TCheckBox + Left = 429 + Top = 9 + Width = 97 + Height = 17 + Caption = #26657#39564#20070#28304 + TabOrder = 3 + end + object CheckBox4: TCheckBox + Left = 517 + Top = 9 + Width = 97 + Height = 17 + Hint = #33258#21160#32473#20070#28304#28155#21152#25110#21024#38500#21457#29616#20998#32452#26631#35782 + Caption = #33258#21160#21457#29616 + Checked = True + ParentShowHint = False + ShowHint = True + State = cbChecked + TabOrder = 5 + end + object CheckBox5: TCheckBox + Left = 605 + Top = 9 + Width = 116 + Height = 17 + Hint = #36873#20013#26102#22788#29702#25152#26377#20070#28304'('#21253#25324#34987#36807#28388#25481#30340#20070#28304'),'#19981#36873#20013#21482#22788#29702#24403#21069#36807#28388#21518#30340#20070#28304 + Caption = #22788#29702#25152#26377#20070#28304 + Checked = True + ParentShowHint = False + ShowHint = True + State = cbChecked + TabOrder = 6 + end + object CheckBox6: TCheckBox + Left = 711 + Top = 9 + Width = 97 + Height = 17 + Hint = #33258#21160#32473#20070#28304#35780#20998'('#19981#21246#36873#26102#25209#37327#26657#39564#20070#28304#19981#26657#39564#21457#29616')' + Caption = #33258#21160#35780#20998 + Checked = True + ParentShowHint = False + ShowHint = True + State = cbChecked + TabOrder = 7 + end + end + object EditData: TSynMemo + Left = 0 + Top = 36 + Width = 828 + Height = 150 + Align = alClient + Ctl3D = True + ParentCtl3D = False + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -13 + Font.Name = 'Courier New' + Font.Style = [] + PopupMenu = PopupMenu2 + TabOrder = 0 + CodeFolding.GutterShapeSize = 11 + CodeFolding.CollapsedLineColor = clGrayText + CodeFolding.FolderBarLinesColor = clGrayText + CodeFolding.IndentGuidesColor = clGray + CodeFolding.IndentGuides = True + CodeFolding.ShowCollapsedLine = False + CodeFolding.ShowHintMark = True + UseCodeFolding = False + BorderStyle = bsNone + Gutter.AutoSize = True + Gutter.BorderStyle = gbsNone + Gutter.Color = cl3DLight + Gutter.BorderColor = clWindowFrame + Gutter.Font.Charset = DEFAULT_CHARSET + Gutter.Font.Color = clWindowText + Gutter.Font.Height = -11 + Gutter.Font.Name = 'Courier New' + Gutter.Font.Style = [] + Gutter.ShowLineNumbers = True + Highlighter = SynJSONSyn1 + WordWrap = True + OnChange = EditDataChange + FontSmoothing = fsmNone + end + object Panel5: TPanel + Left = 0 + Top = 190 + Width = 828 + Height = 141 + Align = alBottom + BevelOuter = bvNone + TabOrder = 2 + DesignSize = ( + 828 + 141) + object Label2: TLabel + Left = 6 + Top = 2 + Width = 36 + Height = 13 + Caption = #26085#24535#65306 + Transparent = False + end + object SpeedButton1: TSpeedButton + Left = 783 + Top = 0 + Width = 43 + Height = 20 + Anchors = [akTop, akRight] + Caption = #28165#31354 + Flat = True + Font.Charset = DEFAULT_CHARSET + Font.Color = clTeal + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Pitch = fpFixed + Font.Style = [] + ParentFont = False + OnClick = SpeedButton1Click + end + object edtLog: TSynMemo + AlignWithMargins = True + Left = 0 + Top = 20 + Width = 828 + Height = 121 + Margins.Left = 0 + Margins.Top = 20 + Margins.Right = 0 + Margins.Bottom = 0 + Align = alClient + Ctl3D = False + ParentCtl3D = False + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -12 + Font.Name = 'Courier New' + Font.Style = [] + TabOrder = 0 + CodeFolding.GutterShapeSize = 11 + CodeFolding.CollapsedLineColor = clGrayText + CodeFolding.FolderBarLinesColor = clGrayText + CodeFolding.IndentGuidesColor = clGray + CodeFolding.IndentGuides = False + CodeFolding.ShowCollapsedLine = False + CodeFolding.ShowHintMark = True + UseCodeFolding = False + BookMarkOptions.EnableKeys = False + BookMarkOptions.GlyphsVisible = False + BorderStyle = bsNone + Gutter.AutoSize = True + Gutter.BorderStyle = gbsNone + Gutter.Color = cl3DLight + Gutter.BorderColor = clWindowFrame + Gutter.Font.Charset = DEFAULT_CHARSET + Gutter.Font.Color = clWindowText + Gutter.Font.Height = -11 + Gutter.Font.Name = 'Courier New' + Gutter.Font.Style = [] + Gutter.ShowLineNumbers = True + Gutter.Visible = False + Gutter.Width = 0 + Options = [eoScrollPastEol, eoShowScrollHint, eoSmartTabDelete, eoSmartTabs, eoTabsToSpaces] + ReadOnly = True + RightEdge = 0 + WordWrap = True + OnChange = EditDataChange + FontSmoothing = fsmClearType + end + end + end + object StatusBar1: TStatusBar + Left = 0 + Top = 337 + Width = 1145 + Height = 25 + Panels = < + item + Width = 500 + end + item + Width = 50 + end> + end + object ProgressBar1: TProgressBar + Left = 0 + Top = 331 + Width = 1145 + Height = 6 + Align = alBottom + Position = 100 + TabOrder = 3 + Visible = False + end + object PopupMenu1: TPopupMenu + OnPopup = PopupMenu1Popup + Left = 136 + Top = 192 + object C3: TMenuItem + Caption = #22797#21046#26032#22686'(&A)' + OnClick = C3Click + end + object N7: TMenuItem + Caption = #26032#24314#20070#28304'(&N)...' + OnClick = N7Click + end + object E1: TMenuItem + Caption = #32534#36753#20070#28304'(&E)...' + OnClick = E1Click + end + object N18: TMenuItem + Caption = #23548#20986#36873#20013#20070#28304'...' + OnClick = N18Click + end + object N5: TMenuItem + Caption = '-' + end + object S2: TMenuItem + Caption = #25490#24207' - '#20070#28304#21517#31216'(&S)' + OnClick = S2Click + end + object G1: TMenuItem + Caption = #25490#24207' - '#20998#32452'(&G)' + OnClick = G1Click + end + object W3: TMenuItem + Caption = #25490#24207' - '#26435#37325'(&W)' + OnClick = W3Click + end + object O2: TMenuItem + Caption = #25490#24207' - '#35780#20998'(&O)' + OnClick = O2Click + end + object N9: TMenuItem + Caption = '-' + end + object F2: TMenuItem + Caption = #26597#25214#20070#28304'(&F)...' + ShortCut = 16454 + OnClick = F2Click + end + object N14: TMenuItem + Caption = #26597#25214#19979#19968#20010 + ShortCut = 114 + OnClick = N14Click + end + object B1: TMenuItem + Caption = #20070#28304#21517#31216#26367#25442'(&B)...' + OnClick = B1Click + end + object B2: TMenuItem + Caption = #20070#28304'URL'#26367#25442'(&U)...' + OnClick = B2Click + end + object H2: TMenuItem + Caption = #20998#32452#21517#31216#26367#25442'(&H)...' + OnClick = H2Click + end + object N16: TMenuItem + Caption = '-' + end + object N15: TMenuItem + Caption = #25209#37327#28155#21152#20998#32452#21517#31216'...' + OnClick = N15Click + end + object N17: TMenuItem + Caption = #25209#37327#21024#38500#20998#32452#21517#31216'...' + OnClick = N17Click + end + object N6: TMenuItem + Caption = '-' + end + object C4: TMenuItem + Caption = #22797#21046#20070#28304'(&C)' + ShortCut = 16451 + OnClick = C4Click + end + object X2: TMenuItem + Caption = #21098#20999#20070#28304'(&X)' + ShortCut = 16472 + OnClick = X2Click + end + object P2: TMenuItem + Caption = #31896#36148#20070#28304'(&P)' + ShortCut = 16470 + OnClick = P2Click + end + object D1: TMenuItem + Caption = #21024#38500#20070#28304'(&D)' + OnClick = D1Click + end + object N13: TMenuItem + Caption = '-' + end + object C1: TMenuItem + Caption = #28165#31354'(&L)' + OnClick = C1Click + end + end + object SynJSONSyn1: TSynJSONSyn + Options.AutoDetectEnabled = False + Options.AutoDetectLineLimit = 0 + Options.Visible = False + Left = 552 + Top = 352 + end + object PopupMenu2: TPopupMenu + OnPopup = PopupMenu2Popup + Left = 632 + Top = 352 + object S1: TMenuItem + Caption = #20445#23384#20462#25913'(&S)' + ShortCut = 16467 + OnClick = S1Click + end + object T1: TMenuItem + Caption = #27979#35797#20070#28304'(&T)' + OnClick = T1Click + end + object N3: TMenuItem + Caption = '-' + end + object U1: TMenuItem + Caption = #26356#26032#26102#38388#25139'(&U)' + OnClick = U1Click + end + object N20: TMenuItem + Caption = '-' + end + object R1: TMenuItem + Caption = #25764#28040'(&R)' + OnClick = R1Click + end + object Z1: TMenuItem + Caption = #37325#20570'(&Z)' + OnClick = Z1Click + end + object N1: TMenuItem + Caption = '-' + end + object C2: TMenuItem + Caption = #22797#21046'(&C)' + OnClick = C2Click + end + object X1: TMenuItem + Caption = #21098#20999'(&X)' + OnClick = X1Click + end + object P1: TMenuItem + Caption = #31896#36148'(&P)' + OnClick = P1Click + end + object N2: TMenuItem + Caption = '-' + end + object A1: TMenuItem + Caption = #20840#36873'(&A)' + OnClick = A1Click + end + object N4: TMenuItem + Caption = '-' + end + object W1: TMenuItem + Caption = #33258#21160#25442#34892'(&W)' + OnClick = W1Click + end + end + object Timer1: TTimer + Interval = 100 + OnTimer = Timer1Timer + Left = 464 + Top = 440 + end + object MainMenu1: TMainMenu + Left = 448 + Top = 136 + object F1: TMenuItem + Caption = #25991#20214'(&F)' + object O1: TMenuItem + Caption = #25171#24320#20070#28304#25991#20214'(&O)...' + OnClick = O1Click + end + object A2: TMenuItem + Caption = #28155#21152#20070#28304#25991#20214'(&A)...' + OnClick = A2Click + end + object N12: TMenuItem + Caption = '-' + end + object N11: TMenuItem + Caption = #26032#24314#20070#28304'(&N)...' + OnClick = N7Click + end + object N10: TMenuItem + Caption = '-' + end + object E2: TMenuItem + Caption = #23548#20986#20070#28304#25991#20214'(&E)...' + OnClick = E2Click + end + object S3: TMenuItem + Caption = #23548#20986#36873#20013#20070#28304#21040#25991#20214'(&S)...' + OnClick = S3Click + end + end + object E3: TMenuItem + Caption = #32534#36753'(&E)' + object B3: TMenuItem + Caption = #20070#28304#21517#31216#26367#25442'(&B)...' + OnClick = B1Click + end + object URLU1: TMenuItem + Caption = #20070#28304'URL'#26367#25442'(&U)...' + OnClick = B2Click + end + object H3: TMenuItem + Caption = #20998#32452#21517#31216#26367#25442'(&H)...' + OnClick = H2Click + end + object N19: TMenuItem + Caption = '-' + end + object URL1: TMenuItem + Caption = #26597#25214#20070#28304': '#25628#32034#20070#28304'URL' + Checked = True + OnClick = URL1Click + end + end + object H1: TMenuItem + Caption = #24110#21161'(&H)' + object I1: TMenuItem + Caption = #20851#20110'(&I)' + OnClick = I1Click + end + object N8: TMenuItem + Caption = '-' + end + object W2: TMenuItem + Caption = #20316#32773#21338#23458'(&W)' + OnClick = W2Click + end + object R2: TMenuItem + Caption = #23567#35828#38405#35835#22120'(&R)' + OnClick = R2Click + end + end + end + object SaveDialog1: TSaveDialog + Filter = #20070#28304#25991#20214'(*.json)|*.json|'#25152#26377#25991#20214'(*.*)|*.*' + Options = [ofHideReadOnly, ofPathMustExist, ofNoReadOnlyReturn, ofEnableSizing] + Title = #23548#20986#20070#28304 + Left = 472 + Top = 352 + end + object OpenDialog1: TOpenDialog + Filter = #20070#28304#25991#20214'(*.json)|*.json|'#25152#26377#25991#20214'(*.*)|*.*' + Options = [ofHideReadOnly, ofPathMustExist, ofFileMustExist, ofEnableSizing] + Left = 544 + Top = 280 + end +end diff --git a/tool/书源整理工具/uFrmMain.pas b/tool/书源整理工具/uFrmMain.pas new file mode 100644 index 000000000..4a035dde4 --- /dev/null +++ b/tool/书源整理工具/uFrmMain.pas @@ -0,0 +1,1784 @@ +unit uFrmMain; + +interface + +uses + iocp.Http.Client, iocp.Utils.Str, DateUtils, RegularExpressions, + YxdJson, YxdStr, YxdHash, YxdWorker, ShellAPI, Math, StrUtils, + uBookSourceBean, + Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, + Dialogs, StdCtrls, ExtCtrls, Menus, SynEdit, SynMemo, ComCtrls, SyncObjs, + SynEditHighlighter, SynHighlighterJSON, Vcl.Buttons; + +type + PProcessState = ^TProcessState; + TProcessState = record + STime: Int64; + NeedFree: Boolean; + Min: Integer; + Max: Integer; + Value: Integer; + end; + +type + TForm1 = class(TForm) + Panel1: TPanel; + SrcList: TListBox; + Splitter1: TSplitter; + Panel2: TPanel; + PopupMenu1: TPopupMenu; + C1: TMenuItem; + Panel3: TPanel; + EditData: TSynMemo; + Button1: TButton; + Panel4: TPanel; + lbCount: TLabel; + bookGroupList: TComboBox; + StatusBar1: TStatusBar; + ProgressBar1: TProgressBar; + SynJSONSyn1: TSynJSONSyn; + PopupMenu2: TPopupMenu; + S1: TMenuItem; + N1: TMenuItem; + C2: TMenuItem; + X1: TMenuItem; + P1: TMenuItem; + A1: TMenuItem; + N2: TMenuItem; + N3: TMenuItem; + R1: TMenuItem; + Z1: TMenuItem; + N4: TMenuItem; + W1: TMenuItem; + Label1: TLabel; + Edit1: TEdit; + CheckBox1: TCheckBox; + CheckBox2: TCheckBox; + D1: TMenuItem; + N6: TMenuItem; + C3: TMenuItem; + N5: TMenuItem; + S2: TMenuItem; + G1: TMenuItem; + N7: TMenuItem; + E1: TMenuItem; + Timer1: TTimer; + CheckBox3: TCheckBox; + MainMenu1: TMainMenu; + F1: TMenuItem; + H1: TMenuItem; + E2: TMenuItem; + I1: TMenuItem; + SaveDialog1: TSaveDialog; + W2: TMenuItem; + N8: TMenuItem; + R2: TMenuItem; + N9: TMenuItem; + H2: TMenuItem; + E3: TMenuItem; + H3: TMenuItem; + N10: TMenuItem; + N11: TMenuItem; + T1: TMenuItem; + Panel5: TPanel; + Splitter2: TSplitter; + Label2: TLabel; + edtLog: TSynMemo; + SpeedButton1: TSpeedButton; + StaticText1: TStaticText; + O1: TMenuItem; + N12: TMenuItem; + OpenDialog1: TOpenDialog; + A2: TMenuItem; + C4: TMenuItem; + X2: TMenuItem; + P2: TMenuItem; + N13: TMenuItem; + B1: TMenuItem; + F2: TMenuItem; + N14: TMenuItem; + CheckBox4: TCheckBox; + N15: TMenuItem; + N16: TMenuItem; + N17: TMenuItem; + N18: TMenuItem; + S3: TMenuItem; + B2: TMenuItem; + B3: TMenuItem; + URLU1: TMenuItem; + N19: TMenuItem; + URL1: TMenuItem; + RadioButton1: TRadioButton; + RadioButton2: TRadioButton; + RadioButton3: TRadioButton; + RadioButton4: TRadioButton; + CheckBox5: TCheckBox; + N20: TMenuItem; + U1: TMenuItem; + W3: TMenuItem; + Panel6: TPanel; + Button2: TButton; + Button3: TButton; + Button4: TButton; + Button5: TButton; + Shape1: TShape; + CheckBox6: TCheckBox; + O2: TMenuItem; + procedure FormCreate(Sender: TObject); + procedure C1Click(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure SrcListKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); + procedure FormDestroy(Sender: TObject); + procedure SrcListData(Control: TWinControl; Index: Integer; + var Data: string); + procedure PopupMenu2Popup(Sender: TObject); + procedure R1Click(Sender: TObject); + procedure Z1Click(Sender: TObject); + procedure C2Click(Sender: TObject); + procedure X1Click(Sender: TObject); + procedure P1Click(Sender: TObject); + procedure A1Click(Sender: TObject); + procedure S1Click(Sender: TObject); + procedure SrcListClick(Sender: TObject); + procedure EditDataChange(Sender: TObject); + procedure W1Click(Sender: TObject); + procedure D1Click(Sender: TObject); + procedure C3Click(Sender: TObject); + procedure Button1Click(Sender: TObject); + procedure Timer1Timer(Sender: TObject); + procedure bookGroupListChange(Sender: TObject); + procedure N7Click(Sender: TObject); + procedure E1Click(Sender: TObject); + procedure SrcListDblClick(Sender: TObject); + procedure I1Click(Sender: TObject); + procedure E2Click(Sender: TObject); + procedure W2Click(Sender: TObject); + procedure R2Click(Sender: TObject); + procedure S2Click(Sender: TObject); + procedure G1Click(Sender: TObject); + procedure H2Click(Sender: TObject); + procedure T1Click(Sender: TObject); + procedure SpeedButton1Click(Sender: TObject); + procedure O1Click(Sender: TObject); + procedure A2Click(Sender: TObject); + procedure PopupMenu1Popup(Sender: TObject); + procedure C4Click(Sender: TObject); + procedure X2Click(Sender: TObject); + procedure P2Click(Sender: TObject); + procedure B1Click(Sender: TObject); + procedure F2Click(Sender: TObject); + procedure N14Click(Sender: TObject); + procedure N15Click(Sender: TObject); + procedure N17Click(Sender: TObject); + procedure S3Click(Sender: TObject); + procedure N18Click(Sender: TObject); + procedure B2Click(Sender: TObject); + procedure URL1Click(Sender: TObject); + procedure RadioButton1Click(Sender: TObject); + procedure RadioButton2Click(Sender: TObject); + procedure RadioButton3Click(Sender: TObject); + procedure RadioButton4Click(Sender: TObject); + procedure U1Click(Sender: TObject); + procedure W3Click(Sender: TObject); + procedure Button2Click(Sender: TObject); + procedure Button3Click(Sender: TObject); + procedure Button4Click(Sender: TObject); + procedure Button5Click(Sender: TObject); + procedure O2Click(Sender: TObject); + procedure Button6Click(Sender: TObject); + private + { Private declarations } + OldListWndProc, OldTextWndProc: TWndMethod; + FBookSrcData: JSONArray; + FBookCopyData: JSONArray; + FBookGroups: TStringHash; + FIsChange, FChanging: Boolean; + FCurIndex: Integer; + + FWaitStop: Integer; + FTaskRef: Integer; + FTaskStartTime: Int64; + FCheckLastTime: Int64; + FMaxWorkers: Integer; + + FFilterList: TList; + FCurCheckIndex: Integer; + FCheckCount, FCheckFinish: Integer; + FAutoFind, FAutoDel, FAllSrc, FAutoScore: Boolean; + + FWaitCheckBookSourceSingId: Integer; + + FLocker: TCriticalSection; + FStateMsg: string; + FLastSortFlag: Integer; + FLastFindSource: string; + FBookType: string; + procedure SetBookType(const Value: string); + + protected + procedure SrcListWndProc(var Message: TMessage); + procedure SrcListTextWndProc(var Message: TMessage); + procedure AddSrcFiles(ADrop: Integer); + procedure WMDropFiles(var Msg: TWMDropFiles); message WM_DROPFILES; + public + { Public declarations } + function CheckItem(Item: TBookSourceItem): Boolean; + function CheckSaveState(): Boolean; + + + function CheckBookSourceItem(Item: TBookSourceItem; RaiseErr: Boolean = False; OutLog: TStrings = nil): Boolean; overload; + function CheckBookSourceItem(Item: TBookSourceItem; Http: THttpClient; Header: THttpHeaders; RaiseErr: Boolean = False; OutLog: TStrings = nil): Boolean; overload; + + procedure AddSrcFile(const FileName: string); + procedure UpdateBookGroup(Item: TBookSourceItem); + + procedure RemoveRepeat(AJob: PJob); + procedure WaitCheckBookSource(AJob: PJob); + procedure DoCheckBookSourceItem(AJob: PJob); + + procedure TaskFinish(AJob: PJob); + procedure DoNotifyDataChange(AJob: PJob); + procedure DoUpdateProcess(AJob: PJob); + + procedure Log(const Msg: string); + procedure LogD(const Msg: string); + procedure DispLog(); + procedure NotifyListChange(Flag: Integer = 0); + + procedure RemoveSelected(); + procedure CopySelected(); + procedure Paste(); + procedure CutSelectedt(); + procedure FindSource(const FindStr: string); + procedure EditSource(Item: TBookSourceItem); + procedure ExportSelectedToFile(); + + procedure ChangeItemIndex(const CurIndex, NewIndex: Integer); + + property BookType: string read FBookType write SetBookType; + end; + +var + Form1: TForm1; + +implementation + +{$R *.dfm} + +uses + uFrmWait, uFrmEditSource, uFrmReplaceGroup; + +function GetCurJavaDateTime(): Int64; +begin + Result := Round(((Now - 25569) * 86400000 - 3600000 * 8) / 1000); +end; + +procedure CutOrCopyFiles(FileList: AnsiString; bCopy: Boolean); +type + PDropFiles = ^TDropFiles; + + TDropFiles = record + pfiles: DWORD; + pt: TPoint; + fNC: BOOL; + fwide: BOOL; + end; +const + DROPEFFECT_COPY = 1; + DROPEFFECT_MOVE = 2; +var + hGblFileList: hGlobal; + pFileListDate: Pbyte; + HandleDropEffect: UINT; + hGblDropEffect: hGlobal; + pdwDropEffect: PDWORD; + iLen: Integer; +begin + iLen := Length(FileList) + 2; + FileList := FileList + #0#0; + hGblFileList := GlobalAlloc(GMEM_ZEROINIT or GMEM_MOVEABLE or GMEM_SHARE, + SizeOf(TDropFiles) + iLen); + pFileListDate := GlobalLock(hGblFileList); + PDropFiles(pFileListDate)^.pfiles := SizeOf(TDropFiles); + PDropFiles(pFileListDate)^.pt.Y := 0; + PDropFiles(pFileListDate)^.pt.X := 0; + PDropFiles(pFileListDate)^.fNC := False; + PDropFiles(pFileListDate)^.fwide := False; + Inc(pFileListDate, SizeOf(TDropFiles)); + CopyMemory(pFileListDate, @FileList[1], iLen); + GlobalUnlock(hGblFileList); + HandleDropEffect := RegisterClipboardFormat('Preferred DropEffect '); + hGblDropEffect := GlobalAlloc(GMEM_ZEROINIT or GMEM_MOVEABLE or GMEM_SHARE, + SizeOf(DWORD)); + pdwDropEffect := GlobalLock(hGblDropEffect); + if (bCopy) then pdwDropEffect^ := DROPEFFECT_COPY + else pdwDropEffect^ := DROPEFFECT_MOVE; + GlobalUnlock(hGblDropEffect); + if OpenClipboard(0) then begin + EmptyClipboard(); + SetClipboardData(HandleDropEffect, hGblDropEffect); + SetClipboardData(CF_HDROP, hGblFileList); + CloseClipboard(); + end; +end; + +// ļļ #0 ָ +procedure CopyFileClipbrd(const FName: string); +begin + CutOrCopyFiles(AnsiString(FName), True); +end; + +procedure TForm1.AddSrcFiles(ADrop: Integer); +var + i: Integer; + p: array[0..1023] of Char; +begin + for i := 0 to DragQueryFile(ADrop, $FFFFFFFF, nil, 0) - 1 do begin + DragQueryFile(ADrop, i, p, 1024); + AddSrcFile(StrPas(p)); + end; +end; + +procedure TForm1.B1Click(Sender: TObject); +var + FindStr, NewStr: string; + I, Flag: Integer; + Item: TBookSourceItem; +begin + Flag := 1; + if ShowReplaceGroup(Self, '滻 - Դ', FindStr, NewStr, Flag) then begin + if (FindStr <> '') and (Flag = 0) then + Exit; + for I := 0 to FBookSrcData.Count - 1 do begin + Item := TBookSourceItem(FBookSrcData.O[I]); + if not Assigned(Item) then Continue; + Item.bookSourceName := StringReplace(Trim(Item.bookSourceName), FindStr, NewStr, [rfReplaceAll, rfIgnoreCase]); + end; + NotifyListChange(); + end; +end; + +procedure TForm1.B2Click(Sender: TObject); +var + FindStr, NewStr: string; + I, Flag: Integer; + Item: TBookSourceItem; +begin + Flag := 1; + if ShowReplaceGroup(Self, '滻 - ԴURL', FindStr, NewStr, Flag) then begin + if (FindStr <> '') and (Flag = 0) then + Exit; + for I := 0 to FBookSrcData.Count - 1 do begin + Item := TBookSourceItem(FBookSrcData.O[I]); + if not Assigned(Item) then Continue; + Item.bookSourceUrl := StringReplace(Trim(Item.bookSourceUrl), FindStr, NewStr, [rfReplaceAll, rfIgnoreCase]); + end; + NotifyListChange(); + end; +end; + +procedure TForm1.bookGroupListChange(Sender: TObject); +begin + if FChanging then + Exit; + FChanging := True; + try + EditData.Text := ''; + FIsChange := False; + FCurIndex := -1; + NotifyListChange(1); + finally + FChanging := False; + end; +end; + +procedure TForm1.Button1Click(Sender: TObject); +begin + if Button1.Tag = 0 then begin + Button1.Tag := 1; + Button1.Caption := 'ֹͣ(&S)'; + + FTaskRef := 0; + FWaitStop := 0; + FCheckLastTime := GetTimestamp; + FTaskStartTime := GetTimestamp; + FMaxWorkers := Max(1, StrToIntDef(Edit1.Text, 8)); + Workers.MaxWorkers := FMaxWorkers; + + edtLog.Lines.Clear; + Log('ڳʼ...'); + + Timer1.Enabled := True; + ProgressBar1.Min := 0; + ProgressBar1.Max := 100; + ProgressBar1.Position := 0; + + FAutoFind := CheckBox4.Checked; + FAutoDel := CheckBox1.Checked; + FAllSrc := CheckBox5.Checked; + FAutoScore := CheckBox6.Checked; + + if FAutoDel or FAutoFind then begin + Inc(FTaskRef); + Log('ڴ...'); + Workers.Post(RemoveRePeat, Pointer(Integer(CheckBox3.Checked))); + end; + if CheckBox2.Checked then begin + Inc(FTaskRef); + if not CheckBox1.Checked then + Workers.SendSignal(FWaitCheckBookSourceSingId); + end; + + ShowWaitDlg(); + end else begin + AtomicIncrement(FTaskRef); + if AtomicDecrement(FTaskRef) <= 0 then begin + Button1.Tag := 0; + Button1.Caption := 'ʼ(&B)'; + Timer1.Enabled := False; + FTaskStartTime := 0; + ProgressBar1.Visible := False; + HideWaitDlg; + Log(''); + end else begin + Button1.Tag := 2; + Button1.Caption := 'ֹͣ...'; + AtomicIncrement(FWaitStop); + end; + end; + //Application.ProcessMessages; +end; + +procedure TForm1.Button2Click(Sender: TObject); +begin + ChangeItemIndex(SrcList.ItemIndex, 0); +end; + +procedure TForm1.Button3Click(Sender: TObject); +begin + ChangeItemIndex(SrcList.ItemIndex, SrcList.ItemIndex - 1); +end; + +procedure TForm1.Button4Click(Sender: TObject); +begin + ChangeItemIndex(SrcList.ItemIndex, SrcList.ItemIndex + 1); +end; + +procedure TForm1.Button5Click(Sender: TObject); +begin + ChangeItemIndex(SrcList.ItemIndex, SrcList.Count - 1); +end; + +procedure TForm1.Button6Click(Sender: TObject); +var + url: string; +begin + url := 'http://www.baidu.com/?aaa=0'; + url := TRegEx.Replace(url, '', '{{page$1}}', [roIgnoreCase]); + ShowMessage(url); +end; + +procedure TForm1.A1Click(Sender: TObject); +begin + EditData.SelectAll; +end; + +procedure TForm1.A2Click(Sender: TObject); +begin + OpenDialog1.Title := 'Դļ'; + if OpenDialog1.Execute(Handle) then + AddSrcFile(OpenDialog1.FileName); +end; + +procedure TForm1.AddSrcFile(const FileName: string); +var + Data: JSONArray; + Item: TBookSourceItem; + I: Integer; +begin + Data := JSONArray.Create; + try + Data.LoadFromFile(FileName); + I := Data.Count; + while I > 0 do begin + try + Item := TBookSourceItem(Data.O[0]); + if Assigned(Item) and (Item.bookSourceUrl <> '') then begin + UpdateBookGroup(Item); + FBookSrcData.Add(Data.O[0]); + end; + except + end; + Dec(I); + end; + finally + Data.Free; + NotifyListChange; + end; +end; + +procedure TForm1.C1Click(Sender: TObject); +begin + FBookSrcData.Clear; + NotifyListChange; +end; + +procedure TForm1.C2Click(Sender: TObject); +begin + EditData.CopyToClipboard; +end; + +procedure TForm1.C3Click(Sender: TObject); +var + S: string; + Item, NewItem: TBookSourceItem; +begin + if SrcList.ItemIndex < 0 then Exit; + if not CheckSaveState then Exit; + Item := TBookSourceItem(FFilterList[SrcList.ItemIndex]); + S := InputBox('Դ', 'Դ', Item.bookSourceName); + + NewItem := TBookSourceItem(FBookSrcData.AddChildObject); + NewItem.Parse(Item.ToString); + NewItem.bookSourceName := S; + + NotifyListChange; + if FFilterList.Count > 0 then + SrcList.ItemIndex := FFilterList.Count - 1; +end; + +procedure TForm1.C4Click(Sender: TObject); +begin + CopySelected; +end; + +function TForm1.CheckBookSourceItem(Item: TBookSourceItem; RaiseErr: Boolean; OutLog: TStrings): Boolean; +var + Http: THttpClient; + Header: THttpHeaders; +begin + Result := False; + try + if not Assigned(Item) then Exit; + Http := THttpClient.Create(nil); + if Assigned(OutLog) then begin + Http.ConnectionTimeOut := 6000; + Http.RecvTimeOut := 30000; + end else begin + Http.ConnectionTimeOut := 30000; + Http.RecvTimeOut := 30000; + end; + Header := THttpHeaders.Create; + + FAutoScore := True; + Result := CheckBookSourceItem(Item, Http, Header, RaiseErr, OutLog); + + finally + FreeAndNil(Http); + FreeAndNil(Header); + end; +end; + +procedure TForm1.ChangeItemIndex(const CurIndex, NewIndex: Integer); +var + Item1, Item2: TBookSourceItem; + I1, I2, NIndex: Integer; +begin + if CurIndex < 0 then Exit; + if SrcList.Count <= 1 then Exit; + NIndex := NewIndex; + if NIndex >= SrcList.Count then + NIndex := SrcList.Count - 1; + if NIndex < 0 then Exit; + if NIndex = CurIndex then Exit; + + Item1 := TBookSourceItem(FFilterList[CurIndex]); + Item2 := TBookSourceItem(FFilterList[NIndex]); + + I1 := FBookSrcData.IndexOfObject(Item1); + I2 := FBookSrcData.IndexOfObject(Item2); + + if I1 < 0 then Exit; + if I2 < 0 then Exit; + + FBookSrcData.MoveItem(I1, I2); + FCurIndex := NIndex; + NotifyListChange(1); +end; + +function TForm1.CheckBookSourceItem(Item: TBookSourceItem; Http: THttpClient; + Header: THttpHeaders; RaiseErr: Boolean; OutLog: TStrings): Boolean; + + function ValidationURL(const BaseURL, URL: string): string; + begin + if (BaseURL <> '') and (BaseURL <> '-') and (URL <> '-') and (Pos('://', URL) < 1) then begin + if URL = '' then + Result := BaseURL + else if URL[1] = '/' then begin + if BaseURL[Length(BaseURL)] = '/' then + Result := BaseURL + URL.Substring(2) + else + Result := BaseURL + URL + end else begin + if BaseURL[Length(BaseURL)] = '/' then + Result := BaseURL + URL + else + Result := BaseURL + '/' + URL; + end; + end else + Result := URL; + Result := StringReplace(Result, '=searchPage', '=1', [rfReplaceAll, rfIgnoreCase]); + end; + + function CheckURL(const URL, Title: string; RaiseErr: Boolean = False; Try404: Boolean = False): Boolean; + var + Resp: THttpResult; + Msg: string; + begin + Result := (URL <> '') and (URL <> '-') and (Pos('http', LowerCase(URL)) = 1); + if Result then begin + try + Resp := Http.Get(UrlEncodeEx(URL), nil, Header); + if (Resp.StatusCode = 200) or (Try404 and (Resp.StatusCode >= 400) and (Resp.StatusCode < 500)) then begin + Result := True; + if Assigned(OutLog) then OutLog.Add(Title + 'ӳɹ.'); + end else begin + Result := False; + Msg := Format('%sʧ(StatusCode: %d, %s).', [Title, Resp.StatusCode, URL]); + if Assigned(OutLog) then OutLog.Add(Msg); + if RaiseErr then + raise Exception.Create(Msg); + end; + except + Result := False; + Msg := Format('%sԳ(%s).', [Title, Exception(ExceptObject).Message]); + if Assigned(OutLog) then OutLog.Add(Msg); + if RaiseErr then + raise Exception.Create(Msg); + end; + end else if Assigned(OutLog) then + OutLog.Add('Ч' + Title + '.'); + end; + + // ⷢб + function CheckFindURL(AItem: TBookSourceItem; const BaseURL, Text, Title: string; RaiseErr: Boolean): Boolean; + var + I, J, L: Integer; + Msg, Item, SubTitle, AURL: string; + begin + Result := False; + if Text = '' then begin + Result := True; + Exit; + end; + try + J := 1; + while (J > 0) and (J <= Length(Text)) do begin + I := PosEx('&&', Text, J); + L := 2; + if I <= 0 then begin + I := PosEx(#$A, Text, J); + L := 1; + end; + if I > 0 then begin + Item := MidStr(Text, J, I - J); + J := I + L; + end else begin + Item := Trim(RightStr(Text, Length(Text) - J + 1)); + J := Length(Text) + 1; + end; + + if (Item = #$A) or (Item = #13) then + Continue; + + Item := StringReplace(Item, #13, '', [rfReplaceAll]); + Item := StringReplace(Item, #10, '', [rfReplaceAll]); + Item := StringReplace(Item, '\n', '', [rfReplaceAll, rfIgnoreCase]); + Item := Trim(Item); + + I := Pos('::', Item); + if (Item = '') or (I < 1) then begin + if FAutoScore then + AItem.score := AItem.score - 20; + if Assigned(OutLog) then + OutLog.Add('бʽ'); + Continue; + end else begin + SubTitle := Trim(LeftStr(Item, I - 1)); + AURL := Trim(RightStr(Item, Length(Item) - I - 1)); + if not CheckURL(ValidationURL(BaseURL, AURL), 'б' + SubTitle + '') then + AItem.score := AItem.score - 1; + end; + end; + except + Result := False; + Msg := Format('%sԳ(%s).', [Title, Exception(ExceptObject).Message]); + if Assigned(OutLog) then OutLog.Add(Msg); + if RaiseErr then + raise Exception.Create(Msg); + end; + end; + +var + T: Int64; + AScore, I: Integer; + URL: string; + Json: JSONObject; +begin + Result := False; + if not Assigned(Item) then Exit; + Json := JSONObject.Create; + try + if Item.bookSourceUrl <> '' then begin + T := GetTimestamp; + if FAutoScore then + Item.score := 0; + Header.Clear; + Header.Add('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36'); + if Item.header <> '' then begin + if Json.Parse(Item.header, True) then begin + for I := 0 to Json.Count do + Header.Add(Json.Items[i].FName, Json.Items[i].AsString); + end; + end; + + // ԴURL + Result := CheckURL(Trim(Item.bookSourceUrl), 'ԴURL', RaiseErr, True); + + if Result then begin + if FAutoScore then + Item.score := Item.score + 50; + // URL + URL := Trim(Item.searchUrl); + if CheckURL(ValidationURL(Trim(Item.bookSourceUrl), URL), 'ַ', RaiseErr) then begin + if FAutoScore then + Item.score := Item.score + 50; + end; + // ⷢб + if FAutoScore or (Assigned(OutLog)) then + CheckFindURL(Item, Trim(Item.bookSourceUrl), Trim(Item.exploreUrl), '', RaiseErr); + end; + + if Assigned(OutLog) then + OutLog.Add(Format('ʱ %d ms.', [GetTimestamp - T])); + end else begin + if Assigned(OutLog) then + OutLog.Add('ԴURLδ.'); + raise Exception.Create('ԴURLЧ'); + end; + finally + FreeAndNil(Json); + end; +end; + +function TForm1.CheckItem(Item: TBookSourceItem): Boolean; +begin + Result := Assigned(Item) and (Item.bookSourceUrl <> ''); +end; + +function TForm1.CheckSaveState: Boolean; +var + LR: Integer; +begin + if FIsChange and (FCurIndex >= 0) and (FCurIndex < SrcList.Count) then begin + LR := MessageBox(Handle, 'ԴѾ޸ģǷ񱣴棿', 'ʾ', 64 + MB_YESNOCANCEL); + if LR = IDCANCEL then begin + Result := False; + Exit; + end; + if LR = IDYES then + S1Click(S1); + end; + Result := True; +end; + +procedure TForm1.CopySelected; +var + I: Integer; + Item: JSONObject; +begin + FBookCopyData.Clear; + for I := SrcList.Count - 1 downto 0 do begin + if SrcList.Selected[I] then begin + Item := FBookCopyData.AddChildObject; + Item.Assign(JSONObject(FFilterList[I])); + end; + end; +end; + +procedure TForm1.CutSelectedt; +begin + CopySelected; + RemoveSelected; +end; + +procedure TForm1.D1Click(Sender: TObject); +begin + RemoveSelected; +end; + +procedure TForm1.DispLog; +begin + if FTaskStartTime > 0 then begin + if ProgressBar1.Visible then + StatusBar1.Panels[1].Text := Format('%s (%d/%d, %d%%) (ʱ: %dms)', + [FStateMsg, ProgressBar1.Position, ProgressBar1.Max, Round(ProgressBar1.Position / ProgressBar1.Max * 100), + GetTimestamp - FTaskStartTime]) + else + StatusBar1.Panels[1].Text := Format('%s (ʱ: %dms)', [FStateMsg, GetTimestamp - FTaskStartTime]) + end else + StatusBar1.Panels[1].Text := FStateMsg; +end; + +procedure TForm1.DoCheckBookSourceItem(AJob: PJob); +var + Item: TBookSourceItem; + State: PProcessState; + V: Integer; + IsOK: Boolean; + Http: THttpClient; + Header: THttpHeaders; +begin + V := 0; + try + Http := THttpClient.Create(nil); + Http.ConnectionTimeOut := 30000; + Http.RecvTimeOut := 30000; + Http.AllowCookies := False; + Header := THttpHeaders.Create; + + while (not AJob.IsTerminated) and (FWaitStop = 0) do begin + V := AtomicIncrement(FCurCheckIndex) - 1; + + FLocker.Enter; + if (GetTimestamp - FCheckLastTime) > 100 then begin + FCheckLastTime := GetTimestamp; + New(State); + State.Min := 0; + State.Max := FCheckCount; + State.Value := FCheckFinish; + Workers.Post(DoUpdateProcess, State, True); + Sleep(10); + end; + FLocker.Leave; + + if V < FCheckCount then begin + Item := TBookSourceItem(FBookSrcData.O[V]); + if not Assigned(Item) then Exit; + + if (FAllSrc) or (FFilterList.IndexOf(Item) >= 0) then begin + + try + IsOK := CheckBookSourceItem(Item, Http, Header); + except + IsOK := False; + end; + + if IsOK then + Item.RemoveGroup('ʧЧ') + else + Item.AddGroup('ʧЧ'); + + Sleep(50); + end; + + AtomicIncrement(FCheckFinish); + end else + Break; + + end; + finally + + if (V = FCheckCount) or (FWaitStop > 0) then begin + Sleep(100); + while not AJob.IsTerminated do begin + if (FCheckFinish >= FCheckCount) or (FWaitStop > 0) then + Break; + + FLocker.Enter; + if (GetTimestamp - FCheckLastTime) > 1000 then begin + FCheckLastTime := GetTimestamp; + New(State); + State.Min := 0; + State.Max := FCheckCount; + State.Value := FCheckFinish; + Workers.Post(DoUpdateProcess, State, True); + Sleep(10); + end; + FLocker.Leave; + + Sleep(100); + end; + Workers.Post(TaskFinish, nil, True); + end; + + FreeAndNil(Http); + FreeAndNil(Header); + end; +end; + +procedure TForm1.DoNotifyDataChange(AJob: PJob); +begin + NotifyListChange; +end; + +procedure TForm1.DoUpdateProcess(AJob: PJob); +var + V: PProcessState; +begin + if not Assigned(Self) then Exit; + V := AJob.Data; + if V = nil then + ProgressBar1.Visible := False + else begin + ProgressBar1.Min := V.Min; + ProgressBar1.Max := V.Max; + ProgressBar1.Position := V.Value; + ProgressBar1.Visible := Button1.Tag <> 0; + if V.NeedFree then + Dispose(V); + end; +end; + +procedure TForm1.E1Click(Sender: TObject); +begin + if SrcList.ItemIndex < 0 then Exit; + EditSource(TBookSourceItem(FFilterList[SrcList.ItemIndex])); +end; + +procedure TForm1.E2Click(Sender: TObject); +var + FName: JSONString; +begin + if SaveDialog1.Execute(Handle) then begin + FName := SaveDialog1.FileName; + if ExtractFileExt(FName) = '' then + FName := FName + '.json'; + FBookSrcData.SaveToFile(FName, 4, YxdStr.TTextEncoding.teUTF8, False); + end; +end; + +procedure TForm1.EditDataChange(Sender: TObject); +begin + FIsChange := True; +end; + +procedure TForm1.EditSource(Item: TBookSourceItem); +begin + ShowEditSource(Item, + procedure (Item: TBookSourceItem) + begin + if FBookSrcData.IndexOfObject(Item) < 0 then + FBookSrcData.Add(JSONObject(Item)); + NotifyListChange; + if (FCurIndex >= 0) and (FCurIndex < FFilterList.Count) then begin + if TObject(FFilterList[FCurIndex]) = Item then begin + EditData.Text := TBookSourceItem(FFilterList[FCurIndex]).ToString(4); + FIsChange := False; + end; + end; + end + ); +end; + +procedure TForm1.ExportSelectedToFile; +var + FName: JSONString; + I: Integer; + Item: TBookSourceItem; + Items: JSONArray; +begin + if SrcList.SelCount = 0 then + Exit; + if SaveDialog1.Execute(Handle) then begin + FName := SaveDialog1.FileName; + if ExtractFileExt(FName) = '' then + FName := FName + '.json'; + Items := JSONArray.Create; + try + for I := 0 to SrcList.Count - 1 do begin + if SrcList.Selected[I] then begin + Item := TBookSourceItem(JSONObject(FFilterList[I])); + if not Assigned(Item) then Continue; + Items.AddChildObject.Assign(Item); + end; + end; + Items.SaveToFile(FName, 4, YxdStr.TTextEncoding.teUTF8, False); + finally + Items.Free; + end; + end; +end; + +procedure TForm1.F2Click(Sender: TObject); +begin + FindSource(InputBox('Դ', 'ҪҵĹؼ', '')); +end; + +procedure TForm1.FindSource(const FindStr: string); +var + I, J: Integer; + Item: TBookSourceItem; +begin + if FindStr = '' then Exit; + FLastFindSource := FindStr; + J := SrcList.ItemIndex + 1; + if J < 0 then J := 0; + for I := J to SrcList.Count - 1 do begin + Item := TBookSourceItem(JSONObject(FFilterList[I])); + if not Assigned(Item) then Continue; + J := Pos(FindStr, Item.bookSourceName); + if (Pos(FindStr, Item.bookSourceName) > 0) or (URL1.Checked and (Pos(FindStr, Item.bookSourceUrl) > 0)) then begin + SrcList.ClearSelection; + SrcList.ItemIndex := I; + SrcList.Selected[I] := True; + SrcList.ScrollBy(0, SrcList.ItemHeight * I + 1); + Exit; + end; + end; + LogD('Ҳ "' + FindStr + '" '); +end; + +procedure TForm1.FormCreate(Sender: TObject); +begin + JsonNameAfterSpace := True; + JsonCaseSensitive := False; + FBookCopyData := JSONArray.Create; + FBookSrcData := JSONArray.Create; + FBookGroups := TStringHash.Create(997); + FFilterList := TList.Create; + FLocker := TCriticalSection.Create; + + FWaitCheckBookSourceSingId := Workers.RegisterSignal('WaitCheckBookSource'); + Workers.PostWait(WaitCheckBookSource, FWaitCheckBookSourceSingId); +end; + +procedure TForm1.FormDestroy(Sender: TObject); +begin + FreeAndNil(FBookSrcData); + FreeAndNil(FBookGroups); + FreeAndNil(FFilterList); + FreeAndNil(FBookCopyData); + FreeAndNil(FLocker); +end; + +procedure TForm1.FormShow(Sender: TObject); +begin + DragAcceptFiles(SrcList.Handle, True); + DragAcceptFiles(StaticText1.Handle, True); + + OldListWndProc := SrcList.WindowProc; + OldTextWndProc := StaticText1.WindowProc; + SrcList.WindowProc := SrcListWndProc; + StaticText1.WindowProc := SrcListTextWndProc; + + NotifyListChange; +end; + +procedure TForm1.G1Click(Sender: TObject); +var + IsDX: Boolean; +begin + if FLastSortFlag <> 2 then begin + FLastSortFlag := 2; + IsDX := False; + end else begin + IsDX := True; + FLastSortFlag := 0; + end; + FBookSrcData.Sort( + function (A, B: Pointer): Integer + var + Item1: PJSONValue absolute A; + Item2: PJSONValue absolute B; + S1, S2: string; + begin + if (Item1.FType = Item2.FType) and (Item1.FType = jdtObject) and + (Item1.AsJsonObject <> nil) and (Item2.AsJsonObject <> nil) + then begin + S1 := TBookSourceItem(Item1.AsJsonObject).bookSourceGroup; + S2 := TBookSourceItem(Item2.AsJsonObject).bookSourceGroup; + if IsDX then + Result := CompareStr(S2, S1) + else + Result := CompareStr(S1, S2); + end else + Result := 0; + end + ); + NotifyListChange(1); +end; + +procedure TForm1.H2Click(Sender: TObject); +var + FindStr, NewStr: string; + I, Flag: Integer; + Item: TBookSourceItem; +begin + Flag := 0; + if ShowReplaceGroup(Self, '滻 - Դ', FindStr, NewStr, Flag) then begin + if (FindStr <> '') and (Flag = 0) then + Exit; + for I := 0 to FBookSrcData.Count - 1 do begin + Item := TBookSourceItem(FBookSrcData.O[I]); + if not Assigned(Item) then Continue; + if Flag = 0 then begin + Item.bookSourceGroup := StringReplace(Trim(Item.bookSourceGroup), FindStr, NewStr, [rfReplaceAll, rfIgnoreCase]); + end else begin + if NewStr = '' then + Item.RemoveGroup(FindStr) + else + Item.ReplaceGroup(FindStr, NewStr); + end; + end; + NotifyListChange(); + end; +end; + +procedure TForm1.I1Click(Sender: TObject); +var + Msg: string; +begin + Msg := Application.Title + sLineBreak + 'YangYxd Ȩ 2019'; + MessageBox(Handle, PChar(Msg), '', 64); +end; + +procedure TForm1.Log(const Msg: string); +begin + LogD(Msg); + FStateMsg := Msg; + DispLog(); +end; + +procedure TForm1.LogD(const Msg: string); +begin + edtLog.Lines.Add(Format('[%s] %s', [FormatDateTime('hh:mm:ss.zzz', Now), Msg])); +end; + +procedure TForm1.N14Click(Sender: TObject); +begin + FindSource(FLastFindSource); +end; + +procedure TForm1.N15Click(Sender: TObject); +var + I: Integer; + GName: string; + Item: TBookSourceItem; +begin + GName := InputBox('ӷ', '', ''); + if GName = '' then Exit; + + for I := 0 to SrcList.Count - 1 do begin + if SrcList.Selected[I] then begin + Item := TBookSourceItem(JSONObject(FFilterList[I])); + if not Assigned(Item) then Continue; + Item.AddGroup(GName); + end; + end; + NotifyListChange; +end; + +procedure TForm1.N17Click(Sender: TObject); +var + I: Integer; + GName: string; + Item: TBookSourceItem; +begin + GName := InputBox('ӷ', '', ''); + if GName = '' then Exit; + + for I := 0 to SrcList.Count - 1 do begin + if SrcList.Selected[I] then begin + Item := TBookSourceItem(JSONObject(FFilterList[I])); + if not Assigned(Item) then Continue; + Item.RemoveGroup(GName); + end; + end; + NotifyListChange; +end; + +procedure TForm1.N18Click(Sender: TObject); +begin + ExportSelectedToFile; +end; + +procedure TForm1.N7Click(Sender: TObject); +var + Item: TBookSourceItem; +begin + Item := TBookSourceItem(JSONObject.Create); + EditSource(Item); +end; + +procedure TForm1.NotifyListChange(Flag: Integer); +var + I, J: Integer; + Key: string; + Item: TBookSourceItem; + + function EqualsBookType(const ABookType: string): Boolean; + begin + Result := (FBookType = '') or (FBookType = UpperCase(ABookType)) or + ((FBookType = 'TEXT') and (ABookType = '')); + end; + +begin + J := FCurIndex; + + if Flag = 0 then begin + for I := 0 to FBookSrcData.Count - 1 do + UpdateBookGroup(TBookSourceItem(FBookSrcData.O[I])); + bookGroupList.Items.Clear; + bookGroupList.Items.Add(''); + bookGroupList.Items.Add('ʧЧ'); + FBookGroups.GetKeyList(bookGroupList.Items); + end; + + FFilterList.Clear; + Key := LowerCase(bookGroupList.Text); + if Key <> '' then begin + for I := 0 to FBookSrcData.Count - 1 do begin + Item := TBookSourceItem(FBookSrcData.O[I]); + if Item.bookSourceType = 0 then begin // EqualsBookType(Item.bookSourceType) + if (Pos(Key, Item.bookSourceGroup) > 0) or (Pos(Key, Item.bookSourceName) > 0) then + FFilterList.Add(Item); + end; + end; + end else begin + for I := 0 to FBookSrcData.Count - 1 do begin + Item := TBookSourceItem(FBookSrcData.O[I]); + if Item.bookSourceType = 0 then // EqualsBookType(Item.bookSourceType) + FFilterList.Add(Item); + end; + end; + + SrcList.Count := FFilterList.Count; + StaticText1.Visible := SrcList.Count = 0; + if (J < SrcList.Count) and (J >= 0) then begin + SrcList.ClearSelection; + SrcList.ItemIndex := J; + SrcList.Selected[J] := True; + SrcListClick(SrcList); + end; + + SrcList.ShowHint := SrcList.Count = 0; + StatusBar1.Panels[0].Text := Format('Դ%d, ǰ: %d', [FBookSrcData.Count, FFilterList.Count]); +end; + +procedure TForm1.O1Click(Sender: TObject); +begin + OpenDialog1.Title := 'Դļ'; + if OpenDialog1.Execute(Handle) then begin + FBookSrcData.Clear; + AddSrcFile(OpenDialog1.FileName); + end; +end; + +procedure TForm1.O2Click(Sender: TObject); +var + IsDX: Boolean; +begin + if FLastSortFlag <> 4 then begin + FLastSortFlag := 4; + IsDX := False; + end else begin + IsDX := True; + FLastSortFlag := 0; + end; + FBookSrcData.Sort( + function (A, B: Pointer): Integer + var + Item1: PJSONValue absolute A; + Item2: PJSONValue absolute B; + begin + if (Item1.FType = Item2.FType) and (Item1.FType = jdtObject) and + (Item1.AsJsonObject <> nil) and (Item2.AsJsonObject <> nil) + then begin + if IsDX then + Result := TBookSourceItem(Item1.AsJsonObject).score - TBookSourceItem(Item2.AsJsonObject).score + else + Result := TBookSourceItem(Item2.AsJsonObject).score - TBookSourceItem(Item1.AsJsonObject).score; + end else + Result := 0; + end + ); + NotifyListChange(1); +end; + +procedure TForm1.P1Click(Sender: TObject); +begin + EditData.PasteFromClipboard; +end; + +procedure TForm1.P2Click(Sender: TObject); +begin + Paste; +end; + +procedure TForm1.Paste; +var + I: Integer; +begin + for I := 0 to FBookCopyData.Count - 1 do + FBookSrcData.AddChildObject.Assign(FBookCopyData.O[I]); + NotifyListChange(); +end; + +procedure TForm1.PopupMenu1Popup(Sender: TObject); +begin + C4.Enabled := SrcList.SelCount > 0; + X2.Enabled := C4.Enabled; + C3.Enabled := C4.Enabled; + E1.Enabled := C4.Enabled; + D1.Enabled := C4.Enabled; + P2.Enabled := FBookCopyData.Count > 0; + N14.Enabled := FLastFindSource <> ''; +end; + +procedure TForm1.PopupMenu2Popup(Sender: TObject); +begin + S1.Enabled := SrcList.ItemIndex >= 0; + P1.Enabled := EditData.CanPaste; + X1.Enabled := EditData.SelLength > 0; + C2.Enabled := X1.Enabled; + R1.Enabled := EditData.CanUndo; + Z1.Enabled := EditData.CanRedo; + W1.Checked := EditData.WordWrap; +end; + +procedure TForm1.R1Click(Sender: TObject); +begin + EditData.Undo; +end; + +procedure TForm1.R2Click(Sender: TObject); +begin + ShellExecute(0, 'OPEN', PChar('https://github.com/yangyxd/MyBookshelf'), nil, nil, SW_SHOWMAXIMIZED) +end; + +procedure TForm1.RadioButton1Click(Sender: TObject); +begin + BookType := ''; +end; + +procedure TForm1.RadioButton2Click(Sender: TObject); +begin + BookType := 'TEXT'; +end; + +procedure TForm1.RadioButton3Click(Sender: TObject); +begin + BookType := 'AUDIO'; +end; + +procedure TForm1.RadioButton4Click(Sender: TObject); +begin + BookType := 'IMAGE'; +end; + +procedure TForm1.RemoveRepeat(AJob: PJob); +var + CheckName: Boolean; + + function Equals(A, B: TBookSourceItem): Boolean; + begin + Result := + (LowerCase(A.bookSourceUrl) = LowerCase(B.bookSourceUrl)) and + (LowerCase(A.loginUrl) = LowerCase(B.loginUrl)) and + (LowerCase(A.header) = LowerCase(B.header)) and + (LowerCase(A.exploreUrl) = LowerCase(B.exploreUrl)) and + (LowerCase(A.ruleContent_content) = LowerCase(B.ruleContent_content)) and + (LowerCase(A.ruleContent_nextContentUrl) = LowerCase(B.ruleContent_nextContentUrl)) and + (LowerCase(A.ruleSearch_kind) = LowerCase(B.ruleSearch_kind)) and + (LowerCase(A.ruleSearch_lastChapter) = LowerCase(B.ruleSearch_lastChapter)) and + (LowerCase(A.ruleSearch_name) = LowerCase(B.ruleSearch_name)) and + (A.bookSourceType = B.bookSourceType) and + (LowerCase(A.ruleSearch_bookUrl) = LowerCase(B.ruleSearch_bookUrl)) and + (LowerCase(A.ruleSearch_coverUrl) = LowerCase(B.ruleSearch_coverUrl)) and + (LowerCase(A.ruleSearch_intro) = LowerCase(B.ruleSearch_intro)) and + (LowerCase(A.bookUrlPattern) = LowerCase(B.bookUrlPattern)) and + (LowerCase(A.ruleToc_chapterName) = LowerCase(B.ruleToc_chapterName)) and + (LowerCase(A.ruleToc_chapterList) = LowerCase(B.ruleToc_chapterList)) and + (LowerCase(A.ruleToc_chapterUrl) = LowerCase(B.ruleToc_chapterUrl)) and + (LowerCase(A.ruleToc_nextTocUrl) = LowerCase(B.ruleToc_nextTocUrl)) and + (LowerCase(A.ruleContent_webJs) = LowerCase(B.ruleContent_webJs)) and + (LowerCase(A.ruleBookInfo_author) = LowerCase(B.ruleBookInfo_author)) and + (LowerCase(A.ruleBookInfo_name) = LowerCase(B.ruleBookInfo_name)) and + (LowerCase(A.ruleExplore_bookList) = LowerCase(B.ruleExplore_bookList)) and + (LowerCase(A.ruleExplore_name) = LowerCase(B.ruleExplore_name)) and + (LowerCase(A.ruleExplore_lastChapter) = LowerCase(B.ruleExplore_lastChapter)); + if not CheckName then + Result := Result and + (LowerCase(A.bookSourceName) = LowerCase(B.bookSourceName)) and + (LowerCase(A.bookSourceGroup) = LowerCase(B.bookSourceGroup)); + end; + +var + I, J, LastCount, ST: Integer; + Item: TBookSourceItem; + T: TProcessState; + State: PProcessState; + List: TList; +begin + I := 0; + LastCount := FBookSrcData.Count; + CheckName := Boolean(Integer(AJob.Data)); + + T.STime := GetTimestamp; + T.Min := 0; + T.Value := 0; + ST := 1000; + + try + + while I < FBookSrcData.Count do begin + Item := TBookSourceItem(FBookSrcData.O[I]); + Inc(I); + + if (not FAllSrc) and (FFilterList.IndexOf(Item) < 0) then + Continue; + + if FAutoDel then begin + for J := FBookSrcData.Count - 1 downto I do begin + if Equals(Item, TBookSourceItem(FBookSrcData.O[J])) then + FBookSrcData.Remove(J); + end; + end; + + if FAutoFind then begin + if Item.exploreUrl <> '' then + Item.AddGroup('') + else + Item.RemoveGroup(''); + end; + + if AJob.IsTerminated or (FWaitStop > 0) then + Break; + if GetTimestamp - T.STime > ST then begin + ST := 200; + T.Value := I; + T.Max := FBookSrcData.Count; + New(State); + State^ := T; + State.NeedFree := True; + Workers.Post(DoUpdateProcess, State, True); + end; + end; + + finally + if LastCount <> FBookSrcData.Count then + Workers.Post(DoNotifyDataChange, nil, True); + Sleep(100); + Workers.Post(TaskFinish, nil, True); + end; +end; + +procedure TForm1.RemoveSelected; +var + I, V: Integer; +begin + for I := SrcList.Count - 1 downto 0 do begin + if SrcList.Selected[I] then begin + V := FBookSrcData.IndexOfObject(JSONObject(FFilterList[I])); + if V >= 0 then + FBookSrcData.Remove(V); + end; + end; + NotifyListChange; +end; + +procedure TForm1.S1Click(Sender: TObject); +var + S: string; + Item: TBookSourceItem; +begin + if (FCurIndex < 0) or (FCurIndex >= SrcList.Count) then Exit; + Item := TBookSourceItem(FFilterList[FCurIndex]); + if not Assigned(Item) then Exit; + try + FIsChange := False; + S := Item.ToString(); + Item.Parse(EditData.Text); + if not CheckItem(Item) then + Item.Parse(S); + finally + NotifyListChange; + end; +end; + +procedure TForm1.S2Click(Sender: TObject); +var + IsDX: Boolean; +begin + if FLastSortFlag <> 1 then begin + FLastSortFlag := 1; + IsDX := False; + end else begin + IsDX := True; + FLastSortFlag := 0; + end; + FBookSrcData.Sort( + function (A, B: Pointer): Integer + var + Item1: PJSONValue absolute A; + Item2: PJSONValue absolute B; + S1, S2: string; + begin + if (Item1.FType = Item2.FType) and (Item1.FType = jdtObject) and + (Item1.AsJsonObject <> nil) and (Item2.AsJsonObject <> nil) + then begin + S1 := TBookSourceItem(Item1.AsJsonObject).bookSourceName; + S2 := TBookSourceItem(Item2.AsJsonObject).bookSourceName; + if IsDX then + Result := CompareStr(S2, S1) + else + Result := CompareStr(S1, S2); + end else + Result := 0; + end + ); + NotifyListChange(1); +end; + +procedure TForm1.S3Click(Sender: TObject); +begin + ExportSelectedToFile(); +end; + +procedure TForm1.SetBookType(const Value: string); +begin + if UpperCase(FBookType) <> UpperCase(Value) then begin + FBookType := UpperCase(Value); + NotifyListChange(); + end; +end; + +procedure TForm1.SpeedButton1Click(Sender: TObject); +begin + edtLog.Lines.Clear; +end; + +procedure TForm1.SrcListClick(Sender: TObject); +begin + if SrcList.ItemIndex < 0 then Exit; + if not CheckSaveState then Exit; + FCurIndex := SrcList.ItemIndex; + EditData.Text := TBookSourceItem(FFilterList[FCurIndex]).ToString(4); + FIsChange := False; +end; + +procedure TForm1.SrcListData(Control: TWinControl; Index: Integer; + var Data: string); +var + Item: TBookSourceItem; +begin + if Index < FBookSrcData.Count then begin + Item := TBookSourceItem(FFilterList[index]); + Data := Format('%s%s', [Item.bookSourceGroup, Item.bookSourceName]); + end else + Data := ''; +end; + +procedure TForm1.SrcListDblClick(Sender: TObject); +begin + E1Click(E1); +end; + +procedure TForm1.SrcListKeyDown(Sender: TObject; var Key: Word; + Shift: TShiftState); + + procedure PasteItems(); + var + pGlobal : Thandle; + begin + OpenClipboard(Handle); + try + pGlobal := GetClipboardData(CF_HDROP); //ȡļ + if pGlobal > 0 then + AddSrcFiles(pGlobal); + finally + CloseClipboard; + end; + end; + +begin + if Key = VK_DELETE then begin + RemoveSelected(); + end else if Key = Ord('V') then begin // ճ + PasteItems(); + end; +end; + +procedure TForm1.SrcListTextWndProc(var Message: TMessage); +begin + if Message.Msg = WM_DROPFILES then + WMDropFiles(TWMDropFiles(Message)) + else + OldTextWndProc(Message); +end; + +procedure TForm1.SrcListWndProc(var Message: TMessage); +begin + if Message.Msg = WM_DROPFILES then + WMDropFiles(TWMDropFiles(Message)) + else + OldListWndProc(Message); +end; + +procedure TForm1.T1Click(Sender: TObject); +var + Item: TBookSourceItem; +begin + Item := TBookSourceItem(JSONObject.Create); + try + Item.Parse(EditData.Text); + if CheckBookSourceItem(Item, True, edtLog.Lines) then + LogD('ϲ, ͨ!') + else + LogD('Դ쳣!'); + EditData.Text := Item.ToString(4); + finally + FreeAndNil(Item); + end; +end; + +procedure TForm1.TaskFinish(AJob: PJob); +var + I: Integer; +begin + I := AtomicDecrement(FTaskRef); + if (I <= 0) or (FWaitStop > 0) then begin + if (I = 0) and Assigned(Self) and (not (csDestroying in ComponentState)) then begin + NotifyListChange(); + Button1Click(Button1); + end; + end else if not (csDestroying in ComponentState) then begin + Log('УԴ...'); + Workers.SendSignal(FWaitCheckBookSourceSingId); + end; +end; + +procedure TForm1.Timer1Timer(Sender: TObject); +begin + DispLog; +end; + +procedure TForm1.U1Click(Sender: TObject); +var + Item: TBookSourceItem; +begin + Item := TBookSourceItem(JSONObject.Create); + try + Item.Parse(EditData.Text); + Item.lastUpdateTime := GetCurJavaDateTime; + finally + FreeAndNil(Item); + end; +end; + +procedure TForm1.UpdateBookGroup(Item: TBookSourceItem); +var + J: Integer; + ARef: Number; + ABookGroup: TArray; + AGroup: string; +begin + ABookGroup := Item.GetGroupList; + + for J := 0 to High(ABookGroup) do begin + ARef := 0; + AGroup := Trim(ABookGroup[J]); + FBookGroups.TryGetValue(AGroup, ARef); + Inc(ARef); + FBookGroups.AddOrUpdate(AGroup, ARef); + end; +end; + +procedure TForm1.URL1Click(Sender: TObject); +begin + TMenuItem(Sender).Checked := not TMenuItem(Sender).Checked; +end; + +procedure TForm1.W1Click(Sender: TObject); +begin + EditData.WordWrap := not W1.Checked; +end; + +procedure TForm1.W2Click(Sender: TObject); +begin + ShellExecute(0, 'OPEN', PChar('http://www.cnblogs.com/yangyxd/'), nil, nil, SW_SHOWMAXIMIZED) +end; + +procedure TForm1.W3Click(Sender: TObject); +var + IsDX: Boolean; +begin + if FLastSortFlag <> 3 then begin + FLastSortFlag := 3; + IsDX := False; + end else begin + IsDX := True; + FLastSortFlag := 0; + end; + FBookSrcData.Sort( + function (A, B: Pointer): Integer + var + Item1: PJSONValue absolute A; + Item2: PJSONValue absolute B; + begin + if (Item1.FType = Item2.FType) and (Item1.FType = jdtObject) and + (Item1.AsJsonObject <> nil) and (Item2.AsJsonObject <> nil) + then begin + if IsDX then + Result := TBookSourceItem(Item1.AsJsonObject).weight - TBookSourceItem(Item2.AsJsonObject).weight + else + Result := TBookSourceItem(Item2.AsJsonObject).weight - TBookSourceItem(Item1.AsJsonObject).weight; + end else + Result := 0; + end + ); + NotifyListChange(1); +end; + +procedure TForm1.WaitCheckBookSource(AJob: PJob); +var + I, J: Integer; +begin + if FBookSrcData.Count > 0 then begin + FCheckCount := FBookSrcData.Count; + FCurCheckIndex := 0; + FCheckFinish := 0; + J := Min(FBookSrcData.Count, FMaxWorkers); + for I := 0 to J - 1 do begin + if AJob.IsTerminated then + Break; + Workers.Post(DoCheckBookSourceItem, nil); + end; + end else + Workers.Post(TaskFinish, nil, True); +end; + +procedure TForm1.WMDropFiles(var Msg: TWMDropFiles); +begin + AddSrcFiles(Msg.Drop); +end; + +procedure TForm1.X1Click(Sender: TObject); +begin + EditData.CopyToClipboard; + EditData.SelText := ''; +end; + +procedure TForm1.X2Click(Sender: TObject); +begin + CutSelectedt; +end; + +procedure TForm1.Z1Click(Sender: TObject); +begin + EditData.Redo; +end; + +end. diff --git a/tool/书源整理工具/uFrmReplaceGroup.dfm b/tool/书源整理工具/uFrmReplaceGroup.dfm new file mode 100644 index 000000000..4554a0263 --- /dev/null +++ b/tool/书源整理工具/uFrmReplaceGroup.dfm @@ -0,0 +1,80 @@ +object frmReplaceGroup: TfrmReplaceGroup + Left = 0 + Top = 0 + BorderStyle = bsDialog + ClientHeight = 166 + ClientWidth = 345 + Color = clWindow + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + Position = poMainFormCenter + DesignSize = ( + 345 + 166) + PixelsPerInch = 96 + TextHeight = 13 + object Label1: TLabel + Left = 24 + Top = 16 + Width = 60 + Height = 13 + Caption = #26597#25214#20869#23481#65306 + end + object Label2: TLabel + Left = 24 + Top = 63 + Width = 60 + Height = 13 + Caption = #26367#25442#20869#23481#65306 + end + object Edit1: TEdit + Left = 24 + Top = 35 + Width = 289 + Height = 21 + TabOrder = 0 + end + object Edit2: TEdit + Left = 24 + Top = 82 + Width = 289 + Height = 21 + TabOrder = 1 + end + object CheckBox1: TCheckBox + Left = 24 + Top = 128 + Width = 97 + Height = 17 + Caption = #20840#23383#21305#37197 + Checked = True + State = cbChecked + TabOrder = 2 + end + object Button1: TButton + Left = 239 + Top = 125 + Width = 75 + Height = 25 + Anchors = [akRight, akBottom] + Caption = #30830#23450'(&O)' + Default = True + TabOrder = 3 + OnClick = Button1Click + end + object Button2: TButton + Left = 151 + Top = 125 + Width = 75 + Height = 25 + Anchors = [akRight, akBottom] + Cancel = True + Caption = #21462#28040'(&C)' + ModalResult = 2 + TabOrder = 4 + end +end diff --git a/tool/书源整理工具/uFrmReplaceGroup.pas b/tool/书源整理工具/uFrmReplaceGroup.pas new file mode 100644 index 000000000..28878c9f6 --- /dev/null +++ b/tool/书源整理工具/uFrmReplaceGroup.pas @@ -0,0 +1,62 @@ +unit uFrmReplaceGroup; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; + +type + TfrmReplaceGroup = class(TForm) + Label1: TLabel; + Edit1: TEdit; + Label2: TLabel; + Edit2: TEdit; + CheckBox1: TCheckBox; + Button1: TButton; + Button2: TButton; + procedure Button1Click(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + frmReplaceGroup: TfrmReplaceGroup; + +function ShowReplaceGroup(Sender: TComponent; const Title: string; var FindStr, NewStr: string; var Flag: Integer): Boolean; + +implementation + +{$R *.dfm} + +function ShowReplaceGroup(Sender: TComponent; const Title: string; var FindStr, NewStr: string; var Flag: Integer): Boolean; +var + F: TfrmReplaceGroup; +begin + F := TfrmReplaceGroup.Create(Sender); + try + F.Caption := Title; + F.CheckBox1.Enabled := Flag = 0; + Result := F.ShowModal = mrOk; + if Result then begin + FindStr := Trim(F.Edit1.Text); + NewStr := Trim(F.Edit2.Text); + Flag := Ord(F.CheckBox1.Checked); + end; + finally + F.Free; + end; +end; + +procedure TfrmReplaceGroup.Button1Click(Sender: TObject); +begin +// if Trim(Edit1.Text) = '' then begin +// ShowMessage('Ҫҵ'); +// Exit; +// end; + ModalResult := mrOk; +end; + +end. diff --git a/tool/书源整理工具/uFrmWait.dfm b/tool/书源整理工具/uFrmWait.dfm new file mode 100644 index 000000000..1f755de5c --- /dev/null +++ b/tool/书源整理工具/uFrmWait.dfm @@ -0,0 +1,62 @@ +object Form2: TForm2 + Left = 0 + Top = 0 + BorderStyle = bsNone + BorderWidth = 1 + Caption = 'Form2' + ClientHeight = 173 + ClientWidth = 251 + Color = clSilver + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + Position = poOwnerFormCenter + OnClose = FormClose + PixelsPerInch = 96 + TextHeight = 13 + object Panel1: TPanel + Left = 0 + Top = 0 + Width = 251 + Height = 173 + Align = alClient + BevelOuter = bvNone + Color = clWindow + ParentBackground = False + TabOrder = 0 + object Label1: TLabel + Left = 73 + Top = 88 + Width = 103 + Height = 13 + Alignment = taCenter + Caption = #27491#22312#22788#29702', '#35831#31561#24453'...' + end + object ActivityIndicator1: TActivityIndicator + AlignWithMargins = True + Left = 112 + Top = 32 + Animate = True + end + object Button1: TButton + Left = 71 + Top = 120 + Width = 106 + Height = 25 + Cancel = True + Caption = #21462#28040'(&C)' + TabOrder = 1 + OnClick = Button1Click + end + end + object Timer1: TTimer + Enabled = False + Interval = 100 + OnTimer = Timer1Timer + Left = 184 + Top = 56 + end +end diff --git a/tool/书源整理工具/uFrmWait.pas b/tool/书源整理工具/uFrmWait.pas new file mode 100644 index 000000000..e32f1f8c2 --- /dev/null +++ b/tool/书源整理工具/uFrmWait.pas @@ -0,0 +1,77 @@ +unit uFrmWait; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.WinXCtrls, + Vcl.ExtCtrls; + +type + TForm2 = class(TForm) + Panel1: TPanel; + ActivityIndicator1: TActivityIndicator; + Label1: TLabel; + Button1: TButton; + Timer1: TTimer; + procedure Button1Click(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure Timer1Timer(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + end; + +var + Form2: TForm2; + +procedure ShowWaitDlg(); +procedure HideWaitDlg(); + +implementation + +{$R *.dfm} + +uses + uFrmMain; + +var + fWait: TForm2; + +procedure ShowWaitDlg(); +begin + if Assigned(fWait) then + Exit; + fWait := TForm2.Create(Application); + fWait.ShowModal; +end; + +procedure HideWaitDlg(); +begin + if Assigned(fWait) then + fWait.Timer1.Enabled := True; +end; + +procedure TForm2.Button1Click(Sender: TObject); +begin + if Form1.Button1.Tag <> 0 then begin + Timer1.Enabled := True; + Form1.Button1Click(Button1); + end; +end; + +procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction); +begin + fWait := nil; + Action := caFree; +end; + +procedure TForm2.Timer1Timer(Sender: TObject); +begin + if Form1.Button1.Tag = 0 then begin + ModalResult := mrCancel; + end; +end; + +end.