artwork.d 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. /*
  2. * pixiv_down - CLI-based downloading tool for https://www.pixiv.net.
  3. * Copyright (C) 2024 Mio
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, version 3 of the License.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  16. */
  17. module app.cmds.artwork;
  18. import pd.configuration: Config;
  19. /**
  20. * Download specified artworks.
  21. *
  22. * The expected format of *args* is: `["pixiv_down", "artwork", "id1", ...]`
  23. *
  24. * Params:
  25. * args = The arguments passed to pixiv_down.
  26. * config = pixiv_down configuration
  27. * Returns: 0 on success, non-zero on error
  28. */
  29. public int artworkHandle(string[] args, in Config config)
  30. {
  31. import std.algorithm.searching : all, find;
  32. import std.conv : ConvException, to;
  33. import std.getopt : getopt, GetOptOption = config;
  34. import std.stdio : stderr, stdout;
  35. import pd.pixiv;
  36. import pd.pixiv_downloader;
  37. import app.util : sleep;
  38. // When an exception occurs.
  39. string[] invalidArtworks;
  40. // The error message for the invalidArtworks
  41. // each index in the array matches the ID.
  42. string[] errorMessages;
  43. bool groupErrors = false;
  44. bool forceDownload = false;
  45. int returnCode = 0;
  46. /* artwork <id> */
  47. if (args.length < 2) {
  48. displayArtworkHelp();
  49. return 1;
  50. }
  51. auto helpInformation = getopt(args,
  52. GetOptOption.passThrough,
  53. "group-errors", &groupErrors,
  54. "force|f", &forceDownload,
  55. );
  56. if (helpInformation.helpWanted) {
  57. displayArtworkHelp();
  58. return 0;
  59. }
  60. string[] ids = find!(isValidID)(args);
  61. foreach(id; ids) {
  62. try {
  63. ArtworkInfo info = fetchArtworkInfo(id, config);
  64. downloadArtwork(info, config, forceDownload);
  65. } catch (PixivJSONException pje) {
  66. if (groupErrors) {
  67. invalidArtworks ~= id;
  68. errorMessages ~= pje.msg;
  69. } else {
  70. stderr.writefln("Error: Failed to fetch and download ID '%s'", id);
  71. stderr.writeln(pje.msg);
  72. }
  73. continue;
  74. }
  75. sleep(1, 5);
  76. }
  77. if (groupErrors && 0 < invalidArtworks.length) {
  78. stderr.writeln("Failed to download the following IDs:");
  79. foreach (index, id; invalidArtworks) {
  80. stderr.writefln(" %s - %s", id, errorMessages[index]);
  81. }
  82. }
  83. return returnCode;
  84. }
  85. void displayArtworkHelp()
  86. {
  87. import std.stdio : stderr;
  88. stderr.writefln(
  89. "pixiv_down artwork - Download specific artwork(s)\n" ~
  90. "\nUsage:\tpixiv_down artwork [options] <id> [<additional ids...>]\n" ~
  91. "\nYou can download one or more artworks via this command. Any\n" ~
  92. "artworks that fail to download are mentioned after attempting to\n" ~
  93. "download, you can change this to only print at the end by using the\n" ~
  94. "--group-errors option.\n" ~
  95. "\nOptions:\n" ~
  96. " -f, --force-download\tOverwrite existing downloads.\n" ~
  97. " --group-errors \tDisplay errors at the end instead.\n" ~
  98. "\nExamples:\n" ~
  99. "\n Download a single artwork:\n" ~
  100. " pixiv_down artwork id\n" ~
  101. "\n Download multiple artworks and display failed IDs at the end:\n" ~
  102. " pixiv_down artwork --group-errors id1 id2\n");
  103. }
  104. private:
  105. bool isValidID(const(char)[] id) {
  106. import std.algorithm.searching : all;
  107. import std.ascii : isDigit;
  108. return id.all!(isDigit);
  109. }