123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- /*
- * pixiv_down - CLI-based downloading tool for https://www.pixiv.net.
- * Copyright (C) 2023, 2024 Mio
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- module app.app;
- import std.datetime.systime : SysTime;
- import pd.configuration;
- import std.experimental.logger;
- import app.pd_version : VCS_TAG;
- // dup (logger.d); should be moved to config file.
- enum PIXIV_DOWN_VERSION_STRING = "2024.10.0";
- version(PD_USE_GAMUT)
- {
- pragma(msg, "NOTE: pixiv_down doesn't make proper use of gamut yet. GIFs won't download successfully.");
- }
- /*
- * --------------------------------------------------------------------------
- * Handles
- * --------------------------------------------------------------------------
- */
- ///
- /// Handle any "help" commands.
- ///
- /// This only runs when "help" is used as a command by itself, or when it
- /// is succeeded by a different command (thus displaying the help message
- /// for that command).
- ///
- int helpHandle(string[] args, in Config)
- {
- import app.cmds;
- if (args.length == 1) {
- displayDefaultHelp(true);
- return 0;
- }
- switch(args[1]) {
- case "artist":
- displayArtistHelp();
- break;
- case "artwork":
- displayArtworkHelp();
- break;
- case "bookmarked":
- displayBookmarkedHelp();
- break;
- case "compact":
- displayCompactHelp();
- break;
- case "daily":
- displayDailyHelp();
- break;
- case "following":
- displayFollowingHelp();
- break;
- case "novel":
- displayNovelHelp();
- break;
- case "prune":
- displayPruneHelp();
- break;
- default:
- displayDefaultHelp();
- return 2;
- }
- return 0;
- }
- /*
- * --------------------------------------------------------------------------
- * Help
- * --------------------------------------------------------------------------
- */
- ///
- /// Print the default help information.
- ///
- /// Params:
- /// programName = The name of the executable being run
- /// showMore = Show examples and links to pixiv_down's websites.
- ///
- void displayDefaultHelp(bool showMore = false)
- {
- import std.stdio : stderr;
- stderr.writefln(
- "pixiv_down - A tool for downloading from pixiv.net [%s (%s)]\n" ~
- "\nUsage:\tpixiv_down <command> [options]\n" ~
- "\npixiv_down is a tool that allows you to download various content\n" ~
- "from the pixiv website. You can download illustrations, manga, and\n" ~
- "novels.\n" ~
- "\nMain Commands:\n" ~
- "\tartist \tDownload content from a specified artist.\n" ~
- "\tartwork \tDownload specific artworks via IDs.\n" ~
- "\tbookmarked\tDownload all bookmarked content.\n" ~
- "\tcompact \tCompact all account directories in to one.\n" ~
- "\tdaily \tDownload all followed users' content between dates.\n" ~
- "\tfollowing \tDownload all followed users' content by account.\n" ~
- "\tnovel \tDownload specific novels via IDs.\n" ~
- "\tprune \tRemove unfollowed and/or non-existing accounts.\n" ~
- "\nSide Commands:\n" ~
- "\thelp \tDisplay this help information and exit.\n" ~
- "\treset \tReset your PHPSESSID.\n" ~
- "\tversion \tDisplay the current version of pixiv_down.",
- PIXIV_DOWN_VERSION_STRING, VCS_TAG);
- if (showMore) {
- stderr.writeln(
- "\nExamples:\n" ~
- "\n Download a single illustration:\n" ~
- " pixiv_down artwork 108985926\n" ~
- "\n Download all content from a single user:\n" ~
- " pixiv_down artist 10109777\n" ~
- "\nYou can find more information about pixiv_down at\n" ~
- " <https://yume-neru.neocities.org/p/pixiv_down.html>.\n" ~
- "\nIf you have any issues or feedback, please see the project's page" ~
- " at codeberg\n" ~ " <https://codeberg.org/supercell/pixiv_down>.");
- } else {
- stderr.writeln("\n" ~
- "For more information (including examples) use the ``help'' command.");
- }
- }
- /*
- * --------------------------------------------------------------------------
- * Util
- * --------------------------------------------------------------------------
- */
- version(PD_USE_MAGICK) {
- ///
- /// Print GraphicsMagick version information to the pixiv_down log file.
- ///
- void logLibGMVersion()
- {
- import std.string : fromStringz;
- import pd.imaging.magick : GetMagickVersion;
- infof("%s", fromStringz(GetMagickVersion(null)));
- }
- } // version(PD_USE_MAGICK)
- /// Returns the two character locale set in the environment.
- string getLocale()
- {
- import core.stdc.locale;
- import std.string : fromStringz;
- setlocale(LC_ALL, "");
- char* currentLocale = setlocale(LC_MESSAGES, null);
- if (null is currentLocale) {
- return "en";
- }
- char[] arr = fromStringz(currentLocale);
- if ("C" == arr || "POSIX" == arr) {
- return "en";
- }
- return arr[0..2].dup;
- }
- /*
- * --------------------------------------------------------------------------
- * Main
- * --------------------------------------------------------------------------
- */
- // Don't compile in |main| when building unittests.
- version(unittest) {} else:
- int main(string[] args)
- {
- import app.cmds;
- import pd.pixiv : fetchCSRFToken;
- import std.stdio : stderr, writeln, writefln;
- import std.file : exists, remove;
- import app.logger: initializeLogger;
- auto subcmds = [
- "artist": &artistHandle,
- "artwork": &artworkHandle,
- "bookmarked": &bookmarkedHandle,
- "compact": &compactHandle,
- "daily": &dailyHandle,
- "following": &followingHandle,
- "novel": &novelHandle,
- "prune": &pruneHandle,
- "help": &helpHandle,
- ];
- if (args.length < 2) {
- displayDefaultHelp(false);
- return 2;
- }
- Config cliConfigOverrides;
- string configFilePathOverride;
- size_t subCommandIndex = 1;
- foreach(idx, arg; args[1..$]) {
- if (arg in subcmds) {
- subCommandIndex = idx + 1;
- break;
- }
- switch(arg) {
- case "-h":
- case "--help":
- displayDefaultHelp(true);
- return 0;
- case "-v":
- case "--version":
- case "version":
- writefln("pixiv_down %s (%s)", PIXIV_DOWN_VERSION_STRING, VCS_TAG);
- return 0;
- case "--output-directory":
- if (idx + 2 >= args.length) {
- stderr.writefln("error: invalid argument: %s (no output directory provided)", arg);
- return 1;
- }
- cliConfigOverrides.outputDirectory = args[idx + 2];
- subCommandIndex += 2;
- break;
- case "--config-file":
- if (idx + 2 >= args.length) {
- stderr.writefln("error: invalid argument: %s (no path provided for config file", arg);
- return 1;
- }
- configFilePathOverride = args[idx + 2];
- subCommandIndex += 2;
- break;
- case "reset":
- resetSessionID();
- return 0;
- default:
- break;
- }
- import std.string : indexOf, startsWith;
- import app.util : split;
- if (arg.startsWith("--") && arg.indexOf("=") != -1) {
- string[] argAndValue = arg.split('=', 2);
- if (argAndValue[0] == "--config-file") {
- configFilePathOverride = argAndValue[1];
- } else if (argAndValue[0] == "--output-directory") {
- cliConfigOverrides.outputDirectory = argAndValue[1];
- }
- }
- }
- if (subCommandIndex >= args.length) {
- stderr.writeln("error: no command provided.");
- displayDefaultHelp(false);
- return 2;
- }
- auto func = (args[subCommandIndex] in subcmds);
- if (func is null) {
- stderr.writefln("%s: '%s' is not a valid pixiv_down command. See '%s help'.", args[0],
- args[subCommandIndex], args[0]);
- // TODO: Suggest similar commands (if possible).
- // e.g. pixiv_down user <id> -> Did you mean artist? [y/N]
- return 2;
- }
- initializeLogger();
- version(PD_USE_MAGICK)
- {
- // TODO: remove from app.d, should be in plugin.
- import pd.imaging.magick;
- loadMagick(args[0]);
- scope(exit) destroyMagick();
- logLibGMVersion();
- }
- Config config = configFilePathOverride == "" ? loadConfig() : loadConfig(configFilePathOverride);
- if (cliConfigOverrides.outputDirectory != "") {
- infof("Provided config outputDirectory override: %s", cliConfigOverrides.outputDirectory);
- config.outputDirectory = cliConfigOverrides.outputDirectory;
- }
- infof("config outputDirectory: %s", config.outputDirectory);
- config.locale = getLocale();
- infof("Current locale = %s", config.locale);
- return (*func)(args[subCommandIndex..$], config);
- }
|