module config.downloaderconfig; /++ + This struct represents the config of this + programm and is used by the other classes + to configure stuff +/ struct Config { /++ + This variable holds the folder/path into which + mangas are downloaded by default +/ string standard_download_folder; /++ + This variable determins if mangas should be downloaded + again even if they already are downloaded +/ bool redownload_mangas_regardless; /++ + This variable determins if the downloader should output debug infos +/ bool enable_debug_output; } /++ + This class handles reading and creating the config files +/ class DownloaderConfig { static private: import std.stdio : writeln; import std.json : JSONValue, parseJSON; import std.file : exists, mkdir, readText, copy; import std.stdio : toFile; import std.string: strip; import std.array : replace; /++ + This specifies the default path to the config +/ string default_config_path = "/.config/hentai_downloader/config.json"; /++ + This specifies the default path to the template file config file +/ immutable string default_config_template_path = "./default_config_template.json"; /++ + This holds the text of the `default_config_template.json` file in case it + doesn't exist in the default path anymore +/ immutable string default_config_template_text = ` { "standard_download_folder" : "~/Downloads/Lewds/", "redownload_mangas_regardless" : false, "enable_debug_output" : false } `; /++ + This function checks the config in `config_path` exists +/ bool configExists(string config_path) { return exists(config_path); } /++ + This function creates a new default config at `config_path` +/ void createNewConfig(string config_path) { writeln("[*] Creating new config file in ", config_path); // The folder that holds the config file immutable string config_dir = "/home/" ~ getUsername() ~ "/.config/hentai_downloader"; /* writeln("Config folder:", config_dir); */ // if the folder ~/.config/hentai_downloader doesnt exist if(!exists(config_dir)) mkdir(config_dir); // Create it /* writeln("Config file: ", config_path); */ // Write to template file into the config folder if(!exists(config_path)) { /* writeln("Saving default config to file: ", config_path); */ default_config_template_text.toFile(config_path); } } /++ + Turns a relative path e.g. "~/.config" into an absolute path "/home/user/.config" +/ string makeRelativePathAbsolute(string path) { return path.replace("~", "/home/"~getUsername()); } /++ + This function checks if the folder specified in the config file exists + and if not creates it +/ void checkStandardFolder(Config config) { // FIXME: nested folders break me // Replace the relative path string absolutePath = makeRelativePathAbsolute(config.standard_download_folder); if(!exists(absolutePath)) { // If the `standard_download_folder` doesnt exist, create it! absolutePath.mkdir(); } } /++ + Gets the username of the current user +/ string getUsername() { import std.process : executeShell; import core.stdc.stdlib : exit, EXIT_FAILURE; // Execute whoami to get the current username auto whoami = executeShell(`whoami`); if(whoami.status != 0) { // If whoami fails exit the program // FIXME: raise an exception or something writeln("[!] Failed to get the current username"); exit(EXIT_FAILURE); } // Return the stripped username return whoami.output.strip(); } /++ + Get the users .config path +/ string getUserConfigPath() { // Return the combined path to the .config folder of the user return "/home/" ~ getUsername() ~ default_config_path; } /++ + This function trys to parse the config file + given in `config_path`, and return a Config struct +/ Config parseConfig(string config_path) { import std.conv : to; // Read the config file string config_text = to!string(readText(config_path)); // Parse the config as JSON auto config_json = parseJSON(config_text); // Create a new config Config _config; // Assign the values that were parsed from the config file _config.standard_download_folder = config_json["standard_download_folder"].str(); _config.redownload_mangas_regardless = config_json["redownload_mangas_regardless"].boolean(); _config.enable_debug_output = config_json["enable_debug_output"].boolean(); // Adjust the foler path _config.standard_download_folder = makeRelativePathAbsolute(_config.standard_download_folder); return _config; } /++ + Loads and checks the given config +/ Config loadMyConfig(string config_path) { // Get the cofig path for this user config_path = getUserConfigPath(); // Check if the given config exists if(!configExists(config_path)) createNewConfig(config_path); // If it doesn't, create it! // Parse the config Config _config = parseConfig(config_path); // Check the download folder checkStandardFolder(_config); return _config; } public: /++ + This loads and parses the default config at `default_config_path` + into a `Config` struct +/ static Config loadConfig() { return loadMyConfig(this.default_config_path); } /++ + This loads and parses a custom config from `custom_config_path` + into a `Config` struct +/ static Config loadConfig(string custom_config_path) { return loadMyConfig(custom_config_path); } }