From 438ccdc9d7f3316a8ebd5eb5dff993c8de514884 Mon Sep 17 00:00:00 2001 From: Nedko Date: Mon, 1 Jul 2024 12:52:39 +0300 Subject: [PATCH] Reworked downloaded now available. Tagging not working --- .gitignore | 4 +- Makefile | 7 +- README | 53 +- TODO | 4 + common.cpp | 6 +- config_example.json | 2 +- main.cpp | 1170 +++++-------------------------------------- monstercat_dl.cpp | 6 +- 8 files changed, 167 insertions(+), 1085 deletions(-) diff --git a/.gitignore b/.gitignore index 30b87c6..e7b0f39 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,3 @@ -login.json -release.json -cookies.txt +config.json mcat_dl* .vscode/* diff --git a/Makefile b/Makefile index 249132b..4f6ef7e 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,9 @@ +srcs += main.cpp +srcs += curl_dl.cpp +srcs += monstercat_dl.cpp +srcs += common.cpp + all: - g++ main.cpp -o mcat_dl + g++ ${srcs} -lcurl -o mcat_dl .PHONY: all diff --git a/README b/README index a2bd982..8072cae 100644 --- a/README +++ b/README @@ -1,26 +1,42 @@ ---- Usage --- -There must be a file named "login.json" in the working directory with your monstercat credentials. -See example_login.json for the template. +# Usage +There must be a file named "config.json" in the working directory with your monstercat credentials and other configurations. +See config_example.json for the template. ---- JSON Library Source --- +# Download File Structure +### Release Folder +**download_path/Type/YYYY-MM-DD - CatalogID - Artist - Title** +* download_path - Set in config.json +* Type - Album/EP/Single +* YYYY-MM-DD - Release Date in ISO format for easy sorting +* Artist/Title - removed featuring artists from "Artist" and added to "Title" + +### Cover +* Cover(.jpg/.png) - Full resolution from Monstercat +* Cover_small.jpg - 750x750 added to files + +### MP3 and FLAC folders +Separate folders if more than 1 track otherwise put in main folder + +### File Naming +* Artist - Title.(mp3/flac) - Used when only 1 track + +* Number - Title.(mp3/flac) - Used when track artist **matches** release artist +* Number - Artist - Title.(mp3/flac) - Used when track artist **does not match** release artist + +# JSON Library Source https://github.com/nlohmann/json Release - 3.10.5 Commit - 4f8fba14066156b73f1189a2b8bd568bde5284c5 ---- id3edit --- -https://github.com/rstemmer/id3edit -For MP3 tagging -id3edit - --set-name "Title" - --set-album "Album" - --set-artist "Artist" - --set-track "Track Number" - --set-artwork "/path/to/cover" - file.mp3 +# eyeD3 +https://eyed3.readthedocs.io/en/latest/ +* For MP3 tagging +* TODO: Add info here ---- metaflac --- +# metaflac https://xiph.org/flac/download.html For FLAC tagging +``` metaflac // Common --preserve-modtime @@ -44,11 +60,14 @@ metaflac --dont-use-padding file.flac +``` ---- imagemagick --- +# imagemagick https://imagemagick.org/script/download.php For Image Resizing -magick +``` +convert Cover -resize 750x750 Cover_small.jpg +``` diff --git a/TODO b/TODO index e69de29..6c2742f 100644 --- a/TODO +++ b/TODO @@ -0,0 +1,4 @@ +* Rate limit +* Use external tools +* Download and resize cover before tracks +* Tag tracks diff --git a/common.cpp b/common.cpp index 77d5966..cb4a3da 100644 --- a/common.cpp +++ b/common.cpp @@ -124,7 +124,11 @@ bool ensure_folder(const string& main_path, const string& folder) if (!path_exists(main_path)) { - return false; + error = mkdir(main_path.c_str(), 0775); + if (0 != error) + { + return false; + } } full_path = build_fname(main_path, folder, ""); diff --git a/config_example.json b/config_example.json index 730f21b..917280e 100644 --- a/config_example.json +++ b/config_example.json @@ -1,5 +1,5 @@ { - "Email": "user@example.ccom", + "Email": "user@example.com", "Pass": "password", "download_path": "/path/to/monstercat", "convert_exec": "convert", diff --git a/main.cpp b/main.cpp index 38450f9..c591eb6 100644 --- a/main.cpp +++ b/main.cpp @@ -1,1108 +1,162 @@ -// C++ Libs +#include #include -#include -#include -#include #include -#include -// C Libs -#include -#include +#include "monstercat_dl.h" +#include "common.h" -// File Libs #include "json.hpp" -struct tag -{ - std::string artist; - std::string title; - std::string number; -}; - -constexpr const char RELEASE_JSON[] = "release.json"; -constexpr bool IS_MP3 = true; -constexpr bool IS_FLAC = false; -constexpr bool IS_JPG = true; -constexpr bool IS_PNG = false; -constexpr uint32_t COVER_SIZE = 750; -constexpr const char ID3EDIT_INVOKE[] = "id3edit"; -constexpr const char MAGICK_INVOKE[] = "magick"; - -#ifdef _WIN32 -constexpr const char FOLDER_DELIM = '\\'; -#else -constexpr const char FOLDER_DELIM = '/'; -#endif - using namespace std; using nlohmann::json; -// 1. Login -// 2. For each release - -// 2.1 Download Release JSON -// 2.2 Parse JSON -// 2.3 Make Release Folder -// (Catalog Number %*d - Artist - Title) -// 2.4 Make MP3 & FLAC Folders ??? (If Tracks > 1) -// 2.5 Download Cover -// 2.6 Make 750x750 Cover JPEG Image -// 2.7 Rename Cover Image (Proper Extension) -// 2.8 Download Track (MP3) -// (Track Num - Artist - Title) -// 2.9 Tag MP3 -// 2.10 Download Track (FLAC) -// (Track Num - Artist - Title) -// 2.11 Tag FLAC - -// 3. Logout - -void usage(const string& name) +void usage(const char *name) { - cout << "Usage:" << endl; - cout << name << " [path]" << endl; - cout << " -1 " << endl; - cout << " Single release" << endl; - cout << " -j " << endl; - cout << " JSON file denoting release range or releases array" << endl; - cout << " path - root path to download to" << endl; - cout << " Default: ." << endl; -} - -bool system_command(const string& cmd) -{ - int result = system(cmd.c_str()); - if (0 == result) - { - return true; - } - else - { - return false; - } -} - -bool login() -{ - string cmd; - - cmd = "curl -f -L -c cookies.txt -b cookies.txt -X POST"; - cmd += " https://player.monstercat.app/api/sign-in"; - cmd += " -H \"Content-Type: application/json\" --data-binary \"@login.json\""; - - return system_command(cmd); -} - -bool logout() -{ - string cmd; - - cmd = "curl -f -L -c cookies.txt -b cookies.txt -X POST"; - cmd += " https://player.monstercat.app/api/sign-out"; - - return system_command(cmd); -} - -bool download_release_json(const string& catalog_release) -{ - string cmd; - - cmd = "curl -f -L -c cookies.txt -b cookies.txt"; - cmd += " https://player.monstercat.app/api/catalog/release/"; - cmd += catalog_release; - cmd += " -o "; - cmd += RELEASE_JSON; - - return system_command(cmd); -} - -bool download_cover(const string& release_id, const string& path) -{ - string cmd; - - cmd = "curl -f -L -c cookies.txt -b cookies.txt"; - cmd += " \"https://www.monstercat.com/release/"; - cmd += release_id; - cmd += "/cover\" -o \""; - cmd += path; - cmd += FOLDER_DELIM; - cmd += "Cover\""; - - return system_command(cmd); -} - -json parse_json_file(const string& filename) -{ - json j; - ifstream file; - string str; - - file.open(filename); - str.assign(std::istreambuf_iterator(file), std::istreambuf_iterator()); - file.close(); - j = json::parse(str); - - return j; -} - -pair get_artist_feat(const string& str) -{ - pair result; - int pos; - - pos = str.find("feat."); - if (string::npos == pos) - { - result.first = str; - result.second = ""; - } - else - { - result.first = str.substr(0, pos - 1); - result.second = str.substr(pos); - } - - return result; -} - -pair get_artist_title(const json& obj) -{ - pair result; - pair artist_feat; - string str; - string feat; - string version; - bool contains; - int pos; - - artist_feat = get_artist_feat(obj["ArtistsTitle"]); - result.first = artist_feat.first; - - contains = false; - - str = obj["Title"]; - if (!artist_feat.second.empty()) - { - str += " ("; - str += artist_feat.second; - str += ')'; - contains = true; - } - - // Empty does not work on json string - version = obj["Version"]; - if (!version.empty()) - { - str += contains ? " [" : " ("; - str += version; - str += contains ? ']' : ')'; - } - - result.second = str; - return result; -} - -tag get_single_tag(const json& track) -{ - tag result; - pair artist_title; - - result.number = to_string(track["TrackNumber"]); - artist_title = get_artist_title(track); - result.artist = artist_title.first; - result.title = artist_title.second; - - return result; -} - -vector get_tags_from_release(const json& info) -{ - vector result; - - for (int i = 0; i < info["Tracks"].size(); ++i) - { - result.push_back(get_single_tag(info["Tracks"][i])); - } - - return result; -} - -bool make_dir(const string& path) -{ - string cmd; - - cmd = "mkdir \""; - cmd += path; - cmd += '\"'; - - return system_command(cmd); -} - -bool download_track(const string& release_id, const string& track_id, - const string& path, const string& filename, bool single_folder, bool is_mp3) -{ - string format_str; - string format_ext; - string format_folder; - - string cmd; - - if (is_mp3) - { - format_str = "mp3_320"; - format_ext = "mp3"; - format_folder = FOLDER_DELIM; - format_folder += "MP3"; - } - else - { - format_str = "flac"; - format_ext = "flac"; - format_folder = FOLDER_DELIM; - format_folder += "FLAC"; - } - - cmd = "curl -f -L -c cookies.txt -b cookies.txt"; - cmd += " \"https://player.monstercat.app/api/release/"; - cmd += release_id; - cmd += "/track-download/"; - cmd += track_id; - cmd += "?format="; - cmd += format_str; - cmd += "\" -o \""; - cmd += path; - - if (!single_folder) - { - cmd += format_folder; - } - - cmd += FOLDER_DELIM; - cmd += filename; - cmd += "."; - cmd += format_ext; - cmd += "\""; - - return system_command(cmd); -} - -string num_to_str(int num, int precision) -{ - string result; - - result = to_string(num); - - while (result.size() < precision) - { - result.insert(result.begin(), '0'); - } - - return result; -} - -string get_release_dir_name(const string& main_path, const string& release_prefix, - int release_num, const string& release_suffix, const string& artist, - const string& title, int precision) -{ - string path; - - path = main_path; - path += FOLDER_DELIM; - path += release_prefix; - path += FOLDER_DELIM; - path += num_to_str(release_num, precision); - path += release_suffix; - path += " - "; - - if ((artist != "Monstercat") && (artist != "Various Artists")) - { - path += artist; - path += " - "; - } - - path += title; - - return path; -} - -string get_track_filename(int track_num, const string& artist, - const string& title, const string& album_artist) -{ - string filename; - - if (0 != track_num) - { - filename = num_to_str(track_num, 2); - filename += " - "; - } - - if ((artist != "Monstercat") && (artist != "Various Artists") && - (artist != album_artist)) - { - filename += artist; - filename += " - "; - } - - filename += title; - - return filename; -} - -bool should_resize_JPG(const string& path) -{ - // Do a resize by default - bool result = true; - ifstream file; - string filename; - int marker = 0; - int symbol; - - filename = path; - filename += FOLDER_DELIM; - filename += "Cover"; - file.open(filename); - - // Check Header 1 - symbol = file.get(); - if (symbol != 0xFF) - { - return result; - } - - // Check Header 2 - symbol = file.get(); - if (symbol != 0xD8) - { - return result; - } - - while(1) - { - int discarded_bytes = 0; - - if (file.eof()) - { - return result; - } - marker = file.get(); - - // Seek to 0xFF - while (marker != 0xFF) - { - discarded_bytes++; - if (file.eof()) - { - return result; - } - marker = file.get(); - } - - // Find end of 0xFF - do - { - if (file.eof()) - { - return result; - } - marker = file.get(); - } - while (marker == 0xFF); - - // ??? - if (0 == discarded_bytes) - { - return result; - } - - switch(marker) - { - // Read width & height - case 0xC0: - case 0xC1: - case 0xC2: - case 0xC3: - case 0xC5: - case 0xC6: - case 0xC7: - case 0xC9: - case 0xCA: - case 0xCB: - case 0xCD: - case 0xCE: - case 0xCF: - int16_t width; - int16_t height; - - // Skip 3 bytes - file.get(); - file.get(); - file.get(); - - file.read(reinterpret_cast(&height), 2); - file.read(reinterpret_cast(&width), 2); - - if ((width > COVER_SIZE) || (height > COVER_SIZE)) - { - return true; - } - else - { - return false; - } - break; - - // ??? - case 0xDA: - case 0xD9: - return result; - break; - - // Skip length-2 bytes - default: - int16_t length; - - file.read(reinterpret_cast(&length), 2); - if (length < 2) - { - return 0; - } - - length -= 2; - for (int i = 0; i < length; ++i) - { - file.get(); - } - - if (file.eof()) - { - return result; - } - break; - } - } -} - -bool should_resize_PNG(const string& path) -{ - ifstream file; - string filename; - uint8_t buf[4]; - uint32_t width; - uint32_t height; - - filename = path; - filename += FOLDER_DELIM; - filename += "Cover"; - file.open(filename); - - // Seek - file.seekg(16); - - // Read width - width = 0; - file.read(reinterpret_cast(&buf), 4); - for (int i = 0; i < 4; ++i) - { - width <<= 8; - width += buf[i]; - } - - // Read height - height = 0; - file.read(reinterpret_cast(&buf), 4); - for (int i = 0; i < 4; ++i) - { - height <<= 8; - height += buf[i]; - } - - file.close(); - - if ((width > COVER_SIZE) || (height > COVER_SIZE)) - { - return true; - } - else - { - return false; - } -} - -bool get_cover_type(const string& path) -{ - string filename; - ifstream file; - int header; - - filename = path; - filename += FOLDER_DELIM; - filename += "Cover"; - - file.open(filename); - - header = file.peek(); - switch (header) - { - // JPG - case 0xFF: - return IS_JPG; - break; - case 0x89: - return IS_PNG; - break; - } - - throw invalid_argument(filename); -} - -bool resize_cover(const string& path, bool is_jpg) -{ - string cmd; - bool should_resize; - - // Should we actually resize - if (is_jpg == IS_JPG) - { - should_resize = should_resize_JPG(path); - } - else - { - should_resize = should_resize_PNG(path); - } - - cmd = MAGICK_INVOKE; - cmd += " \""; - cmd += path; - cmd += FOLDER_DELIM; - cmd += "Cover"; - cmd += "\" "; - - if (should_resize) - { - cmd += "-resize "; - cmd += to_string(COVER_SIZE); - cmd += "x"; - cmd += to_string(COVER_SIZE); - cmd += " "; - } - - cmd += "\""; - cmd += path; - cmd += FOLDER_DELIM; - cmd += "Cover_small.jpg\""; - - return system_command(cmd); -} - -bool rename_cover(const string& path, bool is_jpg) -{ - string filename; - string filename_new; - int error; - - filename = path; - filename += FOLDER_DELIM; - filename += "Cover"; - - filename_new = filename; - if (is_jpg == IS_JPG) - { - filename_new += ".jpg"; - } - else - { - filename_new += ".png"; - } - - error = rename(filename.c_str(), filename_new.c_str()); - if (0 != error) - { - return false; - } - - return true; -} - -bool tag_MP3(const string& path, const string& filename, bool is_single_dir, - const string& title, const string& album, const string& artist, - const string& tracknum) -{ - string cmd; - - cmd = ID3EDIT_INVOKE; - cmd += " --set-name \""; - cmd += title; - cmd += "\" --set-album \""; - cmd += album; - cmd += "\" --set-artist \""; - cmd += artist; - cmd += "\" --set-track "; - cmd += tracknum; - cmd += " --set-artwork \""; - cmd += path; - cmd += FOLDER_DELIM; - cmd += "Cover_small.jpg\" \""; - cmd += path; - cmd += FOLDER_DELIM; - if (!is_single_dir) - { - cmd += "MP3"; - cmd += FOLDER_DELIM; - } - cmd += filename; - cmd += ".mp3\""; - - return system_command(cmd); -} - -bool tag_FLAC(const string& path, const string& filename, bool is_single_dir, - const string& title, const string& album, const string& artist, - const string& tracknum) -{ - string cmd; - bool ok; - - // First command - remove tags - cmd = "metaflac --preserve-modtime --no-utf8-convert "; - cmd += "--remove-tag=TITLE "; - cmd += "--remove-tag=ARTIST "; - cmd += "--remove-tag=ALBUM "; - cmd += "--remove-tag=TRACKNUMBER \""; - cmd += path; - cmd += FOLDER_DELIM; - if (!is_single_dir) - { - cmd += "FLAC"; - cmd += FOLDER_DELIM; - } - cmd += filename; - cmd += ".flac\""; - - ok = system_command(cmd); - if (!ok) - { - return false; - } - - // Second command - remove pictures - cmd = "metaflac --preserve-modtime --no-utf8-convert "; - cmd += "--remove --block-type=PICTURE \""; - cmd += path; - cmd += FOLDER_DELIM; - if (!is_single_dir) - { - cmd += "FLAC"; - cmd += FOLDER_DELIM; - } - cmd += filename; - cmd += ".flac\""; - - ok = system_command(cmd); - if (!ok) - { - return false; - } - - // Third command - set metadata - cmd = "metaflac --preserve-modtime --no-utf8-convert --dont-use-padding "; - cmd += "\"--import-picture-from=3|image/jpeg|||"; - cmd += path; - cmd += FOLDER_DELIM; - cmd += "Cover_small.jpg\" \"--set-tag=TITLE="; - cmd += title; - cmd += "\" \"--set-tag=ARTIST="; - cmd += artist; - cmd += "\" \"--set-tag=ALBUM="; - cmd += album; - cmd += "\" --set-tag=TRACKNUMBER="; - cmd += tracknum; - cmd += " \""; - cmd += path; - cmd += FOLDER_DELIM; - if (!is_single_dir) - { - cmd += "FLAC"; - cmd += FOLDER_DELIM; - } - cmd += filename; - cmd += ".flac\""; - - return system_command(cmd); -} - -void save_release_date(const string& path, const string& date) -{ - ofstream file; - string filepath; - - filepath = path; - filepath += FOLDER_DELIM; - filepath += "Date.txt"; - - file.open(filepath); - file << date << endl; - file.close(); -} - -bool full_donwload(const string& path, const string& release_prefix, - int release_num, const string& release_suffix) -{ - bool ok; - string catalog_release_str; - json info; - string release_dir; - string track_filename; - pair release_artist_title; - int release_precision; - bool is_single_dir; - bool cover_is_jpg; - vector tags; - - catalog_release_str = release_prefix; - catalog_release_str += num_to_str(release_num, 3); - catalog_release_str += release_suffix; - - release_precision = 3; - if (release_prefix == "MCS") - { - release_precision = 4; - } - - // Download Release JSON - ok = download_release_json(catalog_release_str); - if (!ok) - { - return false; - } - - // Parse JSON - info = parse_json_file(RELEASE_JSON); - - release_artist_title = get_artist_title(info["Release"]); - release_dir = get_release_dir_name(path, release_prefix, release_num, - release_suffix, release_artist_title.first, release_artist_title.second, - release_precision); - - // Make Release Folder - ok = make_dir(release_dir); - if (!ok) - { - return false; - } - - // Save Release Date - save_release_date(release_dir, info["Release"]["ReleaseDate"]); - - is_single_dir = (info["Tracks"].size() == 1); - - // Make MP3 & FLAC Folders (If more than 1 Track) - if (!is_single_dir) - { - string tmp; - - tmp = release_dir; - tmp += FOLDER_DELIM; - tmp += "MP3"; - - ok = make_dir(tmp); - if (!ok) - { - return false; - } - - tmp = release_dir; - tmp += FOLDER_DELIM; - tmp += "FLAC"; - - ok = make_dir(tmp); - if (!ok) - { - return false; - } - } - - // Download Cover - ok = download_cover(catalog_release_str, release_dir); - if (!ok) - { - return false; - } - - // Try to find out Cover type - try - { - cover_is_jpg = get_cover_type(release_dir); - } - catch (const std::exception& e) - { - return false; - } - - // Make 750x750 Cover JPEG Image - ok = resize_cover(release_dir, cover_is_jpg); - if (!ok) - { - return false; - } - - // Rename Cover Image (Proper Extension) - ok = rename_cover(release_dir, cover_is_jpg); - if (!ok) - { - return false; - } - - tags = get_tags_from_release(info); - for (int i = 0; i < info["Tracks"].size(); ++i) - { - track_filename = get_track_filename(info["Tracks"][i]["TrackNumber"], - tags[i].artist, tags[i].title, release_artist_title.first); - - // Download Track (MP3) - ok = download_track(info["Release"]["Id"], info["Tracks"][i]["Id"], - release_dir, track_filename, is_single_dir, IS_MP3); - if (!ok) - { - return false; - } - - // Tag MP3 - ok = tag_MP3(release_dir, track_filename, is_single_dir, tags[i].title, - release_artist_title.second, tags[i].artist, tags[i].number); - if (!ok) - { - return false; - } - - // Download Track (FLAC) - ok = download_track(info["Release"]["Id"], info["Tracks"][i]["Id"], - release_dir, track_filename, is_single_dir, IS_FLAC); - if (!ok) - { - return false; - } - - // Tag FLAC - ok = tag_FLAC(release_dir, track_filename, is_single_dir, tags[i].title, - release_artist_title.second, tags[i].artist, tags[i].number); - if (!ok) - { - return false; - } - } - - return true; -} - -bool break_down_release_str(const string& release, string& prefix, int& num, string& suffix) -{ - int pos; - int pos2; - string digits = "0123456789"; - - prefix = ""; - num = 0; - suffix = ""; - - pos = release.find_first_of(digits); - if (string::npos == pos) - { - return false; - } - - prefix = release.substr(0, pos); - pos2 = release.find_first_not_of(digits, pos); - if (string::npos == pos2) - { - try - { - num = stod(release.substr(pos)); - } - catch(const std::exception& e) - { - return false; - } - } - else - { - try - { - num = stod(release.substr(pos, pos2 - pos)); - } - catch(const std::exception& e) - { - return false; - } - suffix = release.substr(pos2); - } - - return true; + cout << "Usage: " << name << " [catalog id] ..." << endl; } int main(int argc, char **argv) { - vector args(&argv[1], &argv[argc]); + // Config stuff + bool ok; + json config; + string email; + string pass; + string main_path; + string convert_exec = "convert"; + string eyed3_exec = "eyeD3"; + string metaflac_exec = "metaflac"; - pair single_release = {false, ""}; - pair json_option = {false, ""}; - string path = "."; + vector catalog_ids(&(argv[1]), &(argv[argc])); + json j; + Monstercat_DL mcat; + Release release; - if (argc < 3) + // Folder stuff + string release_folder; + string mp3_folder; + string flac_folder; + string extended_folder; + string filename; + string filepath; + + ok = read_config(config); + if (!ok) + { + cout << "Could not read config" << endl; + return -1; + } + + json_extract(config, "Email", email); + json_extract(config, "Pass", pass); + json_extract(config, "download_path", main_path); + + ok = mcat.login(email, pass); + if (!ok) + { + cout << "Could not login" << endl; + return -1; + } + + if (argc < 2) { - cout << "Too few arguments" << endl; usage(argv[0]); return -1; } - // Ugly getopt - for (int i = 0; i < args.size(); ++i) + for (string& id : catalog_ids) { - if ((args[i] == "-1") && (i + 1 < args.size())) + // Gather data + j = mcat.get_release_json(id); + release = mcat.parse_release_json(j); + j = mcat.get_browse_json(release.id); + mcat.add_extended_mixes(release, j); + + // Calculate folders + release_folder = mcat.calc_release_folder(release, main_path); + mp3_folder = release_folder; + flac_folder = release_folder; + if (release.tracks.size() > 1) { - single_release.first = true; - single_release.second = args[i + 1]; - args.erase(args.begin() + i); - args.erase(args.begin() + i); - --i; + mp3_folder = build_fname(release_folder, "MP3", ""); + flac_folder = build_fname(release_folder, "FLAC", ""); + } + extended_folder = build_fname(release_folder, "Extended", ""); + ok = ensure_folder(mp3_folder, ""); + if (!ok) + { + cout << "Could not ensure MP3 folder - '" << mp3_folder << "'" << endl; continue; } - if ((args[i] == "-j") && (i + 1 < args.size())) + ok = ensure_folder(flac_folder, ""); + if (!ok) { - json_option.first = true; - json_option.second = args[i + 1]; - args.erase(args.begin() + i); - args.erase(args.begin() + i); - --i; + cout << "Could not ensure FLAC folder - '" << mp3_folder << "'" << endl; continue; } - } - // Both selected - if (single_release.first && json_option.first) - { - cout << "Both single release and json file are selected." << endl; - usage(argv[0]); - return -1; - } - - // None selected - if (!single_release.first && !json_option.first) - { - cout << "Neither single release nor json file are selected." << endl; - usage(argv[0]); - return -1; - } - - // Add path from arguments - if (!args.empty()) - { - path = args[0]; - } - - // Remove trailing slash - if (path[path.size() - 1] == FOLDER_DELIM) - { - path.erase(path.size() - 1); - } - -#if 1 - // BEGIN TEST PRINTS - if (single_release.first) - { - cout << "SINGLE: " << single_release.second << endl; - } - if (json_option.first) - { - cout << "JSON: " << json_option.second << endl; - } - cout << "PATH: " << path << endl; - // END TEST PRINTS -#endif - - vector releases; - vector::iterator it; - - // Add single release - if (single_release.first) - { - releases.push_back(single_release.second); - } - - // Parse JSON - if (json_option.first) - { - json j = parse_json_file(json_option.second); - - if (j.contains("releases") && j["releases"].is_array()) + // Download tracks (1 -- N) + for (Track& track : release.tracks) { - for (int i = 0; i < j["releases"].size(); ++i) + filename = mcat.calc_track_filename(release, track.number); + + // Download MP3 + filepath = build_fname(mp3_folder, "", filename); + ok = mcat.download_track(release.id, track.id, filepath, FORMAT_MP3); + if (!ok) { - releases.push_back(j["releases"][i]); + cout << "Could not download MP3 track " << track.number << + " from release " << release.catalog_id << endl; + continue; } - } - else if (j.contains("prefix") && - j.contains("start") && j["start"].is_number_integer() && - j.contains("end") && j["end"].is_number_integer()) - { - string tmp; - for (int i = j["start"]; i <= j["end"]; ++i) - { - // Add release - tmp = j["prefix"]; - tmp += num_to_str(i, 3); - releases.push_back(tmp); - // Add release with suffix - if (j.contains("suffix_try") && !j["suffix_try"].empty()) + // Download FLAC + filepath = build_fname(flac_folder, "", filename); + ok = mcat.download_track(release.id, track.id, filepath, FORMAT_FLAC); + if (!ok) + { + cout << "Could not download MP3 track " << track.number << + " from release " << release.catalog_id << endl; + continue; + } + + // Download Extended Mix + if (!track.extended_mix_file_id.empty()) + { + ok = ensure_folder(extended_folder, ""); + if (!ok) { - tmp += j["suffix_try"]; - releases.push_back(tmp); + cout << "Could not ensure extended folder - '" << + extended_folder << "'" << endl; + continue; + } + + filepath = build_fname(extended_folder, "", filename); + filepath += track.extended_mix_extension; + ok = mcat.download_file(track.extended_mix_file_id, filepath); + if (!ok) + { + cout << "Could not download extended track " << track.number << + " from release " << release.catalog_id << endl; + continue; } } } - else - { - cout << "JSON not recognized" << endl; - return -1; - } - } - string release_prefix; - int release_num; - string release_suffix; - bool ok; - - - ok = login(); - if (!ok) - { - cout << "Failed to login" << endl; - return -1; - } - - // Break down release string - for (it = releases.begin(); it != releases.end(); ++it) - { - ok = break_down_release_str(*it, release_prefix, release_num, release_suffix); + // Download Cover + ok = mcat.download_cover(release.catalog_id, release_folder); if (!ok) { - cout << "Failed to break down - " << *it << endl; + cout << "Could not download cover for release " << release.catalog_id << endl; continue; } - - ok = full_donwload(path, release_prefix, release_num, release_suffix); - if (!ok) - { - cout << "Could not download - " << *it << endl; - } } - ok = logout(); + ok = mcat.logout(); if (!ok) { - cout << "Failed to logout" << endl; + cout << "Could not log out" << endl; } return 0; diff --git a/monstercat_dl.cpp b/monstercat_dl.cpp index cc20f6d..de5980d 100644 --- a/monstercat_dl.cpp +++ b/monstercat_dl.cpp @@ -455,8 +455,7 @@ bool Monstercat_DL::download_cover(const string& catalog_id, const string& path) return false; } - filepath = path; - filepath += "Cover"; + filepath = build_fname(path, "", "Cover"); if (0 == out_headers.count("content-type")) { if (nullptr != m_log) @@ -572,7 +571,6 @@ bool Monstercat_DL::download_file(const string& file_id, const string& filepath) CURL_DL& curl = CURL_DL::get_handle(); bool ok; string url; - string filepath; stringstream out_data; ofstream out_file; @@ -608,5 +606,5 @@ bool Monstercat_DL::download_file(const string& file_id, const string& filepath) out_file << out_data.rdbuf(); out_file.close(); - return false; + return true; }