diff --git a/monstercat_dl.cpp b/monstercat_dl.cpp index 3f03f24..22c6301 100644 --- a/monstercat_dl.cpp +++ b/monstercat_dl.cpp @@ -12,6 +12,74 @@ using std::stringstream; using nlohmann::json; +static bool json_extract(const json& j, const string& key, string& value) +{ + bool result = false; + + if (j.contains(key) && j[key].is_string()) + { + value = j[key]; + result = true; + } + + return result; +} + +static string trim_whitespace(const string& s) +{ + const string whitespace = " \t\r\n\f\v"; + string result(s); + size_t pos; + + pos = result.find_first_not_of(whitespace); + result.erase(0, pos); + pos = result.find_last_not_of(whitespace); + result.erase(pos + 1); + + return result; +} + +string Monstercat_DL::calc_proper_artist(const string& artist_raw) +{ + size_t pos; + string result; + + pos = artist_raw.find("feat."); + if (string::npos == pos) + { + return artist_raw; + } + + result = artist_raw.substr(0, pos); + result = trim_whitespace(result); + + return result; +} + +string Monstercat_DL::calc_proper_title(const string& artist_raw, + const string& title_raw, const string& version_raw) +{ + size_t pos; + string result; + + result = trim_whitespace(title_raw); + + pos = artist_raw.find("feat."); + if (string::npos != pos) + { + result += " ("; + result += trim_whitespace(artist_raw.substr(pos)); + result += ")"; + } + + if (!version_raw.empty()) + { + result += " ("; + result += trim_whitespace(version_raw); + result += ")"; + } +} + Monstercat_DL::Monstercat_DL() : log(&std::cout), m_base_url("https://player.monstercat.app/api/"), m_is_logged_in(false) @@ -116,6 +184,103 @@ json Monstercat_DL::get_release_json(const string& catalog_id) return result; } +json Monstercat_DL::get_browse_json(const string& release_id) +{ + CURL_DL& curl = CURL_DL::get_handle(); + bool ok; + json result; + string url; + stringstream out; + + url = m_base_url; + url += "catalog/browse?offset=0&limit=0&search=&sort=&nogold=false&releaseId="; + url += release_id; + + ok = curl.download(url, &out); + if (!ok) + { + if (nullptr != log) + { + *log << "Could not download json" << endl; + *log << "CURL:" << curl.get_error() << endl; + } + return result; + } + + out >> result; + return result; +} + +Release Monstercat_DL::parse_release_json(const json& release_json) +{ + Release result; + json release_object; + json tracks_object; + string artist_raw; + string title_raw; + string version_raw; + Track temp_track; + + if (release_json.contains("Release")) + { + release_object = release_json["Release"]; + } + else + { + return result; + } + + // Parse Release + json_extract(release_object, "Id", result.id); + json_extract(release_object, "Type", result.type); + json_extract(release_object, "ReleaseDate", result.release_date); + { + size_t pos = result.release_date.find('T'); + if (pos != string::npos) + { + result.release_date.erase(pos); + } + } + + json_extract(release_object, "ArtistsTitle", artist_raw); + json_extract(release_object, "Title", title_raw); + json_extract(release_object, "Version", version_raw); + + result.artist = calc_proper_artist(artist_raw); + result.title = calc_proper_title(artist_raw, title_raw, version_raw); + + if (release_json.contains("Tracks") && release_json["Tracks"].is_array()) + { + tracks_object = release_json["Tracks"]; + } + else + { + return result; + } + + // Parse Tracks + for (json& curr_track : tracks_object) + { + if (curr_track.contains("TrackNumber") && + curr_track["TrackNumber"].is_number_integer()) + { + temp_track.number = curr_track["TrackNumber"]; + } + json_extract(curr_track, "Id", temp_track.id); + + json_extract(curr_track, "ArtistsTitle", artist_raw); + json_extract(curr_track, "Title", title_raw); + json_extract(curr_track, "Version", version_raw); + + temp_track.artist = calc_proper_artist(artist_raw); + temp_track.title = calc_proper_title(artist_raw, title_raw, version_raw); + + result.tracks.push_back(temp_track); + } + + return result; +} + bool Monstercat_DL::download_cover(const string& catalog_id, const string& path) { CURL_DL& curl = CURL_DL::get_handle(); @@ -141,23 +306,31 @@ bool Monstercat_DL::download_cover(const string& catalog_id, const string& path) return false; } + filename = path; if (0 == out_headers.count("content-type")) { if (nullptr != log) { - *log << "Unknown content-type" << endl; + *log << "No content-type" << endl; } - return false; } - - filename = path; - if (out_headers["content-type"] == "image/jpeg") + else { - filename += ".jpg"; - } - else if (out_headers["content-type"] == "image/png") - { - filename += ".png"; + if (out_headers["content-type"] == "image/jpeg") + { + filename += ".jpg"; + } + else if (out_headers["content-type"] == "image/png") + { + filename += ".png"; + } + else + { + if (nullptr != log) + { + *log << "Unknown Content-Type for cover - " << out_headers["content-type"] << endl; + } + } } out_file.open(filename, std::ios::binary); @@ -176,3 +349,29 @@ bool Monstercat_DL::download_cover(const string& catalog_id, const string& path) return true; } + +bool Monstercat_DL::download_track(const string& release_id, + const string& track_id, const string& path) +{ + string url; + + url = m_base_url; + url += "release/"; + url += release_id; + url += "/track-download/"; + url += track_id; + + return false; +} + +bool Monstercat_DL::download_file(const string& file_id, const string& path) +{ + string url; + + url = m_base_url; + url += "file/"; + url += file_id; + url += "/open?download=true"; + + return false; +} diff --git a/monstercat_dl.h b/monstercat_dl.h index 01b5357..ebdf96e 100644 --- a/monstercat_dl.h +++ b/monstercat_dl.h @@ -3,8 +3,32 @@ #include #include +#include #include "json.hpp" +struct Track +{ +public: + int number; + std::string artist; + std::string title; + + std::string id; + std::string extended_mix_file_id; + std::string extended_mix_extension; +}; + +struct Release +{ + std::string type; + std::string release_date; + std::string artist; + std::string title; + std::vector tracks; + + std::string id; +}; + class Monstercat_DL { private: @@ -14,6 +38,10 @@ private: bool m_is_logged_in; + std::string calc_proper_artist(const std::string& artist_raw); + std::string calc_proper_title(const std::string& artist_raw, + const std::string& title_raw, const std::string& version_raw); + public: Monstercat_DL(); ~Monstercat_DL(); @@ -22,7 +50,15 @@ public: bool logout(); nlohmann::json get_release_json(const std::string& catalog_id); + nlohmann::json get_browse_json(const std::string& release_id); + + Release parse_release_json(const nlohmann::json& release_json); + bool download_cover(const std::string& catalog_id, const std::string& path); + bool download_track(const std::string& release_id, + const std::string& track_id, const std::string& path); + bool download_file(const std::string& file_id, const std::string& path); + }; #endif // MONSTERCAT_DL_H_