285 lines
8.6 KiB
C++
285 lines
8.6 KiB
C++
#include <algorithm>
|
|
#include <map>
|
|
|
|
#ifdef _WIN32
|
|
|
|
#include <codecvt>
|
|
#include <fcntl.h>
|
|
#include <io.h>
|
|
#include <locale>
|
|
#include <windows.h>
|
|
|
|
#endif
|
|
|
|
#ifndef GUI
|
|
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <vector>
|
|
#include "filesystem.hpp"
|
|
|
|
#endif
|
|
|
|
#include "functions.hpp"
|
|
#include "tv_rename.hpp"
|
|
|
|
#ifdef _WIN32
|
|
|
|
constexpr const char_t *dir_divider = L"\\";
|
|
|
|
#define cout std::wcout
|
|
#define cerr std::wcerr
|
|
#define cin std::wcin
|
|
|
|
#else
|
|
|
|
constexpr const char_t *dir_divider = "/";
|
|
|
|
#define cout std::cout
|
|
#define cerr std::cerr
|
|
#define cin std::cin
|
|
|
|
#define TEXT( a ) a
|
|
|
|
#endif
|
|
|
|
// get names for all episodes for a given season
|
|
std::vector< string > parseEpisodeNames( const string &season_code,
|
|
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 );
|
|
end--;
|
|
|
|
while ( iswspace( season_code[end] ) )
|
|
end--;
|
|
|
|
end++;
|
|
episodes.push_back( season_code.substr( pos, end - pos ) );
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
return episodes;
|
|
}
|
|
|
|
std::vector< std::pair< string, std::pair< string, string > > >
|
|
getRenamedFiles( const string &show, int season, string url,
|
|
const string &language, const string &pattern,
|
|
const bool &linux, Curl &c, const std::set< string > &files ) {
|
|
#ifdef _WIN32
|
|
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 =
|
|
parseEpisodeNames( utf8_to_wstring( season_code ), language );
|
|
#else
|
|
auto episodes = parseEpisodeNames( season_code, language );
|
|
#endif
|
|
|
|
if ( episodes.empty() )
|
|
return {};
|
|
|
|
if ( files.empty() )
|
|
return {};
|
|
|
|
std::vector< std::pair< string, std::pair< string, string > > >
|
|
renamed_files;
|
|
|
|
for ( const auto &x : files ) {
|
|
auto last = x.find_last_of( dir_divider );
|
|
string og_name;
|
|
string dir;
|
|
if ( last == string::npos ) {
|
|
og_name = x;
|
|
dir = TEXT( "." );
|
|
} else {
|
|
og_name = x.substr( last + 1 );
|
|
dir = x.substr( 0, last );
|
|
}
|
|
unsigned long num;
|
|
// get file's episode number
|
|
if ( searchSpecificSeason( x.c_str(), pos, season_num ) ) {
|
|
num = std::stoi( x.c_str() + pos );
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
num -= 1;
|
|
if ( num < episodes.size() ) {
|
|
auto pos = og_name.find_last_of( TEXT( "." ) );
|
|
// get desired filename
|
|
auto name = compilePattern( pattern, season, num + 1,
|
|
og_name.substr( 0, pos ), episodes[num],
|
|
show ) +
|
|
og_name.substr( pos );
|
|
// replace '/' with '|'
|
|
for ( size_t i = 0; i < name.size(); i++ ) {
|
|
if ( name[i] == '/' ) {
|
|
name[i] = '|';
|
|
}
|
|
}
|
|
// replace characters illegal in windows if desired
|
|
if ( !linux ) {
|
|
name.erase( std::remove_if( name.begin(), name.end(),
|
|
[]( char_t x ) {
|
|
return x == '?' || x == '"' ||
|
|
x == '\\' || x == '*';
|
|
} ),
|
|
name.end() );
|
|
size_t max{ name.size() };
|
|
for ( size_t i = 0; i < max; i++ ) {
|
|
if ( name[i] == '|' ) {
|
|
name[i] = '-';
|
|
} else if ( name[i] == '<' ) {
|
|
name[i] = 'i';
|
|
name.insert( i + 1, TEXT( "s less than" ) );
|
|
max += 11;
|
|
} else if ( name[i] == '>' ) {
|
|
name[i] = 'i';
|
|
name.insert( i + 1, TEXT( "s more than" ) );
|
|
max += 11;
|
|
} else if ( name[i] == ':' ) {
|
|
name[i] = ' ';
|
|
name.insert( i + 1, 1, '-' );
|
|
max++;
|
|
}
|
|
}
|
|
for ( size_t i = 0; i < max; i++ ) {
|
|
if ( name[i] == ' ' && name[i + 1] == ' ' ) {
|
|
name.erase( i, 1 );
|
|
max--;
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
renamed_files.emplace_back(
|
|
dir, std::pair< string, string >( og_name, name ) );
|
|
}
|
|
}
|
|
return renamed_files;
|
|
}
|
|
|
|
#ifndef GUI
|
|
|
|
void singleSeason( const string &path, string &show, int season, string url,
|
|
const string &language, const string &pattern,
|
|
const bool &linux, const bool &trust, Curl &c,
|
|
std::set< string > const *files_ptr ) {
|
|
if ( url.empty() )
|
|
url = getDefUrl( show, language, c );
|
|
|
|
std::set< string > *found_files = nullptr;
|
|
|
|
if ( files_ptr == nullptr ) {
|
|
found_files = new std::set< string >;
|
|
findSeason( *found_files, season, path );
|
|
files_ptr = found_files;
|
|
}
|
|
|
|
auto renamed_files =
|
|
getRenamedFiles( show, season, std::move( url ), language, pattern,
|
|
linux, c, *files_ptr );
|
|
|
|
for ( auto renamed = renamed_files.begin(); renamed != renamed_files.end();
|
|
++renamed ) {
|
|
cout << renamed->second.first << " --> " << renamed->second.second
|
|
<< std::endl;
|
|
}
|
|
|
|
if ( !trust ) {
|
|
cout << "Does this seem ok? (y/n) ";
|
|
string response;
|
|
cin >> response;
|
|
cin.clear();
|
|
cin.ignore( 1, '\n' );
|
|
if ( response[0] != 'y' && response[0] != 'Y' )
|
|
return;
|
|
}
|
|
|
|
for ( auto renamed = renamed_files.begin(); renamed != renamed_files.end();
|
|
++renamed ) {
|
|
FSLib::rename( renamed->first + dir_divider + renamed->second.first,
|
|
renamed->first + dir_divider + renamed->second.second );
|
|
}
|
|
|
|
if ( found_files != nullptr ) {
|
|
delete found_files;
|
|
}
|
|
}
|
|
|
|
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, Curl &c ) {
|
|
auto url = getDefUrl( show, language, c );
|
|
for ( const auto &x : seasons ) {
|
|
singleSeason( path, show, x.first, url, language, pattern, linux, trust,
|
|
c, &x.second );
|
|
}
|
|
}
|
|
|
|
void multipleSeasons( const string &path, string &show,
|
|
const std::set< int > seasons, const string &language,
|
|
const string &pattern, const bool &linux,
|
|
const bool &trust, Curl &c ) {
|
|
std::map< int, std::set< string > > season_map;
|
|
findSeasons( season_map, path, seasons );
|
|
multipleSeasons( path, show, season_map, language, pattern, linux, trust,
|
|
c );
|
|
}
|
|
|
|
void allSeasons( const string &path, string &show, const string &language,
|
|
const string &pattern, const bool &linux, const bool &trust,
|
|
Curl &c ) {
|
|
std::map< int, std::set< string > > seasons;
|
|
// get all season number from this directory and subdirectories
|
|
iterateFS( seasons, path );
|
|
multipleSeasons( path, show, seasons, language, pattern, linux, trust, c );
|
|
}
|
|
|
|
#endif
|