2019-02-04 16:39:48 +00:00
|
|
|
|
// many thanks to https://www.winprog.org/tutorial from where I got a lot of
|
|
|
|
|
// code for this
|
|
|
|
|
|
|
|
|
|
#include <Windows.h>
|
|
|
|
|
#include <array>
|
|
|
|
|
#include <fstream>
|
|
|
|
|
#include <shlobj.h>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
#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"
|
|
|
|
|
};
|
|
|
|
|
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// filled with possible season numbers
|
2019-02-04 16:39:48 +00:00
|
|
|
|
std::vector< int > options;
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// contains IDs of checboxes created for IDD_SEASONS
|
2019-02-04 16:39:48 +00:00
|
|
|
|
std::vector< int > checkboxes;
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// contains season numbers that have been checked in IDD_SEASONS
|
2019-02-04 16:39:48 +00:00
|
|
|
|
std::vector< int > checked;
|
|
|
|
|
Curl c;
|
|
|
|
|
|
|
|
|
|
wchar_t lang_code[3] = L"en";
|
|
|
|
|
std::wstring default_pattern = L"%filename - %epname";
|
|
|
|
|
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// files separated by season
|
2019-02-04 16:39:48 +00:00
|
|
|
|
std::map< int, std::set< string > > files;
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// possible shows for given query
|
2019-02-04 16:39:48 +00:00
|
|
|
|
std::vector< std::pair< string, string > > possible_shows;
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// files from currently previewed season
|
2019-02-04 16:39:48 +00:00
|
|
|
|
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: {
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// fill with checkboxes for possible seasons
|
2019-02-04 16:39:48 +00:00
|
|
|
|
checked.clear();
|
|
|
|
|
checkboxes.clear();
|
|
|
|
|
int left{ 15 }, top{ 30 };
|
|
|
|
|
for ( int i = 0; i < options.size(); i++ ) {
|
|
|
|
|
if ( checkboxes.empty() ) {
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// start IDs at 2000
|
2019-02-04 16:39:48 +00:00
|
|
|
|
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:
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// store checked seasons in checked
|
2019-02-04 16:39:48 +00:00
|
|
|
|
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:
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// check all seasons
|
2019-02-04 16:39:48 +00:00
|
|
|
|
for ( auto &x : checkboxes ) {
|
|
|
|
|
SendDlgItemMessage( hwnd, x, BM_SETCHECK, BST_CHECKED, 0 );
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case IDNONE:
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// uncheck all seasons
|
2019-02-04 16:39:48 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// choose directory, stolen from
|
2019-02-04 16:39:48 +00:00
|
|
|
|
// 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: {
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// fill IDTEXT with how the rename would look
|
2019-02-04 16:39:48 +00:00
|
|
|
|
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 ) {
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// get show name and url for selected show
|
2019-02-04 16:39:48 +00:00
|
|
|
|
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;
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// if user trusts us, just rename files
|
2019-02-04 16:39:48 +00:00
|
|
|
|
if ( SendDlgItemMessage( hwnd, IDTRUST, BM_GETCHECK, 0, 0 ) ) {
|
|
|
|
|
renameFiles( renamed_files );
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// if user doesn't trust us show what rename would look like
|
2019-02-04 16:39:48 +00:00
|
|
|
|
current_renamed_files = &renamed_files;
|
|
|
|
|
DialogBox( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDD_PREVIEW ),
|
|
|
|
|
hwnd, PreviewBox );
|
|
|
|
|
}
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// if user trusted us, let them know when rename finished
|
2019-02-04 16:39:48 +00:00
|
|
|
|
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();
|
|
|
|
|
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// get possible seasons
|
2019-02-04 16:39:48 +00:00
|
|
|
|
iterateFS( files, path );
|
|
|
|
|
for ( auto &x : files ) {
|
|
|
|
|
options.push_back( x.first );
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// user selects which seasons should be renamed
|
2019-02-04 16:39:48 +00:00
|
|
|
|
DialogBox( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDD_SEASONS ), hwnd,
|
|
|
|
|
SeasonsBox );
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// process selected seasons
|
2019-02-04 16:39:48 +00:00
|
|
|
|
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 );
|
|
|
|
|
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// get language code
|
2019-02-04 16:39:48 +00:00
|
|
|
|
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 );
|
|
|
|
|
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// fill IDSHOWS with possible shows
|
2019-02-04 16:39:48 +00:00
|
|
|
|
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() );
|
|
|
|
|
}
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// select first item
|
2019-02-04 16:39:48 +00:00
|
|
|
|
SendDlgItemMessage( hwnd, IDSHOWS, CB_SETCURSEL, 0, 0 );
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// if stored pattern exists, read it and store the value
|
|
|
|
|
// in default_pattern
|
2019-02-04 16:39:48 +00:00
|
|
|
|
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: {
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// fill IDLANG with possible languages
|
2019-02-04 16:39:48 +00:00
|
|
|
|
for ( int i = 1; i < languages.size(); i += 2 ) {
|
|
|
|
|
SendDlgItemMessage( hwnd, IDLANG, CB_ADDSTRING, 0,
|
|
|
|
|
( LPARAM )languages[i] );
|
|
|
|
|
}
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// select English by default
|
2019-02-04 16:39:48 +00:00
|
|
|
|
SendDlgItemMessage( hwnd, IDLANG, CB_SETCURSEL, 5, 0 );
|
|
|
|
|
|
|
|
|
|
auto appdata = userHome() + L"\\tv_rename";
|
|
|
|
|
if ( !FSLib::isDirectory( appdata ) ) {
|
2019-02-05 00:52:43 +00:00
|
|
|
|
// create the directory so pattern can be stored when changed
|
|
|
|
|
CreateDirectory( appdata.c_str(), NULL );
|
2019-02-04 16:39:48 +00:00
|
|
|
|
} 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 );
|
|
|
|
|
}
|