TV_Rename: refactor

This commit is contained in:
zvon 2020-01-15 22:20:44 +01:00
parent 1e7a714a62
commit c596acb2be
2 changed files with 130 additions and 110 deletions

View File

@ -1,17 +1,12 @@
#include <algorithm> #include <algorithm>
#include <map> #include <map>
#ifdef _WIN32
#include <codecvt>
#include <fcntl.h>
#include <io.h>
#include <locale>
#include <windows.h>
#endif
#include "filesystem.hpp" #include "filesystem.hpp"
#include "functions.hpp"
#include "tv_rename.hpp"
#include "json.hpp"
using json = nlohmann::json;
#ifndef GUI #ifndef GUI
@ -21,20 +16,22 @@
#endif #endif
#include "functions.hpp"
#include "tv_rename.hpp"
#include "json.hpp"
using json = nlohmann::json;
#ifdef _WIN32 #ifdef _WIN32
#include <codecvt>
#include <fcntl.h>
#include <io.h>
#include <locale>
#include <windows.h>
constexpr const char_t *dir_divider = L"\\"; constexpr const char_t *dir_divider = L"\\";
#define cout std::wcout #define cout std::wcout
#define cerr std::wcerr #define cerr std::wcerr
#define cin std::wcin #define cin std::wcin
#define toString( a ) utf8_to_wstring( a )
#else #else
constexpr const char_t *dir_divider = "/"; constexpr const char_t *dir_divider = "/";
@ -44,22 +41,24 @@ constexpr const char_t *dir_divider = "/";
#define cin std::cin #define cin std::cin
#define TEXT( a ) a #define TEXT( a ) a
#define toString( a ) a
#endif #endif
std::string api_token = ""; std::string api_token = "";
Curl c; Request r;
std::vector< std::pair< string, string > > std::vector< std::pair< string, string > >
searchShow( const string &show, const string &language ) { searchShow( const string &show, const string &language ) {
c.addHeader( "Accept: application/json" ); r.addHeader( TEXT( "Accept: application/json" ) );
c.addHeader( "Authorization: Bearer " + api_token ); r.addHeader( TEXT( "Authorization: Bearer " ) + api_token );
c.addHeader( "Accept-Language: " + language ); r.addHeader( TEXT( "Accept-Language: " ) + language );
auto encoded_show = encodeUrl( show ); auto encoded_show = encodeUrl( show );
auto j = json::parse( auto j = json::parse(
c.get( "https://api.thetvdb.com/search/series?name=" + encoded_show ) ); r.get( TEXT( "/search/series?name=" ) + encoded_show ) );
std::vector< json > results; std::vector< json > results;
if( j["data"].is_array() ) { if( j["data"].is_array() ) {
@ -73,10 +72,11 @@ searchShow( const string &show, const string &language ) {
// find all possible shows // find all possible shows
for ( auto &x : results ) { for ( auto &x : results ) {
ret.emplace_back( x["seriesName"].get< string >(), auto show = toString( x["seriesName"].get< std::string >() );
std::to_string( x["id"].get< int >() ) ); auto id = toString( std::to_string( x["id"].get< int >() ) );
ret.emplace_back( show, id );
} }
c.clearHeader(); r.clearHeader();
return ret; return ret;
} }
@ -95,31 +95,33 @@ string getShowId( string &show, const string &language ) {
} }
string showNameFromId( const string &id, const string &language ) { string showNameFromId( const string &id, const string &language ) {
c.addHeader( "Accept: application/json" ); r.addHeader( TEXT( "Accept: application/json" ) );
c.addHeader( "Authorization: Bearer " + api_token ); r.addHeader( TEXT( "Authorization: Bearer " ) + api_token );
c.addHeader( "Accept-Language: " + language ); r.addHeader( TEXT( "Accept-Language: " ) + language );
auto j = json::parse( c.get( "https://api.thetvdb.com/series/" + id ) ); auto j = json::parse( r.get( TEXT( "/series/" ) + id ) );
return j["data"].get< json >()["seriesName"].get< string >(); // TODO check if got json
std::string show = j["data"].get< json >()["seriesName"].get< std::string >();
return toString( show );
} }
// get names for all episodes for a given season // get names for all episodes for a given season
std::vector< string > getEpisodeNames( const string &id, const string &season, std::vector< string > getEpisodeNames( const string &id, const string &season,
const string &language, bool dvd = false ) { const string &language, bool dvd = false ) {
c.addHeader( "Accept: application/json" ); r.addHeader( TEXT( "Accept: application/json" ) );
c.addHeader( "Authorization: Bearer " + api_token ); r.addHeader( TEXT( "Authorization: Bearer " ) + api_token );
c.addHeader( "Accept-Language: " + language ); r.addHeader( TEXT( "Accept-Language: " ) + language );
string page = "1"; string page = TEXT( "1" );
string season_query = "airedSeason="; string season_query = TEXT( "airedSeason=" );
if( dvd ) if( dvd )
season_query = "dvdSeason="; season_query = TEXT( "dvdSeason=" );
std::vector< string > episodes; std::vector< string > episodes;
do { do {
episodes.resize( episodes.size() * 2 ); episodes.resize( episodes.size() * 2 );
auto j = json::parse( c.get( "https://api.thetvdb.com/series/" + id + auto j = json::parse( r.get( TEXT( "/series/" ) + id +
"/episodes/query?" + season_query + season TEXT( "/episodes/query?" ) + season_query + season
+ "&page=" + page ) ); + TEXT( "&page=" ) + page ) );
if( j["data"].is_array() ) { if( j["data"].is_array() ) {
auto epdata = j["data"].get< std::vector< json > >(); auto epdata = j["data"].get< std::vector< json > >();
if( episodes.size() < epdata.size() ) if( episodes.size() < epdata.size() )
@ -131,13 +133,13 @@ std::vector< string > getEpisodeNames( const string &id, const string &season,
if( index > episodes.size() ) if( index > episodes.size() )
episodes.resize( index ); episodes.resize( index );
index--; index--;
episodes[index] = x["episodeName"].get< string >(); episodes[index] = toString( x["episodeName"].get< string >() );
} else { } else {
size_t index = x["airedEpisodeNumber"].get< size_t >(); size_t index = x["airedEpisodeNumber"].get< size_t >();
if( index > episodes.size() ) if( index > episodes.size() )
episodes.resize( index ); episodes.resize( index );
index--; index--;
episodes[index] = x["episodeName"].get<string>(); episodes[index] = toString( x["episodeName"].get<string>() );
} }
} }
} }
@ -146,24 +148,18 @@ std::vector< string > getEpisodeNames( const string &id, const string &season,
} }
if( j["links"]["next"].is_null() ) if( j["links"]["next"].is_null() )
break; break;
page = std::to_string( j["links"]["next"].get< size_t >() ); page = toString( std::to_string( j["links"]["next"].get< size_t >() ) );
} while( 1 ); } while( 1 );
c.clearHeader(); r.clearHeader();
return episodes; return episodes;
} }
std::vector< std::pair< string, std::pair< string, string > > > std::vector< std::pair< std::pair< int, string >, std::pair< string, string > > >
getRenamedFiles( const string &show, int season, const string id, getRenamedFiles( const string &show, int season, const string id,
const string &language, const string &pattern, const string &language, const string &pattern,
const bool &linux, const std::set< string > &files, bool dvd = false ) { const bool &linux, const std::map< int, string > &files, bool dvd ) {
#ifdef _WIN32 auto season_num = toString( std::to_string( season ) );
auto season_num = std::to_wstring( season );
auto episodes =
parseEpisodeNames( utf8_to_wstring( season_code ), language );
#else
auto season_num = std::to_string( season );
auto episodes = getEpisodeNames( id, season_num, language, dvd ); auto episodes = getEpisodeNames( id, season_num, language, dvd );
#endif
if ( episodes.empty() ) if ( episodes.empty() )
return {}; return {};
@ -171,35 +167,27 @@ getRenamedFiles( const string &show, int season, const string id,
if ( files.empty() ) if ( files.empty() )
return {}; return {};
std::vector< std::pair< string, std::pair< string, string > > > std::vector< std::pair< std::pair< int, string >, std::pair< string, string > > >
renamed_files; renamed_files;
size_t pos = 0;
for ( const auto &x : files ) { for ( const auto &x : files ) {
auto last = x.find_last_of( dir_divider ); auto last = x.second.find_last_of( dir_divider );
string og_name; string og_name;
string dir; string dir;
if ( last == string::npos ) { if ( last == string::npos ) {
og_name = x; og_name = x.second;
dir = TEXT( "." ); dir = TEXT( "." );
} else { } else {
og_name = x.substr( last + 1 ); og_name = x.second.substr( last + 1 );
dir = x.substr( 0, last ); dir = x.second.substr( 0, last );
} }
unsigned long num; unsigned long ep_num = x.first - 1;
// get file's episode number
if ( searchSpecificSeason( x.c_str(), pos, season_num ) ) {
num = std::stoi( x.c_str() + pos );
} else {
continue;
}
num--;
if ( num < episodes.size() ) { if ( ep_num < episodes.size() ) {
auto pos = og_name.find_last_of( TEXT( "." ) ); auto pos = og_name.find_last_of( TEXT( "." ) );
// get desired filename // get desired filename
auto name = compilePattern( pattern, season, num + 1, auto name = compilePattern( pattern, season, x.first,
og_name.substr( 0, pos ), episodes[num], og_name.substr( 0, pos ), episodes[ep_num],
show ) + show ) +
og_name.substr( pos ); og_name.substr( pos );
// replace '/' with '|' // replace '/' with '|'
@ -243,7 +231,7 @@ getRenamedFiles( const string &show, int season, const string id,
} }
} }
renamed_files.emplace_back( renamed_files.emplace_back(
dir, std::pair< string, string >( og_name, name ) ); std::pair< int, string >( x.first, dir ), std::pair< string, string >( og_name, name ) );
} }
} }
return renamed_files; return renamed_files;
@ -252,16 +240,22 @@ getRenamedFiles( const string &show, int season, const string id,
void singleSeason( const string &path, string &show, int season, string id, void singleSeason( const string &path, string &show, int season, string id,
const string &language, const string &pattern, const string &language, const string &pattern,
const bool &linux, const bool &trust, const bool &linux, const bool &trust,
std::set< string > const *files_ptr, bool print, bool dvd ) { std::map< int, string > *files_ptr, bool print, bool dvd ) {
if ( id.empty() ) if ( id.empty() )
id = getShowId( show, language ); id = getShowId( show, language );
std::set< string > *found_files = nullptr; std::map< int, std::map< int, string > > *found_files = nullptr;
if ( files_ptr == nullptr ) { if ( files_ptr == nullptr ) {
found_files = new std::set< string >; found_files = new std::map< int, std::map< int, string > >;
findSeason( *found_files, season, path ); iterateFS( *found_files, path );
files_ptr = found_files; if( found_files->find( season ) != found_files->end() )
files_ptr = &(*found_files)[season];
}
if( files_ptr == nullptr ) {
cerr << "Couldn't find episodes with season " << season << std::endl;
return;
} }
auto renamed_files = getRenamedFiles( show, season, id, language, pattern, auto renamed_files = getRenamedFiles( show, season, id, language, pattern,
@ -287,8 +281,11 @@ void singleSeason( const string &path, string &show, int season, string id,
for ( auto renamed = renamed_files.begin(); renamed != renamed_files.end(); for ( auto renamed = renamed_files.begin(); renamed != renamed_files.end();
++renamed ) { ++renamed ) {
FSLib::rename( renamed->first + dir_divider + renamed->second.first, FSLib::rename( renamed->first.second + dir_divider + renamed->second.first,
renamed->first + dir_divider + renamed->second.second ); renamed->first.second + dir_divider + renamed->second.second );
if( found_files == nullptr ) {
files_ptr[0][renamed->first.first] = renamed->first.second + dir_divider + renamed->second.second;
}
} }
if ( found_files != nullptr ) { if ( found_files != nullptr ) {
@ -296,46 +293,52 @@ void singleSeason( const string &path, string &show, int season, string id,
} }
} }
void singleSeason( const string &path, string &show, int season, string id,
const string &language, const string &pattern,
const size_t &flags, std::map< int, string > *files_ptr,
bool print ) {
singleSeason( path, show, season, id, language, pattern, flags & TV_LINUX,
flags & TV_TRUST, files_ptr, print, flags & TV_DVD );
}
#ifndef GUI #ifndef GUI
void multipleSeasons( const string &path, string &show,
const std::map< int, std::set< string > > &seasons,
const string &language, const string &pattern,
const bool &linux, const bool &trust, bool dvd ) {
auto id = getShowId( show, language );
for ( const auto &x : seasons ) {
singleSeason( path, show, x.first, id, language, pattern, linux, trust,
&x.second, dvd );
}
}
void multipleSeasons( const string &path, string &show, void multipleSeasons( const string &path, string &show,
const std::set< int > seasons, const string &language, const std::set< int > seasons, const string &language,
const string &pattern, const bool &linux, const string &pattern, const size_t &flags ) {
const bool &trust, bool dvd ) { std::map< int, std::map< int, string > > season_map;
std::map< int, std::set< string > > season_map; iterateFS( season_map, path );
findSeasons( season_map, path, seasons ); auto id = getShowId( show, language );
multipleSeasons( path, show, season_map, language, pattern, linux, trust, dvd ); for( auto &x : season_map ) {
if( seasons.find( x.first ) != seasons.end() ) {
singleSeason( path, show, x.first, id, language, pattern, flags & TV_LINUX, flags & TV_TRUST,
&x.second, flags & TV_DVD );
}
}
} }
void allSeasons( const string &path, string &show, const string &language, void allSeasons( const string &path, string &show, const string &language,
const string &pattern, const bool &linux, const bool &trust, bool dvd ) { const string &pattern, const size_t &flags ) {
std::map< int, std::set< string > > seasons; std::map< int, std::map< int, string > > seasons;
// get all season number from this directory and subdirectories // get all season number from this directory and subdirectories
iterateFS( seasons, path ); iterateFS( seasons, path );
multipleSeasons( path, show, seasons, language, pattern, linux, trust, dvd ); auto id = getShowId( show, language );
for( auto &x : seasons ) {
singleSeason( path, show, x.first, id, language, pattern, flags & TV_LINUX, flags & TV_TRUST,
&x.second, flags & TV_DVD );
}
} }
std::vector< std::pair< std::string, std::string > > getLangs() { std::vector< std::pair< std::string, std::string > > getLangs() {
std::vector< std::pair< std::string, std::string > > langs; std::vector< std::pair< std::string, std::string > > langs;
c.addHeader( "Accept: application/json" ); r.addHeader( TEXT( "Accept: application/json" ) );
c.addHeader( "Authorization: Bearer " + api_token ); r.addHeader( TEXT( "Authorization: Bearer " ) + api_token );
auto j = json::parse( c.get( "https://api.thetvdb.com/languages" ) ); auto j = json::parse( r.get( TEXT( "/languages" ) ) );
c.clearHeader(); r.clearHeader();
auto langs_json = j["data"].get< std::vector< json > >(); auto langs_json = j["data"].get< std::vector< json > >();
for ( auto &x : langs_json ) { for ( auto &x : langs_json ) {
langs.emplace_back( x["abbreviation"].get< std::string >(), langs.emplace_back( toString( x["abbreviation"].get< std::string >() ),
x["name"].get< std::string >() ); toString( x["name"].get< std::string >() ) );
} }
return langs; return langs;
} }
@ -354,12 +357,17 @@ bool findLanguage( const char_t *language ) {
} }
bool authenticate( const std::string &api_key ) { bool authenticate( const std::string &api_key ) {
c.addHeader( "Accept: application/json" ); #ifdef _WIN32
c.addHeader( "Content-Type: application/json" ); r.setServer( "api.thetvdb.com" );
auto j = json::parse( c.post( "https://api.thetvdb.com/login", #else
r.setServer( "https://api.thetvdb.com" );
#endif
r.addHeader( TEXT( "Accept: application/json" ) );
r.addHeader( TEXT( "Content-Type: application/json" ) );
auto j = json::parse( r.post( TEXT( "/login" ),
"{ \"apikey\": \"" + api_key + "\" }" ) ); "{ \"apikey\": \"" + api_key + "\" }" ) );
api_token = j["token"].get< std::string >(); api_token = toString( j["token"].get< std::string >() );
c.clearHeader(); r.clearHeader();
// TODO check return code // TODO check return code
return true; return true;
} }

View File

@ -1,11 +1,18 @@
#ifndef TV_RENAME_HPP #ifndef TV_RENAME_HPP
#define TV_RENAME_HPP #define TV_RENAME_HPP
#include <map>
#include <set> #include <set>
#include <vector> #include <vector>
#include "network.hpp" #include "network.hpp"
// TV flags
#define TV_CHDIR 0x0100
#define TV_TRUST 0x0200
#define TV_LINUX 0x0400
#define TV_DVD 0x0800
#ifdef _WIN32 #ifdef _WIN32
using string = std::wstring; using string = std::wstring;
@ -18,27 +25,32 @@ using char_t = char;
#endif #endif
// TODO change files_ptr contents to new file names
void singleSeason( const string &path, string &show, int season, string id, void singleSeason( const string &path, string &show, int season, string id,
const string &language, const string &pattern, const string &language, const string &pattern,
const bool &linux, const bool &trust, const bool &linux, const bool &trust,
std::set< string > const *files_ptr = nullptr, std::map< int, string > *files_ptr = nullptr,
bool print = true, bool dvd = false ); bool print = true, bool dvd = false );
void singleSeason( const string &path, string &show, int season, string id,
const string &language, const string &pattern,
const size_t &flags, std::map< int, string > *files_ptr = nullptr,
bool print = true );
#ifdef GUI #ifdef GUI
std::vector< std::pair< string, std::pair< string, string > > > std::vector< std::pair< string, std::pair< string, string > > >
getRenamedFiles( const string &show, int season, string url, getRenamedFiles( const string &show, int season, string url,
const string &language, const string &pattern, const string &language, const string &pattern,
const bool &linux, Curl &c, const std::set< string > &files ); const bool &linux, Curl &c, const std::map< int, string > &files, bool dvd = false );
#else #else
void multipleSeasons( const string &path, string &show, void multipleSeasons( const string &path, string &show,
const std::set< int > seasons, const string &language, const std::set< int > seasons, const string &language,
const string &pattern, const bool &linux, const string &pattern, const size_t &flags );
const bool &trust, bool dvd = false );
void allSeasons( const string &path, string &show, const string &language, void allSeasons( const string &path, string &show, const string &language,
const string &pattern, const bool &linux, const bool &trust, bool dvd = false ); const string &pattern, const size_t &flags );
#endif #endif