// API - 2ebc8e784a4072da457fae5c0d291e48 // API READ ONLY - eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIyZWJjOGU3ODRhNDA3MmRhNDU3ZmFlNWMwZDI5MWU0OCIsInN1YiI6IjYwZTJlNGI5MjJlNDgwMDA2MDJmZDMzMyIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.c0y7bTCI5KSsfQRw7igPx1FR40mbMF6hGTJTHn0HXH8 #include #include #include #include "../filesystem/filesystem.hpp" #include "functions.hpp" #include "../library.hpp" #ifdef _WIN32 #include "rapidjson/document.h" #else #include #endif #include #include #ifdef _WIN32 #include #include #include #include #include constexpr const char_t *_tv_rename_dir_divider = L"\\"; #define toString( a ) utf8_to_wstring( a ) #else constexpr const char_t *_tv_rename_dir_divider = "/"; #define toString( a ) a #endif string _moviedb_api_token{}; Request _moviedb_request; bool init(const string &config_path) { Request &request = _moviedb_request; #ifdef _WIN32 request.setServer( TEXT( "api.themoviedb.org/3" ) ); #else request.setServer( "https://api.themoviedb.org/3" ); #endif _moviedb_api_token = "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIyZWJjOGU3ODRhNDA3MmRhNDU3ZmFlNWMwZDI5MWU0OCIsInN1YiI6IjYwZTJlNGI5MjJlNDgwMDA2MDJmZDMzMyIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.c0y7bTCI5KSsfQRw7igPx1FR40mbMF6hGTJTHn0HXH8"; return true; } bool hasKey(const rapidjson::GenericValue> &object, const std::string &key) { return object.FindMember(key.c_str()) != object.MemberEnd(); } std::vector< std::tuple< string, string, string, string > > searchMovie( const string &movie, const string &language, const string &year ) { Request &request = _moviedb_request; request.addHeader( TEXT( "Accept: application/json" ) ); request.addHeader( TEXT( "Authorization: Bearer " ) + _moviedb_api_token ); auto encoded_show = encodeUrl( movie ); int pages = 0; int cur_page = 0; std::vector< std::tuple< string, string, string, string > > ret; do { cur_page++; rapidjson::Document json; auto request_uri = TEXT( "/search/movie?query=" ) + encoded_show + TEXT("&language=" ) + language + TEXT("&page=") + toString(std::to_string(cur_page)); if(!year.empty()) { request_uri += TEXT("&year=") + year; } json.Parse( request.get( request_uri ).c_str() ); if ( json.HasParseError() ) return {}; pages = json["total_pages"].GetInt(); const rapidjson::Value &results = json["results"]; if ( !results.IsArray() ) { return {}; } // find all possible movies for ( size_t i = 0; i < results.Size(); i++ ) { if(!hasKey(results[i], "title") || !hasKey(results[i], "id") || !hasKey(results[i], "release_date") || !hasKey(results[i], "original_title")) { continue; } auto movie = toString( results[i]["title"].GetString() ); auto id = toString( std::to_string( results[i]["id"].GetInt() ) ); string year = toString( results[i]["release_date"].GetString() ); string original = toString( results[i]["original_title"].GetString() ); if(year.empty() ) { year = "0000"; } else { year = year.substr(0, year.find('-')); } ret.emplace_back( movie, id, year, original ); } } while(cur_page < pages && cur_page < 5); request.clearHeader(); return ret; } RenameObject movieToRenameObject( const std::tuple< string, string, string, string > &movie, const std::string &language ) { RenameObject result; result.setPresentedName( std::get<0>(movie) ); result.addCustomField( "id", std::get<1>(movie) ); result.addCustomField( "language", language ); result.addCustomField( "year", std::get<2>(movie) ); result.addCustomField( "original_title", std::get<3>(movie) ); result.addCustomField( "use_original", "false" ); return result; } std::vector< RenameObject > getOptions( const RenameObject &search ) { string lang = "en-US"; string year = ""; if ( search.getCustomFields().find( "language" ) != search.getCustomFields().end() ) { lang = search.getCustomFields().at( "language" ); } if ( search.getCustomFields().find( "year" ) != search.getCustomFields().end() ) { year = search.getCustomFields().at( "year" ); } string name = search.getPresentedName(); auto possibilities = searchMovie( name, lang, year ); std::vector< RenameObject > result{}; for ( auto &movie : possibilities ) { result.push_back( movieToRenameObject( movie, lang ) ); } return result; } std::pair movieFromId( const string &id, const string &language ) { string uri = "/movie/" + id + "?language=" + language; Request &request = _moviedb_request; request.addHeader( TEXT( "Accept: application/json" ) ); request.addHeader( TEXT( "Authorization: Bearer " ) + _moviedb_api_token ); rapidjson::Document json; json.Parse( request.get( uri ).c_str() ); if( json.HasParseError() ) { return {"", ""}; } return {json["title"].GetString(), json["original_title"].GetString()}; } bool renameMovie(const string &path, const string &name, const string &year) { return FSLib::rename(path, FSLib::canonical( FSLib::getContainingDirectory(path) ) + "/" + name + " (" + year + ")." + FSLib::getFileExtension(path) ); } bool renamePath( const string &path, const RenameObject &renamer ) { string id = ""; string lang = "en-US"; std::pair movie = {"",""}; string year = ""; bool use_original = false; if ( renamer.getCustomFields().find( "language" ) != renamer.getCustomFields().end() ) { lang = renamer.getCustomFields().at( "language" ); } if ( renamer.getCustomFields().find( "year" ) != renamer.getCustomFields().end() ) { year = renamer.getCustomFields().at( "year" ); } if ( renamer.getCustomFields().find( "use_original" ) != renamer.getCustomFields().end() ) { auto use = renamer.getCustomFields().at( "use_original" ); use_original = (use == "true" || use == "True" || use == "TRUE"); } if ( renamer.getCustomFields().find( "id" ) == renamer.getCustomFields().end() || renamer.getCustomFields().at( "id" ).empty() ) { auto results = searchMovie( renamer.getPresentedName(), lang, year ); if ( results.empty() ) return false; id = std::get<1>(results[0]); movie = { std::get<0>(results[0]), std::get<3>(results[0]) }; year = std::get<2>(results[0]); } else { id = renamer.getCustomFields().at( "id" ); movie = movieFromId( id, lang ); } return renameMovie( path, use_original ? movie.second : movie.first, year ); } std::vector< string > getCustomKeys() { return { "id", "language", "year", "original_title", "use_original" }; } const string getName() { return "themoviedb"; }