diff --git a/functions.cpp b/functions.cpp index e4af999..5c5d4c0 100644 --- a/functions.cpp +++ b/functions.cpp @@ -156,6 +156,14 @@ void printHelp() { std::cout << " --show-path show path, -p show path" << std::endl; std::cout << "\t\t\tPath of the directory with episodes" << std::endl; std::cout << " --correct-path, -c\tThis is the correct path, stop asking me!" << std::endl; + std::cout << " --name-pattern pattern" << std::endl; + std::cout << "\t\t\tPattern to which change the file name. Possible sequences are:" << std::endl; + std::cout << "\t\t\t\t\%filename - original filename (without filetype extension)" << std::endl; + std::cout << "\t\t\t\t\%show - show name from thetvdb" << std::endl; + std::cout << "\t\t\t\t\%epname - episode name from thetvdb" << std::endl; + std::cout << "\t\t\t\t\%season - season number, possible to specify leading 0 like this: \%2season" << std::endl; + std::cout << "\t\t\t\t\%episode - episode number, possible to specify leading 0 like this: \%2season" << std::endl; + std::cout << "\t\t\tDefault pattern is \"$filename - $epname\"" << std::endl; std::cout << " --trust, -t\t\tDon't ask whether the names are correct" << std::endl; std::cout << " --linux, -x\t\tDon't replace characters characters that are illegal in Windows" << std::endl; std::cout << " --lang language, -l language" << std::endl; @@ -211,3 +219,85 @@ std::string encodeUrl( const std::string &url ) { return encoded.str(); } +std::string compilePattern(const std::string &pattern, int season, int episode, const std::string &filename, const std::string &episodeName, const std::string &showName) { + std::string output; + + for( size_t i = 0; i < pattern.size(); i++ ) { + if( pattern[i] == '%' ) { + // if current character is % check if a pattern follows, otherwise put % + // check for numbers right after % indicating size of zero padding for numbers + auto pos = pattern.find_first_not_of("0123456789", i+1); + + if( pattern.find( "season", pos - 1 ) == pos ) { + // if season is AFTER numbers, put season number padded + // with zeros + + // get number of leading zeros + auto leading = std::atoi( pattern.c_str() + i + 1 ); + // move i to the last char of 'season' + i = pos + 5; + auto season_num = std::to_string(season); + + // get number of zeros to be put before the season number + leading -= season_num.size(); + if( leading < 0 ) + leading = 0; + + // add padded season to output + output += std::string(leading, '0') + season_num; + } else if ( pattern.find( "season", i ) == i + 1 ) { + // if season isn't after numbers, just put season number to output + i += 6; + output += std::to_string(season); + } else if ( pattern.find( "episode", pos - 1 ) == pos ) { + // same principle as with season after number + auto leading = std::atoi( pattern.c_str() + i + 1 ); + + i = pos + 6; + auto ep_num = std::to_string(episode); + + leading -= ep_num.size(); + if( leading < 0 ) + leading = 0; + + output += std::string(leading, '0') + ep_num; + } else if ( pattern.find( "episode", i ) == i + 1 ) { + // if episode isn't after number, just put the episode number to output + i += 7; + output += std::to_string(episode); + } else if ( pattern.find( "epname", i ) == i + 1 ) { + // episode name from thetvdb + i += 6; + output += episodeName; + } else if ( pattern.find( "show", i ) == i + 1 ) { + // show name from thetvdb + i += 4; + output += showName; + } else if ( pattern.find( "filename", i ) == i + 1 ) { + // original file name + i += 8; + output += filename; + } else { + // output % if no escape sequence was found + output += '%'; + } + } else if ( pattern[i] == '\\' ) { + // possibility to escape % + if( pattern[i+1] == '%' ) { + output += '%'; + i++; + } else if ( pattern[i+1] == '\\' ) { + output += '\\'; + i++; + } else { + output += '\\'; + } + } else { + // if char isn't % or / just add it to the output string + output += pattern[i]; + } + } + + return output; +} + diff --git a/functions.hpp b/functions.hpp index 63fae6f..0c55d4b 100644 --- a/functions.hpp +++ b/functions.hpp @@ -22,5 +22,6 @@ void printLangs(); bool findLanguage( const char *language ); std::string encodeUrl( const std::string &url ); +std::string compilePattern(const std::string &pattern, int season, int episode, const std::string &filename, const std::string &episodeName, const std::string &showName); #endif diff --git a/main.cpp b/main.cpp index 22d88e5..f63d141 100644 --- a/main.cpp +++ b/main.cpp @@ -4,7 +4,7 @@ #include "functions.hpp" #include "tv_rename.hpp" -int parseCommandLine(std::string &show, std::set &seasons_num, std::string &path, bool &change_dir, std::string &language, bool &linux, bool &trust, int argc, char **argv) { +int parseCommandLine(std::string &show, std::set &seasons_num, std::string &path, bool &change_dir, std::string &language, std::string &pattern, bool &linux, bool &trust, int argc, char **argv) { static struct option long_options[] = { {"show", required_argument, 0, 's' }, {"season", required_argument, 0, 'n' }, @@ -14,12 +14,13 @@ int parseCommandLine(std::string &show, std::set &seasons_num, std::string {"linux", no_argument, 0, 'x' }, {"lang", required_argument, 0, 'l' }, {"print-langs", no_argument, 0, '0' }, + {"name-pattern", required_argument, 0, '1' }, {"help", no_argument, 0, 'h' } }; while(1) { int option_index{0}; - auto c = getopt_long(argc, argv, "s:n:cp:txl:0h", long_options, &option_index); + auto c = getopt_long(argc, argv, "s:n:cp:txl:01:h", long_options, &option_index); if( c == -1 ) break; switch(c) { @@ -58,6 +59,9 @@ int parseCommandLine(std::string &show, std::set &seasons_num, std::string case 'h': printHelp(); return 1; + case '1': + pattern = optarg; + break; default: return -1; } @@ -74,10 +78,11 @@ int main(int argc, char** argv) { std::string language{"en"}; bool linux{false}; bool trust{false}; + std::string pattern{"%file - %epname"}; Curl c; { - auto tmp = parseCommandLine(show, seasons_num, path, change_dir, language, linux, trust, argc, argv); + auto tmp = parseCommandLine(show, seasons_num, path, change_dir, language, pattern, linux, trust, argc, argv); if( tmp == -1 ) return 1; else if ( tmp == 1 ) @@ -122,11 +127,11 @@ int main(int argc, char** argv) { } if( seasons_num.size() == 1 ) { - singleSeason(path, show, *seasons_num.begin(), "", language, linux, trust, c); + singleSeason(path, show, *seasons_num.begin(), "", language, pattern, linux, trust, c); } else if ( seasons_num.size() != 0 ) { - multipleSeasons(path, show, seasons_num, language, linux, trust, c); + multipleSeasons(path, show, seasons_num, language, pattern, linux, trust, c); } else { - allSeasons(path, show, language, linux, trust, c); + allSeasons(path, show, language, pattern, linux, trust, c); } } diff --git a/tv_rename.cpp b/tv_rename.cpp index ecc011e..ed64f41 100644 --- a/tv_rename.cpp +++ b/tv_rename.cpp @@ -31,7 +31,7 @@ std::vector parseEpisodeNames( const std::string &season_code, cons return episodes; } -void singleSeason( const std::string &path, const std::string &show, int season, std::string url, const std::string &language, const bool &linux, const bool &trust, Curl &c, std::set const *files) { +void singleSeason( const std::string &path, const std::string &show, int season, std::string url, const std::string &language, const std::string &pattern, const bool &linux, const bool &trust, Curl &c, std::set const *files) { if( url.empty() ) url = getDefUrl(show, language, c); url += "/seasons/" + std::to_string(season); @@ -93,7 +93,9 @@ void singleSeason( const std::string &path, const std::string &show, int season, num -= 1; if( num < episodes.size() ) { auto pos = name.find_last_of('.'); - name.insert(pos, " - " + episodes[num]); + // get desired filename + name = compilePattern(pattern, season, num+1, name.substr(0, pos), episodes[num], show) + name.substr(pos); + // replace characters illegal in windows if desired if( !linux ) { season_code.erase(std::remove_if(name.begin(), name.end(), [](char x) {return x == '?' || x == '"' || x == '\\' || x == '|' || x == '*';}), season_code.end()); size_t max{name.size()}; @@ -140,23 +142,23 @@ void singleSeason( const std::string &path, const std::string &show, int season, } } -void multipleSeasons( const std::string &path, const std::string &show, const std::map> &seasons, const std::string &language, const bool &linux, const bool &trust, Curl &c) { +void multipleSeasons( const std::string &path, const std::string &show, const std::map> &seasons, const std::string &language, const std::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, linux, trust, c, &x.second); + singleSeason( path, show, x.first, url, language, pattern, linux, trust, c, &x.second); } } -void multipleSeasons( const std::string &path, const std::string &show, const std::set seasons, const std::string &language, const bool &linux, const bool &trust, Curl &c) { +void multipleSeasons( const std::string &path, const std::string &show, const std::set seasons, const std::string &language, const std::string &pattern, const bool &linux, const bool &trust, Curl &c) { std::map> season_map; findSeasons(season_map, path, seasons); - multipleSeasons(path, show, season_map, language, linux, trust, c); + multipleSeasons(path, show, season_map, language, pattern, linux, trust, c); } -void allSeasons( const std::string &path, const std::string &show, const std::string &language, const bool &linux, const bool &trust, Curl &c) { +void allSeasons( const std::string &path, const std::string &show, const std::string &language, const std::string &pattern, const bool &linux, const bool &trust, Curl &c) { std::map> seasons; //get all season number from this directory and subdirectories iterateFS(seasons, path); - multipleSeasons( path, show, seasons, language, linux, trust, c); + multipleSeasons( path, show, seasons, language, pattern, linux, trust, c); } diff --git a/tv_rename.hpp b/tv_rename.hpp index 06bc62c..4f941d0 100644 --- a/tv_rename.hpp +++ b/tv_rename.hpp @@ -4,8 +4,8 @@ #include #include "network.hpp" -void singleSeason( const std::string &path, const std::string &show, int season, std::string url, const std::string &language, const bool &linux, const bool &trust, Curl &c, std::set const *files=nullptr); -void multipleSeasons( const std::string &path, const std::string &show, const std::set seasons, const std::string &language, const bool &linux, const bool &trust, Curl &c); -void allSeasons( const std::string &path, const std::string &show, const std::string &language, const bool &linux, const bool &trust, Curl &c); +void singleSeason( const std::string &path, const std::string &show, int season, std::string url, const std::string &language, const std::string &pattern, const bool &linux, const bool &trust, Curl &c, std::set const *files=nullptr); +void multipleSeasons( const std::string &path, const std::string &show, const std::set seasons, const std::string &language, const std::string &pattern, const bool &linux, const bool &trust, Curl &c); +void allSeasons( const std::string &path, const std::string &show, const std::string &language, const std::string &pattern, const bool &linux, const bool &trust, Curl &c); #endif