diff --git a/LICENSE b/LICENSE deleted file mode 100644 index fdddb29..0000000 --- a/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to diff --git a/Makefile b/Makefile deleted file mode 100644 index 61f3d36..0000000 --- a/Makefile +++ /dev/null @@ -1,85 +0,0 @@ -CC ?= clang -CXX ?= clang++ -CFLAGS ?= -O2 -Wall -Wextra -std=c++11 -PREFIX ?= /usr/local/bin -APPDIR ?= /usr/share/applications -ICONDIR ?= /usr/share/icons/hicolor - -.PHONY: default -default: tv_rename - -.PHONY: clean -clean: - rm -f *.o tv_rename tv_rename_gui - -.PHONY: install -install: tv_rename - install -d $(PREFIX)/ - install -m 755 tv_rename $(PREFIX)/ - -.PHONY: install_gui -install_gui: gui - install -d $(PREFIX)/ - install -m 755 tv_rename_gui $(PREFIX)/ - install -d $(APPDIR) - install -m 755 tv_rename_gui.desktop $(APPDIR)/ - install -d $(ICONDIR) - install -m 644 tv_rename.svg $(ICONDIR)/scalable/apps/ - gtk-update-icon-cache -f $(ICONDIR) - -.PHONY: uninstall -uninstall: - rm $(PREFIX)/tv_rename - -.PHONY: uninstall_gui -uninstall_gui: - rm $(PREFIX)/tv_rename_gui - rm $(APPDIR)/tv_rename_gui.desktop - rm $(ICONDIR)/scalable/apps/tv_rename.svg - gtk-update-icon-cache -f $(ICONDIR) - -tv_rename: functions.o filesystem_u.o network.o tv_rename.o main.cpp - $(CXX) $(CFLAGS) -o tv_rename main.cpp tv_rename.o functions.o filesystem_u.o network.o -lcurl - -filesystem_u.o: unix/filesystem.cpp - $(CXX) $(CFLAGS) -c unix/filesystem.cpp -o filesystem_u.o - -functions.o: functions.cpp - $(CXX) $(CFLAGS) -c functions.cpp - -network.o: network.cpp - $(CXX) $(CFLAGS) -c network.cpp - -tv_rename.o: tv_rename.cpp - $(CXX) $(CFLAGS) -c tv_rename.cpp - -.PHONY: gui -gui: tv_rename_gui - -tv_rename_gui: gui.cpp mainwindow.cpp seasonwindow.cpp network.o functions_gui.o filesystem_u_gui.o tv_rename_gui.o - $(CXX) $(CFLAGS) -o tv_rename_gui gui.cpp mainwindow.cpp seasonwindow.cpp network.o functions_gui.o filesystem_u_gui.o tv_rename_gui.o `pkg-config gtkmm-3.0 --cflags --libs` -lcurl -DGUI - -filesystem_u_gui.o: unix/filesystem.cpp - $(CXX) $(CFLAGS) -c unix/filesystem.cpp -o filesystem_u_gui.o -DGUI - -functions_gui.o: functions.cpp - $(CXX) $(CFLAGS) -c functions.cpp -o functions_gui.o -DGUI - -tv_rename_gui.o: tv_rename.cpp - $(CXX) $(CFLAGS) -c tv_rename.cpp -o tv_rename_gui.o -DGUI - - -.PHONY: windows -windows: tv_rename.exe - -tv_rename.exe: tv_rename.cpp functions.cpp windows/filesystem.cpp network.cpp main.cpp - $(CXX) -MD -EHsc -Fe"tv_rename" tv_rename.cpp windows/filesystem.cpp functions.cpp network.cpp main.cpp -D_WIN32 -DUNICODE -link wininet.lib shlwapi.lib - -.PHONY: windows_gui -windows_gui: tv_rename_gui.exe - -tv_rename_gui.exe: tv_rename_gui.res tv_rename_gui.cpp tv_rename.cpp windows/filesystem.cpp functions.cpp network.cpp - $(CXX) -MD -EHsc -Fe"tv_rename_gui" tv_rename_gui.cpp tv_rename.cpp windows/filesystem.cpp functions.cpp network.cpp -D_WIN32 -DUNICODE -DGUI -link wininet.lib shlwapi.lib ole32.lib shell32.lib gdi32.lib user32.lib tv_rename_gui.res - -tv_rename_gui.res: tv_rename_gui.rc - rc tv_rename_gui.rc diff --git a/README.md b/README.md deleted file mode 100644 index b4412e7..0000000 --- a/README.md +++ /dev/null @@ -1,66 +0,0 @@ -# Rename TV Show files -This program downloads episode names from http://thetvdb.com and adds them as a suffix to the appropriate files - -For this to work your file needs to contain the season and episode number (in accordance to thetvdb) in this format: S#E# (doesn't matter if lower or upper case) - -The program only supports the aired order so far - -## Usage -Enter the directory in which the files you want to rename are (you can have subdirectories with different seasons, just not different shows) and call the program - -Arguments: - -`-s, --show` - Name of the show - -`-n, --season` - Seasons to be renamed (numbers separated by space or 'all' for all seasons in the directory and sub directories) - -`-p, --show-path` - Path to the show's directory - -`-c, --correct-path` - Don't ask if path is correct - -`-t, --trust` - Don't prompt before changing file names - -`-x, --linux` - Don't replace characters that are illegal in NTFS - -`-l, --lang` - Language of the episode titles - -`--print_langs` - Print available languages - -`--name-pattern` - Pattern by which the files should be renamed - -- %filename - original filename -- %show - show name from thetvdb -- %epname - episode name from thetvdb -- %season - season number, possible to specify leading 0 like this: %2season (number means how many leading zeros) -- %episode - episode number, possible to specify leading 0 like this: %3season (number means how many leading zeros) - -## Installation - -For installation of command line version you'll need: - -- *libcurl-dev* (or your distro's equivalent) -- some sort of C++ compiler (*clang++* for example) -- *make* - -When you have all prerequisites installed you need to do this sequence of commands: - - git clone 'https://gitlab.com/zvon/tv_rename_cpp' - cd tv_rename_cpp - make - sudo make install - -For installation of GUI version you'll need: - -- *libcurl-dev* (or your distro's equivalent) -- some sort of C++ compiler (*clang++* for example) -- *make* -- *libgtkmm* (or your distro's equivalent) - -When you have all prerequisites installed you need to do this sequence of commands: - - git clone 'https://gitlab.com/zvon/tv_rename_cpp' - cd tv_rename_cpp - make gui - sudo make install_gui - -You can uninstall both versions by running either `sudo make uninstall` or `sudo make uninstall_gui` diff --git a/filesystem.hpp b/filesystem.hpp deleted file mode 100644 index 4a2cfa6..0000000 --- a/filesystem.hpp +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef FSLIB_H -#define FSLIB_H - -#include -#include - -#ifdef _WIN32 - -#include - -#else - -#include - -#endif - -// set apropriate data types for each operating system -#ifdef _WIN32 - -using string = std::wstring; -using char_t = wchar_t; - -#else - -using string = std::string; -using char_t = char; - -#endif - -// windows version stolen from -// http://www.martinbroadhurst.com/list-the-files-in-a-directory-in-c.html - -namespace FSLib { - -#ifndef GUI -bool exists( const string &path ); -string canonical( const string &path ); -#endif - -bool isDirectory( const string &path ); -bool rename( const string &file_a, const string &file_b ); - -class Directory { -public: - Directory( const string &path_ ); - Directory() = delete; - Directory( const Directory &d ) = default; - Directory( Directory &&d ) = default; - - class Iterator { - public: - Iterator( const Directory &d_ ); - ~Iterator(); - -#ifdef _WIN32 - Iterator( bool ended_ ); -#else - Iterator( const Directory &d_, const struct dirent *current_entry_ ); -#endif - - Iterator() = delete; - - Iterator( const Iterator &i ) = default; - - Iterator( Iterator &&i ) = default; - - char_t const *operator*() const; - - Iterator &operator++(); - - bool operator==( const Iterator &i_other ) const; - - Iterator operator++( int ) { - Iterator ret( *this ); - operator++(); - return ret; - } - - bool operator!=( const Iterator &i_other ) const { - return !( i_other == *this ); - } - - private: -#ifndef _WIN32 - DIR *d; - const struct dirent *current_entry; -#else - HANDLE hFind; - WIN32_FIND_DATA data; - bool ended{ false }; -#endif - }; - - using iterator = Iterator; - using const_iterator = Iterator; - - iterator end(); - - const_iterator end() const; - - iterator begin() { - return Iterator( *this ); - } - - const_iterator begin() const { - return Iterator( *this ); - } - - const_iterator cbegin() const { - return begin(); - } - - const_iterator cend() const { - return end(); - } - - const char_t *path() const { - return dir_path.c_str(); - } - - -private: - string dir_path; -}; -} // namespace FSLib - -#endif diff --git a/functions.cpp b/functions.cpp deleted file mode 100644 index 47defb4..0000000 --- a/functions.cpp +++ /dev/null @@ -1,560 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 - -#include -#include -#include - -#else // UNIX - -#ifndef GUI - -#include -#include -#include - -#else // UNIX and GUI - -#include -#include - -#endif // GUI - -#endif // UNIX - -#include "filesystem.hpp" -#include "functions.hpp" - -#ifdef _WIN32 - -#define cout std::wcout -#define cerr std::wcerr -#define cin std::wcin - -constexpr const char_t *dir_divider = L"\\"; - -#else // UNIX - -#define TEXT( a ) a - -#define cout std::cout -#define cerr std::cerr -#define cin std::cin - -constexpr const char_t *dir_divider = "/"; - -#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 - -// functions to convert between string and wstring - -std::string wstring_to_utf8( const std::wstring &wstring ) { - std::wstring_convert< std::codecvt_utf8_utf16< wchar_t > > wconv; - return wconv.to_bytes( wstring ); -} - -std::wstring utf8_to_wstring( const std::string &utf8 ) { - std::wstring_convert< std::codecvt_utf8_utf16< wchar_t > > wconv; - return wconv.from_bytes( utf8 ); -} - -#endif // _WIN32 - -// encode url so it's valid even with UTF-8 characters -string encodeUrl( const string &url ) { - // stolen from here - - // https://stackoverflow.com/questions/154536/encode-decode-urls-in-c -#ifdef _WIN32 - std::wstringstream encoded; - auto url_c = wstring_to_utf8( url ); -#else - std::stringstream encoded; - const auto &url_c = url; -#endif - encoded.fill( '0' ); - encoded << std::hex; - for ( const auto &x : url_c ) { - if ( isalnum( static_cast< unsigned char >( x ) ) || x == '-' || - x == '_' || x == '.' || x == '~' ) { - encoded << x; - continue; - } - encoded << std::uppercase << '%' << std::setw( 2 ); - encoded << int( static_cast< unsigned char >( x ) ) << std::nouppercase; - } - return encoded.str(); -} - -// return true if filename has specified season -// set ep_pos to position where episode number starts -bool searchSpecificSeason( const char_t *const path, size_t &ep_pos, - const string &number ) { - size_t cur_pos{}; -#ifdef _WIN32 - auto ncompare = wcsncmp; -#else - auto ncompare = strncmp; -#endif - // search for S[0-9]+E[0-9]+ - while ( path[cur_pos] != '\0' ) { - if ( ( path[cur_pos] == 's' || path[cur_pos] == 'S' ) && - iswdigit( path[cur_pos + 1] ) ) { - cur_pos++; - while ( path[cur_pos] == '0' ) - cur_pos++; - // if season number is 0, move back because previous while skipped it - if( number == TEXT("0") ) - cur_pos--; - // make sure season's number is the same as provided in argument - // `number` - if ( !ncompare( path + cur_pos, number.c_str(), number.size() ) ) { - cur_pos += number.size(); - if ( ( path[cur_pos] == 'e' || path[cur_pos] == 'E' ) && - iswdigit( path[cur_pos + 1] ) ) { - ep_pos = cur_pos + 1; - return true; - } - } - } - cur_pos++; - } - return false; -} - -bool searchSpecificSeason( const char_t *const p, const string &number ) { - size_t tmp; - return searchSpecificSeason( p, tmp, number ); -} - -// return true if file contains S[0-9]+E[0-9]+ nad set -// season_pos to start of season number -bool searchSeason( const char_t *const path, size_t &season_pos ) { - size_t cur_pos{}; - while ( path[cur_pos] != '\0' ) { - if ( ( path[cur_pos] == 's' || path[cur_pos] == 'S' ) && - iswdigit( path[cur_pos + 1] ) ) { - cur_pos++; - season_pos = cur_pos; // after ++ because we want the first pos to - // point to season's number - while ( iswdigit( path[cur_pos] ) ) - cur_pos++; - if ( ( path[cur_pos] == 'e' || path[cur_pos] == 'E' ) && - iswdigit( path[cur_pos + 1] ) ) { - return true; - } - } - cur_pos++; - } - return false; -} - -bool searchSeason( const char_t *const path ) { - size_t tmp{}; - return searchSeason( path, tmp ); -} - -void iterateFS( std::map< int, std::set< string > > &seasons, - const string &path ) { - // season_pos - position of first digit of the season - size_t season_pos{ string::npos }; - for ( const auto p : FSLib::Directory( path ) ) { - // if p is directory, iterate through it - if ( FSLib::isDirectory( path + dir_divider + p ) ) { - iterateFS( seasons, path + dir_divider + p ); - continue; - } - - // if file is a correct format, add it to file list - // for its season - if ( searchSeason( p, season_pos ) ) - seasons[std::stoi( p + season_pos )].insert( - path + dir_divider + p ); - } -} - -#ifndef GUI -// following functions are only needed for CLI version - -// find all files for provided season in `path` and store it in `files` -void findSeason( std::set< string > &files, int season, const string &path ) { -#ifdef _WIN32 - auto number = std::to_wstring( season ); -#else - auto number = std::to_string( season ); -#endif - - for ( const auto p : FSLib::Directory( path ) ) { - // if p is directory, iterate through it - if ( FSLib::isDirectory( path + dir_divider + p ) ) { - findSeason( files, season, path + dir_divider + p ); - continue; - } - - if ( searchSpecificSeason( p, number ) ) - files.insert( path + dir_divider + p ); - } -} - -// find all files that comply with the S[0-9]+E[0-9]+ pattern -// and their season is in season_numbers and store tem in `seasons` -void findSeasons( std::map< int, std::set< string > > &seasons, - const string &path, const std::set< int > &season_numbers ) { - // season_pos - position of first digit of the season - size_t season_pos{ string::npos }; - for ( const auto p : FSLib::Directory( path ) ) { - // if p is directory, iterate through it - if ( FSLib::isDirectory( path + dir_divider + p ) ) { - findSeasons( seasons, path + dir_divider + p, season_numbers ); - continue; - } - - if ( searchSeason( p, season_pos ) ) { - auto num = std::stoi( p + season_pos ); - if ( season_numbers.find( num ) != season_numbers.end() ) - seasons[num].insert( path + dir_divider + p ); - } - } -} - -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; -} - -void printHelp() { - cout << "usage: tv_rename [--help] [--show show name] [--season season " - "number]" - << std::endl; - cout - << " [--correct-path] [--show-path show path] [--trust]" - << std::endl; - cout << " [--linux] [--lang language] [--print-langs]" - << std::endl; - cout << std::endl - << "Rename TV episodes" << std::endl - << std::endl - << "optional arguments:" << std::endl; - cout << " -h, --help\t\tshow this help message and exit" << std::endl; - cout << " --show show name, -s show name" << std::endl; - cout << "\t\t\tTV show from which you want episode names (needs to be" - << std::endl; - cout << "\t\t\tin quotation marks if it has more than one word)" - << std::endl; - cout << " --season season number, -n season number" << std::endl; - cout << "\t\t\tSeason number/s (if multiple seasons, put them in" - << std::endl; - cout << "\t\t\tquotation marks and seperate by one space)" << std::endl; - cout << "\t\t\tor 'all' for all seasons in selected subdirectory" - << std::endl; - cout << " --show-path show path, -p show path" << std::endl; - cout << "\t\t\tPath of the directory with episodes" << std::endl; - cout << " --correct-path, -c\tThis is the correct path, stop asking me!" - << std::endl; - cout << " --name-pattern pattern" << std::endl; - cout << "\t\t\tPattern to which change the file name. Possible sequences " - "are:" - << std::endl; - cout << "\t\t\t\t%filename - original filename (without filetype extension)" - << std::endl; - cout << "\t\t\t\t%show - show name from thetvdb" << std::endl; - cout << "\t\t\t\t%epname - episode name from thetvdb" << std::endl; - cout << "\t\t\t\t%season - season number" << std::endl; - cout << "\t\t\t\ttpossible to specify leading 0 like this: %2season " - "(number means how many leading zeros)" - << std::endl; - cout << "\t\t\t\t%episode - episode number" << std::endl; - cout << "\t\t\t\t\tpossible to specify leading 0 like this: %2episode " - "(number means how many leading zeros)" - << std::endl; - cout << "\t\t\tDefault pattern is \"$filename - $epname\"" << std::endl; - cout << " --trust, -t\t\tDon't ask whether the names are correct" - << std::endl; - cout << " --linux, -x\t\tDon't replace characters characters that are " - "illegal in Windows" - << std::endl; - cout << " --lang language, -l language" << std::endl; - cout << "\t\t\tSelect which language the episode names shoud be in" - << std::endl; - cout << " --print-langs\t\tPring available language" << std::endl; -} - -// parse command line argument --seasons (e.g. '1 2 3 4 5') -// and store season numbers as integers in seasons_num -void parseSeasonNumbers( std::set< int > &seasons_num, - const char_t *argument ) { - size_t pos{ 0 }; - - while ( !iswdigit( argument[pos] ) && argument[pos] != '\0' ) - pos++; - - if ( argument[pos] == '\0' ) { - seasons_num.clear(); - return; - } - - int temp; - -#ifdef _WIN32 - std::wstringstream iss( argument + pos ); -#else - std::stringstream iss( argument + pos ); -#endif - - while ( iss >> temp ) { - seasons_num.insert( temp ); - } -} - -// 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; -} - -#ifndef _WIN32 - -// get user's home directory -string userHome() { - uid_t user_uid; // current user's uid - { - uid_t eid; - uid_t sid; - getresuid( &user_uid, &eid, &sid ); // don't need eid and sid - } - // password file entry - auto user_passwd = getpwuid( user_uid ); - - if ( user_passwd == nullptr ) - throw std::runtime_error( - "User with uid " + std::to_string( user_uid ) + " doesn't exist!" ); - return user_passwd->pw_dir; -} - -#else // UNIX - -// get user's %APPDATA% folder location -string userHome() { - wchar_t *dir = static_cast< wchar_t * >( CoTaskMemAlloc( MAX_PATH ) ); - auto res = SHGetKnownFolderPath( FOLDERID_RoamingAppData, 0, NULL, &dir ); - if ( res == S_OK ) { - string dir_s = dir; - CoTaskMemFree( dir ); - return dir_s; - } - return L""; -} - -#endif // UNIX - -#endif // ndef GUI - -// create file name based on given pattern -string compilePattern( const string &pattern, int season, int episode, - const string &filename, const string &episodeName, - const string &showName ) { - string output; - -#ifdef _WIN32 - auto season_num = std::to_wstring( season ); - auto ep_num = std::to_wstring( episode ); -#else - auto season_num = std::to_string( season ); - auto ep_num = std::to_string( episode ); -#endif - - for ( size_t i = 0; i < pattern.size(); i++ ) { - // if current character is % check if a pattern follows, otherwise - // put % - if ( pattern[i] == '%' ) { - // check for numbers right after % indicating size of zero - // padding for numbers - auto pos = pattern.find_first_not_of( TEXT( "0123456789" ), i + 1 ); - - if ( pattern.find( TEXT( "season" ), pos - 1 ) == pos && - pos != i + 1 ) { - // if season is AFTER numbers, put season number padded - // with zeros - - // get number of leading zeros - auto leading = std::stoi( pattern.c_str() + i + 1 ); - // move i to the last char of 'season' - i = pos + 5; - - // 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 += string( leading, '0' ) + season_num; - } else if ( pattern.find( TEXT( "season" ), i ) == i + 1 ) { - // if season isn't after numbers, just put season number to - // output - i += 6; - output += season_num; - } else if ( pattern.find( TEXT( "episode" ), pos - 1 ) == pos && - pos != i + 1 ) { - // same principle as with season after number - auto leading = std::stoi( pattern.c_str() + i + 1 ); - - i = pos + 6; - - leading -= ep_num.size(); - if ( leading < 0 ) - leading = 0; - - output += string( leading, '0' ) + ep_num; - } else if ( pattern.find( TEXT( "episode" ), i ) == i + 1 ) { - // if episode isn't after number, just put the episode number to - // output - i += 7; - output += ep_num; - } else if ( pattern.find( TEXT( "epname" ), i ) == i + 1 ) { - // episode name from thetvdb - i += 6; - output += episodeName; - } else if ( pattern.find( TEXT( "show" ), i ) == i + 1 ) { - // show name from thetvdb - i += 4; - output += showName; - } else if ( pattern.find( TEXT( "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 deleted file mode 100644 index 9a1d2a6..0000000 --- a/functions.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef TV_FUNCTIONS_H -#define TV_FUNCTIONS_H - -#include -#include -#include -#include - -#ifdef GUI - -#include - -#endif - -#include "network.hpp" - -#ifdef _WIN32 - -using string = std::wstring; -using char_t = wchar_t; - -std::wstring utf8_to_wstring( const std::string &utf8 ); - -#else - -using string = std::string; -using char_t = char; - -#endif - -#ifndef GUI -// CLI functions - -string getDefUrl( string &show, const string &language, Curl &c ); -void findSeason( std::set< string > &files, int season, const string &path ); -void findSeasons( std::map< int, std::set< string > > &seasons, - const string &path, const std::set< int > &season_numbers ); -void printHelp(); - -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 ); - -void parseSeasonNumbers( std::set< int > &seasons_num, const char_t *argument ); -void printLangs(); -bool findLanguage( const char_t *language ); - -string encodeUrl( const string &url ); - -#else -// GUI functions - -std::vector< std::pair< string, string > > -getPossibleShows( string show, const string &language, Curl &c ); -string userHome(); - -#endif // GUI - -void iterateFS( std::map< int, std::set< string > > &seasons, - const string &path ); - -bool searchSpecificSeason( const char_t *const path, size_t &ep_pos, - const string &number ); - -string compilePattern( const string &pattern, int season, int episode, - const string &filename, const string &episodeName, - const string &showName ); - -#endif diff --git a/gui.cpp b/gui.cpp deleted file mode 100644 index 2a78acc..0000000 --- a/gui.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include - -#include "mainwindow.hpp" - -int main( int argc, char **argv ) { - auto app = Gtk::Application::create( - argc, argv, "org.idonthaveanorganization.tvrename" ); - - MainWindow mw( app ); - - return app->run( mw ); -} diff --git a/main.cpp b/main.cpp deleted file mode 100644 index 899cde8..0000000 --- a/main.cpp +++ /dev/null @@ -1,262 +0,0 @@ -#include -#include - -#ifdef _WIN32 - -#include -#include -#include - -#else - -#include - -#endif - -#include "filesystem.hpp" -#include "functions.hpp" -#include "tv_rename.hpp" - -#ifdef _WIN32 - -using char_t = wchar_t; -using string = std::wstring; - -#define cerr std::wcerr -#define cout std::wcout -#define cin std::wcin - -#else - -using char_t = char; -using string = std::string; - -#define cerr std::cerr -#define cout std::cout -#define cin std::cin - -#define TEXT( a ) a - -#endif - -int handleArgument( char_t c, string &show, std::set< int > &seasons_num, - bool &change_dir, string &path, bool &trust, bool &linux, - string &language, string &pattern, char_t *optional, - int &i ) { - switch ( c ) { - case 's': - show = optional; - i++; - break; - case 'n': - parseSeasonNumbers( seasons_num, optional ); - i++; - break; - case 'c': - change_dir = false; - break; - case 'p': - path = string( optional ); - i++; - // if path provided, assume it's correct - change_dir = false; - break; - case 't': - trust = true; - break; - case 'x': - linux = true; - break; - case 'l': - if ( findLanguage( optional ) ) { - language = optional; - } else { - cerr << "Invalid language choice" << std::endl; - printLangs(); - return -1; - } - i++; - break; - case '0': - printLangs(); - return 1; - case 'h': - printHelp(); - return 1; - case '1': - pattern = optional; - i++; - break; - default: - return -1; - } - return 0; -} - -#ifdef _WIN32 - -string getOptions( const char_t *option ) { - if ( option[1] != '-' ) - return option + 1; - if ( !wcscmp( option, L"--show" ) ) - return L"s"; - else if ( !wcscmp( option, L"--season" ) ) - return L"n"; - else if ( !wcscmp( option, L"--correct-path" ) ) - return L"c"; - else if ( !wcscmp( option, L"--show-path" ) ) - return L"p"; - else if ( !wcscmp( option, L"--trust" ) ) - return L"t"; - else if ( !wcscmp( option, L"--linux" ) ) - return L"x"; - else if ( !wcscmp( option, L"--lang" ) ) - return L"l"; - else if ( !wcscmp( option, L"--print-langs" ) ) - return L"0"; - else if ( !wcscmp( option, L"--name-pattern" ) ) - return L"1"; - else if ( !wcscmp( option, L"--help" ) ) - return L"h"; - return L""; -} - -// there's no getopt for windows, so just use wcscmp -int parseCommandLine( string &show, std::set< int > &seasons_num, string &path, - bool &change_dir, string &language, string &pattern, - bool &linux, bool &trust, const int argc, - char_t **argv ) { - for ( auto i = 1; i < argc; i++ ) { - auto options = getOptions( argv[i] ); - char_t *optional = ( i < argc - 1 ) ? argv[i + 1] : nullptr; - for ( const auto &x : options ) { - auto res = - handleArgument( x, show, seasons_num, change_dir, path, trust, - linux, language, pattern, optional, i ); - if ( res != 0 ) - return res; - } - } - return 0; -} - -#else - -// parse command line arguments using getopt -int parseCommandLine( string &show, std::set< int > &seasons_num, string &path, - bool &change_dir, string &language, 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' }, - { "correct-path", no_argument, 0, 'c' }, - { "show-path", required_argument, 0, 'p' }, - { "trust", no_argument, 0, 't' }, - { "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' } - }; - - int i{}; // this is useless, but needed for handleArgument - - while ( 1 ) { - int option_index{ 0 }; - auto c = getopt_long( argc, argv, "s:n:cp:txl:01:h", long_options, - &option_index ); - if ( c == -1 ) - break; - auto res = handleArgument( c, show, seasons_num, change_dir, path, - trust, linux, language, pattern, optarg, i ); - if ( res != 0 ) - return res; - } - - return 0; -} - -#endif - -// windows needs wmain for unicode support -#ifdef _WIN32 -int wmain -#else -int main -#endif - ( int argc, char_t **argv ) { -#ifdef _WIN32 - // set console to unicode - _setmode( _fileno( stdout ), _O_U16TEXT ); -#endif - string show{}; - std::set< int > seasons_num{}; - bool change_dir{ true }; - bool linux{ false }; - bool trust{ false }; - string path{ TEXT( "." ) }; - string language{ TEXT( "en" ) }; - string pattern{ TEXT( "%filename - %epname" ) }; - Curl c; - - { - auto tmp = - parseCommandLine( show, seasons_num, path, change_dir, language, - pattern, linux, trust, argc, argv ); - if ( tmp == -1 ) - return 1; - else if ( tmp == 1 ) - return 0; - } - - if ( !FSLib::isDirectory( path ) ) - change_dir = true; - - while ( change_dir ) { - if ( !FSLib::isDirectory( path ) ) { - cout << "This directory doesn't exist, please insert a correct " - "path: " - << std::endl; - std::getline( cin, path ); - continue; - } - cout << "Is this the right directory? " << FSLib::canonical( path ) - << std::endl; - string response; - cin >> response; - cin.ignore( 1, '\n' ); - cin.clear(); - if ( response[0] == 'y' || response[0] == 'Y' ) { - change_dir = false; - } else { - cout << "Insert correct path:" << std::endl; - std::getline( cin, path ); - } - } - - if ( show.empty() ) { - show = FSLib::canonical( path ); - auto pos = show.find_last_of( '/' ); - if ( pos != string::npos ) - show = show.substr( ++pos ); - cout << "Is this the right show name? " << show << std::endl; - string response; - cin >> response; - cin.ignore( 1, '\n' ); - cin.clear(); - if ( response[0] != 'y' && response[0] != 'Y' ) { - cout << "Insert the correct show name: " << std::endl; - std::getline( cin, show ); - } - } - - if ( seasons_num.size() == 1 ) { - singleSeason( path, show, *seasons_num.begin(), string(), language, - pattern, linux, trust, c ); - } else if ( seasons_num.size() != 0 ) { - multipleSeasons( path, show, seasons_num, language, pattern, linux, - trust, c ); - } else { - allSeasons( path, show, language, pattern, linux, trust, c ); - } -} diff --git a/mainwindow.cpp b/mainwindow.cpp deleted file mode 100644 index 5384c86..0000000 --- a/mainwindow.cpp +++ /dev/null @@ -1,380 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "filesystem.hpp" -#include "functions.hpp" -#include "mainwindow.hpp" -#include "tv_rename.hpp" - -constexpr std::array< const char *, 46 > languages{ - "en", "English", "sv", "Svenska", "no", "Norsk", "da", "Dansk", - "fi", "Suomeksi", "nl", "Nederlands", "de", "Deutsch", "it", "Italiano", - "es", "Español", "fr", "Français", "pl", "Polski", "hu", "Magyar", - "el", "Greek", "tr", "Turkish", "ru", "Russian", "he", "Hebrew", - "ja", "Japanese", "pt", "Portuguese", "zh", "Chinese", "cs", "Czech", - "sl", "Slovenian", "hr", "Croatian", "ko", "Korea" -}; - -void MainWindow::chooseFile() { - // create a dialog for choosing directory - Gtk::FileChooserDialog dialog( "Select a directory", - Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER ); - dialog.set_transient_for( *this ); - // add cancel and select buttons - dialog.add_button( "_Cancel", Gtk::RESPONSE_CANCEL ); - dialog.add_button( "Select", Gtk::RESPONSE_OK ); - - auto result = dialog.run(); - - switch ( result ) { - case Gtk::RESPONSE_OK: - m_entry_dir.set_text( dialog.get_filename() ); - std::cout << dialog.get_filename() << std::endl; - break; - case Gtk::RESPONSE_CANCEL: - std::cout << "Canceled" << std::endl; - break; - default: - std::cout << "Closed dialog" << std::endl; - break; - } -} - -void MainWindow::quit() { - std::cout << "Quitting" << std::endl; - hide(); -} - -void MainWindow::patternHelp() { - Gtk::MessageDialog dialog( *this, "Pattern escape sequences" ); - dialog.set_secondary_text( - "%filename - original filename (without type extension)\n" - "%show - show name from thetvdb\n" - "%epname - episode name from thetvdb\n" - "%season - season number\n" - "%episode - episode number\n" - "Both season number and episode number can be padded with zeros, just " - "add width of padding" - " right after %, like this: %2season.\n" - "Default pattern is \"%filename - %epname\", you might want to change " - "this to" - " \"S%2seasonE%2episode - %epname\" or \"%show - S%2seasonE%2episode - " - "%epname\"" ); - dialog.run(); -} - -void MainWindow::process() { - // check required field is filled out - if ( m_entry_show.get_text().empty() ) { - Gtk::MessageDialog dialog( *this, "Show field is empty" ); - dialog.run(); - return; - } - - // language code - language_code = - ( *m_combo_language.get_active() )[m_columns_language.m_col_code]; - - // fill up m_combo_possible with possible tv shows - auto possible_shows = getPossibleShows( - std::string( m_entry_show.get_text() ), language_code, c ); - - // if no possible shows were found, tell the user - if ( possible_shows.size() == 0 ) { - Gtk::MessageDialog dialog( *this, - "No results found for given show name" ); - dialog.run(); - return; - } - - // show widgets - m_label_possible.show(); - m_button_get_names.show(); - m_combo_possible.show(); - - // fill up combo box with results from thetvdb - auto model = Gtk::ListStore::create( m_columns_url ); - - m_combo_possible.set_model( model ); - - auto row = *( model->append() ); - - row[m_columns_url.m_col_show] = possible_shows[0].first; - row[m_columns_url.m_col_url] = possible_shows[0].second; - m_combo_possible.set_active( row ); - - for ( size_t i = 1; i < possible_shows.size(); i++ ) { - auto row = *( model->append() ); - row[m_columns_url.m_col_show] = possible_shows[i].first; - row[m_columns_url.m_col_url] = possible_shows[i].second; - } -} - -void MainWindow::getNames() { - // check required field is filled out - if ( m_entry_dir.get_text().empty() ) { - Gtk::MessageDialog dialog( *this, "Directory field is empty" ); - dialog.run(); - return; - } - // check directory exists - if ( !FSLib::isDirectory( m_entry_dir.get_text() ) ) { - Gtk::MessageDialog dialog( *this, "Directory doesn't exist" ); - dialog.run(); - return; - } - - path = m_entry_dir.get_text(); - - selected.clear(); - files.clear(); - - std::vector< int > options; - - // get all files in path and seperate them in map `files` by season - iterateFS( files, path ); - - for ( auto &x : files ) { - options.push_back( x.first ); - } - - // create a window with possible seasons to rename - // store selected seasons in `selected` - sw = new SeasonWindow( options, selected ); - sw->signal_hide().connect( - sigc::mem_fun( *this, &MainWindow::finishedSelection ) ); - - app->add_window( *sw ); - sw->show(); -} - -/* change names of original files to generated new names - * orig - original filenames - * renamed - renamed filenames (sorted in the same order as `orig`) - */ -void renameFiles( - const std::vector< - std::pair< std::string, std::pair< std::string, std::string > > > - &renamed ) { - for ( auto renamed_it = renamed.begin(); renamed_it != renamed.end(); - ++renamed_it ) { - std::cout << renamed_it->first << "/" << renamed_it->second.first - << " --> " << renamed_it->first << "/" - << renamed_it->second.second << std::endl; - FSLib::rename( renamed_it->first + "/" + renamed_it->second.first, - renamed_it->first + "/" + renamed_it->second.second ); - } -} - -void MainWindow::finishedSelection() { - // remove created SeasonWindow and delete it from memory - app->remove_window( *sw ); - delete sw; - - auto iter = m_combo_possible.get_active(); - - // debug output - std::cout << ( *iter )[m_columns_url.m_col_show] << " " << language_code - << std::endl; - - std::string url = - static_cast< Glib::ustring >( ( *iter )[m_columns_url.m_col_url] ); - - // shouldn't ever happen, but just to be sure - if ( url.empty() ) - return; - - std::cout << "https://www.thetvdb.com" << url << std::endl; - - std::string input_pattern = m_entry_pattern.get_text(); - - // store pattern to cache if it's different from default - if ( input_pattern != default_pattern ) { - std::ofstream file( userHome() + "/.cache/tv_rename_pattern" ); - if ( file ) { - file << input_pattern; - } - } - - for ( auto &x : selected ) { - // get renamed files for given season - auto renamed_files = getRenamedFiles( - static_cast< Glib::ustring >( ( *iter )[m_columns_url.m_col_show] ), - x, "https://www.thetvdb.com" + url, language_code, - ( input_pattern.empty() ? default_pattern : input_pattern ), - !m_check_linux.get_active(), c, files[x] ); - - if ( renamed_files.empty() ) - continue; - - // if trust checkbox is ticked, rename files - if ( m_check_trust.get_active() ) { - renameFiles( renamed_files ); - continue; - } - - // create a custom dialog box with textview of new episode names - Gtk::Dialog dialog( "Rename confirmation", *this ); - auto content = dialog.get_content_area(); - - Gtk::TextView tx; - content->pack_start( tx ); - tx.set_editable( false ); - dialog.add_button( "_No", Gtk::RESPONSE_CANCEL ); - dialog.add_button( "_Yes", Gtk::RESPONSE_OK ); - tx.show(); - - auto buff = tx.get_buffer(); - buff->place_cursor( buff->begin() ); - buff->insert_at_cursor( renamed_files[0].second.first.c_str() ); - buff->insert_at_cursor( " --> " ); - buff->insert_at_cursor( renamed_files[0].second.second.c_str() ); - - for ( size_t i = 1; i < renamed_files.size(); i++ ) { - buff->insert_at_cursor( "\n" ); - buff->insert_at_cursor( renamed_files[i].second.first.c_str() ); - buff->insert_at_cursor( " --> " ); - buff->insert_at_cursor( renamed_files[i].second.second.c_str() ); - } - - auto response = dialog.run(); - - // if user clicked "Yes" in dialog, rename files - switch ( response ) { - case Gtk::RESPONSE_OK: - renameFiles( renamed_files ); - default: - break; - } - } -} - -MainWindow::MainWindow( const Glib::RefPtr< Gtk::Application > &ptr ) - : app( ptr ) { - set_title( "TV Rename" ); - - set_default_size( 400, 310 ); - set_resizable( false ); - - { - // if cached pattern exists, load that instead of default - std::ifstream file( userHome() + "/.cache/tv_rename_pattern" ); - if ( file ) { - std::getline( file, default_pattern ); - } else { - default_pattern = "%filename - %epname"; - } - } - - add( m_layout ); - - // set widgets' location - m_layout.put( m_label_show, 5, 5 ); - m_layout.put( m_label_language, 190, 5 ); - m_layout.put( m_entry_show, 5, 25 ); - m_layout.put( m_combo_language, 190, 25 ); - m_layout.put( m_label_dir, 5, 60 ); - m_layout.put( m_entry_dir, 5, 80 ); - m_layout.put( m_button_dir, 190, 80 ); - m_layout.put( m_label_pattern, 5, 115 ); - m_layout.put( m_entry_pattern, 5, 135 ); - m_layout.put( m_button_pattern, 190, 135 ); - m_layout.put( m_check_linux, 95, 169 ); - m_layout.put( m_button_process, 5, 173 ); - m_layout.put( m_check_trust, 95, 187 ); - m_layout.put( m_label_possible, 5, 210 ); - m_layout.put( m_combo_possible, 5, 230 ); - m_layout.put( m_button_get_names, 5, 265 ); - m_layout.put( m_button_quit, 315, 275 ); - - // set button texts - m_button_process.set_label( "Process" ); - m_button_get_names.set_label( "Get names" ); - m_button_quit.set_label( "Quit" ); - m_button_dir.set_label( "Choose directory" ); - m_button_pattern.set_label( "Pattern help" ); - m_check_linux.set_label( "Replace windows-illegal characters" ); - m_check_trust.set_label( "Don't ask for rename confirmation" ); - - // set label texts - m_label_show.set_label( "Show:" ); - m_label_language.set_label( "Language:" ); - m_label_possible.set_label( "Possible shows:" ); - m_label_dir.set_label( "Directory:" ); - m_label_pattern.set_label( "Pattern:" ); - - // set dimensions - m_combo_language.set_size_request( 120 ); - m_combo_possible.set_size_request( 200 ); - - m_entry_show.set_size_request( 170, 30 ); - m_entry_dir.set_size_request( 170, 30 ); - - m_button_dir.set_size_request( 80, 30 ); - m_button_quit.set_size_request( 80, 30 ); - m_button_process.set_size_request( 80, 30 ); - m_button_get_names.set_size_request( 80, 30 ); - - // set default pattern - m_entry_pattern.set_text( default_pattern ); - - // put languages in combo box - { - auto model = Gtk::ListStore::create( m_columns_language ); - m_combo_language.set_model( model ); - - auto row = *( model->append() ); - row[m_columns_language.m_col_code] = "en"; - row[m_columns_language.m_col_language] = "English"; - - m_combo_language.set_active( row ); - - for ( size_t i = 2; i < languages.size(); i += 2 ) { - row = *( model->append() ); - row[m_columns_language.m_col_code] = languages[i]; - row[m_columns_language.m_col_language] = languages[i + 1]; - } - } - - // set column to be shown in comboboxes - m_combo_language.pack_start( m_columns_language.m_col_language ); - m_combo_possible.pack_start( m_columns_url.m_col_show ); - - // set signals - m_button_dir.signal_clicked().connect( - sigc::mem_fun( *this, &MainWindow::chooseFile ) ); - m_button_quit.signal_clicked().connect( - sigc::mem_fun( *this, &MainWindow::quit ) ); - m_button_process.signal_clicked().connect( - sigc::mem_fun( *this, &MainWindow::process ) ); - m_button_get_names.signal_clicked().connect( - sigc::mem_fun( *this, &MainWindow::getNames ) ); - m_entry_show.signal_activate().connect( - sigc::mem_fun( *this, &MainWindow::process ) ); - m_entry_dir.signal_activate().connect( - sigc::mem_fun( *this, &MainWindow::process ) ); - m_button_pattern.signal_clicked().connect( - sigc::mem_fun( *this, &MainWindow::patternHelp ) ); - - // show everything except possible shows and items related to them - m_layout.show(); - m_label_show.show(); - m_label_language.show(); - m_entry_show.show(); - m_entry_dir.show(); - m_combo_language.show(); - m_button_process.show(); - m_button_quit.show(); - m_button_dir.show(); - m_check_linux.show(); - m_check_linux.set_active( true ); - m_check_trust.show(); - m_button_pattern.show(); - m_entry_pattern.show(); - m_label_pattern.show(); - m_label_dir.show(); -} diff --git a/mainwindow.hpp b/mainwindow.hpp deleted file mode 100644 index 92e99c3..0000000 --- a/mainwindow.hpp +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef GTKMM_MAIN_WINDOW -#define GTKMM_MAIN_WINDOW - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "network.hpp" -#include "seasonwindow.hpp" - -class MainWindow : public Gtk::Window { -public: - MainWindow( const Glib::RefPtr< Gtk::Application > &ptr ); - virtual ~MainWindow() = default; - -private: - void quit(); - void process(); - void getNames(); - void finishedSelection(); - void chooseFile(); - void patternHelp(); - -protected: - Gtk::Button m_button_dir; - Gtk::Button m_button_get_names; - Gtk::Button m_button_quit; - Gtk::Button m_button_process; - Gtk::Button m_button_pattern; - - Gtk::CheckButton m_check_linux; - Gtk::CheckButton m_check_trust; - - Gtk::ComboBox m_combo_language; - Gtk::ComboBox m_combo_possible; - - Gtk::Entry m_entry_show; - Gtk::Entry m_entry_dir; - Gtk::Entry m_entry_pattern; - - Gtk::Label m_label_language; - Gtk::Label m_label_possible; - Gtk::Label m_label_show; - Gtk::Label m_label_dir; - Gtk::Label m_label_pattern; - - Gtk::Layout m_layout; - - Curl c; - - class LanguageColumns : public Gtk::TreeModel::ColumnRecord { - public: - LanguageColumns() { - add( m_col_code ); - add( m_col_language ); - } - - Gtk::TreeModelColumn< std::string > m_col_code; - Gtk::TreeModelColumn< std::string > m_col_language; - }; - - class UrlColumns : public Gtk::TreeModel::ColumnRecord { - public: - UrlColumns() { - add( m_col_url ); - add( m_col_show ); - } - Gtk::TreeModelColumn< Glib::ustring > m_col_url; - Gtk::TreeModelColumn< Glib::ustring > m_col_show; - }; - - LanguageColumns m_columns_language; - UrlColumns m_columns_url; - - Glib::RefPtr< Gtk::Application > app; - - SeasonWindow *sw; - std::vector< int > selected; - std::map< int, std::set< std::string > > files; - std::string path; - std::string language_code; - std::string default_pattern; -}; - -#endif // GTKMM_MAIN_WINDOW diff --git a/network.cpp b/network.cpp deleted file mode 100644 index 74ee373..0000000 --- a/network.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include -#include "network.hpp" - -#ifdef _WIN32 - -// shamelessly stolen from http://www.cplusplus.com/forum/windows/109799/ - -Curl::Curl() { - connect = InternetOpen( L"WinInet/1.0", INTERNET_OPEN_TYPE_PRECONFIG, - nullptr, nullptr, 0 ); - if ( !connect ) - std::wcerr << "Something went wrong while connecting" << std::endl; -} - -Curl::~Curl() { - if ( connect ) - InternetCloseHandle( connect ); -} - -std::string Curl::execute( const std::wstring &url ) { - std::string source{}; - source.reserve( 10000 ); - - HINTERNET openAddress = InternetOpenUrl( - connect, url.c_str(), nullptr, 0, - INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_KEEP_CONNECTION, 0 ); - - if ( !openAddress ) { - unsigned long errorNum = GetLastError(); - std::wcout << "Failed to open URL" << std::endl - << "Error No: " << errorNum << std::endl; - return ""; - } - - char dataReceived[4096]; - unsigned long numberOfBytesRead = 0; - while ( InternetReadFile( openAddress, dataReceived, 4096, - &numberOfBytesRead ) && - numberOfBytesRead ) { - source.append( dataReceived, numberOfBytesRead ); - } - - InternetCloseHandle( openAddress ); - return source; -} - -#else - -size_t writeCallback( void *contents, size_t size, size_t nmemb, - void *target ) { - *static_cast< std::string * >( target ) += - std::string( static_cast< char * >( contents ), size * nmemb ); - return size * nmemb; -} - -Curl::Curl() { - curl_global_init( CURL_GLOBAL_ALL ); - curl_handle = curl_easy_init(); - curl_easy_setopt( curl_handle, CURLOPT_WRITEFUNCTION, writeCallback ); - curl_easy_setopt( curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0" ); -} - -Curl::~Curl() { - curl_easy_cleanup( curl_handle ); - curl_global_cleanup(); -} - -std::string Curl::execute( const std::string &url ) { - std::string source; - source.reserve( 100000 ); - curl_easy_setopt( curl_handle, CURLOPT_WRITEDATA, - static_cast< void * >( &source ) ); - curl_easy_setopt( curl_handle, CURLOPT_URL, url.c_str() ); - 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; -} - -#endif diff --git a/network.hpp b/network.hpp deleted file mode 100644 index 41ec21b..0000000 --- a/network.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef NETWORK_HPP -#define NETWORK_HPP - -#ifdef _WIN32 - -#include -#include - -using string = std::wstring; - -#else - -#include -#include - -using string = std::string; - -#endif - -class Curl { -public: - Curl(); - ~Curl(); - std::string execute( const string &url ); - -private: -#ifdef _WIN32 - HINTERNET connect = nullptr; -#else - CURL *curl_handle; -#endif -}; - -#endif diff --git a/resource.h b/resource.h deleted file mode 100644 index 4a441c6..0000000 --- a/resource.h +++ /dev/null @@ -1,50 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by tv_rename_gui.rc -// -#define IDC_MYICON 2 -#define IDD_TV_RENAME_GUI_DIALOG 102 -#define IDS_APP_TITLE 103 -#define IDI_TV_RENAME_GUI 107 -#define IDI_SMALL 108 -#define IDC_TV_RENAME_GUI 109 -#define IDR_MAINFRAME 128 -#define IDD_MAIN 129 -#define IDD_SEASONS 130 -#define IDD_HELP 131 -#define IDD_DIALOG1 132 -#define IDD_PREVIEW 132 -#define IDC_COMBO1 1000 -#define IDLANG 1000 -#define IDOK_MAIN 1001 -#define ID 1002 -#define IDEND 1002 -#define IDALL 1003 -#define IDC_BUTTON2 1004 -#define IDNONE 1004 -#define IDDIRB 1004 -#define IDSHOWIN 1006 -#define ID_STATIC 1007 -#define IDLANGUAGE 1009 -#define IDDIR 1010 -#define IDPATTERN 1011 -#define IDPROCESS 1013 -#define IDTRUST 1015 -#define IDSHOWS 1016 -#define IDSEASONS 1017 -#define IDC_STATIC6 1019 -#define ID_STATIC6 1019 -#define IDTEXT 1020 -#define IDC_STATIC -1 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NO_MFC 1 -#define _APS_NEXT_RESOURCE_VALUE 133 -#define _APS_NEXT_COMMAND_VALUE 32771 -#define _APS_NEXT_CONTROL_VALUE 1021 -#define _APS_NEXT_SYMED_VALUE 110 -#endif -#endif diff --git a/seasonwindow.cpp b/seasonwindow.cpp deleted file mode 100644 index f473d3b..0000000 --- a/seasonwindow.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include -#include "seasonwindow.hpp" - -void SeasonWindow::confirm() { - // go through all checkbuttons and save numbers - // of checked boxes into returned vector - // then quit - for ( auto &x : m_checks ) { - if ( x.get_active() ) { - returned.push_back( std::stoi( x.get_label() ) ); - } - } - hide(); -} - -void SeasonWindow::select_all() { - // set all check boxes to checked - for ( auto &x : m_checks ) { - x.set_active( true ); - } -} - -void SeasonWindow::select_none() { - // set all check boxes to unchecked - for ( auto &x : m_checks ) { - x.set_active( false ); - } -} - -SeasonWindow::SeasonWindow( const std::vector< int > &seasons, - std::vector< int > &_returned ) - : returned( _returned ) { - set_title( "Choose seasons" ); - - set_default_size( 250, 250 ); - set_resizable( false ); - - add( m_layout ); - - size_t x{ 5 }, y{ 25 }; - - // create a check box for each season - for ( auto &s : seasons ) { - m_checks.emplace_back( std::to_string( s ) ); - m_layout.put( m_checks.back(), x, y ); - - if ( x == 185 ) { - x = 5; - y += 20; - } else { - x += 60; - } - } - - m_layout.put( m_label, 5, 5 ); - m_label.set_label( "Select seasons:" ); - - m_layout.put( m_confirm, 165, 215 ); - m_layout.put( m_all, 130, 175 ); - m_layout.put( m_none, 5, 175 ); - - m_confirm.set_size_request( 80, 30 ); - m_all.set_size_request( 80, 30 ); - m_none.set_size_request( 80, 30 ); - - m_confirm.set_label( "Select" ); - m_all.set_label( "Select All" ); - m_none.set_label( "Unselect All" ); - - m_confirm.signal_clicked().connect( - sigc::mem_fun( *this, &SeasonWindow::confirm ) ); - m_all.signal_clicked().connect( - sigc::mem_fun( *this, &SeasonWindow::select_all ) ); - m_none.signal_clicked().connect( - sigc::mem_fun( *this, &SeasonWindow::select_none ) ); - - show_all_children(); -} diff --git a/seasonwindow.hpp b/seasonwindow.hpp deleted file mode 100644 index 4b7de80..0000000 --- a/seasonwindow.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef GTKMM_SEASON_WINDOW -#define GTKMM_SEASON_WINDOW - -#include -#include -#include -#include -#include - -class SeasonWindow : public Gtk::Window { -public: - SeasonWindow( const std::vector< int > &seasons, - std::vector< int > &_returned ); - virtual ~SeasonWindow() = default; - -private: - void confirm(); - void select_all(); - void select_none(); - -protected: - Gtk::Button m_confirm; - Gtk::Button m_all; - Gtk::Button m_none; - - Gtk::Label m_label; - - Gtk::Layout m_layout; - - std::vector< Gtk::CheckButton > m_checks; - - std::vector< int > &returned; -}; - -#endif diff --git a/small.ico b/small.ico deleted file mode 100644 index 57544cd..0000000 Binary files a/small.ico and /dev/null differ diff --git a/tv_rename.cpp b/tv_rename.cpp deleted file mode 100644 index 7a318a7..0000000 --- a/tv_rename.cpp +++ /dev/null @@ -1,284 +0,0 @@ -#include -#include - -#ifdef _WIN32 - -#include -#include -#include -#include -#include - -#endif - -#ifndef GUI - -#include -#include -#include -#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( "" ); - 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 diff --git a/tv_rename.hpp b/tv_rename.hpp deleted file mode 100644 index 121b866..0000000 --- a/tv_rename.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef TV_RENAME_HPP -#define TV_RENAME_HPP - -#include - -#ifdef GUI -#include -#endif - -#include "network.hpp" - -#ifdef _WIN32 - -using string = std::wstring; -using char_t = wchar_t; - -#else - -using string = std::string; -using char_t = char; - -#endif - -#ifdef GUI - -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 ); - -#else - -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 = nullptr ); -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 ); -void allSeasons( const string &path, string &show, const string &language, - const string &pattern, const bool &linux, const bool &trust, - Curl &c ); - -#endif - -#endif // TV_RENAME_HPP diff --git a/tv_rename.svg b/tv_rename.svg deleted file mode 100644 index 3cf84d4..0000000 --- a/tv_rename.svg +++ /dev/null @@ -1,120 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - diff --git a/tv_rename_gui.cpp b/tv_rename_gui.cpp deleted file mode 100644 index e48f87a..0000000 --- a/tv_rename_gui.cpp +++ /dev/null @@ -1,385 +0,0 @@ -// many thanks to https://www.winprog.org/tutorial from where I got a lot of -// code for this - -#include -#include -#include -#include -#include -#include - -#include "filesystem.hpp" -#include "functions.hpp" -#include "resource.h" -#include "tv_rename.hpp" - -constexpr std::array< const wchar_t *, 46 > languages{ - L"en", L"English", L"sv", L"Svenska", L"no", L"Norsk", - L"da", L"Dansk", L"fi", L"Suomeksi", L"nl", L"Nederlands", - L"de", L"Deutsch", L"it", L"Italiano", L"es", L"Español", - L"fr", L"Français", L"pl", L"Polski", L"hu", L"Magyar", - L"el", L"Greek", L"tr", L"Turkish", L"ru", L"Russian", - L"he", L"Hebrew", L"ja", L"Japanese", L"pt", L"Portuguese", - L"zh", L"Chinese", L"cs", L"Czech", L"sl", L"Slovenian", - L"hr", L"Croatian", L"ko", L"Korea" -}; - -// filled with possible season numbers -std::vector< int > options; -// contains IDs of checboxes created for IDD_SEASONS -std::vector< int > checkboxes; -// contains season numbers that have been checked in IDD_SEASONS -std::vector< int > checked; -Curl c; - -wchar_t lang_code[3] = L"en"; -std::wstring default_pattern = L"%filename - %epname"; - -// files separated by season -std::map< int, std::set< string > > files; -// possible shows for given query -std::vector< std::pair< string, string > > possible_shows; -// files from currently previewed season -std::vector< std::pair< string, std::pair< string, string > > > - *current_renamed_files{ nullptr }; - -BOOL CALLBACK HelpBox( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) { - switch ( message ) { - case WM_COMMAND: - switch ( LOWORD( wParam ) ) { - case IDOK: - EndDialog( hwnd, 0 ); - default: - break; - } - break; - case WM_CLOSE: - EndDialog( hwnd, 0 ); - break; - default: - return FALSE; - } - return TRUE; -} - -BOOL CALLBACK SeasonsBox( HWND hwnd, UINT message, WPARAM wParam, - LPARAM lParam ) { - switch ( message ) { - case WM_INITDIALOG: { - // fill with checkboxes for possible seasons - checked.clear(); - checkboxes.clear(); - int left{ 15 }, top{ 30 }; - for ( int i = 0; i < options.size(); i++ ) { - if ( checkboxes.empty() ) { - // start IDs at 2000 - checkboxes.push_back( 2000 ); - } else { - checkboxes.push_back( checkboxes.back() + 1 ); - } - auto hCheckBox = CreateWindowEx( - 0, L"Button", std::to_wstring( options[i] ).c_str(), - WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, left, top, 60, 20, - hwnd, ( HMENU )checkboxes.back(), GetModuleHandle( NULL ), - NULL ); - if ( hCheckBox == NULL ) { - MessageBox( hwnd, L"Could not create checkbox", L"Error", - MB_OK | MB_ICONERROR ); - return TRUE; - } - auto hfDefault = GetStockObject( DEFAULT_GUI_FONT ); - SendMessage( hCheckBox, WM_SETFONT, ( WPARAM )hfDefault, - MAKELPARAM( FALSE, 0 ) ); - if ( left == 195 ) { - left = 15; - top += 20; - } else { - left += 60; - } - } - } - return TRUE; - case WM_COMMAND: - switch ( LOWORD( wParam ) ) { - case IDOK: - // store checked seasons in checked - for ( int i = 0; i < checkboxes.size(); i++ ) { - if ( SendDlgItemMessage( hwnd, checkboxes[i], BM_GETCHECK, 0, - 0 ) ) - checked.push_back( options[i] ); - } - EndDialog( hwnd, 0 ); - break; - case IDALL: - // check all seasons - for ( auto &x : checkboxes ) { - SendDlgItemMessage( hwnd, x, BM_SETCHECK, BST_CHECKED, 0 ); - } - break; - case IDNONE: - // uncheck all seasons - for ( auto &x : checkboxes ) { - SendDlgItemMessage( hwnd, x, BM_SETCHECK, BST_UNCHECKED, 0 ); - } - break; - default: - break; - } - break; - case WM_CLOSE: - EndDialog( hwnd, 0 ); - break; - default: - return FALSE; - } - return TRUE; -} - -// choose directory, stolen from -// https://www.codeproject.com/Articles/2604/Browse-Folder-dialog-search-folder-and-all-sub-fol -std::wstring getDir() { - wchar_t path[MAX_PATH]; - BROWSEINFO bi{}; - bi.lpszTitle = L"Choose a folder"; - LPITEMIDLIST pidl = SHBrowseForFolder( &bi ); - if ( pidl != 0 ) { - SHGetPathFromIDList( pidl, path ); - IMalloc *imalloc = 0; - if ( SUCCEEDED( SHGetMalloc( &imalloc ) ) ) { - imalloc->Free( pidl ); - imalloc->Release(); - } - } else { - path[0] = '\0'; - } - return path; -} - -void renameFiles( - const std::vector< std::pair< string, std::pair< string, string > > > - &renamed ) { - for ( auto renamed_it = renamed.begin(); renamed_it != renamed.end(); - ++renamed_it ) { - FSLib::rename( renamed_it->first + L"\\" + renamed_it->second.first, - renamed_it->first + L"\\" + renamed_it->second.second ); - } -} - -BOOL CALLBACK PreviewBox( HWND hwnd, UINT message, WPARAM wParam, - LPARAM lParam ) { - switch ( message ) { - case WM_INITDIALOG: { - // fill IDTEXT with how the rename would look - std::wstring text{}; - for ( auto renamed_it = current_renamed_files->begin(); - renamed_it != current_renamed_files->end(); ++renamed_it ) { - text += renamed_it->second.first + L" --> " + - renamed_it->second.second + L"\r\n"; - } - SetDlgItemText( hwnd, IDTEXT, text.c_str() ); - } - return TRUE; - case WM_COMMAND: - switch ( LOWORD( wParam ) ) { - case IDYES: { - renameFiles( *current_renamed_files ); - EndDialog( hwnd, IDYES ); - } break; - case IDNO: - EndDialog( hwnd, IDNO ); - default: - break; - } - break; - case WM_CLOSE: - EndDialog( hwnd, 0 ); - break; - default: - return FALSE; - } - return TRUE; -} - -void finishedSelection( HWND hwnd ) { - // get show name and url for selected show - auto index = SendDlgItemMessage( hwnd, IDSHOWS, CB_GETCURSEL, 0, 0 ); - auto url = possible_shows[index].second; - auto show = possible_shows[index].first; - wchar_t input_pattern[100]; - - GetDlgItemText( hwnd, IDPATTERN, input_pattern, 100 ); - - if ( input_pattern != default_pattern ) { - std::wofstream file( userHome() + L"\\tv_rename\\pattern" ); - if ( file ) { - file << input_pattern; - } - } - - for ( auto &x : checked ) { - auto renamed_files = getRenamedFiles( - show, x, L"https://www.thetvdb.com" + url, lang_code, - ( input_pattern[0] == '\0' ? default_pattern : input_pattern ), - false, c, files[x] ); - if ( renamed_files.empty() ) - continue; - // if user trusts us, just rename files - if ( SendDlgItemMessage( hwnd, IDTRUST, BM_GETCHECK, 0, 0 ) ) { - renameFiles( renamed_files ); - continue; - } - - // if user doesn't trust us show what rename would look like - current_renamed_files = &renamed_files; - DialogBox( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDD_PREVIEW ), - hwnd, PreviewBox ); - } - // if user trusted us, let them know when rename finished - if ( SendDlgItemMessage( hwnd, IDTRUST, BM_GETCHECK, 0, 0 ) ) { - MessageBox( hwnd, L"Finished renaming files", L"Info", - MB_OK | MB_ICONINFORMATION ); - } -} - -void getNames( HWND hwnd ) { - wchar_t path[MAX_PATH]; - GetDlgItemText( hwnd, IDDIR, path, MAX_PATH ); - - if ( wcslen( path ) == 0 ) { - MessageBox( hwnd, L"Folder field is empty", L"Error", - MB_OK | MB_ICONERROR ); - return; - } - if ( !FSLib::isDirectory( path ) ) { - MessageBox( hwnd, L"Folder doesn't exist", L"Error", - MB_OK | MB_ICONERROR ); - return; - } - - checked.clear(); - checkboxes.clear(); - options.clear(); - files.clear(); - - // get possible seasons - iterateFS( files, path ); - for ( auto &x : files ) { - options.push_back( x.first ); - } - - // user selects which seasons should be renamed - DialogBox( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDD_SEASONS ), hwnd, - SeasonsBox ); - // process selected seasons - finishedSelection( hwnd ); -} - -void process( HWND hwnd ) { - wchar_t show[100]; - GetDlgItemText( hwnd, IDSHOWIN, show, 100 ); - - if ( wcslen( show ) == 0 ) { - MessageBox( hwnd, L"Show field is empty", L"Error", - MB_OK | MB_ICONERROR ); - return; - } - - wchar_t language[20]; - GetDlgItemText( hwnd, IDLANG, language, 20 ); - - // get language code - for ( int i = 1; i < languages.size(); i += 2 ) { - if ( !wcscmp( languages[i], language ) ) { - wcscpy_s( lang_code, languages[i - 1] ); - break; - } - } - - possible_shows = getPossibleShows( show, lang_code, c ); - if ( possible_shows.size() == 0 ) { - MessageBox( hwnd, L"No results found for given show name", L"Error", - MB_OK | MB_ICONERROR ); - return; - } - - ShowWindow( GetDlgItem( hwnd, ID_STATIC6 ), SW_SHOW ); - ShowWindow( GetDlgItem( hwnd, IDSHOWS ), SW_SHOW ); - ShowWindow( GetDlgItem( hwnd, IDSEASONS ), SW_SHOW ); - - // fill IDSHOWS with possible shows - SendDlgItemMessage( hwnd, IDSHOWS, CB_RESETCONTENT, 0, 0 ); - for ( int i = 0; i < possible_shows.size(); i++ ) { - SendDlgItemMessage( hwnd, IDSHOWS, CB_ADDSTRING, 0, - ( LPARAM )possible_shows[i].first.c_str() ); - } - // select first item - SendDlgItemMessage( hwnd, IDSHOWS, CB_SETCURSEL, 0, 0 ); -} - -// if stored pattern exists, read it and store the value -// in default_pattern -void readDefaultPattern( const string &base_dir ) { - std::wifstream file( base_dir + L"\\pattern" ); - if ( file ) { - std::getline( file, default_pattern ); - } -} - -BOOL CALLBACK MainBox( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) { - switch ( message ) { - case WM_INITDIALOG: { - // fill IDLANG with possible languages - for ( int i = 1; i < languages.size(); i += 2 ) { - SendDlgItemMessage( hwnd, IDLANG, CB_ADDSTRING, 0, - ( LPARAM )languages[i] ); - } - // select English by default - SendDlgItemMessage( hwnd, IDLANG, CB_SETCURSEL, 5, 0 ); - - auto appdata = userHome() + L"\\tv_rename"; - if ( !FSLib::isDirectory( appdata ) ) { - // create the directory so pattern can be stored when changed - CreateDirectory( appdata.c_str(), NULL ); - } else { - readDefaultPattern( appdata ); - } - - SetDlgItemText( hwnd, IDPATTERN, default_pattern.c_str() ); - } - return TRUE; - case WM_COMMAND: - switch ( LOWORD( wParam ) ) { - case IDPROCESS: { - process( hwnd ); - } break; - case IDEND: - EndDialog( hwnd, IDOK_MAIN ); - break; - case IDSEASONS: - getNames( hwnd ); - break; - case IDDIRB: - SetDlgItemText( hwnd, IDDIR, getDir().c_str() ); - break; - case IDHELP: - DialogBox( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDD_HELP ), - hwnd, HelpBox ); - break; - default: - break; - } - break; - case WM_CLOSE: - EndDialog( hwnd, 0 ); - break; - default: - return FALSE; - } - return TRUE; -} - -int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, - LPSTR lpCmdLine, int nCmdShow ) { - return DialogBox( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDD_MAIN ), - NULL, MainBox ); -} diff --git a/tv_rename_gui.desktop b/tv_rename_gui.desktop deleted file mode 100755 index c930d03..0000000 --- a/tv_rename_gui.desktop +++ /dev/null @@ -1,9 +0,0 @@ -[Desktop Entry] -Encoding=UTF-8 -Value=1.0 -Type=Application -Name=TV Rename -GenericName=TV Rename -Comment=TV Rename -Icon=tv_rename -Exec=tv_rename_gui diff --git a/tv_rename_gui.ico b/tv_rename_gui.ico deleted file mode 100644 index 60f0036..0000000 Binary files a/tv_rename_gui.ico and /dev/null differ diff --git a/tv_rename_gui.rc b/tv_rename_gui.rc deleted file mode 100644 index f0c8f7c..0000000 Binary files a/tv_rename_gui.rc and /dev/null differ diff --git a/unix/filesystem.cpp b/unix/filesystem.cpp deleted file mode 100644 index 9918d12..0000000 --- a/unix/filesystem.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include -#include "../filesystem.hpp" - -FSLib::Directory::Directory( const string &path_ ) : dir_path( path_ ) {} - -FSLib::Directory::Iterator::Iterator( const Directory &d_ ) : d( opendir( d_.path() ) ) { - current_entry = readdir( d ); - if ( current_entry != nullptr && - ( !strcmp( current_entry->d_name, "." ) || - !strcmp( current_entry->d_name, ".." ) ) ) - ++( *this ); -} - -FSLib::Directory::Iterator::Iterator( const Directory &d_, const struct dirent *current_entry_ ) - : d( opendir( d_.path() ) ), current_entry( current_entry_ ) {} - -FSLib::Directory::Iterator::~Iterator() { - closedir( d ); -} - -#ifndef GUI // these functions aren't needed in GUI - -bool FSLib::exists( const string &path ) { - struct stat path_stat; - return stat( path.c_str(), &path_stat ) == 0; -} - -string FSLib::canonical( const string &path ) { - - char_t *canonical_path = new char_t[PATH_MAX]; - - auto failed = realpath( path.c_str(), canonical_path ) == nullptr; - - if ( failed ) { - delete[] canonical_path; - return string(); - } - - string canonical_string{ canonical_path }; - delete[] canonical_path; - return canonical_string; -} - -#endif // ndef GUI - -bool FSLib::isDirectory( const string &path ) { - struct stat path_stat; - - stat( path.c_str(), &path_stat ); - - return S_ISDIR( path_stat.st_mode ); -} - -bool FSLib::rename( const string &file_a, const string &file_b ) { - return ::rename( file_a.c_str(), file_b.c_str() ) == 0; -} - -FSLib::Directory::iterator FSLib::Directory::end() { - return Iterator( *this, nullptr ); -} - -FSLib::Directory::const_iterator FSLib::Directory::end() const { - return Iterator( *this, nullptr ); -} - -char_t const *FSLib::Directory::Iterator::operator*() const { - return current_entry->d_name; -} - -FSLib::Directory::Iterator &FSLib::Directory::Iterator::operator++() { - if ( current_entry == nullptr ) - return *this; - current_entry = readdir( d ); - // skip . and .. - if ( current_entry != nullptr && - ( !strcmp( current_entry->d_name, "." ) || - !strcmp( current_entry->d_name, ".." ) ) ) - return operator++(); - return *this; -} - -bool FSLib::Directory::Iterator::operator==( const Iterator &i_other ) const { - return i_other.current_entry == current_entry; -} diff --git a/windows/filesystem.cpp b/windows/filesystem.cpp deleted file mode 100644 index fa49268..0000000 --- a/windows/filesystem.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include -#include -#include "../filesystem.hpp" - -FSLib::Directory::Directory( const string &path_ ) : dir_path( path_ ) { - // need to append \\* for windows to search files in directory - dir_path.append( L"\\*" ); -} - -FSLib::Directory::Iterator::Iterator( const Directory &d_ ) { - hFind = FindFirstFileW( d_.path(), &data ); - if ( hFind != INVALID_HANDLE_VALUE ) { - if ( !wcscmp( data.cFileName, L"." ) || - !wcscmp( data.cFileName, L".." ) ) { - ++( *this ); - } - } else { - ended = true; - } -} - -FSLib::Directory::Iterator::~Iterator() { - if ( hFind ) - FindClose( hFind ); -} - -// this is definitely not a good way to create the "end" iterator -// but it was the only way I thought of with my limited knowledge of -// windows.h -FSLib::Directory::Iterator::Iterator( bool ended_ ) : ended( ended_ ) {} - -#ifndef GUI // these functions aren't needed in GUI - -bool FSLib::exists( const string &path ) { - struct _stat path_stat; - return _wstat( path.c_str(), &path_stat ) == 0; -} - -string FSLib::canonical( const string &path ) { - char_t *canonical_path = new char_t[MAX_PATH]; - - auto failed = !PathCanonicalizeW( canonical_path, path.c_str() ); - - if ( failed ) { - delete[] canonical_path; - return string(); - } - - string canonical_string{ canonical_path }; - delete[] canonical_path; - return canonical_string; -} - -#endif // ndef GUI - -bool FSLib::isDirectory( const string &path ) { - struct _stat path_stat; - - _wstat( path.c_str(), &path_stat ); - - return path_stat.st_mode & _S_IFDIR; -} - -bool FSLib::rename( const string &file_a, const string &file_b ) { - return MoveFileExW( file_a.c_str(), file_b.c_str(), - MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING ); -} - -FSLib::Directory::iterator FSLib::Directory::end() { - return Iterator( true ); -} - -FSLib::Directory::const_iterator FSLib::Directory::end() const { - return Iterator( true ); -} - -char_t const *FSLib::Directory::Iterator::operator*() const { - return data.cFileName; -} - -FSLib::Directory::Iterator &FSLib::Directory::Iterator::operator++() { - if ( ended == true ) - return *this; - // skip . and .. - if ( FindNextFileW( hFind, &data ) == 0 ) { - ended = true; - } else if ( !wcscmp( data.cFileName, L"." ) || - !wcscmp( data.cFileName, L".." ) ) { - return operator++(); - } - return *this; -} - -bool FSLib::Directory::Iterator::operator==( const Iterator &i_other ) const { - return i_other.ended == ended; -}