diff options
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/Spotify.cpp | 290 |
1 files changed, 0 insertions, 290 deletions
diff --git a/src/plugins/Spotify.cpp b/src/plugins/Spotify.cpp deleted file mode 100644 index d41446b..0000000 --- a/src/plugins/Spotify.cpp +++ /dev/null @@ -1,290 +0,0 @@ -#include "../../plugins/Spotify.hpp" -#include "../../include/NetUtils.hpp" -#include "../../include/Utils.hpp" -#include "../../include/Scale.hpp" - -namespace QuickMedia { - SpotifyPage::SpotifyPage(Program *program) : Page(program) { - Path spotify_cache_path = get_cache_dir().join("spotify").join("access_token"); - if(file_get_content(spotify_cache_path, access_token) != 0) - access_token.clear(); - } - - DownloadResult SpotifyPage::download_json_error_retry(Json::Value &json_root, const std::string &url, std::vector<CommandArg> additional_args) { - if(access_token.empty()) { - PluginResult update_token_res = update_token(); - if(update_token_res != PluginResult::OK) return DownloadResult::ERR; - } - - std::string authorization = "authorization: Bearer " + access_token; - additional_args.push_back({ "-H", authorization.c_str() }); - - std::string err_msg; - DownloadResult result = download_json(json_root, url, additional_args, true, &err_msg); - if(result != DownloadResult::OK) return result; - - if(!json_root.isObject()) - return DownloadResult::ERR; - - const Json::Value &error_json = json_root["error"]; - if(error_json.isObject()) { - const Json::Value &status_json = error_json["status"]; - if(status_json.isInt() && status_json.asInt() == 401) { - fprintf(stderr, "Spotify access token expired, requesting a new token...\n"); - PluginResult update_token_res = update_token(); - if(update_token_res != PluginResult::OK) return DownloadResult::ERR; - - authorization = "authorization: Bearer " + access_token; - additional_args.back().value = authorization.c_str(); - DownloadResult result = download_json(json_root, url, additional_args, true); - if(result != DownloadResult::OK) return result; - - if(!json_root.isObject()) - return DownloadResult::ERR; - } - } - - return DownloadResult::OK; - } - - PluginResult SpotifyPage::update_token() { - std::string url = "https://open.spotify.com/get_access_token?reason=transport&productType=web_player"; - - std::vector<CommandArg> additional_args = { - { "-H", "authority: application/json" }, - { "-H", "Referer: open.spotify.com" }, - { "-H", "app-platform: WebPlayer" }, - { "-H", "spotify-app-version: 1.1.53.594.g8178ce9b" } - }; - - Json::Value json_root; - DownloadResult result = download_json(json_root, url, std::move(additional_args), true); - if(result != DownloadResult::OK) return download_result_to_plugin_result(result); - - if(!json_root.isObject()) - return PluginResult::ERR; - - const Json::Value &access_token_json = json_root["accessToken"]; - if(!access_token_json.isString()) - return PluginResult::ERR; - - access_token = access_token_json.asString(); - Path spotify_cache_dir = get_cache_dir().join("spotify"); - if(create_directory_recursive(spotify_cache_dir) == 0) - fprintf(stderr, "Failed to create spotify cache directory\n"); - spotify_cache_dir.join("access_token"); - file_overwrite_atomic(spotify_cache_dir, access_token); - return PluginResult::OK; - } - - static void image_sources_set_thumbnail(BodyItem *body_item, const Json::Value &sources_list_json) { - if(!sources_list_json.isArray()) - return; - - for(const Json::Value &source_json : sources_list_json) { - if(!source_json.isObject()) - continue; - - const Json::Value &width_json = source_json["width"]; - const Json::Value &height_json = source_json["height"]; - const Json::Value &url_json = source_json["url"]; - if(!width_json.isInt() || !height_json.isInt() || !url_json.isString()) - continue; - - if(height_json.asInt() >= 200 && height_json.asInt() <= 350) { - body_item->thumbnail_url = url_json.asString(); - body_item->thumbnail_mask_type = ThumbnailMaskType::CIRCLE; - body_item->thumbnail_size.x = width_json.asInt(); - body_item->thumbnail_size.y = height_json.asInt(); - body_item->thumbnail_size = clamp_to_size(body_item->thumbnail_size, sf::Vector2i(150, 150)); - return; - } - } - } - - SearchResult SpotifyPodcastSearchPage::search(const std::string &str, BodyItems &result_items) { - PluginResult result = get_page(str, 0, result_items); - if(result != PluginResult::OK) - return SearchResult::ERR; - return SearchResult::OK; - } - - PluginResult SpotifyPodcastSearchPage::get_page(const std::string &str, int page, BodyItems &result_items) { - std::string url = "https://api.spotify.com/v1/search?query="; - url += url_param_encode(str); - url += "&type=show&include_external=audio&market=US&offset=" + std::to_string(page * 10) + "&limit=10"; - - std::vector<CommandArg> additional_args = { - { "-H", "accept: application/json" }, - { "-H", "Referer: https://open.spotify.com/" }, - { "-H", "app-platform: WebPlayer" }, - { "-H", "spotify-app-version: 1.1.53.594.g8178ce9b" } - }; - - Json::Value json_root; - DownloadResult result = download_json_error_retry(json_root, url, additional_args); - if(result != DownloadResult::OK) return download_result_to_plugin_result(result); - - if(!json_root.isObject()) - return PluginResult::ERR; - - const Json::Value &shows_json = json_root["shows"]; - if(!shows_json.isObject()) - return PluginResult::ERR; - - const Json::Value &items_json = shows_json["items"]; - if(!items_json.isArray()) - return PluginResult::ERR; - - for(const Json::Value &item_json : items_json) { - if(!item_json.isObject()) - continue; - - const Json::Value &name_json = item_json["name"]; - const Json::Value &uri_json = item_json["uri"]; - if(!name_json.isString() || !uri_json.isString()) - continue; - - auto body_item = BodyItem::create(name_json.asString()); - body_item->url = uri_json.asString(); - - const Json::Value &publisher_json = item_json["publisher"]; - if(publisher_json.isString()) { - body_item->set_description(publisher_json.asString()); - body_item->set_description_color(sf::Color(179, 179, 179)); - } - - image_sources_set_thumbnail(body_item.get(), item_json["images"]); - result_items.push_back(std::move(body_item)); - } - - return PluginResult::OK; - } - - PluginResult SpotifyPodcastSearchPage::submit(const std::string &, const std::string &url, std::vector<Tab> &result_tabs) { - auto body = create_body(); - auto episode_list_page = std::make_unique<SpotifyEpisodeListPage>(program, url); - PluginResult result = episode_list_page->get_page("", 0, body->items); - if(result != PluginResult::OK) - return result; - - result_tabs.push_back(Tab{std::move(body), std::move(episode_list_page), nullptr}); - return result; - } - - static std::string unix_time_to_local_time_str(time_t unix_time) { - struct tm time_tm; - localtime_r(&unix_time, &time_tm); - char time_str[128] = {0}; - strftime(time_str, sizeof(time_str) - 1, "%Y-%m-%d %H:%M", &time_tm); - return time_str; - } - - PluginResult SpotifyEpisodeListPage::get_page(const std::string &, int page, BodyItems &result_items) { - std::string request_url = "https://api-partner.spotify.com/pathfinder/v1/query?operationName=queryShowEpisodes&variables="; - request_url += url_param_encode("{\"uri\":\"" + url + "\",\"offset\":" + std::to_string(page * 50) + ",\"limit\":50}"); - request_url += "&extensions="; - request_url += url_param_encode("{\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"e0e5ce27bd7748d2c59b4d44ba245a8992a05be75d6fabc3b20753fc8857444d\"}}"); - - std::vector<CommandArg> additional_args = { - { "-H", "authority: api-partner.spotify.com" }, - { "-H", "accept: application/json" }, - { "-H", "Referer: https://open.spotify.com/" }, - { "-H", "app-platform: WebPlayer" }, - { "-H", "spotify-app-version: 1.1.54.40.g75ab4382" } - }; - - Json::Value json_root; - DownloadResult result = download_json_error_retry(json_root, request_url, additional_args); - if(result != DownloadResult::OK) return download_result_to_plugin_result(result); - - if(!json_root.isObject()) - return PluginResult::ERR; - - const Json::Value &data_json = json_root["data"]; - if(!data_json.isObject()) - return PluginResult::ERR; - - const Json::Value &podcast_json = data_json["podcast"]; - if(!podcast_json.isObject()) - return PluginResult::ERR; - - const Json::Value &episodes_json = podcast_json["episodes"]; - if(!episodes_json.isObject()) - return PluginResult::ERR; - - const Json::Value &episode_items_json = episodes_json["items"]; - if(!episode_items_json.isArray()) - return PluginResult::ERR; - - for(const Json::Value &episode_item_json : episode_items_json) { - if(!episode_item_json.isObject()) - continue; - - const Json::Value &episode_json = episode_item_json["episode"]; - if(!episode_json.isObject()) - continue; - - const Json::Value &name_json = episode_json["name"]; - if(!name_json.isString()) - continue; - - const Json::Value &sharing_info_json = episode_json["sharingInfo"]; - if(!sharing_info_json.isObject()) - continue; - - const Json::Value &share_url_json = sharing_info_json["shareUrl"]; - if(!share_url_json.isString()) - continue; - - auto body_item = BodyItem::create(name_json.asString()); - body_item->url = share_url_json.asString(); - - std::string description; - std::string time; - - const Json::Value &description_json = episode_json["description"]; - if(description_json.isString()) - description += description_json.asString(); - - const Json::Value &release_data_json = episode_json["releaseDate"]; - if(release_data_json.isObject()) { - const Json::Value &iso_string_json = release_data_json["isoString"]; - if(iso_string_json.isString()) - time += unix_time_to_local_time_str(iso_utc_to_unix_time(iso_string_json.asCString())); - } - - const Json::Value &duration_json = episode_json["duration"]; - if(duration_json.isObject()) { - const Json::Value &total_ms_json = duration_json["totalMilliseconds"]; - if(total_ms_json.isInt()) { - if(!time.empty()) - time += " • "; - time += std::to_string(total_ms_json.asInt() / 1000 / 60) + " min"; - } - } - - if(!time.empty()) { - if(!description.empty()) - description += '\n'; - description += std::move(time); - } - - body_item->set_description(std::move(description)); - body_item->set_description_color(sf::Color(179, 179, 179)); - - const Json::Value &cover_art_json = episode_json["coverArt"]; - if(cover_art_json.isObject()) - image_sources_set_thumbnail(body_item.get(), cover_art_json["sources"]); - - result_items.push_back(std::move(body_item)); - } - - return PluginResult::OK; - } - - PluginResult SpotifyEpisodeListPage::submit(const std::string &, const std::string &url, std::vector<Tab> &result_tabs) { - result_tabs.push_back(Tab{nullptr, std::make_unique<SpotifyAudioPage>(program, url), nullptr}); - return PluginResult::OK; - } -}
\ No newline at end of file |