#include "monstercat_dl.h" #include "curl_dl.h" #include #include using std::endl; using std::map; using std::ofstream; using std::string; 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) {} Monstercat_DL::~Monstercat_DL() { } bool Monstercat_DL::login(const string& user, const string& pass) { CURL_DL& curl = CURL_DL::get_handle(); bool ok; json data; string url; stringstream out; data["Email"] = user; data["Password"] = pass; url = m_base_url; url += "sign-in"; ok = curl.post_json(url, data, &out); if (!ok) { if (nullptr != log) { *log << "Could not post json" << endl; *log << "CURL:" << curl.get_error() << endl; } return false; } data.clear(); out >> data; if (data.contains("Needs2FA") && data["Needs2FA"].is_boolean() && data["Needs2FA"] == false) { m_is_logged_in = true; return true; } return false; } bool Monstercat_DL::logout() { CURL_DL& curl = CURL_DL::get_handle(); bool ok; json data; string url; if (!m_is_logged_in) { return false; } url = m_base_url; url += "sign-out"; ok = curl.post_json(url, data, nullptr); if (!ok) { if (nullptr != log) { *log << "Could not post json" << endl; *log << "CURL:" << curl.get_error() << endl; } return false; } return ok; } json Monstercat_DL::get_release_json(const string& catalog_id) { CURL_DL& curl = CURL_DL::get_handle(); bool ok; json result; string url; stringstream out; url = m_base_url; url += "catalog/release/"; url += catalog_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; } 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(); bool ok; string url; stringstream out; ofstream out_file; map out_headers; string filename; url = "https://www.monstercat.com/release/"; url += catalog_id; url += "/cover"; ok = curl.download(url, &out, nullptr, &out_headers); if (!ok) { if (nullptr != log) { *log << "Could not download image" << endl; *log << "CURL:" << curl.get_error() << endl; } return false; } filename = path; if (0 == out_headers.count("content-type")) { if (nullptr != log) { *log << "No content-type" << endl; } } else { 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); if (!out_file.is_open()) { if (nullptr != log) { *log << "Could not open file for write" << endl; *log << filename << endl; } return false; } out_file << out.rdbuf(); out_file.close(); 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; }