123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- /*
- * 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 pd.configuration;
- private enum ProjectQualifier = null;
- private enum ProjectOrg = "YumeNeru Software";
- private enum ProjectName = "pixiv_down";
- private enum PHPSessionIDFileName = ".phpsessid";
- /// pixiv_down configuration.
- ///
- /// Use `configuration.loadConfig` to load the correct values.
- struct Config
- {
- /// The directory where content is downloaded to.
- string outputDirectory;
- /// The PHPSESSID of the current account.
- string sessionid;
- /// Cross Site Request Forgery Token (unused)
- string csrfToken;
- /// Two character locale used for pixiv requests
- string locale;
- /// Configuration for the `bookmarked` command
- BookmarkedConfig bookmarked;
- }
- private struct BookmarkedConfig
- {
- /// Whether invalid works should automatically be removed
- /// from the account's bookmarks.
- bool alwaysRemoveInvalid;
- }
- public Config loadConfig(string path)
- {
- import mlib.configparser: ConfigParser;
- import mlib.directories: getUserDirectories;
- import std.exception: ErrnoException;
- import std.experimental.logger: errorf, tracef;
- const userDirectories = getUserDirectories();
- tracef("Loading configuration file at %s", path);
- try {
- auto parser = new ConfigParser();
- parser.read(path);
- const outputDirectory = parser.get("output", "directory",
- parser.get("output", "base_directory",
- userDirectories.pictureDir));
- const alwaysRemoveInvalid = parser.getBool("bookmarked", "always_remove_invalid", false);
- return Config(outputDirectory, fetchSessionID(), "", "",
- BookmarkedConfig(alwaysRemoveInvalid));
- } catch(ErrnoException e) {
- errorf("Failed to load configuration file: %s", e.msg);
- // Fallback to default values
- return Config(userDirectories.pictureDir, fetchSessionID());
- }
- }
- /// Load the configuration for pixiv_down.
- public Config loadConfig()
- {
- import mlib.directories: getProjectDirectories;
- import std.file: exists;
- import std.path: buildPath;
- const projectDirs = getProjectDirectories(ProjectQualifier, ProjectOrg, ProjectName);
- const newConfigPath = buildPath(projectDirs.configDir, "pixiv_down.conf");
- const oldConfigPath = buildPath(projectDirs.configDir, "settings.conf");
- /* I'd prefer to use the new config path over the old one when possible,
- * but if that's the only one present then use it. */
- const path = exists(newConfigPath) ? newConfigPath : (exists(oldConfigPath) ? oldConfigPath : newConfigPath);
- return loadConfig(path);
- }
- /// Prompt to reset the PHPSESSID.
- ///
- /// This will store the value in the appropriate location so it
- /// can be read in the future.
- public void resetSessionID() @safe
- {
- import mlib.directories: getProjectDirectories;
- import std.file: exists, mkdirRecurse;
- import std.path: buildPath;
- const projectDirs = getProjectDirectories(ProjectQualifier, ProjectOrg, ProjectName);
- const id = promptForSessionID();
- if (false == exists(projectDirs.dataDir)) {
- mkdirRecurse(projectDirs.dataDir);
- }
- storeSessionID(id, buildPath(projectDirs.dataDir, PHPSessionIDFileName));
- }
- private string promptForSessionID() @trusted
- {
- import std.stdio : readln, stderr, write;
- import std.string : empty, strip;
- import core.stdc.stdlib : exit;
- stderr.writeln("========== NOTICE ==========");
- stderr.writeln("No PHPSESSID found.\n");
- stderr.writeln("Please see the below webpage for instructions to find your PHPSESSID");
- stderr.writeln("https://codeberg.org/supercell/pixiv_down/src/branch/trunk/HowTo-PHPSESSID.txt");
- stderr.writeln("============================");
- write("\nPlease enter your PHPSESSID (leave blank to exit): ");
- const sessionid = readln.strip;
- if (empty(sessionid))
- {
- exit(0);
- }
- return sessionid;
- }
- pragma(inline, true)
- private void storeSessionID(const(char)[] sessionid, const(char)[] path) @safe
- {
- import std.stdio : File;
- File(path, "w+").writeln(sessionid);
- }
- private string fetchSessionID() /* @safe */
- {
- import std.file : exists, mkdirRecurse;
- import std.path : buildPath;
- import std.process : environment;
- import std.stdio : File;
- import std.string : empty, strip;
- import mlib.directories : getProjectDirectories;
- // Environment variable takes precedence over stored value
- const environmentValue = environment.get("PIXIV_DOWN_SESSID");
- if (environmentValue !is null) {
- return environmentValue;
- }
- const projectDirs = getProjectDirectories(ProjectQualifier, ProjectOrg, ProjectName);
- const sessidPath = buildPath(projectDirs.dataDir, PHPSessionIDFileName);
- if (false == exists(sessidPath)) {
- mkdirRecurse(projectDirs.dataDir);
- const newID = promptForSessionID();
- storeSessionID(newID, sessidPath);
- return newID;
- }
- const sessionid = File(sessidPath).readln.strip;
- if (empty(sessionid)) {
- const newID = promptForSessionID();
- storeSessionID(newID, sessidPath);
- return newID;
- }
- return sessionid;
- }
|