From 2c2a2fcafeb66e4193a4034ba88fab02ef81e51e Mon Sep 17 00:00:00 2001
From: dazedcat19 <59296763+dazedcat19@users.noreply.github.com>
Date: Sat, 22 Feb 2020 01:55:06 +0800
Subject: [PATCH] rewrite lua module updater, now working with directories
-github api has a limitation of 5000 queries per day. so authorization token is needed here.
-added simple dialog with tmemo. maybe need to fix later
-todo: move non website module file to other director-y
---
baseunits/FMDOptions.pas | 6 +-
baseunits/GithubRepo.pas | 271 +++++++++++
changelog.txt | 4 +
config/base.ini | 12 +-
make_release_win.bat | 4 +-
mangadownloader/forms/frmDialogYesNo.lfm | 65 +++
mangadownloader/forms/frmDialogYesNo.lrj | 5 +
mangadownloader/forms/frmDialogYesNo.pas | 32 ++
.../forms/frmLuaModulesUpdater.lfm | 321 ++++---------
.../forms/frmLuaModulesUpdater.pas | 441 ++++++++++--------
mangadownloader/forms/uBackupSettings.pas | 2 +-
mangadownloader/md.lpi | 14 +-
update | 7 +-
13 files changed, 749 insertions(+), 435 deletions(-)
create mode 100644 baseunits/GithubRepo.pas
create mode 100644 mangadownloader/forms/frmDialogYesNo.lfm
create mode 100644 mangadownloader/forms/frmDialogYesNo.lrj
create mode 100644 mangadownloader/forms/frmDialogYesNo.pas
diff --git a/baseunits/FMDOptions.pas b/baseunits/FMDOptions.pas
index 79d5e0625..6cd07c1e0 100644
--- a/baseunits/FMDOptions.pas
+++ b/baseunits/FMDOptions.pas
@@ -97,7 +97,8 @@ TIniFileRun = class(IniFiles.TMemIniFile)
EXTRAS_FOLDER,
MANGAFOXTEMPLATE_FOLDER,
LUA_WEBSITEMODULE_FOLDER,
- LUA_WEBSITEMODULE_FILE,
+ LUA_REPO_FOLDER,
+ LUA_REPO_FILE,
BACKUP_FOLDER: String;
// dll
@@ -330,7 +331,7 @@ procedure SetAppDataDirectory(const ADir: String);
CONFIG_FILE := CONFIG_FOLDER + 'config.ini';
ACCOUNTS_FILE := CONFIG_FOLDER + 'accounts.db';
MODULES_FILE := CONFIG_FOLDER + 'modules.json';
- LUA_WEBSITEMODULE_FILE := CONFIG_FOLDER + 'luamodules.json';
+ LUA_REPO_FILE := CONFIG_FOLDER + 'lua.json';
DATA_FOLDER := APPDATA_DIRECTORY + 'data' + PathDelim;
@@ -343,6 +344,7 @@ procedure SetAppDataDirectory(const ADir: String);
FAVORITESDB_FILE := WORK_FOLDER + 'favorites.db';
LUA_WEBSITEMODULE_FOLDER := FMD_DIRECTORY + 'lua' + PathDelim + 'modules' + PathDelim;
+ LUA_REPO_FOLDER := FMD_DIRECTORY + 'lua' + PathDelim;
SetIniFiles;
end;
diff --git a/baseunits/GithubRepo.pas b/baseunits/GithubRepo.pas
new file mode 100644
index 000000000..2c6db38a1
--- /dev/null
+++ b/baseunits/GithubRepo.pas
@@ -0,0 +1,271 @@
+unit GitHubRepo;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, httpsendthread, BaseThread, fpjson;
+
+type
+{ TGitHubRepo }
+
+ TGitHubRepo = class
+ private
+ ConfigFile: String;
+ HTTP: THTTPSendThread;
+ Tree: TJSONArray;
+ Props: TJSONObject;
+ protected
+ procedure SetAuth;
+ function QueryLastCommit: String;
+ function QueryTree: String;
+ function QueryProps(const ANames: TStrings): String;
+ public
+ api_url,
+ download_url,
+ owner,
+ name,
+ token,
+ ref,
+ path,
+ last_commit: String;
+ max_deep: Integer;
+ constructor Create(const AConfigFile: String; const AThread: TBaseThread = nil);
+ destructor Destroy; override;
+ function GetLastCommit: String;
+ function GetTree: TJSONArray;
+ function GetDownloadURL(const AName: String): String;
+ function GetProps(const ANames: TStrings): TJSONObject;
+ end;
+
+implementation
+
+uses jsonparser, jsonscanner, IniFiles, uBaseUnit;
+
+{ TGitHubRepo }
+
+procedure TGitHubRepo.SetAuth;
+begin
+ HTTP.Headers.Values['Authorization']:=' bearer '+token;
+end;
+
+function TGitHubRepo.QueryLastCommit: String;
+var
+ lpath: String;
+begin
+ lpath:=path; if lpath<>'' then lpath := ', path: "'+lpath+'"';
+ Result := '{"query": "'+StringToJSONString(
+ '{'+
+ 'repository(owner: "'+owner+'", name: "'+name+'") {'+
+ 'ref(qualifiedName: "'+ref+'") {'+
+ 'target {'+
+ '... on Commit {'+
+ 'history(first: 1'+lpath+'){ '+
+ 'nodes {'+
+ 'oid'+
+ '}'+
+ '}'+
+ '}'+
+ '}'+
+ '}'+
+ '}'+
+ '}'
+ )+'"}';
+end;
+
+function TGitHubRepo.QueryTree: String;
+
+ function onTree(const x: Integer):string;
+ begin
+ Result:= '... on Tree {'+
+ 'entries {'+
+ 'oid '+
+ 'name ';
+ if x>1 then
+ Result+= 'object {'+
+ onTree(x-1)+
+ '}';
+ Result+= '}'+
+ '}';
+ end;
+begin
+ Result := '{"query": "'+StringToJSONString(
+ '{'+
+ 'repository(owner: "'+owner+'", name: "'+name+'") {'+
+ 'object(expression: "'+last_commit+':'+path+'") {'+
+ onTree(max_deep)+
+ '}'+
+ '}'+
+ '}'
+ )+'"}';
+end;
+
+function TGitHubRepo.QueryProps(const ANames: TStrings): String;
+ function onProps:String;
+ var
+ i: Integer;
+ lpath: String;
+ begin
+ Result:='';
+ lpath :=path; if lpath<>'' then lpath+='/';
+ for i:=0 to ANames.Count-1 do
+ begin
+ Result += 'p'+IntToStr(i)+': history(path: "'+lpath+ANames[i]+'", first: 1) {'+
+ 'nodes {'+
+ 'message '+
+ 'committedDate'+
+ '}'+
+ '} ';
+ end;
+ end;
+begin
+ Result := '{"query": "'+StringToJSONString(
+ '{'+
+ 'repository(owner: "'+owner+'", name: "'+name+'") {'+
+ 'object(oid: "'+last_commit+'") {'+
+ '... on Commit {'+
+ onProps+
+ '}'+
+ '}'+
+ '}'+
+ '}'
+ )+'"}';
+end;
+
+constructor TGitHubRepo.Create(const AConfigFile: String;
+ const AThread: TBaseThread);
+begin
+ ConfigFile := AConfigFile;
+ HTTP := THTTPSendThread.Create(AThread);
+ if FileExists(ConfigFile) then
+ with TIniFile.Create(ConfigFile) do
+ try
+ api_url := ReadString ('GitHub', 'api_url' , '');
+ download_url := ReadString ('GitHub', 'download_url', '');
+ owner := ReadString ('GitHub', 'owner' , '');
+ name := ReadString ('GitHub', 'name' , '');
+ token := DecryptString(ReadString ('GitHub', 'token' , ''));
+ ref := ReadString ('GitHub', 'ref' , '');
+ path := ReadString ('GitHub', 'path' , '');
+ max_deep := ReadInteger ('GitHub', 'max_deep' , 2);
+ finally
+ Free;
+ end;
+ if api_url = '' then api_url := 'https://api.github.com/graphql';
+ if ref = '' then ref := 'master';
+ if max_deep < 1 then max_deep := 1;
+ last_commit:= ref;
+end;
+
+destructor TGitHubRepo.Destroy;
+begin
+ if Assigned(Tree) then Tree.Free;
+ if Assigned(Props) then Props.Free;
+ HTTP.Free;
+ inherited Destroy;
+end;
+
+function TGitHubRepo.GetLastCommit: String;
+var
+ d: TJSONData;
+ a: TJSONArray;
+begin
+ last_commit:='';
+ HTTP.Reset;
+ SetAuth;
+ d:=nil;
+ if HTTP.POST(api_url, QueryLastCommit) then
+ with TJSONParser.Create(HTTP.Document, [joUTF8]) do
+ try
+ d:=Parse;
+ finally
+ free;
+ end;
+ if Assigned(d) then
+ try
+ a:=TJSONArray(d.GetPath('data.repository.ref.target.history.nodes'));
+ if Assigned(a) then
+ last_commit:=TJSONObject(a.Items[0]).Get('oid','');
+ except
+ end;
+ d.free;
+ Result := last_commit;
+end;
+
+function TGitHubRepo.GetTree: TJSONArray;
+var
+ d: TJSONData;
+ a: TJSONArray;
+begin
+ result:=nil;
+ HTTP.Reset;
+ SetAuth;
+ if last_commit='' then
+ last_commit := 'master';
+ d:=nil;
+ if HTTP.POST(api_url, QueryTree) then
+ with TJSONParser.Create(HTTP.Document, [joUTF8]) do
+ try
+ d:=Parse;
+ finally
+ free;
+ end;
+ if Assigned(Tree) then
+ FreeAndNil(Tree);
+ if Assigned(d) then
+ begin
+ try
+ a:=TJSONArray(d.GetPath('data.repository.object.entries'));
+ if Assigned(a) then
+ Tree:=TJSONArray(a.Clone);
+ except
+ end;
+ d.free;
+ end;
+ Result := Tree;
+end;
+
+function TGitHubRepo.GetDownloadURL(const AName: String): String;
+var
+ lpath: String;
+begin
+ lpath:=path; if lpath<>'' then lpath:=lpath+'/';
+ Result:=AppendURLDelim(download_url)+owner+'/'+name+'/'+ref+'/'+lpath+AName;
+end;
+
+function TGitHubRepo.GetProps(const ANames: TStrings): TJSONObject;
+var
+ d: TJSONData;
+ o: TJSONObject;
+begin
+ result:=nil;
+ HTTP.Reset;
+ SetAuth;
+ if last_commit='' then
+ last_commit := 'master';
+ d:=nil;
+ if HTTP.POST(api_url, QueryProps(ANames)) then
+ with TJSONParser.Create(HTTP.Document, [joUTF8]) do
+ try
+ d:=Parse;
+ finally
+ free;
+ end;
+ if Assigned(Props) then
+ FreeAndNil(Props);
+ if Assigned(d) then
+ begin
+ try
+ o:=TJSONObject(d.GetPath('data.repository.object'));
+ if Assigned(o) then
+ Props:=TJSONObject(o.Clone);
+ except
+ end;
+ d.free;
+ end;
+ Result := Props;
+end;
+
+end.
+
diff --git a/changelog.txt b/changelog.txt
index 3ca7ac9d8..56322367f 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -4,6 +4,10 @@ https://github.com/fmd-project-team/FMD
Changelog:
([!] Important, [+] Addition, [-] Removal, [*] Fix/Change, [?] Feedback needed)
+1.2.0.0 (22.02.2020)
+[*] Lua modules structure changed
+Full changes: https://github.com/fmd-project-team/FMD/compare/1.1.4.0...1.2.0.0
+
1.1.4.0 (15.02.2020)
[*] Various changes and bug fixes
Full changes: https://github.com/fmd-project-team/FMD/compare/1.1.3.0...1.1.4.0
diff --git a/config/base.ini b/config/base.ini
index 0cfae077f..5bb57edf0 100644
--- a/config/base.ini
+++ b/config/base.ini
@@ -4,5 +4,13 @@ DB_URL=https://raw.githubusercontent.com/fmd-project-team/FMD-WebsiteDatabases/m
UPDATE_URL=https://raw.githubusercontent.com/fmd-project-team/FMD/master/update
CHANGELOG_URL=https://raw.githubusercontent.com/fmd-project-team/FMD/master/changelog.txt
UPDATE_PACKAGE_NAME=updatepackage.7z
-MODULES_URL=https://api.github.com/repos/fmd-project-team/FMD/contents/lua/modules
-MODULES_URL2=https://github.com/fmd-project-team/FMD/file-list/master/lua/modules
+
+[GitHub]
+api_url=https://api.github.com/graphql
+download_url=https://raw.githubusercontent.com/
+owner=fmd-project-team
+name=FMD
+token=q0NI9Ztgiv1z5s5sYwscdz/CCYQnfGkbRbDGd02dwhsFzXNH9WPNWg==
+ref=master
+path=lua
+max_deep=4
diff --git a/make_release_win.bat b/make_release_win.bat
index 4458df4ea..e221e632f 100644
--- a/make_release_win.bat
+++ b/make_release_win.bat
@@ -8,10 +8,10 @@ SET repodl=https://github.com/fmd-project-team/FMD/releases/download/
ECHO ; automatically build with make_release_win.bat>update
CALL :makerelease i386-win32 Win32 --no-write-project
-ECHO WIN32=%repodl%%fver%/%oname%>>update
+ECHO WIN32=%repodl%%fverb%/%oname%>>update
CALL :makerelease x86_64-win64 Win64 --no-write-project
-ECHO WIN64=%repodl%%fver%/%oname%>>update
+ECHO WIN64=%repodl%%fverb%/%oname%>>update
ECHO VERSION=%fverb%>>update
diff --git a/mangadownloader/forms/frmDialogYesNo.lfm b/mangadownloader/forms/frmDialogYesNo.lfm
new file mode 100644
index 000000000..cb962b639
--- /dev/null
+++ b/mangadownloader/forms/frmDialogYesNo.lfm
@@ -0,0 +1,65 @@
+object frmDialogYN: TfrmDialogYN
+ Left = 414
+ Height = 325
+ Top = 174
+ Width = 437
+ BorderIcons = [biSystemMenu]
+ Caption = 'Dialog'
+ ChildSizing.LeftRightSpacing = 6
+ ChildSizing.TopBottomSpacing = 6
+ ChildSizing.HorizontalSpacing = 6
+ ChildSizing.VerticalSpacing = 6
+ ClientHeight = 325
+ ClientWidth = 437
+ Color = clWindow
+ Position = poDesktopCenter
+ LCLVersion = '2.1.0.0'
+ object btYes: TButton
+ AnchorSideRight.Control = btNo
+ AnchorSideBottom.Control = btNo
+ AnchorSideBottom.Side = asrBottom
+ Left = 339
+ Height = 25
+ Top = 294
+ Width = 44
+ Anchors = [akRight, akBottom]
+ AutoSize = True
+ Caption = '&Yes'
+ Default = True
+ ModalResult = 6
+ TabOrder = 0
+ end
+ object btNo: TButton
+ AnchorSideRight.Control = Owner
+ AnchorSideRight.Side = asrBottom
+ AnchorSideBottom.Control = Owner
+ AnchorSideBottom.Side = asrBottom
+ Left = 389
+ Height = 25
+ Top = 294
+ Width = 42
+ Anchors = [akRight, akBottom]
+ AutoSize = True
+ Caption = '&No'
+ ModalResult = 7
+ TabOrder = 1
+ end
+ object mMessages: TMemo
+ AnchorSideLeft.Control = Owner
+ AnchorSideTop.Control = Owner
+ AnchorSideRight.Control = Owner
+ AnchorSideRight.Side = asrBottom
+ AnchorSideBottom.Control = btNo
+ Left = 6
+ Height = 282
+ Top = 6
+ Width = 425
+ Anchors = [akTop, akLeft, akRight, akBottom]
+ BorderStyle = bsNone
+ Color = clWindow
+ ReadOnly = True
+ ScrollBars = ssAutoBoth
+ TabOrder = 2
+ WordWrap = False
+ end
+end
diff --git a/mangadownloader/forms/frmDialogYesNo.lrj b/mangadownloader/forms/frmDialogYesNo.lrj
new file mode 100644
index 000000000..7ba8043b4
--- /dev/null
+++ b/mangadownloader/forms/frmDialogYesNo.lrj
@@ -0,0 +1,5 @@
+{"version":1,"strings":[
+{"hash":78611287,"name":"tfrmdialogyn.caption","sourcebytes":[68,105,97,108,111,103],"value":"Dialog"},
+{"hash":180163,"name":"tfrmdialogyn.btyes.caption","sourcebytes":[38,89,101,115],"value":"&Yes"},
+{"hash":11087,"name":"tfrmdialogyn.btno.caption","sourcebytes":[38,78,111],"value":"&No"}
+]}
diff --git a/mangadownloader/forms/frmDialogYesNo.pas b/mangadownloader/forms/frmDialogYesNo.pas
new file mode 100644
index 000000000..db2c506c9
--- /dev/null
+++ b/mangadownloader/forms/frmDialogYesNo.pas
@@ -0,0 +1,32 @@
+unit frmDialogYesNo;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls;
+
+type
+
+ { TfrmDialogYN }
+
+ TfrmDialogYN = class(TForm)
+ btYes: TButton;
+ btNo: TButton;
+ mMessages: TMemo;
+ private
+
+ public
+
+ end;
+
+var
+ frmDialogYN: TfrmDialogYN;
+
+implementation
+
+{$R *.lfm}
+
+end.
+
diff --git a/mangadownloader/forms/frmLuaModulesUpdater.lfm b/mangadownloader/forms/frmLuaModulesUpdater.lfm
index 32acc0461..d5e18a538 100644
--- a/mangadownloader/forms/frmLuaModulesUpdater.lfm
+++ b/mangadownloader/forms/frmLuaModulesUpdater.lfm
@@ -11,7 +11,7 @@ object LuaModulesUpdaterForm: TLuaModulesUpdaterForm
ClientWidth = 580
OnCreate = FormCreate
OnDestroy = FormDestroy
- LCLVersion = '2.0.6.0'
+ LCLVersion = '2.1.0.0'
object vtLuaModulesRepos: TVirtualStringTree
AnchorSideLeft.Control = Owner
AnchorSideTop.Control = btCheckUpdate
@@ -186,231 +186,100 @@ object LuaModulesUpdaterForm: TLuaModulesUpdaterForm
left = 200
top = 128
Bitmap = {
- 4C69070000001000000010000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
- FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
- FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF003B7F320015A9000015A9000015A9
- 000015A9000015AA009915AA00CC15AA00CC15AA009915A9000015A9000015A9
- 000015A90000094D0000FFFFFF00FFFFFF00119A0000129F000014A8000014A8
- 000014A8000014A800CC72E961FF71E860FF14A800CC14A8000014A8000014A8
- 0000129F0000119A0000FFFFFF00FFFFFF00119A0000119B0000129E000014A5
- 000014A5000014A500CC69E058FF69E058FF14A500CC14A5000014A50000129E
- 0000119B0000119A0000FFFFFF00FFFFFF00119A0000119B0000119B0000129D
- 000013A2000013A200CC62D951FF61D850FF13A200CC13A20000129D0000119B
- 0000119B0000119A0000FFFFFF00FFFFFF00119A0000119B0000119B0000119B
- 0000129C0000129E00CC5AD149FF59D048FF129E00CC129C0000119B0000119B
- 0000119B0000119A0000FFFFFF00FFFFFF00119A0099119A00CC119A00CC119A
- 00CC119A00CC119A00CC54CB43FF52C941FF119A00CC119A00CC119A00CC119A
- 00CC119A00CC119A0099FFFFFF00FFFFFF00109600CC5ED54DFF55CC44FF54CB
- 43FF53CA42FF52C941FF4BC23AFF4AC139FF4FC63EFF4EC53DFF4DC43CFF4CC3
- 3BFF4EC53DFF109600CCFFFFFF00FFFFFF000F9200CC59D048FF50C73FFF50C7
- 3FFF4FC63EFF4AC139FF3BB32AFF31A920FF31A920FF2CA51BFF2BA31AFF2DA5
- 1CFF33AB22FF0F9200CCFFFFFF00FFFFFF000E8E00990E8D00CC0E8D00CC0E8D
- 00CC0E8D00CC0E8D00CC2DAE1CFF2BAC1AFF0E8D00CC0E8D00CC0E8D00CC0E8D
- 00CC0E8D00CC0E8E0099FFFFFF00FFFFFF000E8D00000E8C00000E8C00000E8C
- 00000E8B00000D8900CC29B618FF27B416FF0D8900CC0E8B00000E8C00000E8C
- 00000E8C00000E8D0000FFFFFF00FFFFFF000E8D00000E8C00000E8C00000E8A
- 00000C8400000C8400CC25C014FF24C013FF0C8400CC0C8400000E8A00000E8C
- 00000E8C00000E8D0000FFFFFF00FFFFFF000747000000000000000000000320
- 00000A7D00000A7D00CC23CD12FF22CC11FF0A7D00CC0A7D0000032000000000
- 00000000000000000000FFFFFF00FFFFFF000000000000000000000000000000
- 0000021D0000066D00CC22D811FF22D811FF066D00CC021D0000000000000000
- 00000000000000000000FFFFFF00FFFFFF0000000000000000040000001B0000
- 003000000033024700A6025D00CC025D00CC024700A600000033000000310000
- 001F0000000600000000FFFFFF00FFFFFF0000000000000000020000000E0000
- 00180000001A0000001A0000001A0000001A0000001A0000001A000000190000
- 00100000000300000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
- FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
- FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000063CE000065D0000064
- CF000069D400006AD548006AD5CC006AD5CC006AD5660069D4000064CF000065
- D0000063CE00FFFFFF00FFFFFF00FFFFFF00FFFFFF000063CE000065D01A0064
- CF000066D1000067D2CC38C1F8F938C7F8FD0067D2C90066D1000064CF000065
- D01A0063CE00FFFFFF00FFFFFF00FFFFFF00FFFFFF000063CE660063CECC0063
- CEB30062CD4D0063CECC3AC8F8FF2FC0F1FD0063CEB30062CD4D0063CEB30063
- CECC0063CE66FFFFFF00FFFFFF00FFFFFF00FFFFFF00005FCACC39C2F5FF34B8
- F2F9117AD7D9005FCACC38C1F4FF2AAFE9F9005FCAB71079D6D932B6F0F936BF
- F3FF005FCACCFFFFFF00FFFFFF00FFFFFF00FFFFFF00005AC5CC27A4E3F92CAD
- E7FF31B3ECFF1075D3D935B9F0FF249EE1F50F74D2D930B2EBFF2CADE7FF27A4
- E3F9005AC5CCFFFFFF00FFFFFF00FFFFFF00FFFFFF000056C13E0055C0B31074
- CDE01A87D5EC2DAAE6FF2DA9E6FF28A3E1FF2DA9E6FF1A87D5EC1074CDE00055
- C0B30056C13EFFFFFF00FFFFFF00FFFFFF00FFFFFF000050BA000050BB000050
- BB480050BBCC1C8BD6F3249CDEFF249CDEFF1C8BD6F30050BBCC0050BB480050
- BB000050BA00FFFFFF00FFFFFF00FFFFFF00FFFFFF000049B33E004BB5B31474
- CCE01B87D6EC2099DDFF2099DDFF239EE1FF2099DDFF1884D3EC1070C9E0004B
- B5B30049B33EFFFFFF00FFFFFF00FFFFFF00FFFFFF000045AFCC24A1E4F91C9D
- E1FF1A9ADFFF075ABBD9158BD7F520A1E5FF075ABBD91A9ADFFF1B9BE0FF1C97
- DFF90045AFCCFFFFFF00FFFFFF00FFFFFF00FFFFFF00003DA8CC139DE2FF1192
- DCF90554B6D9003DA8B71194DCF918A2E6FF003DA8CC0554B6D91192DCF9139D
- E2FF003DA8CCFFFFFF00FFFFFF00FFFFFF00FFFFFF0000329D6600309BCC0030
- 9BB300339E4D00309BB30C9EE5FD0FA4E9FF00309BCC00339E4D00309BB30030
- 9BCC00329D66FFFFFF00FFFFFF00FFFFFF00FFFFFF0000184E0000154A1A0017
- 4C00000A250000248EC908A2E8FD0899E2F900248ECC000A250000174C000015
- 4A1A00184E00FFFFFF00FFFFFF00FFFFFF00FFFFFF00000000000000000D0000
- 00210000002700135E79002B91D1002B91D100104B6100000027000000230000
- 001000000001FFFFFF00FFFFFF00FFFFFF00FFFFFF0000000000000000080000
- 00160000001A0000001A0000001A0000001A0000001A0000001A000000170000
- 000A00000001FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
- FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
- FF00FFFFFF00FFFFFF00FFFFFF00000000000000000000000000212121006565
- 65008B8B8B002502B0002502B2002502B3002602B5372602B47B2502B47C2502
- B3382502AF002402AC002302A800000000001D1D1D005C5C5C00808080008686
- 86008B8B8B002502B0002502B2002502B3382502B37CC9B8FDFFCAB9FEFF2502
- B17E2502AF392402AC002302A800525252007373730079797900808080008686
- 86008B8B8B002502B0002502B2392502B17EC6B5FCFFB6A5ECFFB8A7ECFFCAB9
- FEFF2402AD812402AC3B2302A8006C6C6C007373730079797900808080008686
- 86008B8B8B002502B0392502B07FC4B3FBFFB3A2EAFFB5A4EBFFB6A5ECFFB8A7
- ECFFCAB9FEFF2402A9862302A83D6C6C6C007373730079797900808080008686
- 86008A8A8A2F88888866C1B0F9FFB09FE9FFB2A1E9FFB3A2EAFFB5A4EBFFB6A5
- ECFF9887DCFFAA99EEFF2302A58A6C6C6C007373730079797900808080008585
- 852F83838366F8F8F8FFF5F5F5FFAE9DE8FFB09FE9FFB2A1E9FFB3A2EAFF9584
- D9FF9786DBFFA998EDFF2202A18D6C6C6C0073737300797979007F7F7F2F7D7D
- 7D66F6F6F6FFF2F2F2FFF2F2F2FFF2F2F2FFAE9DE8FFB09FE9FF9281D6FF9483
- D8FFA695EAFF22029F9022029F416C6C6C00737373007878782F76767666F4F4
- F4FFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFF8E7DD2FF907FD4FFA392
- E7FF21029D9221029C4221029E006C6C6C007272722F70707066F3F3F3FFECEC
- ECFFECECECFFECECECFFECECECFFECECECFFCECECEFFD0D0D0FF9F8EE3FF2102
- 9B9521029A4321029C0021029E006B6B6B2F69696966F1F1F1FFE9E9E9FFE9E9
- E9FFE9E9E9FFE9E9E9FFE9E9E9FFCACACAFFCCCCCCFFDCDCDCFF363636662003
- 98452102990021029C0021029E0063636366F0F0F0FFE6E6E6FFE6E6E6FFE6E6
- E6FFE6E6E6FFE6E6E6FFC6C6C6FFC8C8C8FFD8D8D8FF272727662323232F2003
- 9700210299001902750011014F0058585866F0F0F0FFE3E3E3FFE3E3E3FFE3E3
- E3FFE3E3E3FFC2C2C2FFC4C4C4FFD4D4D4FF1A1A1A661616162F202020001803
- 71000801260000000000000000004848482F3D3D3D66F0F0F0FFE1E1E1FFE1E1
- E1FFBFBFBFFFC0C0C0FFD1D1D1FF0F0F0F660C0C0C2F0F0F0F00080808000000
- 0000000000000000000000000000101010001E1E1E2F20202066DFDFDFFFCECE
- CEFFCECECEFFCECECEFF050505660202022F0202020000000000000000000000
- 00000000000000000000000000000000001100000026090909480A0A0A660505
- 05660202026601010166000000400000001E00000019000000130000000E0000
- 000000000005000000020000000000000000000000130000001A000000190000
- 00180000001600000014000000120000000F0000000D0000000A000000070000
- 0005000000030000000100000000000000000000000000000000000000002222
- 2200696969002502B0002502B2002502B3002602B5372602B47B2502B47C2502
- B3382502AF002402AC002302A80000000000000000001F1F1F00616161008686
- 86008B8B8B002502B0002502B2002502B3382502B37CC9B8FDFFCAB9FEFF2502
- B17E2502AF392402AC002302A8001C1C1C005757570079797900808080008686
- 86008B8B8B002502B0002502B2392502B17EC6B5FCFFB6A5ECFFB8A7ECFFCAB9
- FEFF2402AD812402AC3B2302A8006C6C6C007373730079797900808080008686
- 86008B8B8B002502B0392502B07FC4B3FBFFB3A2EAFFB5A4EBFFB6A5ECFFB8A7
- ECFFCAB9FEFF2402A9862302A83D6C6C6C007373730079797900808080008686
- 86008A8A8A2F88888866C1B0F9FFB09FE9FFB2A1E9FFB3A2EAFFB5A4EBFFB6A5
- ECFF9887DCFFAA99EEFF2302A58A6C6C6C007373730079797900808080008585
- 852F83838366F8F8F8FFF5F5F5FFAE9DE8FFB09FE9FFB2A1E9FFB3A2EAFF9584
- D9FF9786DBFFA998EDFF2202A18D6C6C6C0073737300797979007F7F7F2F7D7D
- 7D66F6F6F6FFF2F2F2FFF2F2F2FFF2F2F2FFAE9DE8FFB09FE9FF9281D6FF9483
- D8FFA695EAFF22029F9022029F416C6C6C00737373007878782F76767666F4F4
- F4FFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFFEFEFEFFF8E7DD2FF907FD4FFA392
- E7FF21029D9221029C4221029E006C6C6C007272722F70707066F3F3F3FFECEC
- ECFFECECECFFECECECFFECECECFFECECECFFCECECEFFD0D0D0FF9F8EE3FF2102
- 9B9521029A4321029C0021029E006B6B6B2F69696966F1F1F1FFE9E9E9FFE9E9
- E9FFE9E9E9FFE9E9E9FFE9E9E9FFCACACAFFCCCCCCFFDCDCDCFF363636662003
- 984519029D000901A7000000A70063636366F0F0F0FFE6E6E6FFE6E6E6FFE6E6
- E6FFE6E6E6FFE6E6E6FFC6C6C6FFC8C8C8FFD8D8D8FF272727661A1A452F0801
- A5000000AA000000AA000000A70058585866F0F0F0FFE3E3E3FFE3E3E3FFE3E3
- E3FFE3E3E3FFC2C2C2FFC4C4C4FFD4D4D4FF0A0A7BC20202A1D50000A7CC0000
- A7CC0000A7CC0000A7CC0000A6994848482F3D3D3D66F0F0F0FFE1E1E1FFE1E1
- E1FFBFBFBFFFC0C0C0FFD1D1D1FF0F0F0F66010192D55E5EF7FF5E5EF7FF5E5E
- F7FF5E5EF7FF5E5EF7FF000098CC101010001E1E1E2F20202066DFDFDFFFCECE
- CEFFCECECEFFCECECEFF050505660202022F00006299000080CC000080CC0000
- 80CC000080CC000080CC000084990000001100000026090909480A0A0A660505
- 05660202026601010166000000400000001E00000019000000130000000E0000
- 000000000005000000020000400000000000000000130000001A000000190000
- 00180000001600000014000000120000000F0000000D0000000A000000070000
- 0005000000030000000100000000FFFFFF00E99E3F00E99E3F00E99E3F00EA9F
- 4099EA9F40CCEA9F4099EA9F4000EA9F40CCEA9F4000E59A3D00E3983B00E398
- 3B00E3983B00FFFFFF00FFFFFF00FFFFFF00E69B3D00E69B3D00E69B3D00E69B
- 3DCCFFE195FFE69B3DCCE4993C00E69B3D00E4993C00E3983B00E3983B00E398
- 3B00E3983B00FFFFFF00FFFFFF00FFFFFF00E3983B00E3983B00E3983B00E398
- 3B99E2973ACCE2973ACCE2973ACCE2973A99E2973A00E2973ACCE2973A00E297
- 3A00E2973A00FFFFFF00FFFFFF00FFFFFF00DD923600DD923600DD923600DD92
- 3600DD923600DD9236CCFEDC90FFDD9236CCDB903400DD923600DC913500DC91
- 3500DC913500FFFFFF00FFFFFF00FFFFFF00D68B3100D68B3100D68B3100D78C
- 3299D88D32CCD88D32CCD88D32CCD88D32CCD88D32CCD78C3299D68B3100D68B
- 3100D68B3100FFFFFF00FFFFFF00FFFFFF00D2872E00D2872E00D2872E00D287
- 2ECCFBD589FFD38930CEFAD488FFD2872ECCFAD286FFD2872ECCD2872E00D287
- 2E00D2872E00FFFFFF00FFFFFF00FFFFFF00B86D1A00C97E2700C97E2700CA7F
- 2899D58E39D7D58E39D7D08731D2CB8029CCCB8029CCCA7F2899C97E2700C97E
- 2700B86D1A00FFFFFF00FFFFFF00FFFFFF00B86D1A00BD721E00C57A2400C57A
- 24CCF7CC80FFDA9645E3F6CA7EFFC87E29CFF6C97DFFC57A24CCC57A2400BD72
- 1E00B86D1A00FFFFFF00FFFFFF00FFFFFF00B86D1A00B96E1B00BB701D00BE73
- 1FCCEDB96CF8E1A153EFDB9949E8D4903FE1D4903FE1BD721F99B96E1B00B96E
- 1B00B86D1A00FFFFFF00FFFFFF00FFFFFF00B76C1A99B86D1ACCB86D1ACCB86D
- 1ACCF3C074FFE9AC60FAEEB266FFE4A659F5F2BD71FFB86D1ACCB86D1ACCB86D
- 1ACCB76C1A99FFFFFF00FFFFFF00FFFFFF00B267165CB16615CCF7CB7FFFF2BF
- 73FFF0B86CFFE9AD61FFDFA357FFD5994DFFD49B4FFFD6A054FFDDAB5FFFB166
- 15CCB267165CFFFFFF00FFFFFF00FFFFFF00B1661500AC61115CAB6010CCF2C3
- 77FFDB9E4CFFD09341FFCF9240FFCF9240FFCF9240FFDCA858FFAB6010CCAC61
- 115CB1661500FFFFFF00FFFFFF00FFFFFF00B1661500AB601000A65B0D5CA55A
- 0CCCEAB44BFFE09E29FFE09E29FFE09E29FFE8AE43FFA55A0CCCA65B0D5CAB60
- 1000B1661500FFFFFF00FFFFFF00FFFFFF000000000000000000532D0600A156
- 095CA05508CCF7B92EFFF5AB0EFFF7B629FFA05508CCA156095C532D06000000
- 000000000000FFFFFF00FFFFFF00FFFFFF0000000000000000030000000F0000
- 00196D39046E9B5005CCFFBB19FF9B5005CC6D39046E0000001A000000110000
- 000400000000FFFFFF00FFFFFF00FFFFFF0000000000000000050000001D0000
- 00320000003363320274974C02CC633202740000003300000033000000220000
- 000800000000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
- FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
- FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
- FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
- FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF0011970000129B0000129C0000129B
- 00001197000013A2000014A5000014A5000014A6000015A8000015A9001F15AA
- 00CC15AA004814A70000FFFFFF00FFFFFF0011970000129B0000129C0000129B
- 00001197000011990000129F0000129F000013A2000014A5001014A700B077EE
- 66FF14A700CC14A70048FFFFFF00FFFFFF0011970000129B0000129C0000129B
- 00001197000011990000129F0000129F000013A2000614A3009E43C631E56BE2
- 5AFF70E95FFB14A300CCFFFFFF00FFFFFF0011970000129B0000129C0000129B
- 00001197000011990000129F0000129F000113A0008533B820DE61D850FF5CD5
- 4BFA1EA80CD213A1004CFFFFFF00FFFFFF0011970000129B0048129B00CC129B
- 0048119700000F93000011970000129B006924AA13D857CF46FE55CD44FD21A7
- 10D6129C006313A00000FFFFFF00FFFFFF0011960048119700CC73EA62FD1197
- 00CC119600480F9300001196004C189D08D33DB62CFB37AF26FE1FA00EDA1197
- 007B11980000129B0000FFFFFF00FFFFFF000F9200CC6DE55CFA59D048FF69E1
- 58FC0F9200CC0F92006D139504CB34B423F832B221FF1F9F0FDF0F92008C1094
- 00021095000010950000FFFFFF00FFFFFF000E8E00480E8D00CC5FD94FF933BC
- 22FF50D040F80E8D00CC2AB21AF32CB81BFF1EA20FE40E8D009E0F8F00081094
- 000010950000084B0000FFFFFF00FFFFFF000E8D00000D8800480D8700CC43CA
- 33F629C318FF39CC28FF28C217FF1EAA0FEA0D8700AE0D8A00100F8F0000084A
- 00000000000000000000FFFFFF00FFFFFF00074700000A6500000B8300480B82
- 00CC2AC01BF424CD13FF1DB60EEF0C8301BB0C85001B07450000000000000000
- 00000000000000000000FFFFFF00FFFFFF000000000000000000032000000657
- 0048077200CC16A60AE8087601C406570029021E000000000000000000000000
- 00000000000000000000FFFFFF00FFFFFF00000000020000000F0000001F0000
- 002D02330066025F00CC012B005500000029000000220000001A000000130000
- 000C0000000600000001FFFFFF00FFFFFF000000000100000008000000100000
- 00170000001A000000190000001700000015000000110000000D0000000A0000
- 00060000000300000001FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
- FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
- FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
- FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
- FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF000000A2000000A5000000A8000000
- A91A0000AA6C0000AAA60000AAC40000AAC40000AAA60000AA6C0000A91A0000
- A8000000A5000000A200FFFFFF00FFFFFF000000A2000000A5000000A84D0909
- AEBF3737D0E35C5CEAF56A6AF3FD6969F2FD5B5BE9F53636CFE30909AEBF0000
- A84D0000A5000000A200FFFFFF00FFFFFF000000A2000000A54D1010B1CD5B5B
- E8F65F5FE7FF5B5BE3FF4949D1FF4949D1FF5B5BE3FF5F5FE7FF5858E4F60F0F
- B0CD0000A54D0000A200FFFFFF00FFFFFF000000A11A0808A8BF5656E2F65151
- D9FF4F4FD7FF4040C8FFFFFFFFFFFFFFFFFF4040C8FF4F4FD7FF5050D8FF4F4F
- DCF60707A7BF0000A11AFFFFFF00FFFFFF0000009E6C3232C6E34949D1FF4242
- CAFF4242CAFF3636BEFFFFFFFFFFFFFFFFFF3636BEFF4242CAFF4242CAFF4747
- CFFF2A2ABDE300009E6CFFFFFF00FFFFFF0000009AA74747D3F53737BFFF3737
- BFFF3737BFFF2A2AB2FFE8E8E8FFDADADAFF15159EFF12129CFF12129CFF1616
- A0FF2727B4F500009AA7FFFFFF00FFFFFF00000096C44949D1FD3333BBFF2E2E
- B8FF1D1DABFF1212A1FFCCCCCCFFD1D1D1FF1111A0FF1111A1FF1111A1FF1111
- A1FF1D1DACFD000096C4FFFFFF00FFFFFF00000092C44444CDFD2626B5FF1414
- ABFF1111AAFF1111A6FFD1D1D1FFDCDCDCFF1111A6FF1111AAFF1111AAFF1111
- AAFF1818AFFD000092C4FFFFFF00FFFFFF0000008DA72E2EC0F51212B4FF1111
- B4FF1111B4FF1111B4FF1111A8FF1111A8FF1111B4FF1111B4FF1111B4FF1111
- B4FF1212AFF500008DA7FFFFFF00FFFFFF000000896C1616AAE21616C1FF1111
- BEFF1111BEFF1111B5FFE8E8E8FFEEEEEEFF1111B5FF1111BEFF1111BEFF1111
- BEFF0909A1E30000896CFFFFFF00FFFFFF000000851A03038ABF1818C1F61212
- C8FF1111C8FF1111BCFFEEEEEEFFEEEEEEFF1111BCFF1111C8FF1111C8FF0F0F
- BCF6020289BF0000851AFFFFFF00FFFFFF000000830000007F4D040488CD1212
- C4F61212D1FF1111D1FF1111B6FF1111B6FF1111D1FF1111D1FF0F0FC2F60303
- 88CD00007F4D00008300FFFFFF00FFFFFF000000000000001F000000534D0202
- 74BF08089DE30E0EC4F51111D4FD1111D4FD0E0EC4F508089DE3020274BF0000
- 534D00001F0000000000FFFFFF00FFFFFF0000000004000000170000002B0000
- 1A430000448000005AAB00005DC400005DC400005AAB0000448000001A430000
- 002D0000001800000004FFFFFF00FFFFFF00000000020000000C000000160000
- 001A0000001A0000001A0000001A0000001A0000001A0000001A0000001A0000
- 00170000000C00000002FFFFFF00
+ 4C7A070000001000000010000000A70B00000000000078DAED987B5454E516C0
+ F71C7C0C84CC0C20E1F07EF8C0170A859A51E6E38A29699A4A4A1A7A9D16892D
+ 53B3AC14BBBE35BD46F91815144D40343550C2EB032432C40F450505A5145103
+ 231FE02068B8EFB70F6786C30C965EFBE3AE75EF59EBB7BEFDEDBD7F6786D1EF
+ 3C3E44047C4AFA460740DB1DD09464D0739884DEBC6E1D0A265FB301C07E3380
+ 635213D88C8A087CBFFC6DA4585EA35E72E4BE6623CFC7F1FA76132CF2721812
+ 141BF3D443BDCDF9E23962011CB68AB049C5AF6344D108A498725433F63DCA17
+ CFB149FC1C36EEF4107C333F0429A69CBCC7CCD77398396F9C1880238FBF82CD
+ D5C831FAEAB5C0261486E2683610C91995DB5FF48666BD80AF1EED83C38FBD84
+ AFFD108CA1D92FE2B0EFFB8A3139465F15038CBEE7881F5F16A17EF2FAA676C6
+ 9E3B3C45BA6E77C12EDBB4D86DBB2B06EEF446728CBEDD2AD0DBAD04664EB7DD
+ AED86597169BAB9163F25702D87D2E6305409B65C0FCD29CB1E33E27A498724D
+ 7A5636FE7E4DFCE500B60B4558FB4C47F4CD74408A2947B5E6FCD683C1745879
+ 02D8CC15613E79F6E8CD344831E5A8263F8CBEF921B801B49A06CCBB488304C5
+ 94333FCCFC161C174E0F4EA030181284B7B847F098729C9E1C0F4EAB667C8163
+ C771E6681F413B8E9AFE4CB9FF5700934F024CC907F8FB2980C80280770B4338
+ 4C4227E6A8463DBCF711BE56ECD19D0678E70CEB7DB4B6AEF78FB5F53C3E2EE6
+ 1A7CED237C1D87715261525E28C52FE4D4A27FE69D7A592E55EAD159F8137359
+ 9F2C033E975E55A7F9F87C31CD7B1FBD8B9DF754D4F1F83BF59C73C50169B7EB
+ 8232AA916A16FEB81F58C7AFCBEABA7EF30BF64CAD44F507678B9F3F701B7DE3
+ 4A0DAA59678A7BA4FC8A54A31EEAB5F0C71C7D094667A6AA67E55DD62E29ACEC
+ 967C1DBBEDB88E9DB6958A23E5A8463DD46BE18FF817E72011C261AE2BCE55FB
+ 6EFA19098A2927D5C45E0B7F48EA4B30747FAAE32C76D965C9B94A4FFD4F48F8
+ C4958AA3F3C2B395EAE9C72F530FF55AF883F630DFF8AB75AEB1A5A8DD70095B
+ 8F3B58DC76C5798367FC3531A69CCBC6CBE8BAEE521DF55AF8C149CC21F60A6A
+ 624AEA5ABE9156CCE7DF69BE2AA973DE7A1DA94639AA510FCD2DFC80581DF4D8
+ C838A91018174AA36DDCB57AD5D71528E6A59C18F35E0BDFF9357E637A550BCF
+ 0EE38BBF3D80EFAAE3CAADE5F54AFD953A1E33314735EAE1BD167EC3D186E3C5
+ E9080E13E640972F4E8BA887468839001F69FD291EE12B394E7FB07E9FE5D834
+ E7FFC7EB5676787979C194295360C58A15D05ED8CB49E1A44207617FAF0EC2BE
+ 4FDA0BFB3EE5F3DEED853DE02BEC021F2149F4DCDCDC203C3C1CE6CF9F0F8B17
+ 2F36F7797FEAA7C7D3EB31F7C0436C2F7C3B8FFB7D8CFEC8912361E6CC993067
+ CE9CE6FC3ED47F6CFFEF98B6BD12D3132BC573F80ADF7CC6FDBEE44745453DCA
+ E7EEDEE8ECD40798BAF506EEFFFA57B373EC58CCFDE0E6FCE5CB97FB2F5DBA54
+ 77746F1DEEDD5C8129F1154DCEB17E490926EB6FA28FB07DB9B9BF68D122FF05
+ 0B16E86A6B6BD16030E0EED8F226E758B3B018D72DBE883BD6FF86DE42FC4AB9
+ 1F1D1DED3F77EE5C5D4D4D0D56555599309E23E6B373F8D582224C587383BB9B
+ 57735E31FA1F7DF491FFECD9B37577EFDEC55BB76E59B06AEE195C1D5D80DB62
+ 7E412F2136C64BD8D4DF4B88137FBF193366F84F9F3E5D575D5D8D959595169C
+ 3C7912F3F3F371F3AA32EE6E5CE3256C18C07D207FEAD4A9FE919191BA3B77EE
+ 6045458505B9B9B9C818C39292120C0A0AD2795AAD1FE425E8C1E84F9E3C5977
+ FBF66DBC7EFDBA05C78E1DC39C9C1C2C2A2AC28E1D3BEA7C7C7CFC3DADD601F9
+ ED840F40A3180E616161A25F5656D684ACAC2CCCCECEC6828202D46AB53A2727
+ 277F4F4F4F70B67A1F948A0EA6FFF3212121FEC1C1C1E2394A4B4B4532323230
+ 3333134F9F3E8D2A954A676B6BEBCF47502A9516F770B55A0DEEEEEE746EDDA5
+ 4B97C4DFCA48CB962D758220F873E00F0E0DA783B5B575888D8D8D4E72740A85
+ 42C7F3FD38EED27DDB41BABFD3D152BADF1B0F07D9FDDD59BA863872EC392AE9
+ BA44D78DD6924BF77F45735FC6DBDB1BF8BFE713AD7F3A3C3C3C202222E289D7
+ BFABAB2B8C1D3BF6FFEBFF7F68FDB71362C15A91C8FFD7243ED1FAD76A07F92B
+ 15FC250E9225121F6BFDDBD87C922508F185BC9F352541FF38EB5FA188299C30
+ E11E9A03B09E3DCEFA0798A40798CF2C59A87FBAF5DFEFA9D73F3D0354C4BD6C
+ E2C6E67E7A0E93469062B8B62118CAD6F735217F86B8BE31580EC3D23548E355
+ FD8B628E46B96BEE9BD5F457D6BDC064D01CA4188CC8FD9F62829A833D2C598D
+ 345E5CFD9C982BF9E2791372FFDC8A9E26CE7F1EA02F5A19C0CCA1BCBC4FEE9F
+ 59D25D0E7B50B80CCF2EEB71F27EC152A4F9FD338BC551DE27F7D3A769E1F8BC
+ 8E22B9D19DF485ABFA9C27F297F43C7362BE1F23286FECA17E73FFF00C77F8E1
+ 635F82DD63F3F1C2DA416535B9F330679EDFA99AE37391F254A7BEE6FC03EFB9
+ C0C1E96E7064A607FBED40546D69FCA85B17F543CA0B56BF5C4A1C9EE1A1A71E
+ C2DCFF2E4AABE73966A43A731656EC7AFBFECD141D5E4D78D35075F87D94D7A9
+ 5FEEA7BCE314FEADAE2DBB77221AAB3266E2EDF428ACF826022F6D1B8B85FA50
+ 2CD8381CCF6D79037FDA3911A98FFAE53ECFC1AE084DF8CEB7D5ACEAFB0FF162
+ DC30CCFFF2153C15D3CF44495218529DFAA8DFDCE7354818DF267CFB385B7663
+ DF50BC1CE767A27CF700A43CD5A9CFDC371EA3BAB582F831D6E15B462BD9BD03
+ DDD1B0D30EEFA5F921CD294F75F3777F996F25ADD576D3FAB4786FE388960C0F
+ B6431A692EAD6F8DB44FD09C4FEB9A76190268AF607280306BDD3081D128ED1D
+ 10DED23BC65FFAEEFFB468D6F10B9571DF8CF6C6D635ECC199F6F212F86B5792
+ B86FE821ED27863826C21FFA1A7DC33E21219D4BCD9DBD1FDED4211F1927E409
+ FC568EDB206EC0B19ED7A65E1987D32B263EE073F698BEC2610B2C0A4CF7FC99
+ F612C30B87DE774FB23DE3100FC3CCFC100EA391E6AA2FC1988FF44D76281A7B
+ EA6F0F47E70DACF74A549FE39F33999FB3F1EF5F2B3A6CE68D49F534D25CF4D7
+ C230E758E5D9E0B4AE0F7AEDE9F0D0638BDD055EFF44B3BEE17BCAF7FFA65D0B
+ BF4F7B8091A561BFD39C33CD614D8B13CFEDF3A90D48F1428FCDAA4B3CF7B9FA
+ 2B10D46BF873EF1AD9FEDB2A08A13DBD89C5C3EB020F79E388FC7EB534EF9CA2
+ ADEE9AEE82EE5B5557F93C4EF54F50725F7495439BEEDFB5590A216D96001B90
+ 1B58E3F7BD33F6619DB053D6B3E89EACBAC1F3BBDB2C0735F741F9AAE5FE19ED
+ DFD94C01786601843CF30FFEB9992E777DF31CD02DCDEE96ED02C541DB45E0D2
+ 7AD09FEEBF89FB7BADC64248EB19C09C126CCA95B315D97CEE27B837FFE02EF3
+ 0569EDD2DE5C37211074C244608A2E309ACFFDA475A795EED3B6D2FE9D42E62B
+ A475A996DEF18DF7728ADB4AEBDE780F6F65BC7FFFB7AC5F00BEC0809ECBE87D
+ 6007FFEEC9511CBE6A93B325121A72544B927AB736E7875A5BEFCEE8D52BBF2C
+ 3CFC86E1DD77ABEB2323ABEAC78FAF3004059D2AA31AF53CC20F55ABBFCD1B3F
+ BEBC66E2C45F70FCF8321C32E4B408C5940B0BBB5AA352EDCDA3DEA67EBC56A9
+ 4CCA1833E64ACDEBAF17E3F0E1E7B15FBF1C341E14536EC488223E96D4B46E9D
+ 98414EA31F17151070AC8C3EAB7FFF5C91A0A023269F62637EF0E053D8B9F3E1
+ 32721AFD0D8983079F35F4EA9581463A774EC1F2F272BC70E102B66D1B87F6F6
+ 9B449C9CB6F067E17D06721AFDB5D9FCB3EB03030F62F7EEE9E8E6B693F7C68B
+ CFDDF40CABD16CE1C49B7073DB554F4EA31F933D70605E7D870EFBD1D17127EF
+ 49E624882E3DB753DC906BC0D9794F3D398DFECAC4EEDD330DF6F6FB785D4E92
+ 44D3BCBDFD1E03398DFEB22827A7E42B4E4E4779FD88C47EF1EFBF79F3A61837
+ E68FA0B5757C19398DFE22AD95D5F20C67E7A335F6F639BC873824BA0DFE2129
+ 97C39FE70FD508C2B20C721AFD059CE8D0162D96E6D9DB67F373D06F46A44934
+ CC55AAAC1A2BABA579D44B4ED3EB072DFD51A182302B43A98C2DB3B3CB366834
+ 05F504C594A31AF534F436B97EB490D67A17BEF407000C9C0F306E27C05BD90D
+ 504C39AA4137E919BF85D9F5C7F64FF60EE57B88D42B90FB6FD788967A
}
end
object tmRepaintList: TTimer
diff --git a/mangadownloader/forms/frmLuaModulesUpdater.pas b/mangadownloader/forms/frmLuaModulesUpdater.pas
index d9d18b1c8..2cf9f9cee 100644
--- a/mangadownloader/forms/frmLuaModulesUpdater.pas
+++ b/mangadownloader/forms/frmLuaModulesUpdater.pas
@@ -7,7 +7,7 @@ interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
Buttons, Menus, ExtCtrls, VirtualTrees, synautil, httpsendthread, BaseThread,
- XQueryEngineHTML, fpjson, jsonparser, jsonscanner, dateutils;
+ XQueryEngineHTML, GitHubRepo, fpjson, jsonparser, jsonscanner, dateutils;
type
@@ -22,14 +22,13 @@ interface
TLuaModuleRepo = class
name: String;
sha: String;
- size: Integer;
- download_url: String;
last_modified: TDateTime;
last_message: String;
flag: TLuaModuleRepoFlag;
oflag: TLuaModuleRepoFlag;
function Clone: TLuaModuleRepo;
function SyncTo(const t: TLuaModuleRepo): Boolean;
+ constructor Create;
end;
{ TLuaModulesRepos }
@@ -39,6 +38,7 @@ TLuaModulesRepos = class
function GetCount: Integer; inline;
function GetRepo(const AIndex: Integer): TLuaModuleRepo; inline;
public
+ last_commit: String;
Items: TStringList;
constructor Create;
@@ -47,8 +47,6 @@ TLuaModulesRepos = class
procedure Clear; inline;
function Add(const AName: String): TLuaModuleRepo; overload;
procedure Add(const I: TLuaModuleRepo); overload;
- procedure LoadFromRemote(const AHTTP: THTTPSendThread);
- procedure LoadFromRemoteHTML(const AHTTP: THTTPSendThread);
procedure LoadFromFile(const AFileName: String);
procedure SaveToFile(const AFileName: String);
procedure Sort;
@@ -116,8 +114,8 @@ TDownloadThread = class(TBaseThread)
TCheckUpdateThread = class(TBaseThread)
private
+ FGitHubRepo: TGitHubRepo;
FOwner: TLuaModulesUpdaterForm;
- FHTTP: THTTPSendThread;
FReposUp: TLuaModulesRepos;
FRepos: TLuaModulesRepos;
FMainRepos: TLuaModulesRepos;
@@ -126,6 +124,7 @@ TCheckUpdateThread = class(TBaseThread)
FDownloadedCount: Integer;
FProceed: Boolean;
FStatusList: TStringList;
+ Flast_commit: String;
procedure RemoveThread(const T: TDownloadThread);
procedure AddThread(const T: TDownloadThread);
protected
@@ -137,6 +136,7 @@ TCheckUpdateThread = class(TBaseThread)
procedure SyncFinal;
function SyncRepos(const ARepos, AReposUp: TLuaModulesRepos): Boolean;
procedure Download;
+ procedure DoSync;
procedure Execute; override;
public
constructor Create(const AOwner: TLuaModulesUpdaterForm);
@@ -165,7 +165,7 @@ TCheckUpdateThread = class(TBaseThread)
implementation
-uses frmCustomColor, FMDOptions;
+uses frmCustomColor, frmDialogYesNo, FMDOptions, LazFileUtils;
const
// RFC 3339 - ISO 8601
@@ -193,9 +193,6 @@ function TLuaModuleRepo.Clone: TLuaModuleRepo;
Result := TLuaModuleRepo.Create;
Result.name := name;
Result.sha := sha;
- Result.sha := sha;
- Result.size := size;
- Result.download_url := download_url;
Result.last_modified := last_modified;
Result.last_message := last_message;
Result.flag := flag;
@@ -210,7 +207,6 @@ function TLuaModuleRepo.SyncTo(const t: TLuaModuleRepo): Boolean;
if sha <> t.sha then
begin
t.sha := sha;
- t.download_url := download_url;
t.last_modified := last_modified;
t.last_message := last_message;
t.oflag := t.flag;
@@ -218,6 +214,11 @@ function TLuaModuleRepo.SyncTo(const t: TLuaModuleRepo): Boolean;
end;
end;
+constructor TLuaModuleRepo.Create;
+begin
+ last_modified := Now;
+end;
+
{ TLuaModulesRepos }
function TLuaModulesRepos.GetCount: Integer;
@@ -261,106 +262,51 @@ procedure TLuaModulesRepos.Add(const I: TLuaModuleRepo);
Items.AddObject(I.name, I);
end;
-procedure TLuaModulesRepos.LoadFromRemote(const AHTTP: THTTPSendThread);
-var
- j: TJSONParser;
- a: TJSONArray;
- i: Integer;
- o: TJSONObject;
- m: TLuaModuleRepo;
-begin
- Clear;
-
- a := nil;
- j := TJSONParser.Create(AHTTP.Document, [joUTF8]);
- try
- a := TJSONArray(j.Parse);
- finally
- j.Free;
- end;
- if a = nil then
- Exit;
-
- try
- for i := 0 to a.Count - 1 do
- begin
- o := TJSONObject(a.Items[i]);
- m := Add(o.Get('name', ''));
- m.sha := o.Get('sha', '');
- m.download_url := o.Get('download_url', '');
- m.size := o.Get('size', 0);
- end;
- finally
- a.Free;
- end;
-end;
-
-procedure TLuaModulesRepos.LoadFromRemoteHTML(const AHTTP: THTTPSendThread);
-var
- v: IXQValue;
- i: Integer;
-begin
- with TXQueryEngineHTML.Create(AHTTP.Document) do
- try
- v := XPath('//table[starts-with(@class,"files")]//tr[@class="js-navigation-item"]');
- if v.Count = Count then
- for i := 1 to v.Count do
- with Repo[i - 1] do
- begin
- last_message := XPathString('./td[@class="message"]/span/a/@title', v.get(i));
- last_modified := JSONToDateTime(
- XPathString('./td[@class="age"]/span/time-ago/@datetime', v.get(i)));
- end;
- finally
- Free;
- end;
- Sort;
-end;
-
procedure TLuaModulesRepos.LoadFromFile(const AFileName: String);
var
f: TFileStream;
j: TJSONParser;
a: TJSONArray;
- o: TJSONObject;
+ d, o: TJSONObject;
i: Integer;
m: TLuaModuleRepo;
begin
if not FileExists(AFileName) then
Exit;
- a := nil;
+ d := nil;
f := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite);
try
j := TJSONParser.Create(f, [joUTF8]);
try
- a := TJSONArray(j.Parse);
+ d := TJSONObject(j.Parse);
finally
j.Free;
end;
finally
f.Free;
end;
- if a = nil then
- Exit;
+
+ if d = nil then Exit;
try
Self.Clear;
- for i := 0 to a.Count - 1 do
- begin
- o := TJSONObject(a.Items[i]);
- m := Add(o.Get('name', ''));
- m.sha := o.Get('sha', '');
- m.download_url := o.Get('download_url', '');
- m.size := o.Get('size', 0);
- m.last_modified := JSONToDateTime(o.Get('last_modified', ''));
- m.last_message := o.Get('last_message', '');
- m.flag := TLuaModuleRepoFlag(o.Get('flag', 0));
- if (m.flag <> fFailedDownload) and
- (not FileExists(LUA_WEBSITEMODULE_FOLDER + m.name)) then
- m.flag := fFailedDownload;
- end;
+ last_commit := d.Get('last_commit', '');
+ a:=d.Get('files', TJSONArray(nil));
+ if Assigned(a) then
+ for i := 0 to a.Count - 1 do
+ begin
+ o := TJSONObject(a.Items[i]);
+ m := Add(o.Get('name', ''));
+ m.sha := o.Get('sha', '');
+ m.last_modified := JSONToDateTime(o.Get('last_modified', ''));
+ m.last_message := o.Get('last_message', '');
+ m.flag := TLuaModuleRepoFlag(o.Get('flag', 0));
+ if (m.flag <> fFailedDownload) and
+ (not FileExists(LUA_REPO_FOLDER + TrimFilename(m.name))) then
+ m.flag := fFailedDownload;
+ end;
finally
- a.Free;
+ d.Free;
end;
Sort;
end;
@@ -368,38 +314,39 @@ procedure TLuaModulesRepos.LoadFromFile(const AFileName: String);
procedure TLuaModulesRepos.SaveToFile(const AFileName: String);
var
a: TJSONArray;
- o: TJSONObject;
+ d, o: TJSONObject;
i: Integer;
m: TLuaModuleRepo;
f: TMemoryStream;
begin
- a := TJSONArray.Create;
+ d := TJSONObject.Create;
try
+ d.Add('last_commit', last_commit);
+ a := TJSONArray.Create;
for i := 0 to Items.Count - 1 do
begin
o := TJSONObject.Create;
m := Repo[i];
o.Add('name', m.name);
o.Add('sha', m.sha);
- o.Add('download_url', m.download_url);
- o.Add('size', m.size);
o.Add('last_modified', DateTimeToJSON(m.last_modified));
o.Add('last_message', m.last_message);
o.Add('flag', Integer(m.flag));
a.Add(o);
end;
+ d.Add('files', a);
if FileExists(AFileName) then
DeleteFile(AFileName);
f := TMemoryStream.Create;
try
- a.DumpJSON(f);
+ d.DumpJSON(f);
f.SaveToFile(AFileName);
finally
f.Free;
end;
finally
- a.Free;
+ d.Free;
end;
end;
@@ -414,6 +361,7 @@ function TLuaModulesRepos.Clone: TLuaModulesRepos;
i: Integer;
begin
Result := TLuaModulesRepos.Create;
+ Result.last_commit := last_commit;
for i := 0 to Items.Count - 1 do
Result.Items.AddObject(Items[i], Repo[i].Clone);
end;
@@ -428,17 +376,20 @@ procedure TDownloadThread.Execute;
FModule.oflag := FModule.flag;
FModule.flag := fDownloading;
FOwner.FOwner.ListDirty;
- if FHTTP.GET(FModule.download_url) then
+ //if FHTTP.GET(FModule.download_url) then
+ if FHTTP.GET(FOwner.FGitHubRepo.GetDownloadURL(FModule.name)) then
begin
- if ForceDirectories(LUA_WEBSITEMODULE_FOLDER) then
+ if ForceDirectories(LUA_REPO_FOLDER) then
begin
- f := LUA_WEBSITEMODULE_FOLDER + FModule.name;
+ f := LUA_REPO_FOLDER + TrimFilename(FModule.name);
c := True;
if FileExists(f) then
c := DeleteFile(f);
+ c := ForceDirectories(ExtractFileDir(f));
if c then
begin
FHTTP.SaveDocumentToFile(f, False, FModule.last_modified);
+ //FHTTP.SaveDocumentToFile(f);
if FileExists(f) then
begin
case FModule.oflag of
@@ -520,9 +471,14 @@ procedure TCheckUpdateThread.SyncFinishChecking;
procedure TCheckUpdateThread.SyncAskToProceed;
begin
- FProceed := MessageDlg(RS_NewUpdateFoundTitle,
- Format(RS_NewUpdateFoundLostChanges, [Trim(FStatusList.Text)]),
- mtWarning, mbYesNo, 0) = mrYes;
+ with TfrmDialogYN.Create(nil) do
+ try
+ Caption := RS_NewUpdateFoundTitle;
+ mMessages.Lines.Text := Format(RS_NewUpdateFoundLostChanges, [Trim(FStatusList.Text)]);
+ FProceed := ShowModal = mrYes;
+ finally
+ free;
+ end;
end;
procedure TCheckUpdateThread.SyncStartDownload;
@@ -536,6 +492,8 @@ procedure TCheckUpdateThread.SyncFinishDownload;
end;
procedure TCheckUpdateThread.SyncFinal;
+var
+ yesRestart: Boolean;
begin
FOwner.btCheckUpdateTerminate.Visible := False;
FOwner.btCheckUpdate.Caption := RS_CheckUpdate;
@@ -546,10 +504,29 @@ procedure TCheckUpdateThread.SyncFinal;
FOwner.vtLuaModulesRepos.BeginUpdate;
FOwner.Repos := FMainRepos;
FOwner.ReinitList;
- FMainRepos.SaveToFile(LUA_WEBSITEMODULE_FILE);
+ FMainRepos.SaveToFile(LUA_REPO_FILE);
finally
FOwner.vtLuaModulesRepos.EndUpdate;
end;
+
+ if not Terminated then
+ begin
+ if (FDownloadedCount <> 0) then
+ begin
+ yesRestart := OptionModulesUpdaterAutoRestart;
+ if not yesRestart then
+ with TfrmDialogYN.Create(FOwner) do
+ try
+ Caption := RS_ModulesUpdatedTitle;
+ mMessages.Lines.Text := Format(RS_ModulesUpdatedRestart, [Trim(FStatusList.Text)]);
+ yesRestart := ShowModal = mrYes;
+ finally
+ free;
+ end;
+ if yesRestart then
+ RestartFMD;
+ end;
+ end;
end;
function TCheckUpdateThread.SyncRepos(const ARepos, AReposUp: TLuaModulesRepos): Boolean;
@@ -630,6 +607,7 @@ function TCheckUpdateThread.SyncRepos(const ARepos, AReposUp: TLuaModulesRepos):
Inc(i);
end;
end;
+ ARepos.last_commit := AReposUp.last_commit;
if inew <> 0 then
ARepos.Items.Sort;
Result := inew + iupdate <> 0;
@@ -644,21 +622,27 @@ procedure TCheckUpdateThread.Download;
Synchronize(@SyncStartDownload);
FStatusList.Clear;
+
+ // do delete first
+ for i:=0 to FRepos.Items.Count-1 do
+ begin
+ if FRepos[i].flag=fDelete then
+ begin
+ m:=FRepos[i];
+ f := LUA_REPO_FOLDER + TrimFilename(m.name);
+ if FileExists(f) and DeleteFile(f) then
+ begin
+ AddStatus(Format(RS_StatusDelete, [m.name]));
+ m.flag := fDeleted;
+ end;
+ end;
+ end;
+
i := 0;
imax := FRepos.Items.Count;
while i < imax do
begin
m := FRepos[i];
- if m.flag = fDelete then
- begin
- f := LUA_WEBSITEMODULE_FOLDER + m.name;
- if FileExists(f) then
- DeleteFile(f);
- AddStatus(Format(RS_StatusDelete, [m.name]));
- m.flag := fDeleted;
- Inc(i);
- end
- else
if not (m.flag in [fNew, fUpdate, fFailedDownload]) then
Inc(i)
else
@@ -694,101 +678,167 @@ procedure TCheckUpdateThread.Download;
Synchronize(@SyncFinishDownload);
end;
-procedure TCheckUpdateThread.Execute;
+procedure TCheckUpdateThread.DoSync;
var
foundupdate: Boolean;
i, imax: Integer;
m: TLuaModuleRepo;
trepos: TLuaModulesRepos;
-begin
- Synchronize(@SyncStartChecking);
- FReposUp := TLuaModulesRepos.Create;
- if FHTTP.GET(MODULES_URL) then
+ tree: TJSONArray;
+
+ procedure LoadReposUp(const ATree: TJSONArray; const APath: String);
+ var
+ treeItem: Integer;
+ treeObject: TJSONObject;
+ treeArray: TJSONArray;
+ aItem: TLuaModuleRepo;
begin
- FReposUp.LoadFromRemote(FHTTP);
- if FHTTP.GET(MODULES_URL2) then
+ for treeItem:=0 to ATree.Count-1 do
begin
- FReposUp.LoadFromRemoteHTML(FHTTP);
-
- if (FReposUp.Count<>0) and not Terminated then
+ treeObject:= TJSONObject(ATree[treeItem]);
+ treeArray := nil;
+ try
+ treeArray := TJSONArray(treeObject.GetPath('object.entries'));
+ except
+ end;
+ if Assigned(treeArray) then
+ begin
+ LoadReposUp(treeArray, APath+treeObject.Get('name','')+'/');
+ end
+ else
begin
- // check
- FRepos := FOwner.Repos.Clone;
- foundupdate := SyncRepos(FRepos, FReposUp);
+ aItem := FReposUp.Add(APath+treeObject.Get('name', ''));
+ aitem.sha := treeObject.Get('oid', '');
+ end;
+ end;
+ end;
- // look for missing local files and previously failed download
- for i := 0 to FRepos.Items.Count - 1 do
+ procedure LoadReposProps;
+ var
+ ulist: TStringList;
+ aItem: Integer;
+ props: TJSONObject;
+ d: TJSONArray;
+ begin
+ ulist:=TStringList.Create;
+ try
+ for aItem:=0 to FRepos.Items.Count-1 do
+ if FRepos[aItem].flag in [fNew, fUpdate, fFailedDownload] then
+ ulist.AddObject(FRepos[aItem].name, FRepos[aItem]);
+ props:=FGitHubRepo.GetProps(ulist);
+ if Assigned(props) then
+ begin
+ for aItem:=0 to ulist.Count-1 do
begin
- m := FRepos[i];
- if m.flag = fFailedDownload then
- foundupdate := True
- else
- if (not (m.flag in [fNew, fUpdate])) and
- (not FileExists(LUA_WEBSITEMODULE_FOLDER + m.name)) then
- begin
- m.flag := fFailedDownload;
- foundupdate := True;
- end;
- case m.flag of
- fNew: FStatusList.Add(Format(RS_StatusNew, [m.name]));
- fUpdate: FStatusList.Add(Format(RS_StatusUpdate, [m.name]));
- fDelete: FStatusList.Add(Format(RS_StatusDelete, [m.name]));
- fFailedDownload: FStatusList.Add(Format(RS_StatusFailed, [m.name]));
+ m := TLuaModuleRepo(ulist.Objects[aItem]);
+ try
+ d:=TJSONArray(props.GetPath('p'+IntToStr(aItem)+'.nodes'));
+ m.last_message := TJSONObject(d[0]).Get('message','');
+ m.last_modified := JSONToDateTime(TJSONObject(d[0]).Get('committedDate',''));
+ except
end;
end;
+ end;
+ finally
+ ulist.free;
+ end;
+ end;
- Synchronize(@SyncFinishChecking);
+begin
+ FRepos := FOwner.Repos.Clone;
+ Flast_commit:=FGitHubRepo.GetLastCommit;
+ if (Flast_commit<>'') and (Flast_commit<>FRepos.last_commit) then
+ begin
+ // only load new tree with different last_commit
+ tree:=FGitHubRepo.GetTree;
+ if Assigned(tree) then
+ begin
+ FReposUp := TLuaModulesRepos.Create;
+ FReposUp.last_commit := Flast_commit;
+ LoadReposUp(tree,'');
+ FReposUp.Sort;
+ end;
+ end;
- if foundupdate and (not Terminated) then
- begin
- if OptionModulesUpdaterShowUpdateWarning then
- Synchronize(@SyncAskToProceed)
- else
- begin
- FProceed := True;
- Sleep(1500); // delay to show the update status
- end;
- if FProceed then
- Download;
- end;
+ if FReposUp=nil then FReposUp:=FRepos.Clone;
+ if (FReposUp.Count<>0) and not Terminated then
+ begin
+ // check
+ foundupdate := SyncRepos(FRepos, FReposUp);
- // cleanup
- i := 0;
- imax := FRepos.Items.Count;
- while i < imax do
- begin
- m := FRepos[i];
- if m.flag = fDeleted then
- begin
- FRepos.Items.Delete(i);
- Dec(imax);
- end
- else
- begin
- if m.flag in [fNew, fUpdate, fFailedDownload] then
- m.flag := fFailedDownload
- else
- m.flag := fNone;
- Inc(i);
- end;
- end;
- trepos := FMainRepos;
- FMainRepos := FRepos;
- FRepos := trepos;
+ // look for missing local files and previously failed download
+ for i := 0 to FRepos.Items.Count - 1 do
+ begin
+ m := FRepos[i];
+ if m.flag = fFailedDownload then
+ foundupdate := True
+ else
+ if (not (m.flag in [fNew, fUpdate])) and
+ (not FileExists(LUA_REPO_FOLDER + TrimFilename(m.name))) then
+ begin
+ m.flag := fFailedDownload;
+ if not foundupdate then foundupdate := True;
+ end;
+ case m.flag of
+ fNew: FStatusList.Add(Format(RS_StatusNew, [m.name]));
+ fUpdate: FStatusList.Add(Format(RS_StatusUpdate, [m.name]));
+ fDelete: FStatusList.Add(Format(RS_StatusDelete, [m.name]));
+ fFailedDownload: FStatusList.Add(Format(RS_StatusFailed, [m.name]));
+ end;
+ end;
+
+ // get properties
+ if foundupdate and (not Terminated) then
+ LoadReposProps;
+
+ Synchronize(@SyncFinishChecking);
+
+ if foundupdate and (not Terminated) then
+ begin
+ if OptionModulesUpdaterShowUpdateWarning then
+ Synchronize(@SyncAskToProceed)
+ else
+ begin
+ FProceed := True;
+ Sleep(1500); // delay to show the update status
+ end;
+ if FProceed then
+ Download;
+ end;
+
+ // cleanup
+ i := 0;
+ imax := FRepos.Items.Count;
+ while i < imax do
+ begin
+ m := FRepos[i];
+ if m.flag = fDeleted then
+ begin
+ FRepos.Items.Delete(i);
+ Dec(imax);
+ end
+ else
+ begin
+ if m.flag in [fNew, fUpdate, fFailedDownload] then
+ m.flag := fFailedDownload
+ else
+ m.flag := fNone;
+ Inc(i);
end;
end;
+ trepos := FMainRepos;
+ FMainRepos := FRepos;
+ FRepos := trepos;
end;
+end;
+procedure TCheckUpdateThread.Execute;
+begin
+ Synchronize(@SyncStartChecking);
+ DoSync;
if not Terminated then
Sleep(1000);
Synchronize(@SyncFinal);
-
- if not Terminated then
- if (FDownloadedCount <> 0) and (OptionModulesUpdaterAutoRestart or
- (MessageDlg(RS_ModulesUpdatedTitle,
- Format(RS_ModulesUpdatedRestart, [Trim(FStatusList.Text)]),
- mtConfirmation, mbYesNo, 0) = mrYes)) then
- RestartFMD;
end;
constructor TCheckUpdateThread.Create(const AOwner: TLuaModulesUpdaterForm);
@@ -796,10 +846,10 @@ constructor TCheckUpdateThread.Create(const AOwner: TLuaModulesUpdaterForm);
inherited Create(False);
InitCriticalSection(FThreadsCS);
FOwner := AOwner;
- FHTTP := THTTPSendThread.Create(Self);
FThreads := TFPList.Create;
FDownloadedCount := 0;
FStatusList := TStringList.Create;
+ FGitHubRepo := TGitHubRepo.Create(BASE_FILE, Self);
end;
destructor TCheckUpdateThread.Destroy;
@@ -810,7 +860,7 @@ destructor TCheckUpdateThread.Destroy;
FReposUp.Free;
FStatusList.Free;
FThreads.Free;
- FHTTP.Free;
+ FGitHubRepo.Free;
DoneCriticalsection(FThreadsCS);
inherited Destroy;
end;
@@ -922,15 +972,17 @@ procedure TLuaModulesUpdaterForm.vtLuaModulesReposGetImageIndex(Sender: TBaseVir
procedure TLuaModulesUpdaterForm.vtLuaModulesReposGetText(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: String);
+var
+ xNode: PLuaModuleRepo;
begin
- with PLuaModuleRepo(Sender.GetNodeData(Node))^ do
- begin
- case Column of
- 0: CellText := name;
- 1: CellText := DateTimeToStr(last_modified);
- 2: CellText := last_message;
- end;
- end;
+ xNode := Sender.GetNodeData(Node);
+ if Assigned(xNode) then
+ with xNode^ do
+ case Column of
+ 0: CellText := name;
+ 1: CellText := DateTimeToStr(last_modified);
+ 2: CellText := last_message;
+ end;
end;
procedure TLuaModulesUpdaterForm.vtLuaModulesReposHeaderClick(Sender: TVTHeader;
@@ -958,7 +1010,7 @@ procedure TLuaModulesUpdaterForm.ListDirty;
procedure TLuaModulesUpdaterForm.LoadLocalRepos;
begin
- Repos.LoadFromFile(LUA_WEBSITEMODULE_FILE);
+ Repos.LoadFromFile(LUA_REPO_FILE);
ReinitList(False);
end;
@@ -980,3 +1032,4 @@ procedure TLuaModulesUpdaterForm.SortList;
end;
end.
+
diff --git a/mangadownloader/forms/uBackupSettings.pas b/mangadownloader/forms/uBackupSettings.pas
index 59cb66065..42aac28ed 100644
--- a/mangadownloader/forms/uBackupSettings.pas
+++ b/mangadownloader/forms/uBackupSettings.pas
@@ -68,7 +68,7 @@ procedure WriteBackupToFile(const AFileName:String);
Parameters.Add(CleanPath(CONFIG_FILE));
Parameters.Add(CleanPath(ACCOUNTS_FILE));
Parameters.Add(CleanPath(MODULES_FILE));
- Parameters.Add(CleanPath(LUA_WEBSITEMODULE_FILE));
+ Parameters.Add(CleanPath(LUA_REPO_FILE));
Parameters.Add(CleanPath(WORK_FILEDB));
Parameters.Add(CleanPath(DOWNLOADEDCHAPTERSDB_FILE));
Parameters.Add(CleanPath(FAVORITESDB_FILE));
diff --git a/mangadownloader/md.lpi b/mangadownloader/md.lpi
index 05e3d75bf..46cc5ff5e 100644
--- a/mangadownloader/md.lpi
+++ b/mangadownloader/md.lpi
@@ -23,11 +23,8 @@
-
-
-
-
+
@@ -308,7 +305,7 @@
-
+
@@ -430,6 +427,13 @@
+
+
+
+
+
+
+
diff --git a/update b/update
index 27d236360..252f1c6b9 100644
--- a/update
+++ b/update
@@ -1,3 +1,4 @@
-VERSION=1.1.4.0
-WIN32=https://github.com/fmd-project-team/FMD/releases/download/1.1.4.0/fmd_1.1.4.0_Win32.7z
-WIN64=https://github.com/fmd-project-team/FMD/releases/download/1.1.4.0/fmd_1.1.4.0_Win64.7z
+; automatically build with make_release_win.bat
+WIN32=https://github.com/fmd-project-team/FMD/releases/download/1.2.0.0/fmd_1.2.0.0_i386-win32.7z
+WIN64=https://github.com/fmd-project-team/FMD/releases/download/1.2.0.0/fmd_1.2.0.0_x86_64-win64.7z
+VERSION=1.2.0.0