From 00efca3df9b5fc10853f0bbf41641d65b7ffe10c Mon Sep 17 00:00:00 2001 From: zvon Date: Sat, 18 May 2019 15:31:17 +0200 Subject: [PATCH] Delete everything --- LICENSE | 24 -- Makefile | 85 ------- README.md | 66 ----- filesystem.hpp | 127 ---------- functions.cpp | 560 ----------------------------------------- functions.hpp | 69 ----- gui.cpp | 12 - main.cpp | 262 ------------------- mainwindow.cpp | 380 ---------------------------- mainwindow.hpp | 90 ------- network.cpp | 83 ------ network.hpp | 34 --- resource.h | 50 ---- seasonwindow.cpp | 78 ------ seasonwindow.hpp | 35 --- small.ico | Bin 21238 -> 0 bytes tv_rename.cpp | 284 --------------------- tv_rename.hpp | 47 ---- tv_rename.svg | 120 --------- tv_rename_gui.cpp | 385 ---------------------------- tv_rename_gui.desktop | 9 - tv_rename_gui.ico | Bin 75590 -> 0 bytes tv_rename_gui.rc | Bin 11636 -> 0 bytes unix/filesystem.cpp | 84 ------- windows/filesystem.cpp | 96 ------- 25 files changed, 2980 deletions(-) delete mode 100644 LICENSE delete mode 100644 Makefile delete mode 100644 README.md delete mode 100644 filesystem.hpp delete mode 100644 functions.cpp delete mode 100644 functions.hpp delete mode 100644 gui.cpp delete mode 100644 main.cpp delete mode 100644 mainwindow.cpp delete mode 100644 mainwindow.hpp delete mode 100644 network.cpp delete mode 100644 network.hpp delete mode 100644 resource.h delete mode 100644 seasonwindow.cpp delete mode 100644 seasonwindow.hpp delete mode 100644 small.ico delete mode 100644 tv_rename.cpp delete mode 100644 tv_rename.hpp delete mode 100644 tv_rename.svg delete mode 100644 tv_rename_gui.cpp delete mode 100755 tv_rename_gui.desktop delete mode 100644 tv_rename_gui.ico delete mode 100644 tv_rename_gui.rc delete mode 100644 unix/filesystem.cpp delete mode 100644 windows/filesystem.cpp 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 57544cd215e8ec0a0c2210d8758f2d961215a02c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21238 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 JVn#;7{{fikV?+P| 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 60f0036f62705d595191902da5e04a967d255cdb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75590 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 Ukk2QgVX^st+wc3^K0Mg}0QI~*b^rhX diff --git a/tv_rename_gui.rc b/tv_rename_gui.rc deleted file mode 100644 index f0c8f7c8e78d044774130ab9a256a44e324fde54..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11636 zcmds7TT|Oc6yE2~^gpO(GEJs5#5R{CZ(tkn#2D9hNa$pSAzTs~Fch1l>GZd^{l0U2 zyenCfZ3wB;(b$q!yXSt}BmMLDl3Q|-+i_>^$X&Zj*T?VF4KTKcvA(-;hwdDA755X4 z$h~tXu7}?>#s@ebW9%AduDik25w0WL5!#u%!kowMd-ol%EXjERqdh!5$LwR7TNqpa z*u8fJna!08GVfH@5%#)kxsL0)m#*sSZr2^SwyR;ZitDCpxP6Rt@W10WFw(%a;U^9A zcNlecj@%aHl9cf&q;%;n!2bZ!p&Yv4`ZfOR;JN}nDUTY)OZX);oJdMMiR}KNf?zP%)G)u3px@@ITLCkxew{mD0YE4%ou&FRJ!}PCnb!Lq=#z= z^&AH?&*$OO3!F9Xk>WaRp^KcRR@H=7cf_J-4Rx#wk2ySGtIq+xN-Ae%;jawLv-8#hPXipR zy?YZetqP`+a5$?JTi~XT8*(Rlh-Rl{Vl>qcEuvpe)pi~ z4t~t6wU~D4H+9Ukx;Ab*ns=C+ci{=NJk?xLI3!kDY7sWO2)Oj)b@)dYv$t_qfj4k3 z(1>AVT-99ycM6Oa@q_khcH`|OiE%|RSHKamRs~ZFXVS_22>G=*VzXG)v`3>RnUK!V z=jk7WPHtK;4yKVArP>}!Yxxe+Vw9r%H$<+aC7vM*kTR`=wnLja9`g=H6^+@XXhZa+ zKB#o9L5r$G#x>K$G(5H>f@pL#%UHWtUgO>v4I}8)D6Vb83LDUtw;QELt%Y_P@;F(x zEqMK<)L8UPlVnS*jk%?R!#v`N$T1z0))HM=*BHszWE}x=6?j-#{fMWB!1V#=Q;c2X z99B41k7>QfiemtcbFEQFEVP*}C@VnUHxj>WhWd+nX$6*5g9W|7JoQDN^WyeTF4fnS zPx?N+zKGFKrqg)0#SIu)DSQ&=G~{Nog|KVDdbkNq zumbf~!ir`cIO(yT)0JVI_Hi?h{@G~xMQY!{$P!qsRH361@`Cz!528O`j}EWyODLB|Ro( z!_>G`08aJ{+4nk%R!TThB1!yFMVbi*I&nH?r;B-%*~92>@{3L#wzLG5udnMXSbSh zk{sXn?&voD!>X2h6y_spDBXW1+u8%^%CMHV{zT+{hAf!X&#+TshlRUr?cT)aJsfp{ z*x{$G4zSZvS)O1=sGS(@7HGSV+#CEqfK+wIpm_Y9$DizIvxjnw9fz(z0R}&pv~q-< zpG)cbMZwd2NTFvLHQv_<=LY%mE#O}VxI;|o*!?Q2cgFX8>^P|QnEP0vEW*ReVsBP+ zP1fE9c-Br_oR^St)@tmsr^(4v%9@SyBH=fJL=UlsZv(i}cl`boX|R%KRQL@N(%zrW z)|tmcn)trRL!u?U!@b(od(0tae4|A9Mz9P*WcTj_M)Yk4W&K=auevYc-fL)*bZw_= z($y+3y_R6TTtj!Hj{jG{&b`sR^^5K=E`}W;YK+zVM`+>%nxB^#xDRT4<+=|&v0}}y z8_km@*AY#4lGzih2Kwf+oQl*SPqPQLzJ*o??17X3TX!bQa@M}Y4yqaYd|i42tXp&k zkk_>cXC&Vyh5Lu>oyB+;B<>;1fb-cC4*S7IB|Vq&s-p|p#D7z=w>{;VKfa|rmFUI@ zHU8e1>-MB-rGB|W-v$si`!>`K`=eR7(z~FxZ((;|`&98bLp)|z=@9HGJ7k-%6hh+L zEQ7Wd%O5tojptj~MUT&C7AmE#(T-9Qe!O33@VPH%caA-?T zmwh^~*|KMBPq(-)C(H7%6JVB*FPnIk@ZU>lR{u@cz$9zaUdgzGysQ?Gn^|M(dwZR! zZ|SCqt@LXCW{=9>QeLtufU(+tl|#NQkMX*Q7?M6S5*elEh4e3_-XOYb_2xB29Q+RG zHaJv2d0*_1H=j4(4EIe+gV|3(^ql -#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; -}