Somewhat working with API (push before major refactor)
This commit is contained in:
parent
f1063bb14e
commit
81cfc9a53b
228
functions.cpp
228
functions.cpp
@ -55,25 +55,6 @@ constexpr const char_t *dir_divider = "/";
|
|||||||
|
|
||||||
#endif // UNIX
|
#endif // UNIX
|
||||||
|
|
||||||
#ifndef GUI
|
|
||||||
|
|
||||||
constexpr std::array< const char_t *, 46 > languages{
|
|
||||||
TEXT( "en" ), TEXT( "English" ), TEXT( "sv" ), TEXT( "Svenska" ),
|
|
||||||
TEXT( "no" ), TEXT( "Norsk" ), TEXT( "da" ), TEXT( "Dansk" ),
|
|
||||||
TEXT( "fi" ), TEXT( "Suomeksi" ), TEXT( "nl" ), TEXT( "Nederlands" ),
|
|
||||||
TEXT( "de" ), TEXT( "Deutsch" ), TEXT( "it" ), TEXT( "Italiano" ),
|
|
||||||
TEXT( "es" ), TEXT( "Español" ), TEXT( "fr" ), TEXT( "Français" ),
|
|
||||||
TEXT( "pl" ), TEXT( "Polski" ), TEXT( "hu" ), TEXT( "Magyar" ),
|
|
||||||
TEXT( "el" ), TEXT( "Greek" ), TEXT( "tr" ), TEXT( "Turkish" ),
|
|
||||||
TEXT( "ru" ), TEXT( "Russian" ), TEXT( "he" ), TEXT( "Hebrew" ),
|
|
||||||
TEXT( "ja" ), TEXT( "Japanese" ), TEXT( "pt" ), TEXT( "Portuguese" ),
|
|
||||||
TEXT( "zh" ), TEXT( "Chinese" ), TEXT( "cs" ), TEXT( "Czech" ),
|
|
||||||
TEXT( "sl" ), TEXT( "Slovenian" ), TEXT( "hr" ), TEXT( "Croatian" ),
|
|
||||||
TEXT( "ko" ), TEXT( "Korea" )
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // not GUI
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
// functions to convert between string and wstring
|
// functions to convert between string and wstring
|
||||||
@ -90,7 +71,6 @@ std::wstring utf8_to_wstring( const std::string &utf8 ) {
|
|||||||
|
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
// encode url so it's valid even with UTF-8 characters
|
|
||||||
string encodeUrl( const string &url ) {
|
string encodeUrl( const string &url ) {
|
||||||
// stolen from here -
|
// stolen from here -
|
||||||
// https://stackoverflow.com/questions/154536/encode-decode-urls-in-c
|
// https://stackoverflow.com/questions/154536/encode-decode-urls-in-c
|
||||||
@ -202,48 +182,6 @@ void iterateFS( std::map< int, std::set< string > > &seasons,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string getDefUrl( string &show, const string &language, Curl &c ) {
|
|
||||||
std::replace( show.begin(), show.end(), ' ', '+' );
|
|
||||||
|
|
||||||
string base_url = TEXT( "https://www.thetvdb.com" );
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
string source_code = utf8_to_wstring(
|
|
||||||
c.execute( TEXT( "https://www.thetvdb.com/search?q=" ) +
|
|
||||||
encodeUrl( show ) + TEXT( "&l=" ) + language ) );
|
|
||||||
#else
|
|
||||||
string source_code =
|
|
||||||
c.execute( TEXT( "https://www.thetvdb.com/search?q=" ) +
|
|
||||||
encodeUrl( show ) + TEXT( "&l=" ) + language );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
size_t order{}, pos{};
|
|
||||||
std::vector< std::pair< string, string > > urls;
|
|
||||||
|
|
||||||
// find all possible shows
|
|
||||||
while ( true ) {
|
|
||||||
pos = source_code.find( TEXT( "/ser" ), pos );
|
|
||||||
if ( pos != string::npos ) {
|
|
||||||
auto end = source_code.find( TEXT( ">" ), pos );
|
|
||||||
end--;
|
|
||||||
auto end2 = source_code.find( TEXT( "<" ), end + 2 );
|
|
||||||
// store shows in urls, first is name, second is url
|
|
||||||
urls.emplace_back( source_code.substr( end + 2, end2 - end - 2 ),
|
|
||||||
source_code.substr( pos, end - pos ) );
|
|
||||||
cout << ++order << ". " << urls.back().first << std::endl;
|
|
||||||
pos = end2;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cout << "Which TV Show is the right one? ";
|
|
||||||
cin >> pos;
|
|
||||||
cin.clear();
|
|
||||||
cin.ignore( 1, '\n' );
|
|
||||||
show = urls[pos - 1].first;
|
|
||||||
return base_url + urls[pos - 1].second;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find all files for provided season in `path` and store it in `files`
|
// find all files for provided season in `path` and store it in `files`
|
||||||
void findSeason( std::set< string > &files, int season, const string &path ) {
|
void findSeason( std::set< string > &files, int season, const string &path ) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -308,6 +246,7 @@ void printHelp() {
|
|||||||
<< " or 'all'" << std::endl;
|
<< " or 'all'" << std::endl;
|
||||||
cout << " for all seasons in selected directory"
|
cout << " for all seasons in selected directory"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
cout << " --dvd use dvd ordering instead of aired ordering" << std::endl;
|
||||||
cout << " --name-pattern <string> Pattern to which change the file name."
|
cout << " --name-pattern <string> Pattern to which change the file name."
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
cout << " Possible sequences are:" << std::endl;
|
cout << " Possible sequences are:" << std::endl;
|
||||||
@ -389,62 +328,6 @@ void parseSeasonNumbers( std::set< int > &seasons_num,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// print possible language codes and their corresponding language
|
|
||||||
void printLangs() {
|
|
||||||
for ( size_t i = 0; i < languages.size(); i += 2 ) {
|
|
||||||
cout << languages[i] << " - " << languages[i + 1] << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure language is a valide language code
|
|
||||||
bool findLanguage( const char_t *language ) {
|
|
||||||
for ( size_t i = 0; i < languages.size(); i += 2 ) {
|
|
||||||
#ifdef _WIN32
|
|
||||||
if ( !wcscmp( language, languages[i] ) )
|
|
||||||
#else
|
|
||||||
if ( !strcmp( language, languages[i] ) )
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else // GUI
|
|
||||||
// functions that are needed for GUI but not for CLI
|
|
||||||
|
|
||||||
// get possible shows for search query in `show`
|
|
||||||
std::vector< std::pair< string, string > >
|
|
||||||
getPossibleShows( string show, const string &language, Curl &c ) {
|
|
||||||
// encode show name so it can be resolved as url
|
|
||||||
std::replace( show.begin(), show.end(), ' ', '+' );
|
|
||||||
show = encodeUrl( show );
|
|
||||||
#ifdef _WIN32
|
|
||||||
auto source_code = utf8_to_wstring(
|
|
||||||
c.execute( TEXT( "https://www.thetvdb.com/search?q=" ) + show +
|
|
||||||
TEXT( "&l=" ) + language ) );
|
|
||||||
#else
|
|
||||||
auto source_code = c.execute( TEXT( "https://www.thetvdb.com/search?q=" ) +
|
|
||||||
show + TEXT( "&l=" ) + language );
|
|
||||||
#endif
|
|
||||||
size_t pos{};
|
|
||||||
std::vector< std::pair< string, string > > urls;
|
|
||||||
while ( true ) {
|
|
||||||
pos = source_code.find( TEXT( "/ser" ), pos );
|
|
||||||
if ( pos != string::npos ) {
|
|
||||||
auto end = source_code.find( TEXT( ">" ), pos );
|
|
||||||
auto end2 = source_code.find( TEXT( "<" ), end + 1 );
|
|
||||||
end--;
|
|
||||||
urls.emplace_back(
|
|
||||||
source_code.substr( end + 2, end2 - ( end + 2 ) ),
|
|
||||||
source_code.substr( pos, end - pos ) );
|
|
||||||
pos = end + 2;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return urls;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // ndef GUI
|
#endif // ndef GUI
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
@ -616,14 +499,15 @@ void prepareDB( const std::string &_pattern ) {
|
|||||||
<< " write permission for " << getDBName() << std::endl;
|
<< " write permission for " << getDBName() << std::endl;
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
db.exec( "CREATE TABLE IF NOT EXISTS SHOWS (ID INTEGER NOT NULL "
|
db.exec(
|
||||||
"PRIMARY KEY AUTOINCREMENT, URL TEXT NOT NULL, SHOW TEXT NOT NULL,"
|
"CREATE TABLE IF NOT EXISTS SHOWS (ID INTEGER NOT NULL "
|
||||||
|
"PRIMARY KEY AUTOINCREMENT, TVID TEXT NOT NULL, SHOW TEXT NOT NULL,"
|
||||||
"PATH TEXT NOT NULL UNIQUE, LANGUAGE TEXT NOT NULL);" );
|
"PATH TEXT NOT NULL UNIQUE, LANGUAGE TEXT NOT NULL);" );
|
||||||
db.exec( "CREATE TABLE IF NOT EXISTS EPISODES (SHOWID INTEGER NOT NULL,"
|
db.exec( "CREATE TABLE IF NOT EXISTS EPISODES (SHOWID INTEGER NOT NULL,"
|
||||||
"PATH TEXT NOT NULL UNIQUE, FOREIGN KEY(SHOWID) "
|
"PATH TEXT NOT NULL UNIQUE, FOREIGN KEY(SHOWID) "
|
||||||
"REFERENCES SHOWS(ID));" );
|
"REFERENCES SHOWS(ID));" );
|
||||||
const string *pattern;
|
const string *pattern;
|
||||||
if( _pattern.empty() ) {
|
if ( _pattern.empty() ) {
|
||||||
cout << "Insert name pattern for database:" << std::endl;
|
cout << "Insert name pattern for database:" << std::endl;
|
||||||
auto *p = new string;
|
auto *p = new string;
|
||||||
std::getline( cin, *p );
|
std::getline( cin, *p );
|
||||||
@ -631,22 +515,22 @@ void prepareDB( const std::string &_pattern ) {
|
|||||||
} else {
|
} else {
|
||||||
pattern = &_pattern;
|
pattern = &_pattern;
|
||||||
}
|
}
|
||||||
db.exec( TEXT( "INSERT INTO SHOWS ( URL, SHOW, PATH, LANGUAGE ) "
|
db.exec( TEXT( "INSERT INTO SHOWS ( TVID, SHOW, PATH, LANGUAGE ) "
|
||||||
"VALUES ( 'pattern', 'pattern', '" ) + sanitize( *pattern )
|
"VALUES ( 'pattern', 'pattern', '" ) +
|
||||||
+ TEXT( "', 'pattern' );" ) );
|
sanitize( *pattern ) + TEXT( "', 'pattern' );" ) );
|
||||||
if( pattern != &_pattern ) {
|
if ( pattern != &_pattern ) {
|
||||||
delete pattern;
|
delete pattern;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef GUI
|
#ifndef GUI
|
||||||
void addToDB( string &show, const string &path, const string &language,
|
void addToDB( string &show, const string &path, const string &language,
|
||||||
bool linux, Curl &c ) {
|
bool linux ) {
|
||||||
if ( !FSLib::exists( getDBName() ) )
|
if ( !FSLib::exists( getDBName() ) )
|
||||||
prepareDB();
|
prepareDB();
|
||||||
#else
|
#else
|
||||||
void addToDB( string &show, const string &path, const string &language,
|
void addToDB( string &show, const string &path, const string &language,
|
||||||
const string &url, const string &pattern, bool linux, Curl &c ) {
|
const string &id, const string &pattern, bool linux ) {
|
||||||
if ( !FSLib::exists( getDBName() ) )
|
if ( !FSLib::exists( getDBName() ) )
|
||||||
prepareDB( pattern );
|
prepareDB( pattern );
|
||||||
#endif
|
#endif
|
||||||
@ -659,18 +543,19 @@ void addToDB( string &show, const string &path, const string &language,
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
#ifndef GUI
|
#ifndef GUI
|
||||||
auto url = getDefUrl( show, language, c );
|
auto id = getShowId( show, language );
|
||||||
|
show = showNameFromId( id, language );
|
||||||
#endif
|
#endif
|
||||||
string show_id{};
|
string show_id{};
|
||||||
db.exec( TEXT( "INSERT OR IGNORE INTO SHOWS ( URL, SHOW, PATH, LANGUAGE ) "
|
db.exec( TEXT( "INSERT OR IGNORE INTO SHOWS ( TVID, SHOW, PATH, LANGUAGE ) "
|
||||||
"VALUES ( '" ) +
|
"VALUES ( '" ) +
|
||||||
sanitize( url ) + TEXT( "', '" ) + sanitize( show ) +
|
sanitize( id ) + TEXT( "', '" ) + sanitize( show ) +
|
||||||
TEXT( "', '" ) + sanitize( absolute ) + TEXT( "', '" ) +
|
TEXT( "', '" ) + sanitize( absolute ) + TEXT( "', '" ) +
|
||||||
sanitize( language ) + TEXT( "' );" ) );
|
sanitize( language ) + TEXT( "' );" ) );
|
||||||
show_id = std::to_string( db.lastRowID() );
|
show_id = std::to_string( db.lastRowID() );
|
||||||
#ifndef GUI
|
#ifndef GUI
|
||||||
string pattern{};
|
string pattern{};
|
||||||
db.exec( TEXT( "SELECT PATH FROM SHOWS WHERE URL == 'pattern';" ),
|
db.exec( TEXT( "SELECT PATH FROM SHOWS WHERE TVID == 'pattern';" ),
|
||||||
pattern );
|
pattern );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -687,8 +572,8 @@ void addToDB( string &show, const string &path, const string &language,
|
|||||||
ProgressBar::print( 0 );
|
ProgressBar::print( 0 );
|
||||||
#endif
|
#endif
|
||||||
for ( const auto &x : seasons ) {
|
for ( const auto &x : seasons ) {
|
||||||
singleSeason( absolute, show, x.first, url, language, pattern, linux,
|
singleSeason( absolute, show, x.first, id, language, pattern, linux,
|
||||||
true, c, &x.second, false );
|
true, &x.second, false );
|
||||||
i++;
|
i++;
|
||||||
#ifndef GUI
|
#ifndef GUI
|
||||||
ProgressBar::print( ( i * 100 ) / size );
|
ProgressBar::print( ( i * 100 ) / size );
|
||||||
@ -757,7 +642,7 @@ void cleanUpLine() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void refreshDB( bool linux, Curl &c ) {
|
void refreshDB( bool linux ) {
|
||||||
std::vector< std::unordered_map< string, string > > shows;
|
std::vector< std::unordered_map< string, string > > shows;
|
||||||
SQLite::Database db{};
|
SQLite::Database db{};
|
||||||
try {
|
try {
|
||||||
@ -767,12 +652,13 @@ void refreshDB( bool linux, Curl &c ) {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
db.exec( "DELETE FROM EPISODES;" );
|
db.exec( "DELETE FROM EPISODES;" );
|
||||||
db.exec( TEXT( "SELECT ID, URL, SHOW, PATH, LANGUAGE FROM SHOWS WHERE URL "
|
db.exec(
|
||||||
|
TEXT( "SELECT ID, TVID, SHOW, PATH, LANGUAGE FROM SHOWS WHERE TVID "
|
||||||
"!= 'pattern';" ),
|
"!= 'pattern';" ),
|
||||||
shows );
|
shows );
|
||||||
|
|
||||||
string pattern{};
|
string pattern{};
|
||||||
db.exec( TEXT( "SELECT PATH FROM SHOWS WHERE URL == 'pattern';" ),
|
db.exec( TEXT( "SELECT PATH FROM SHOWS WHERE TVID == 'pattern';" ),
|
||||||
pattern );
|
pattern );
|
||||||
|
|
||||||
cout << "Refreshing database" << std::endl << std::endl << std::endl;
|
cout << "Refreshing database" << std::endl << std::endl << std::endl;
|
||||||
@ -798,8 +684,8 @@ void refreshDB( bool linux, Curl &c ) {
|
|||||||
size_t i{};
|
size_t i{};
|
||||||
for ( const auto &x : seasons ) {
|
for ( const auto &x : seasons ) {
|
||||||
singleSeason( show[TEXT( "PATH" )], show[TEXT( "SHOW" )],
|
singleSeason( show[TEXT( "PATH" )], show[TEXT( "SHOW" )],
|
||||||
x.first, show[TEXT( "URL" )],
|
x.first, show[TEXT( "TVID" )],
|
||||||
show[TEXT( "LANGUAGE" )], pattern, linux, true, c,
|
show[TEXT( "LANGUAGE" )], pattern, linux, true,
|
||||||
&x.second, false );
|
&x.second, false );
|
||||||
i++;
|
i++;
|
||||||
#ifndef GUI
|
#ifndef GUI
|
||||||
@ -824,7 +710,7 @@ void refreshDB( bool linux, Curl &c ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateDB( bool linux, Curl &c ) {
|
void updateDB( bool linux ) {
|
||||||
std::vector< std::unordered_map< string, string > > shows;
|
std::vector< std::unordered_map< string, string > > shows;
|
||||||
SQLite::Database db{};
|
SQLite::Database db{};
|
||||||
try {
|
try {
|
||||||
@ -833,12 +719,12 @@ void updateDB( bool linux, Curl &c ) {
|
|||||||
cerr << "Can't open database, make sure it exists" << std::endl;
|
cerr << "Can't open database, make sure it exists" << std::endl;
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
db.exec( TEXT( "SELECT ID, URL, SHOW, PATH, LANGUAGE FROM SHOWS WHERE URL "
|
db.exec( TEXT( "SELECT ID, TVID, SHOW, PATH, LANGUAGE FROM SHOWS WHERE TVID"
|
||||||
"!= 'pattern';" ),
|
" != 'pattern';" ),
|
||||||
shows );
|
shows );
|
||||||
|
|
||||||
string pattern{};
|
string pattern{};
|
||||||
db.exec( TEXT( "SELECT PATH FROM SHOWS WHERE URL == 'pattern';" ),
|
db.exec( TEXT( "SELECT PATH FROM SHOWS WHERE TVID == 'pattern';" ),
|
||||||
pattern );
|
pattern );
|
||||||
|
|
||||||
cout << "Updating database" << std::endl << std::endl << std::endl;
|
cout << "Updating database" << std::endl << std::endl << std::endl;
|
||||||
@ -879,8 +765,8 @@ void updateDB( bool linux, Curl &c ) {
|
|||||||
size_t i{};
|
size_t i{};
|
||||||
for ( const auto &x : new_eps ) {
|
for ( const auto &x : new_eps ) {
|
||||||
singleSeason( show[TEXT( "PATH" )], show[TEXT( "SHOW" )],
|
singleSeason( show[TEXT( "PATH" )], show[TEXT( "SHOW" )],
|
||||||
x.first, show[TEXT( "URL" )],
|
x.first, show[TEXT( "TVID" )],
|
||||||
show[TEXT( "LANGUAGE" )], pattern, linux, true, c,
|
show[TEXT( "LANGUAGE" )], pattern, linux, true,
|
||||||
&x.second, false );
|
&x.second, false );
|
||||||
i++;
|
i++;
|
||||||
#ifndef GUI
|
#ifndef GUI
|
||||||
@ -914,7 +800,7 @@ void changeDBPattern( const string &pattern ) {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
db.exec( TEXT( "UPDATE SHOWS SET PATH = '" ) + pattern +
|
db.exec( TEXT( "UPDATE SHOWS SET PATH = '" ) + pattern +
|
||||||
TEXT( "' WHERE URL == 'pattern';" ) );
|
TEXT( "' WHERE TVID == 'pattern';" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanDB() {
|
void cleanDB() {
|
||||||
@ -926,12 +812,12 @@ void cleanDB() {
|
|||||||
cerr << "Can't open database, make sure it exists" << std::endl;
|
cerr << "Can't open database, make sure it exists" << std::endl;
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
db.exec( TEXT( "SELECT ID, URL, SHOW, PATH, LANGUAGE FROM SHOWS WHERE URL "
|
db.exec( TEXT( "SELECT ID, TVID, SHOW, PATH, LANGUAGE FROM SHOWS WHERE TVID"
|
||||||
"!= 'pattern';" ),
|
" != 'pattern';" ),
|
||||||
shows );
|
shows );
|
||||||
|
|
||||||
string pattern{};
|
string pattern{};
|
||||||
db.exec( TEXT( "SELECT PATH FROM SHOWS WHERE URL == 'pattern';" ),
|
db.exec( TEXT( "SELECT PATH FROM SHOWS WHERE TVID == 'pattern';" ),
|
||||||
pattern );
|
pattern );
|
||||||
|
|
||||||
for ( auto &show : shows ) {
|
for ( auto &show : shows ) {
|
||||||
@ -976,7 +862,6 @@ void removeFromDB( const string &path ) {
|
|||||||
db.exec( TEXT( "DELETE FROM SHOWS WHERE ID == " ) + show_id + TEXT( ";" ) );
|
db.exec( TEXT( "DELETE FROM SHOWS WHERE ID == " ) + show_id + TEXT( ";" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::vector< std::unordered_map< std::string, std::string > > dbGetShows() {
|
std::vector< std::unordered_map< std::string, std::string > > dbGetShows() {
|
||||||
SQLite::Database db{};
|
SQLite::Database db{};
|
||||||
try {
|
try {
|
||||||
@ -986,12 +871,12 @@ std::vector< std::unordered_map< std::string, std::string > > dbGetShows() {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
std::vector< std::unordered_map< std::string, std::string > > ret;
|
std::vector< std::unordered_map< std::string, std::string > > ret;
|
||||||
db.exec( TEXT( "SELECT * FROM SHOWS;"), ret );
|
db.exec( TEXT( "SELECT * FROM SHOWS;" ), ret );
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void changeDB( size_t index, const string &path, const string &language,
|
void changeDB( size_t index, const string &path, const string &language,
|
||||||
const string &url, Curl &c ) {
|
const string &id ) {
|
||||||
SQLite::Database db{};
|
SQLite::Database db{};
|
||||||
auto absolute = FSLib::canonical( path );
|
auto absolute = FSLib::canonical( path );
|
||||||
try {
|
try {
|
||||||
@ -1001,31 +886,21 @@ void changeDB( size_t index, const string &path, const string &language,
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
string show_id = std::to_string(index);
|
string show_id = std::to_string( index );
|
||||||
#else
|
#else
|
||||||
string show_id = std::to_wstring(index);
|
string show_id = std::to_wstring( index );
|
||||||
#endif
|
#endif
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
string source_code = utf8_to_wstring(
|
string source_code = utf8_to_wstring(
|
||||||
c.execute( url );
|
c.execute( url );
|
||||||
#else
|
#else
|
||||||
string source_code =
|
auto real_show = showNameFromId( id, language );
|
||||||
c.execute( url );
|
|
||||||
#endif
|
#endif
|
||||||
auto pos = source_code.find( "series_title" );
|
db.exec( TEXT( "UPDATE SHOWS SET TVID = '" ) + sanitize( id ) + TEXT("', SHOW = '") + sanitize(real_show) + TEXT("', PATH = '") + sanitize(absolute) + TEXT("', LANGUAGE = '") +
|
||||||
pos = source_code.find( ' ', pos );
|
|
||||||
pos = source_code.find_first_not_of( " ", pos );
|
|
||||||
auto end = source_code.find( '<', pos );
|
|
||||||
end--;
|
|
||||||
while( source_code[end] == ' ' )
|
|
||||||
end--;
|
|
||||||
end++;
|
|
||||||
auto real_show = source_code.substr(pos, end - pos);
|
|
||||||
db.exec( TEXT( "UPDATE SHOWS SET URL = '" ) + sanitize( url ) + TEXT("', SHOW = '") + sanitize(real_show) + TEXT("', PATH = '") + sanitize(absolute) + TEXT("', LANGUAGE = '") +
|
|
||||||
sanitize( language ) + TEXT( "' WHERE ID == " + show_id + ";" ) );
|
sanitize( language ) + TEXT( "' WHERE ID == " + show_id + ";" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void refreshSingleDB( const size_t &index, bool linux, Curl &c ) {
|
void refreshSingleDB( const size_t &index, bool linux ) {
|
||||||
std::vector< std::unordered_map< string, string > > shows;
|
std::vector< std::unordered_map< string, string > > shows;
|
||||||
string show_id = std::to_string( index );
|
string show_id = std::to_string( index );
|
||||||
SQLite::Database db{};
|
SQLite::Database db{};
|
||||||
@ -1036,15 +911,19 @@ void refreshSingleDB( const size_t &index, bool linux, Curl &c ) {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
db.exec( "DELETE FROM EPISODES WHERE SHOWID == " + show_id + ";" );
|
db.exec( "DELETE FROM EPISODES WHERE SHOWID == " + show_id + ";" );
|
||||||
db.exec( TEXT( "SELECT URL, SHOW, PATH, LANGUAGE FROM SHOWS WHERE ID == " + show_id + ";" ), shows );
|
db.exec( TEXT( "SELECT TVID, SHOW, PATH, LANGUAGE FROM SHOWS WHERE ID == " +
|
||||||
|
show_id + ";" ),
|
||||||
|
shows );
|
||||||
|
|
||||||
std::unordered_map< string, string > &show = shows[0];
|
std::unordered_map< string, string > &show = shows[0];
|
||||||
|
|
||||||
string pattern{};
|
string pattern{};
|
||||||
db.exec( TEXT( "SELECT PATH FROM SHOWS WHERE URL == 'pattern';" ),
|
db.exec( TEXT( "SELECT PATH FROM SHOWS WHERE TVID == 'pattern';" ),
|
||||||
pattern );
|
pattern );
|
||||||
|
|
||||||
cout << "Refreshing " << show[TEXT( "SHOW" )] << std::endl << std::endl << std::endl;
|
cout << "Refreshing " << show[TEXT( "SHOW" )] << std::endl
|
||||||
|
<< std::endl
|
||||||
|
<< std::endl;
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
cout << std::endl;
|
cout << std::endl;
|
||||||
#endif
|
#endif
|
||||||
@ -1063,10 +942,9 @@ void refreshSingleDB( const size_t &index, bool linux, Curl &c ) {
|
|||||||
#endif
|
#endif
|
||||||
size_t i{};
|
size_t i{};
|
||||||
for ( const auto &x : seasons ) {
|
for ( const auto &x : seasons ) {
|
||||||
singleSeason( show[TEXT( "PATH" )], show[TEXT( "SHOW" )],
|
singleSeason( show[TEXT( "PATH" )], show[TEXT( "SHOW" )], x.first,
|
||||||
x.first, show[TEXT( "URL" )],
|
show[TEXT( "TVID" )], show[TEXT( "LANGUAGE" )],
|
||||||
show[TEXT( "LANGUAGE" )], pattern, linux, true, c,
|
pattern, linux, true, &x.second, false );
|
||||||
&x.second, false );
|
|
||||||
i++;
|
i++;
|
||||||
#ifndef GUI
|
#ifndef GUI
|
||||||
ProgressBar::print( ( i * 100 ) / size );
|
ProgressBar::print( ( i * 100 ) / size );
|
||||||
@ -1082,8 +960,8 @@ void refreshSingleDB( const size_t &index, bool linux, Curl &c ) {
|
|||||||
for ( auto &episode : season.second ) {
|
for ( auto &episode : season.second ) {
|
||||||
db.exec( TEXT( "INSERT INTO EPISODES ( SHOWID, PATH ) "
|
db.exec( TEXT( "INSERT INTO EPISODES ( SHOWID, PATH ) "
|
||||||
"VALUES ( " ) +
|
"VALUES ( " ) +
|
||||||
show_id + TEXT( ", '" ) +
|
show_id + TEXT( ", '" ) + sanitize( episode ) +
|
||||||
sanitize( episode ) + TEXT( "' );" ) );
|
TEXT( "' );" ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,6 @@ using char_t = char;
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
string getDefUrl( string &show, const string &language, Curl &c );
|
|
||||||
void findSeason( std::set< string > &files, int season, const string &path );
|
void findSeason( std::set< string > &files, int season, const string &path );
|
||||||
void findSeasons( std::map< int, std::set< string > > &seasons,
|
void findSeasons( std::map< int, std::set< string > > &seasons,
|
||||||
const string &path, const std::set< int > &season_numbers );
|
const string &path, const std::set< int > &season_numbers );
|
||||||
@ -38,13 +37,12 @@ void findSeasons( std::map< int, std::set< string > > &seasons,
|
|||||||
// CLI functions
|
// CLI functions
|
||||||
void printHelp();
|
void printHelp();
|
||||||
|
|
||||||
|
string encodeUrl( const string &url );
|
||||||
bool searchSpecificSeason( const char_t *const path, const string &number );
|
bool searchSpecificSeason( const char_t *const path, const string &number );
|
||||||
bool searchSeason( const char_t *const path, size_t &season_pos );
|
bool searchSeason( const char_t *const path, size_t &season_pos );
|
||||||
bool searchSeason( const char_t *const path );
|
bool searchSeason( const char_t *const path );
|
||||||
|
|
||||||
void parseSeasonNumbers( std::set< int > &seasons_num, const char_t *argument );
|
void parseSeasonNumbers( std::set< int > &seasons_num, const char_t *argument );
|
||||||
void printLangs();
|
|
||||||
bool findLanguage( const char_t *language );
|
|
||||||
|
|
||||||
string encodeUrl( const string &url );
|
string encodeUrl( const string &url );
|
||||||
|
|
||||||
@ -52,7 +50,7 @@ string encodeUrl( const string &url );
|
|||||||
// GUI functions
|
// GUI functions
|
||||||
|
|
||||||
std::vector< std::pair< string, string > >
|
std::vector< std::pair< string, string > >
|
||||||
getPossibleShows( string show, const string &language, Curl &c );
|
getPossibleShows( string show, const string &language );
|
||||||
|
|
||||||
#endif // GUI
|
#endif // GUI
|
||||||
|
|
||||||
@ -61,20 +59,20 @@ string userHome();
|
|||||||
void prepareDB( const std::string &_pattern = "" );
|
void prepareDB( const std::string &_pattern = "" );
|
||||||
#ifndef GUI
|
#ifndef GUI
|
||||||
void addToDB( string &show, const string &path, const string &language,
|
void addToDB( string &show, const string &path, const string &language,
|
||||||
bool linux, Curl &c );
|
bool linux );
|
||||||
#else
|
#else
|
||||||
void addToDB( string &show, const string &path, const string &language,
|
void addToDB( string &show, const string &path, const string &language,
|
||||||
const string &url, const string &pattern, bool linux, Curl &c );
|
const string &url, const string &pattern, bool linux );
|
||||||
std::vector< std::unordered_map< std::string, std::string > > dbGetShows();
|
std::vector< std::unordered_map< std::string, std::string > > dbGetShows();
|
||||||
#endif
|
#endif
|
||||||
void removeFromDB( const string &path );
|
void removeFromDB( const string &path );
|
||||||
void changeDBPattern( const string &pattern );
|
void changeDBPattern( const string &pattern );
|
||||||
void refreshDB( bool linux, Curl &c );
|
void refreshDB( bool linux );
|
||||||
void updateDB( bool linux, Curl &c );
|
void updateDB( bool linux );
|
||||||
void cleanDB();
|
void cleanDB();
|
||||||
void changeDB( size_t index, const string &path, const string &language,
|
void changeDB( size_t index, const string &path, const string &language,
|
||||||
const string &url, Curl &c);
|
const string &url );
|
||||||
void refreshSingleDB( const size_t &index, bool linux, Curl &c );
|
void refreshSingleDB( const size_t &index, bool linux );
|
||||||
|
|
||||||
void iterateFS( std::map< int, std::set< string > > &seasons,
|
void iterateFS( std::map< int, std::set< string > > &seasons,
|
||||||
const string &path );
|
const string &path );
|
||||||
|
38
main.cpp
38
main.cpp
@ -48,7 +48,7 @@ constexpr size_t DB_PATTERN = 0x0020;
|
|||||||
|
|
||||||
int handleArgument( char_t c, string &show, std::set< int > &seasons_num,
|
int handleArgument( char_t c, string &show, std::set< int > &seasons_num,
|
||||||
bool &change_dir, string &path, bool &trust, bool &linux,
|
bool &change_dir, string &path, bool &trust, bool &linux,
|
||||||
string &language, string &pattern, size_t &db_flags,
|
string &language, string &pattern, bool &dvd, size_t &db_flags,
|
||||||
string &db_pattern, char_t *optional, int &i ) {
|
string &db_pattern, char_t *optional, int &i ) {
|
||||||
switch ( c ) {
|
switch ( c ) {
|
||||||
case 's':
|
case 's':
|
||||||
@ -79,12 +79,14 @@ int handleArgument( char_t c, string &show, std::set< int > &seasons_num,
|
|||||||
language = optional;
|
language = optional;
|
||||||
} else {
|
} else {
|
||||||
cerr << "Invalid language choice" << std::endl;
|
cerr << "Invalid language choice" << std::endl;
|
||||||
|
authenticate( "XXXXX" );
|
||||||
printLangs();
|
printLangs();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
break;
|
break;
|
||||||
case '0':
|
case '0':
|
||||||
|
authenticate( "XXXXX" );
|
||||||
printLangs();
|
printLangs();
|
||||||
return 1;
|
return 1;
|
||||||
case 'h':
|
case 'h':
|
||||||
@ -114,6 +116,9 @@ int handleArgument( char_t c, string &show, std::set< int > &seasons_num,
|
|||||||
case '3':
|
case '3':
|
||||||
db_flags |= DB_REMOVE;
|
db_flags |= DB_REMOVE;
|
||||||
break;
|
break;
|
||||||
|
case '4':
|
||||||
|
dvd = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -177,7 +182,7 @@ int parseCommandLine( string &show, std::set< int > &seasons_num, string &path,
|
|||||||
}
|
}
|
||||||
for ( const auto &x : options ) {
|
for ( const auto &x : options ) {
|
||||||
auto res = handleArgument( x, show, seasons_num, change_dir, path,
|
auto res = handleArgument( x, show, seasons_num, change_dir, path,
|
||||||
trust, linux, language, pattern,
|
trust, linux, language, pattern, dvd,
|
||||||
db_flags, db_pattern, optional, i );
|
db_flags, db_pattern, optional, i );
|
||||||
if ( res != 0 )
|
if ( res != 0 )
|
||||||
return res;
|
return res;
|
||||||
@ -191,7 +196,7 @@ int parseCommandLine( string &show, std::set< int > &seasons_num, string &path,
|
|||||||
// parse command line arguments using getopt
|
// parse command line arguments using getopt
|
||||||
int parseCommandLine( string &show, std::set< int > &seasons_num, string &path,
|
int parseCommandLine( string &show, std::set< int > &seasons_num, string &path,
|
||||||
bool &change_dir, string &language, string &pattern,
|
bool &change_dir, string &language, string &pattern,
|
||||||
bool &linux, bool &trust, size_t &db_flags,
|
bool &linux, bool &trust, bool &dvd, size_t &db_flags,
|
||||||
string &db_pattern, int argc, char **argv ) {
|
string &db_pattern, int argc, char **argv ) {
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
{ "show", required_argument, 0, 's' },
|
{ "show", required_argument, 0, 's' },
|
||||||
@ -207,7 +212,8 @@ int parseCommandLine( string &show, std::set< int > &seasons_num, string &path,
|
|||||||
{ "db-update", no_argument, 0, 'u' },
|
{ "db-update", no_argument, 0, 'u' },
|
||||||
{ "db-name-pattern", required_argument, 0, 'd' },
|
{ "db-name-pattern", required_argument, 0, 'd' },
|
||||||
{ "db-clean", no_argument, 0, '2' },
|
{ "db-clean", no_argument, 0, '2' },
|
||||||
{ "db-remove", required_argument, 0, '3' },
|
{ "db-remove", no_argument, 0, '3' },
|
||||||
|
{ "dvd", no_argument, 0, '4' },
|
||||||
{ "help", no_argument, 0, 'h' },
|
{ "help", no_argument, 0, 'h' },
|
||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
@ -216,12 +222,12 @@ int parseCommandLine( string &show, std::set< int > &seasons_num, string &path,
|
|||||||
|
|
||||||
while ( 1 ) {
|
while ( 1 ) {
|
||||||
int option_index{ 0 };
|
int option_index{ 0 };
|
||||||
auto c = getopt_long( argc, argv, "s:n:cp:txl:01:arud23h", long_options,
|
auto c = getopt_long( argc, argv, "s:n:cp:txl:01:arud234h", long_options,
|
||||||
&option_index );
|
&option_index );
|
||||||
if ( c == -1 )
|
if ( c == -1 )
|
||||||
break;
|
break;
|
||||||
auto res = handleArgument( c, show, seasons_num, change_dir, path,
|
auto res = handleArgument( c, show, seasons_num, change_dir, path,
|
||||||
trust, linux, language, pattern, db_flags,
|
trust, linux, language, pattern, dvd, db_flags,
|
||||||
db_pattern, optarg, i );
|
db_pattern, optarg, i );
|
||||||
if ( res != 0 )
|
if ( res != 0 )
|
||||||
return res;
|
return res;
|
||||||
@ -254,16 +260,16 @@ int main
|
|||||||
bool change_dir{ true };
|
bool change_dir{ true };
|
||||||
bool linux{ false };
|
bool linux{ false };
|
||||||
bool trust{ false };
|
bool trust{ false };
|
||||||
|
bool dvd{ false };
|
||||||
size_t db_flags{};
|
size_t db_flags{};
|
||||||
string path{ TEXT( "." ) };
|
string path{ TEXT( "." ) };
|
||||||
string language{ TEXT( "en" ) };
|
string language{ TEXT( "en" ) };
|
||||||
string pattern{ TEXT( "%filename - %epname" ) };
|
string pattern{ TEXT( "%filename - %epname" ) };
|
||||||
string db_pattern{};
|
string db_pattern{};
|
||||||
Curl c;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
auto tmp = parseCommandLine( show, seasons_num, path, change_dir,
|
auto tmp = parseCommandLine( show, seasons_num, path, change_dir,
|
||||||
language, pattern, linux, trust, db_flags,
|
language, pattern, linux, trust, dvd, db_flags,
|
||||||
db_pattern, argc, argv );
|
db_pattern, argc, argv );
|
||||||
if ( tmp == -1 )
|
if ( tmp == -1 )
|
||||||
return 1;
|
return 1;
|
||||||
@ -271,6 +277,8 @@ int main
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
authenticate( "XXXXX" );
|
||||||
|
|
||||||
if ( !FSLib::isDirectory( path ) && FSLib::exists( path ) ) {
|
if ( !FSLib::isDirectory( path ) && FSLib::exists( path ) ) {
|
||||||
// specified file, not directory
|
// specified file, not directory
|
||||||
auto *file_set = new std::set< string >;
|
auto *file_set = new std::set< string >;
|
||||||
@ -283,7 +291,7 @@ int main
|
|||||||
} else {
|
} else {
|
||||||
auto season = std::stoi( path.c_str() + season_pos );
|
auto season = std::stoi( path.c_str() + season_pos );
|
||||||
singleSeason( path, show, season, TEXT( "" ), language, pattern,
|
singleSeason( path, show, season, TEXT( "" ), language, pattern,
|
||||||
linux, trust, c, file_set );
|
linux, trust, file_set, true, dvd );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else if ( !FSLib::isDirectory( path ) ) {
|
} else if ( !FSLib::isDirectory( path ) ) {
|
||||||
@ -304,15 +312,15 @@ int main
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( db_flags & DB_ADD ) {
|
if ( db_flags & DB_ADD ) {
|
||||||
addToDB( show, path, language, linux, c );
|
addToDB( show, path, language, linux );
|
||||||
cout << "Added to database" << std::endl;
|
cout << "Added to database" << std::endl;
|
||||||
}
|
}
|
||||||
if ( db_flags & DB_REFRESH ) {
|
if ( db_flags & DB_REFRESH ) {
|
||||||
refreshDB( linux, c );
|
refreshDB( linux );
|
||||||
cout << "Refreshed database" << std::endl;
|
cout << "Refreshed database" << std::endl;
|
||||||
}
|
}
|
||||||
if ( db_flags & DB_UPDATE ) {
|
if ( db_flags & DB_UPDATE ) {
|
||||||
updateDB( linux, c );
|
updateDB( linux );
|
||||||
cout << "Updated database" << std::endl;
|
cout << "Updated database" << std::endl;
|
||||||
}
|
}
|
||||||
if ( db_flags & DB_CLEAN ) {
|
if ( db_flags & DB_CLEAN ) {
|
||||||
@ -364,11 +372,11 @@ int main
|
|||||||
|
|
||||||
if ( seasons_num.size() == 1 ) {
|
if ( seasons_num.size() == 1 ) {
|
||||||
singleSeason( path, show, *seasons_num.begin(), string(), language,
|
singleSeason( path, show, *seasons_num.begin(), string(), language,
|
||||||
pattern, linux, trust, c );
|
pattern, linux, trust, nullptr, true, dvd );
|
||||||
} else if ( seasons_num.size() != 0 ) {
|
} else if ( seasons_num.size() != 0 ) {
|
||||||
multipleSeasons( path, show, seasons_num, language, pattern, linux,
|
multipleSeasons( path, show, seasons_num, language, pattern, linux,
|
||||||
trust, c );
|
trust, dvd );
|
||||||
} else {
|
} else {
|
||||||
allSeasons( path, show, language, pattern, linux, trust, c );
|
allSeasons( path, show, language, pattern, linux, trust, dvd );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
39
network.cpp
39
network.cpp
@ -62,15 +62,52 @@ Curl::Curl() {
|
|||||||
|
|
||||||
Curl::~Curl() {
|
Curl::~Curl() {
|
||||||
curl_easy_cleanup( curl_handle );
|
curl_easy_cleanup( curl_handle );
|
||||||
|
curl_slist_free_all( chunk );
|
||||||
curl_global_cleanup();
|
curl_global_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Curl::execute( const std::string &url ) {
|
void cleanUp( CURL *curl_handle ) {
|
||||||
|
curl_easy_setopt( curl_handle, CURLOPT_POST, 0 );
|
||||||
|
curl_easy_setopt( curl_handle, CURLOPT_POSTFIELDS, "" );
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Curl::get( const std::string &url ) {
|
||||||
|
// get rid of garbage
|
||||||
|
cleanUp( curl_handle );
|
||||||
std::string source;
|
std::string source;
|
||||||
source.reserve( 100000 );
|
source.reserve( 100000 );
|
||||||
curl_easy_setopt( curl_handle, CURLOPT_WRITEDATA,
|
curl_easy_setopt( curl_handle, CURLOPT_WRITEDATA,
|
||||||
static_cast< void * >( &source ) );
|
static_cast< void * >( &source ) );
|
||||||
curl_easy_setopt( curl_handle, CURLOPT_URL, url.c_str() );
|
curl_easy_setopt( curl_handle, CURLOPT_URL, url.c_str() );
|
||||||
|
curl_easy_setopt( curl_handle, CURLOPT_HTTPGET, 1 );
|
||||||
|
auto res = curl_easy_perform( curl_handle );
|
||||||
|
if ( res != CURLE_OK ) {
|
||||||
|
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror( res )
|
||||||
|
<< std::endl;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Curl::addHeader( const std::string &header ) {
|
||||||
|
chunk = curl_slist_append( chunk, header.c_str() );
|
||||||
|
curl_easy_setopt( curl_handle, CURLOPT_HTTPHEADER, chunk );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Curl::clearHeader() {
|
||||||
|
curl_slist_free_all( chunk );
|
||||||
|
chunk = NULL;
|
||||||
|
curl_easy_setopt( curl_handle, CURLOPT_HTTPHEADER, chunk );
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Curl::post( const std::string &url, const std::string &data ) {
|
||||||
|
std::string source;
|
||||||
|
source.reserve( 100000 );
|
||||||
|
curl_easy_setopt( curl_handle, CURLOPT_URL, url.c_str() );
|
||||||
|
curl_easy_setopt( curl_handle, CURLOPT_POST, 1 );
|
||||||
|
curl_easy_setopt( curl_handle, CURLOPT_POSTFIELDS, data.c_str() );
|
||||||
|
curl_easy_setopt( curl_handle, CURLOPT_WRITEDATA,
|
||||||
|
static_cast< void * >( &source ) );
|
||||||
auto res = curl_easy_perform( curl_handle );
|
auto res = curl_easy_perform( curl_handle );
|
||||||
if ( res != CURLE_OK ) {
|
if ( res != CURLE_OK ) {
|
||||||
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror( res )
|
std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror( res )
|
||||||
|
11
network.hpp
11
network.hpp
@ -1,18 +1,17 @@
|
|||||||
#ifndef NETWORK_HPP
|
#ifndef NETWORK_HPP
|
||||||
#define NETWORK_HPP
|
#define NETWORK_HPP
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
#include <Windows.h>
|
|
||||||
#include <WinInet.h>
|
#include <WinInet.h>
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
using string = std::wstring;
|
using string = std::wstring;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
using string = std::string;
|
using string = std::string;
|
||||||
|
|
||||||
@ -22,13 +21,17 @@ class Curl {
|
|||||||
public:
|
public:
|
||||||
Curl();
|
Curl();
|
||||||
~Curl();
|
~Curl();
|
||||||
std::string execute( const string &url );
|
std::string get( const string &url );
|
||||||
|
std::string post( const std::string &url, const std::string &data );
|
||||||
|
void addHeader( const std::string &header );
|
||||||
|
void clearHeader();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HINTERNET connect = nullptr;
|
HINTERNET connect = nullptr;
|
||||||
#else
|
#else
|
||||||
CURL *curl_handle;
|
CURL *curl_handle;
|
||||||
|
struct curl_slist *chunk = NULL;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
244
tv_rename.cpp
244
tv_rename.cpp
@ -24,6 +24,9 @@
|
|||||||
#include "functions.hpp"
|
#include "functions.hpp"
|
||||||
#include "tv_rename.hpp"
|
#include "tv_rename.hpp"
|
||||||
|
|
||||||
|
#include "json.hpp"
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
constexpr const char_t *dir_divider = L"\\";
|
constexpr const char_t *dir_divider = L"\\";
|
||||||
@ -44,81 +47,122 @@ constexpr const char_t *dir_divider = "/";
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// get names for all episodes for a given season
|
std::string api_token = "";
|
||||||
std::vector< string > parseEpisodeNames( const string &season_code,
|
Curl c;
|
||||||
const string &language ) {
|
|
||||||
std::vector< string > episodes;
|
|
||||||
size_t pos = 0;
|
|
||||||
while ( true ) {
|
|
||||||
pos =
|
|
||||||
season_code.find( TEXT( "ge=\"" ) + language + TEXT( "\" " ), pos );
|
|
||||||
if ( pos != string::npos ) {
|
|
||||||
if ( language == TEXT( "en" ) )
|
|
||||||
pos += 17;
|
|
||||||
else
|
|
||||||
pos += 29;
|
|
||||||
while ( iswspace( season_code[pos] ) )
|
|
||||||
pos++;
|
|
||||||
|
|
||||||
auto end = season_code.find( TEXT( "<" ), pos );
|
std::vector< std::pair< string, string > >
|
||||||
end--;
|
searchShow( const string &show, const string &language ) {
|
||||||
|
c.addHeader( "Accept: application/json" );
|
||||||
|
c.addHeader( "Authorization: Bearer " + api_token );
|
||||||
|
c.addHeader( "Accept-Language: " + language );
|
||||||
|
|
||||||
while ( iswspace( season_code[end] ) )
|
auto encoded_show = encodeUrl( show );
|
||||||
end--;
|
|
||||||
|
|
||||||
end++;
|
auto j = json::parse(
|
||||||
episodes.push_back( season_code.substr( pos, end - pos ) );
|
c.get( "https://api.thetvdb.com/search/series?name=" + encoded_show ) );
|
||||||
|
|
||||||
|
std::vector< json > results;
|
||||||
|
if( j["data"].is_array() ) {
|
||||||
|
results = j["data"].get< std::vector< json > >();
|
||||||
} else {
|
} else {
|
||||||
|
cout << j << std::endl;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector< std::pair< string, string > > ret;
|
||||||
|
|
||||||
|
// find all possible shows
|
||||||
|
for ( auto &x : results ) {
|
||||||
|
ret.emplace_back( x["seriesName"].get< string >(),
|
||||||
|
std::to_string( x["id"].get< int >() ) );
|
||||||
|
}
|
||||||
|
c.clearHeader();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get show's ID
|
||||||
|
string getShowId( string &show, const string &language ) {
|
||||||
|
size_t order{}, pos{};
|
||||||
|
auto search_results = searchShow( show, language );
|
||||||
|
for( const auto &x : search_results ) {
|
||||||
|
cout << ++order << ". " << x.first << std::endl;
|
||||||
|
}
|
||||||
|
cout << "Which TV Show is the right one? ";
|
||||||
|
cin >> pos;
|
||||||
|
cin.clear();
|
||||||
|
cin.ignore( 1, '\n' );
|
||||||
|
return search_results[pos-1].second;
|
||||||
|
}
|
||||||
|
|
||||||
|
string showNameFromId( const string &id, const string &language ) {
|
||||||
|
c.addHeader( "Accept: application/json" );
|
||||||
|
c.addHeader( "Authorization: Bearer " + api_token );
|
||||||
|
c.addHeader( "Accept-Language: " + language );
|
||||||
|
|
||||||
|
auto j = json::parse( c.get( "https://api.thetvdb.com/series/" + id ) );
|
||||||
|
|
||||||
|
return j["data"].get< json >()["seriesName"].get< string >();
|
||||||
|
}
|
||||||
|
|
||||||
|
// get names for all episodes for a given season
|
||||||
|
std::vector< string > getEpisodeNames( const string &id, const string &season,
|
||||||
|
const string &language, bool dvd = false ) {
|
||||||
|
c.addHeader( "Accept: application/json" );
|
||||||
|
c.addHeader( "Authorization: Bearer " + api_token );
|
||||||
|
c.addHeader( "Accept-Language: " + language );
|
||||||
|
string page = "1";
|
||||||
|
string season_query = "airedSeason=";
|
||||||
|
if( dvd )
|
||||||
|
season_query = "dvdSeason=";
|
||||||
|
std::vector< string > episodes;
|
||||||
|
do {
|
||||||
|
episodes.resize( episodes.size() * 2 );
|
||||||
|
auto j = json::parse( c.get( "https://api.thetvdb.com/series/" + id +
|
||||||
|
"/episodes/query?" + season_query + season
|
||||||
|
+ "&page=" + page ) );
|
||||||
|
if( j["data"].is_array() ) {
|
||||||
|
auto epdata = j["data"].get< std::vector< json > >();
|
||||||
|
if( episodes.size() < epdata.size() )
|
||||||
|
episodes.resize( epdata.size() );
|
||||||
|
for ( auto &x : epdata ) {
|
||||||
|
if( x["episodeName"].is_string() ) {
|
||||||
|
if( dvd ) {
|
||||||
|
size_t index = x["dvdEpisodeNumber"].get< size_t >();
|
||||||
|
if( index > episodes.size() )
|
||||||
|
episodes.resize( index );
|
||||||
|
index--;
|
||||||
|
episodes[index] = x["episodeName"].get< string >();
|
||||||
|
} else {
|
||||||
|
size_t index = x["airedEpisodeNumber"].get< size_t >();
|
||||||
|
if( index > episodes.size() )
|
||||||
|
episodes.resize( index );
|
||||||
|
index--;
|
||||||
|
episodes[index] = x["episodeName"].get<string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cerr << "Couldn't find episode names for season " << season << " of show " << showNameFromId( id, language ) << std::endl;
|
||||||
|
}
|
||||||
|
if( j["links"]["next"].is_null() )
|
||||||
break;
|
break;
|
||||||
}
|
page = std::to_string( j["links"]["next"].get< size_t >() );
|
||||||
}
|
} while( 1 );
|
||||||
|
c.clearHeader();
|
||||||
return episodes;
|
return episodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
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, const string id,
|
||||||
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, const std::set< string > &files, bool dvd = false ) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
auto season_num = std::to_wstring( season );
|
auto season_num = std::to_wstring( season );
|
||||||
#else
|
|
||||||
auto season_num = std::to_string( season );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
url += TEXT( "/seasons/" );
|
|
||||||
url += season_num;
|
|
||||||
|
|
||||||
// get source code of season's page
|
|
||||||
auto season_code = c.execute( url );
|
|
||||||
|
|
||||||
// remove newlines
|
|
||||||
season_code.erase(
|
|
||||||
std::remove_if( season_code.begin(), season_code.end(),
|
|
||||||
[]( char x ) { return x == '\r' || x == '\n'; } ),
|
|
||||||
season_code.end() );
|
|
||||||
|
|
||||||
// first 900 chars or so are useless to us
|
|
||||||
season_code = season_code.substr( 900 );
|
|
||||||
|
|
||||||
// get only the episode names
|
|
||||||
auto pos = season_code.find( "\"translations\"" );
|
|
||||||
|
|
||||||
if ( pos != string::npos ) {
|
|
||||||
season_code = season_code.substr( pos );
|
|
||||||
pos = season_code.find( "</table>" );
|
|
||||||
if ( pos != string::npos )
|
|
||||||
season_code = season_code.substr( 0, pos );
|
|
||||||
else
|
|
||||||
return {};
|
|
||||||
} else {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
auto episodes =
|
auto episodes =
|
||||||
parseEpisodeNames( utf8_to_wstring( season_code ), language );
|
parseEpisodeNames( utf8_to_wstring( season_code ), language );
|
||||||
#else
|
#else
|
||||||
auto episodes = parseEpisodeNames( season_code, language );
|
auto season_num = std::to_string( season );
|
||||||
|
auto episodes = getEpisodeNames( id, season_num, language, dvd );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ( episodes.empty() )
|
if ( episodes.empty() )
|
||||||
@ -130,6 +174,7 @@ getRenamedFiles( const string &show, int season, string url,
|
|||||||
std::vector< std::pair< string, std::pair< string, string > > >
|
std::vector< std::pair< 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.find_last_of( dir_divider );
|
||||||
string og_name;
|
string og_name;
|
||||||
@ -148,8 +193,8 @@ getRenamedFiles( const string &show, int season, string url,
|
|||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
num--;
|
||||||
|
|
||||||
num -= 1;
|
|
||||||
if ( num < episodes.size() ) {
|
if ( 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
|
||||||
@ -204,12 +249,12 @@ getRenamedFiles( const string &show, int season, string url,
|
|||||||
return renamed_files;
|
return renamed_files;
|
||||||
}
|
}
|
||||||
|
|
||||||
void singleSeason( const string &path, string &show, int season, string url,
|
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, Curl &c,
|
const bool &linux, const bool &trust,
|
||||||
std::set< string > const *files_ptr, bool print ) {
|
std::set< string > const *files_ptr, bool print, bool dvd ) {
|
||||||
if ( url.empty() )
|
if ( id.empty() )
|
||||||
url = getDefUrl( show, language, c );
|
id = getShowId( show, language );
|
||||||
|
|
||||||
std::set< string > *found_files = nullptr;
|
std::set< string > *found_files = nullptr;
|
||||||
|
|
||||||
@ -219,13 +264,12 @@ void singleSeason( const string &path, string &show, int season, string url,
|
|||||||
files_ptr = found_files;
|
files_ptr = found_files;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto renamed_files =
|
auto renamed_files = getRenamedFiles( show, season, id, language, pattern,
|
||||||
getRenamedFiles( show, season, std::move( url ), language, pattern,
|
linux, *files_ptr, dvd );
|
||||||
linux, c, *files_ptr );
|
|
||||||
|
|
||||||
if ( print ) {
|
if( print || !trust ) {
|
||||||
for ( auto renamed = renamed_files.begin();
|
for ( auto renamed = renamed_files.begin(); renamed != renamed_files.end();
|
||||||
renamed != renamed_files.end(); ++renamed ) {
|
++renamed ) {
|
||||||
cout << renamed->second.first << " --> " << renamed->second.second
|
cout << renamed->second.first << " --> " << renamed->second.second
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
}
|
}
|
||||||
@ -257,31 +301,67 @@ void singleSeason( const string &path, string &show, int season, string url,
|
|||||||
void multipleSeasons( const string &path, string &show,
|
void multipleSeasons( const string &path, string &show,
|
||||||
const std::map< int, std::set< string > > &seasons,
|
const std::map< int, std::set< string > > &seasons,
|
||||||
const string &language, const string &pattern,
|
const string &language, const string &pattern,
|
||||||
const bool &linux, const bool &trust, Curl &c ) {
|
const bool &linux, const bool &trust, bool dvd ) {
|
||||||
auto url = getDefUrl( show, language, c );
|
auto id = getShowId( show, language );
|
||||||
for ( const auto &x : seasons ) {
|
for ( const auto &x : seasons ) {
|
||||||
singleSeason( path, show, x.first, url, language, pattern, linux, trust,
|
singleSeason( path, show, x.first, id, language, pattern, linux, trust,
|
||||||
c, &x.second );
|
&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 bool &linux,
|
||||||
const bool &trust, Curl &c ) {
|
const bool &trust, bool dvd ) {
|
||||||
std::map< int, std::set< string > > season_map;
|
std::map< int, std::set< string > > season_map;
|
||||||
findSeasons( season_map, path, seasons );
|
findSeasons( season_map, path, seasons );
|
||||||
multipleSeasons( path, show, season_map, language, pattern, linux, trust,
|
multipleSeasons( path, show, season_map, language, pattern, linux, trust, dvd );
|
||||||
c );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
const string &pattern, const bool &linux, const bool &trust, bool dvd ) {
|
||||||
Curl &c ) {
|
|
||||||
std::map< int, std::set< string > > seasons;
|
std::map< int, std::set< 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, c );
|
multipleSeasons( path, show, seasons, language, pattern, linux, trust, dvd );
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector< std::pair< std::string, std::string > > getLangs() {
|
||||||
|
std::vector< std::pair< std::string, std::string > > langs;
|
||||||
|
c.addHeader( "Accept: application/json" );
|
||||||
|
c.addHeader( "Authorization: Bearer " + api_token );
|
||||||
|
auto j = json::parse( c.get( "https://api.thetvdb.com/languages" ) );
|
||||||
|
c.clearHeader();
|
||||||
|
auto langs_json = j["data"].get< std::vector< json > >();
|
||||||
|
for ( auto &x : langs_json ) {
|
||||||
|
langs.emplace_back( x["abbreviation"].get< std::string >(),
|
||||||
|
x["name"].get< std::string >() );
|
||||||
|
}
|
||||||
|
return langs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printLangs() {
|
||||||
|
for ( auto &x : getLangs() )
|
||||||
|
cout << x.first << " - " << x.second << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool findLanguage( const char_t *language ) {
|
||||||
|
for ( auto &x : getLangs() ) {
|
||||||
|
if ( x.first == language )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool authenticate( const std::string &api_key ) {
|
||||||
|
c.addHeader( "Accept: application/json" );
|
||||||
|
c.addHeader( "Content-Type: application/json" );
|
||||||
|
auto j = json::parse( c.post( "https://api.thetvdb.com/login",
|
||||||
|
"{ \"apikey\": \"" + api_key + "\" }" ) );
|
||||||
|
api_token = j["token"].get< std::string >();
|
||||||
|
c.clearHeader();
|
||||||
|
// TODO check return code
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -2,10 +2,7 @@
|
|||||||
#define TV_RENAME_HPP
|
#define TV_RENAME_HPP
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#ifdef GUI
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "network.hpp"
|
#include "network.hpp"
|
||||||
|
|
||||||
@ -21,11 +18,11 @@ using char_t = char;
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void singleSeason( const string &path, string &show, int season, string url,
|
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, Curl &c,
|
const bool &linux, const bool &trust,
|
||||||
std::set< string > const *files = nullptr,
|
std::set< string > const *files_ptr = nullptr,
|
||||||
bool print = true );
|
bool print = true, bool dvd = false );
|
||||||
|
|
||||||
#ifdef GUI
|
#ifdef GUI
|
||||||
|
|
||||||
@ -39,11 +36,18 @@ getRenamedFiles( const string &show, int season, string url,
|
|||||||
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 bool &linux,
|
||||||
const bool &trust, Curl &c );
|
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,
|
const string &pattern, const bool &linux, const bool &trust, bool dvd = false );
|
||||||
Curl &c );
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void printLangs();
|
||||||
|
bool findLanguage( const char_t *language );
|
||||||
|
bool authenticate( const std::string &api_key );
|
||||||
|
string getShowId( string &show, const string &language );
|
||||||
|
string showNameFromId( const string &id, const string &language );
|
||||||
|
std::vector< std::pair< string, string > > searchShow( const string &show,
|
||||||
|
const string &language );
|
||||||
|
|
||||||
#endif // TV_RENAME_HPP
|
#endif // TV_RENAME_HPP
|
||||||
|
Loading…
Reference in New Issue
Block a user