• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

D wrapper around (some) of the pixiv web API


Commit MetaInfo

Revisionab3f05ebdbae3ed2731ae9221fbc72a4f9c977df (tree)
Time2023-08-13 12:03:36
Authorsupercell <stigma@disr...>
Commitersupercell

Log Message

Improve partial download support

Should now work for multi-paged illustrations and manga.

Change Summary

Incremental Difference

--- a/source/pixivd/client.d
+++ b/source/pixivd/client.d
@@ -1,8 +1,7 @@
11 module pixivd.client;
22
3-import core.sync.mutex : Mutex;
4-
53 import std.array : appender;
4+import std.file : FileException, rename;
65 import std.format : format;
76 import std.json;
87 import std.net.curl : HTTP;
@@ -721,33 +720,22 @@ private:
721720 {
722721 import std.datetime.systime;
723722
724- import std.file : FileException, exists, getSize, rename, setTimes;
723+ import std.file : exists, rename, setTimes;
725724 import std.path : extension;
726725 import std.stdio : File;
727726
728727 const baseFileName = illust.id ~ illust.urls["original"].extension;
729728 const partFileName = baseFileName ~ ".part";
729+ string mode = "w+";
730730
731731 if (true == exists(baseFileName) && false == overwrite)
732732 {
733733 throw new FileException(baseFileName, "File already exists");
734734 }
735-
736- string mode = "w+";
737-
738- if (exists(partFileName)) {
739- // Resume previous attempt at downloading.
740- m_client.url = illust.urls["original"];
741- m_client.method = HTTP.Method.head;
742- m_client.perform();
743- if ("accept-ranges" in m_client.responseHeaders()) {
744- ulong bytesRead = getSize(partFileName);
745- m_client.addRequestHeader("Range", format!"bytes=%d-"(bytesRead));
746- mode = "a+";
747- }
748- // If the "accept-ranges" header was not present,
749- // we'll restart the entire download.
750- m_client.method = HTTP.Method.get;
735+ if (true == exists(partFileName)) {
736+ this._setupPartialDownload(illust.urls["original"], partFileName);
737+ mode = "a+";
738+ this._resetHeaders();
751739 }
752740
753741 File imageFile = File(partFileName, mode);
@@ -813,7 +801,17 @@ private:
813801 import std.path : baseName, stripExtension;
814802
815803 const url = jsonobj["urls"]["original"].str;
816- File img = File(baseName(url), "w+");
804+ const baseFileName = baseName(url);
805+ const partFileName = baseFileName ~ ".part";
806+ string mode = "w+";
807+
808+ if (true == exists(partFileName)) {
809+ this._setupPartialDownload(jsonobj["urls"]["original"].str, partFileName);
810+ mode = "a+";
811+ this._resetHeaders();
812+ }
813+
814+ File img = File(partFileName, mode);
817815
818816 m_client.url = url;
819817 m_client.onReceive = (ubyte[] data) {
@@ -828,6 +826,7 @@ private:
828826
829827 m_client.perform();
830828 img.close();
829+ rename(partFileName, baseFileName);
831830 emit(DownloadCompleteEvent());
832831 }
833832 }
@@ -870,11 +869,20 @@ private:
870869 auto bodyArr = json["body"].array;
871870
872871 foreach(obj; bodyArr) {
873- auto filename = baseName(obj["urls"]["original"].str);
874- if (true == exists(filename) && false == overwrite) {
875- throw new FileException(filename, "File already exists");
872+ const baseFileName = baseName(obj["urls"]["original"].str);
873+ const partFileName = baseFileName ~ ".part";
874+ string mode = "w+";
875+
876+ if (true == exists(baseFileName) && false == overwrite) {
877+ throw new FileException(baseFileName, "File already exists");
878+ }
879+ if (true == exists(partFileName)) {
880+ this._setupPartialDownload(obj["urls"]["original"].str, partFileName);
881+ mode = "a+";
882+ this._resetHeaders();
876883 }
877- File outFile = File(filename, "w+");
884+
885+ File outFile = File(partFileName, mode);
878886 m_client.url = obj["urls"]["original"].str;
879887 m_client.onReceive = (ubyte[] data) {
880888 outFile.rawWrite(data);
@@ -886,11 +894,12 @@ private:
886894 };
887895 m_client.perform();
888896 outFile.close();
897+ rename(partFileName, baseFileName);
889898 emit(DownloadCompleteEvent());
890899
891900 SysTime createDate = SysTime.fromISOExtString(illust.createDate);
892901
893- setTimes(filename, createDate, createDate);
902+ setTimes(baseFileName, createDate, createDate);
894903 }
895904 }
896905
@@ -1059,4 +1068,25 @@ private:
10591068 m_client.setCookie("PHPSESSID=" ~ m_phpsessid);
10601069 }
10611070 }
1071+
1072+ ///
1073+ /// Setup m_client for resuming a previous download.
1074+ ///
1075+ /// If the particular request doesn't support partial
1076+ /// downloads
1077+ void _setupPartialDownload(string url, string filename)
1078+ {
1079+ import std.file : getSize;
1080+
1081+ m_client.url = url;
1082+ m_client.method = HTTP.Method.head;
1083+ m_client.perform();
1084+ if ("accept-ranges" in m_client.responseHeaders()) {
1085+ ulong bytesRead = getSize(filename);
1086+ m_client.addRequestHeader("Range", format!"bytes=%d-"(bytesRead));
1087+ }
1088+ // If the "accept-ranges" header was not present,
1089+ // we'll restart the entire download.
1090+ m_client.method = HTTP.Method.get;
1091+ }
10621092 }