Initial support of database
This commit is contained in:
parent
d36d7a385d
commit
d1e82d4a94
32
Makefile
32
Makefile
@ -38,8 +38,9 @@ uninstall_gui:
|
||||
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
|
||||
tv_rename: functions.o filesystem_u.o network.o tv_rename.o progress.o main.cpp
|
||||
$(CXX) $(CFLAGS) -o tv_rename main.cpp tv_rename.o functions.o\
|
||||
filesystem_u.o network.o progress.o -lcurl -lsqlite3
|
||||
|
||||
filesystem_u.o: unix/filesystem.cpp
|
||||
$(CXX) $(CFLAGS) -c unix/filesystem.cpp -o filesystem_u.o
|
||||
@ -53,11 +54,18 @@ network.o: network.cpp
|
||||
tv_rename.o: tv_rename.cpp
|
||||
$(CXX) $(CFLAGS) -c tv_rename.cpp
|
||||
|
||||
progress.o: progress.cpp
|
||||
$(CXX) $(CFLAGS) -c progress.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
|
||||
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
|
||||
@ -72,14 +80,22 @@ tv_rename_gui.o: tv_rename.cpp
|
||||
.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
|
||||
tv_rename.exe: tv_rename.cpp functions.cpp windows/filesystem.cpp network.cpp\
|
||||
progress.cpp sqlite3.c main.cpp
|
||||
$(CXX) -MD -EHsc -Fe"tv_rename" tv_rename.cpp windows/filesystem.cpp\
|
||||
functions.cpp network.cpp progress.cpp sqlite3.c main.cpp\
|
||||
-D_WIN32 -DUNICODE -link wininet.lib shlwapi.lib ole32.lib\
|
||||
shell32.lib user32.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.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
|
||||
|
397
functions.cpp
397
functions.cpp
@ -2,34 +2,38 @@
|
||||
#include <array>
|
||||
#include <cctype>
|
||||
#include <iomanip>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <codecvt>
|
||||
#include <iostream>
|
||||
#include <shlobj.h>
|
||||
|
||||
#else // UNIX
|
||||
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef GUI
|
||||
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
|
||||
#else // UNIX and GUI
|
||||
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#endif // GUI
|
||||
|
||||
#endif // UNIX
|
||||
|
||||
#include "filesystem.hpp"
|
||||
#include "functions.hpp"
|
||||
#include "progress.hpp"
|
||||
#include "sqlitepp.hpp"
|
||||
#include "tv_rename.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
@ -101,7 +105,7 @@ string encodeUrl( const string &url ) {
|
||||
encoded << std::hex;
|
||||
for ( const auto &x : url_c ) {
|
||||
if ( isalnum( static_cast< unsigned char >( x ) ) || x == '-' ||
|
||||
x == '_' || x == '.' || x == '~' ) {
|
||||
x == '_' || x == '.' || x == '~' || x == '+' ) {
|
||||
encoded << x;
|
||||
continue;
|
||||
}
|
||||
@ -243,6 +247,8 @@ void findSeasons( std::map< int, std::set< string > > &seasons,
|
||||
}
|
||||
|
||||
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
|
||||
@ -337,6 +343,23 @@ void printHelp() {
|
||||
cout << " -l, --lang <string> Select which language the episode"
|
||||
<< " names shoud be in" << std::endl;
|
||||
cout << " --print-langs Pring available languages" << std::endl;
|
||||
cout << std::endl;
|
||||
cout << "DATABASE OPTIONS" << std::endl;
|
||||
cout << " --db-add Add path to the database"
|
||||
<< std::endl;
|
||||
cout << " --db-refresh Refresh episode names for all paths"
|
||||
<< " in the database" << std::endl;
|
||||
cout << " --db-update Check all paths in the database,"
|
||||
<< std::endl;
|
||||
cout << " if they contain new files,"
|
||||
<< " rename them" << std::endl;
|
||||
cout << " --db-name-pattern <string> Change name pattern used for files"
|
||||
<< std::endl
|
||||
<< " managed by database" << std::endl;
|
||||
cout << " --db-clean Remove deleted files from the"
|
||||
<< " database" << std::endl;
|
||||
cout << " --db-remove Remove path from the database"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
// parse command line argument --seasons (e.g. '1 2 3 4 5')
|
||||
@ -393,6 +416,7 @@ bool findLanguage( const char_t *language ) {
|
||||
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(
|
||||
@ -421,6 +445,8 @@ getPossibleShows( string show, const string &language, Curl &c ) {
|
||||
return urls;
|
||||
}
|
||||
|
||||
#endif // ndef GUI
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
// get user's home directory
|
||||
@ -456,8 +482,6 @@ string userHome() {
|
||||
|
||||
#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,
|
||||
@ -554,3 +578,358 @@ string compilePattern( const string &pattern, int season, int episode,
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#ifndef GUI
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
std::wstring getDBName() {
|
||||
return userHome() + L"\\tv_rename\\database.db";
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
std::string getDBName() {
|
||||
return userHome() + "/.cache/tv_rename.db";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
string sanitize( const string &str ) {
|
||||
string ret;
|
||||
size_t prev_pos{};
|
||||
size_t pos = str.find_first_of( '\'' );
|
||||
while ( pos != string::npos ) {
|
||||
ret += str.substr( prev_pos, pos - prev_pos );
|
||||
prev_pos = pos + 1;
|
||||
pos = str.find_first_of( '\'', prev_pos );
|
||||
ret += TEXT( "\'\'" );
|
||||
}
|
||||
ret += str.substr( prev_pos, pos );
|
||||
return ret;
|
||||
}
|
||||
|
||||
void prepareDB() {
|
||||
SQLite::Database db{};
|
||||
try {
|
||||
db.open( getDBName(), SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE );
|
||||
} catch ( std::exception &e ) {
|
||||
cerr << "Couldn't create database, make sure you have"
|
||||
<< " write permission for " << getDBName() << std::endl;
|
||||
throw e;
|
||||
}
|
||||
db.exec( "CREATE TABLE IF NOT EXISTS SHOWS (ID INTEGER NOT NULL "
|
||||
"PRIMARY KEY AUTOINCREMENT, URL TEXT NOT NULL, SHOW TEXT NOT NULL,"
|
||||
"PATH TEXT NOT NULL UNIQUE, LANGUAGE TEXT NOT NULL);" );
|
||||
db.exec( "CREATE TABLE IF NOT EXISTS EPISODES (SHOWID INTEGER NOT NULL,"
|
||||
"PATH TEXT NOT NULL UNIQUE, FOREIGN KEY(SHOWID) "
|
||||
"REFERENCES SHOWS(ID));" );
|
||||
cout << "Insert name pattern for database:" << std::endl;
|
||||
string pattern;
|
||||
std::getline( cin, pattern );
|
||||
db.exec( TEXT( "INSERT INTO SHOWS ( URL, SHOW, PATH, LANGUAGE ) "
|
||||
"VALUES ( 'pattern', 'pattern', '" ) +
|
||||
sanitize( pattern ) + TEXT( "', 'pattern' );" ) );
|
||||
}
|
||||
|
||||
void addToDB( string &show, const string &path, const string &language,
|
||||
bool linux, Curl &c ) {
|
||||
if ( !FSLib::exists( getDBName() ) )
|
||||
prepareDB();
|
||||
SQLite::Database db{};
|
||||
auto absolute = FSLib::canonical( path );
|
||||
try {
|
||||
db.open( getDBName(), SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE );
|
||||
} catch ( std::exception &e ) {
|
||||
cerr << "Can't open database, make sure it exists" << std::endl;
|
||||
throw e;
|
||||
}
|
||||
auto url = getDefUrl( show, language, c );
|
||||
string season_id{};
|
||||
string pattern{};
|
||||
db.exec( TEXT( "INSERT OR IGNORE INTO SHOWS ( URL, SHOW, PATH, LANGUAGE ) "
|
||||
"VALUES ( '" ) +
|
||||
sanitize( url ) + TEXT( "', '" ) + sanitize( show ) +
|
||||
TEXT( "', '" ) + sanitize( absolute ) + TEXT( "', '" ) +
|
||||
sanitize( language ) + TEXT( "' );" ) );
|
||||
db.exec( TEXT( "SELECT ID FROM SHOWS WHERE PATH == '" ) +
|
||||
sanitize( absolute ) + TEXT( "';" ),
|
||||
season_id );
|
||||
db.exec( TEXT( "SELECT PATH FROM SHOWS WHERE URL == 'pattern';" ),
|
||||
pattern );
|
||||
|
||||
std::map< int, std::set< string > > seasons;
|
||||
// get all seasons and episodes
|
||||
iterateFS( seasons, absolute );
|
||||
auto size = seasons.size();
|
||||
size_t i = 0;
|
||||
cout << "Renaming" << std::endl;
|
||||
#ifdef WIN32
|
||||
cout << std::endl;
|
||||
#endif
|
||||
ProgressBar::print( 0 );
|
||||
for ( const auto &x : seasons ) {
|
||||
singleSeason( absolute, show, x.first, url, language, pattern, linux,
|
||||
true, c, &x.second, false );
|
||||
i++;
|
||||
ProgressBar::print( ( i * 100 ) / size );
|
||||
}
|
||||
cout << std::endl;
|
||||
seasons.clear();
|
||||
iterateFS( seasons, absolute );
|
||||
size = seasons.size();
|
||||
i = 0;
|
||||
|
||||
cout << "Adding to database" << std::endl;
|
||||
#ifdef WIN32
|
||||
cout << std::endl;
|
||||
#endif
|
||||
ProgressBar::print( 0 );
|
||||
for ( auto &season : seasons ) {
|
||||
for ( auto &episode : season.second ) {
|
||||
db.exec( TEXT( "INSERT OR IGNORE INTO EPISODES ( SHOWID, PATH ) "
|
||||
"VALUES ( " ) +
|
||||
season_id + TEXT( ", '" ) + sanitize( episode ) +
|
||||
TEXT( "' );" ) );
|
||||
}
|
||||
i++;
|
||||
ProgressBar::print( ( i * 100 ) / size );
|
||||
}
|
||||
cout << std::endl;
|
||||
}
|
||||
|
||||
void cleanUpLine() {
|
||||
#ifdef WIN32
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
int width;
|
||||
|
||||
GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &csbi );
|
||||
width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
|
||||
|
||||
static HANDLE h = NULL;
|
||||
if ( !h )
|
||||
h = GetStdHandle( STD_OUTPUT_HANDLE );
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
GetConsoleScreenBufferInfo( h, &info );
|
||||
COORD c = { 0, info.dwCursorPosition.Y - 3 };
|
||||
SetConsoleCursorPosition( h, c );
|
||||
#else
|
||||
struct winsize w;
|
||||
ioctl( 0, TIOCGWINSZ, &w );
|
||||
|
||||
auto width = w.ws_col;
|
||||
|
||||
cout << "\x1b[2A";
|
||||
#endif
|
||||
cout << string( width, ' ' ) << std::endl << std::endl;
|
||||
#ifdef WIN32
|
||||
SetConsoleCursorPosition( h, c );
|
||||
#else
|
||||
cout << "\x1b[2A";
|
||||
#endif
|
||||
}
|
||||
|
||||
void refreshDB( bool linux, Curl &c ) {
|
||||
std::vector< std::unordered_map< string, string > > shows;
|
||||
SQLite::Database db{};
|
||||
try {
|
||||
db.open( getDBName(), SQLite::OPEN_READWRITE );
|
||||
} catch ( std::exception &e ) {
|
||||
cerr << "Can't open database, make sure it exists" << std::endl;
|
||||
throw e;
|
||||
}
|
||||
db.exec( "DELETE FROM EPISODES;" );
|
||||
db.exec( TEXT( "SELECT ID, URL, SHOW, PATH, LANGUAGE FROM SHOWS WHERE URL "
|
||||
"!= 'pattern';" ),
|
||||
shows );
|
||||
|
||||
string pattern{};
|
||||
db.exec( TEXT( "SELECT PATH FROM SHOWS WHERE URL == 'pattern';" ),
|
||||
pattern );
|
||||
|
||||
cout << "Refreshing database" << std::endl << std::endl << std::endl;
|
||||
#ifdef WIN32
|
||||
cout << std::endl;
|
||||
#endif
|
||||
for ( auto &show : shows ) {
|
||||
if ( FSLib::exists( show[TEXT( "PATH" )] ) ) {
|
||||
cleanUpLine();
|
||||
cout << "Refreshing " << show[TEXT( "SHOW" )] << std::endl;
|
||||
#ifdef WIN32
|
||||
cout << std::endl;
|
||||
#endif
|
||||
ProgressBar::print( 0 );
|
||||
std::map< int, std::set< string > > seasons;
|
||||
// get all season number from this directory and subdirectories
|
||||
iterateFS( seasons, show[TEXT( "PATH" )] );
|
||||
auto size = seasons.size();
|
||||
size_t i{};
|
||||
for ( const auto &x : seasons ) {
|
||||
singleSeason( show[TEXT( "PATH" )], show[TEXT( "SHOW" )],
|
||||
x.first, show[TEXT( "URL" )],
|
||||
show[TEXT( "LANGUAGE" )], pattern, linux, true, c,
|
||||
&x.second, false );
|
||||
i++;
|
||||
ProgressBar::print( ( i * 100 ) / size );
|
||||
}
|
||||
ProgressBar::print( 100 );
|
||||
cout << std::endl;
|
||||
seasons.clear();
|
||||
iterateFS( seasons, show[TEXT( "PATH" )] );
|
||||
for ( auto &season : seasons ) {
|
||||
for ( auto &episode : season.second ) {
|
||||
db.exec( TEXT( "INSERT INTO EPISODES ( SHOWID, PATH ) "
|
||||
"VALUES ( " ) +
|
||||
show[TEXT( "ID" )] + TEXT( ", '" ) +
|
||||
sanitize( episode ) + TEXT( "' );" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateDB( bool linux, Curl &c ) {
|
||||
std::vector< std::unordered_map< string, string > > shows;
|
||||
SQLite::Database db{};
|
||||
try {
|
||||
db.open( getDBName(), SQLite::OPEN_READWRITE );
|
||||
} catch ( std::exception &e ) {
|
||||
cerr << "Can't open database, make sure it exists" << std::endl;
|
||||
throw e;
|
||||
}
|
||||
db.exec( TEXT( "SELECT ID, URL, SHOW, PATH, LANGUAGE FROM SHOWS WHERE URL "
|
||||
"!= 'pattern';" ),
|
||||
shows );
|
||||
|
||||
string pattern{};
|
||||
db.exec( TEXT( "SELECT PATH FROM SHOWS WHERE URL == 'pattern';" ),
|
||||
pattern );
|
||||
|
||||
cout << "Updating database" << std::endl << std::endl << std::endl;
|
||||
#ifdef WIN32
|
||||
cout << std::endl;
|
||||
#endif
|
||||
for ( auto &show : shows ) {
|
||||
if ( !FSLib::exists( show[TEXT( "PATH" )] ) ) {
|
||||
continue;
|
||||
}
|
||||
cleanUpLine();
|
||||
cout << "Updating " << show[TEXT( "SHOW" )] << std::endl;
|
||||
#ifdef WIN32
|
||||
cout << std::endl;
|
||||
#endif
|
||||
std::unordered_set< string > episodes;
|
||||
db.exec( TEXT( "SELECT PATH FROM EPISODES WHERE SHOWID == " ) +
|
||||
show[TEXT( "ID" )] + TEXT( ";" ),
|
||||
episodes );
|
||||
std::map< int, std::set< string > > seasons;
|
||||
std::map< int, std::set< string > > new_eps;
|
||||
// get all season number from this directory and subdirectories
|
||||
iterateFS( seasons, show[TEXT( "PATH" )] );
|
||||
for ( const auto &x : seasons ) {
|
||||
for ( const auto &episode : x.second ) {
|
||||
if ( episodes.find( episode ) == episodes.end() ) {
|
||||
new_eps[x.first].insert( episode );
|
||||
}
|
||||
}
|
||||
}
|
||||
ProgressBar::print( 0 );
|
||||
if ( !new_eps.empty() ) {
|
||||
auto size = new_eps.size();
|
||||
size_t i{};
|
||||
for ( const auto &x : new_eps ) {
|
||||
singleSeason( show[TEXT( "PATH" )], show[TEXT( "SHOW" )],
|
||||
x.first, show[TEXT( "URL" )],
|
||||
show[TEXT( "LANGUAGE" )], pattern, linux, true, c,
|
||||
&x.second, false );
|
||||
i++;
|
||||
ProgressBar::print( ( i * 100 ) / size );
|
||||
}
|
||||
seasons.clear();
|
||||
iterateFS( seasons, show[TEXT( "PATH" )] );
|
||||
for ( auto &season : seasons ) {
|
||||
for ( auto &episode : season.second ) {
|
||||
db.exec( TEXT( "INSERT OR IGNORE INTO EPISODES ( SHOWID, "
|
||||
"PATH ) VALUES ( " ) +
|
||||
show[TEXT( "ID" )] + TEXT( ", '" ) +
|
||||
sanitize( episode ) + TEXT( "' );" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
ProgressBar::print( 100 );
|
||||
cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void changeDBPattern( const string &pattern ) {
|
||||
SQLite::Database db{};
|
||||
try {
|
||||
db.open( getDBName(), SQLite::OPEN_READWRITE );
|
||||
} catch ( std::exception &e ) {
|
||||
cerr << "Can't open database, make sure it exists" << std::endl;
|
||||
throw e;
|
||||
}
|
||||
db.exec( TEXT( "UPDATE SHOWS SET PATH = '" ) + pattern +
|
||||
TEXT( "' WHERE URL == 'pattern';" ) );
|
||||
}
|
||||
|
||||
void cleanDB() {
|
||||
std::vector< std::unordered_map< string, string > > shows;
|
||||
SQLite::Database db{};
|
||||
try {
|
||||
db.open( getDBName(), SQLite::OPEN_READWRITE );
|
||||
} catch ( std::exception &e ) {
|
||||
cerr << "Can't open database, make sure it exists" << std::endl;
|
||||
throw e;
|
||||
}
|
||||
db.exec( TEXT( "SELECT ID, URL, SHOW, PATH, LANGUAGE FROM SHOWS WHERE URL "
|
||||
"!= 'pattern';" ),
|
||||
shows );
|
||||
|
||||
string pattern{};
|
||||
db.exec( TEXT( "SELECT PATH FROM SHOWS WHERE URL == 'pattern';" ),
|
||||
pattern );
|
||||
|
||||
for ( auto &show : shows ) {
|
||||
if ( !FSLib::exists( show[TEXT( "PATH" )] ) ) {
|
||||
continue;
|
||||
}
|
||||
std::unordered_set< string > episodes;
|
||||
db.exec( TEXT( "SELECT PATH FROM EPISODES WHERE SHOWID == " ) +
|
||||
show[TEXT( "ID" )] + TEXT( ";" ),
|
||||
episodes );
|
||||
for ( const auto &episode : episodes ) {
|
||||
if ( !FSLib::exists( episode ) ) {
|
||||
db.exec( TEXT( "DELETE FROM EPISODES WHERE PATH == '" ) +
|
||||
sanitize( episode ) + TEXT( "';" ) );
|
||||
}
|
||||
}
|
||||
episodes.clear();
|
||||
db.exec( TEXT( "SELECT PATH FROM EPISODES WHERE SHOWID == " ) +
|
||||
show[TEXT( "ID" )] + TEXT( ";" ),
|
||||
episodes );
|
||||
if ( episodes.empty() ) {
|
||||
db.exec( TEXT( "DELETE FROM SHOWS WHERE ID == " ) +
|
||||
show[TEXT( "ID" )] + TEXT( ";" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void removeFromDB( const string &path ) {
|
||||
SQLite::Database db{};
|
||||
try {
|
||||
db.open( getDBName(), SQLite::OPEN_READWRITE );
|
||||
} catch ( std::exception &e ) {
|
||||
cerr << "Can't open database, make sure it exists" << std::endl;
|
||||
throw e;
|
||||
}
|
||||
string show_id{};
|
||||
db.exec( TEXT( "SELECT ID FROM SHOWS WHERE PATH == '" ) + sanitize( path ) +
|
||||
TEXT( "';" ),
|
||||
show_id );
|
||||
db.exec( TEXT( "DELETE FROM EPISODES WHERE SHOWID == " ) + show_id +
|
||||
TEXT( ";" ) );
|
||||
db.exec( TEXT( "DELETE FROM SHOWS WHERE ID == " ) + show_id + TEXT( ";" ) );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -52,10 +52,22 @@ string encodeUrl( const string &url );
|
||||
|
||||
std::vector< std::pair< string, string > >
|
||||
getPossibleShows( string show, const string &language, Curl &c );
|
||||
string userHome();
|
||||
|
||||
#endif // GUI
|
||||
|
||||
string userHome();
|
||||
|
||||
#ifndef GUI
|
||||
void prepareDB();
|
||||
void addToDB( string &show, const string &path, const string &language,
|
||||
bool linux, Curl &c );
|
||||
void removeFromDB( const string &path );
|
||||
void changeDBPattern( const string &pattern );
|
||||
void refreshDB( bool linux, Curl &c );
|
||||
void updateDB( bool linux, Curl &c );
|
||||
void cleanDB();
|
||||
#endif
|
||||
|
||||
void iterateFS( std::map< int, std::set< string > > &seasons,
|
||||
const string &path );
|
||||
|
||||
|
129
main.cpp
129
main.cpp
@ -39,10 +39,17 @@ using string = std::string;
|
||||
|
||||
#endif
|
||||
|
||||
constexpr size_t DB_ADD = 0x0001;
|
||||
constexpr size_t DB_REFRESH = 0x0002;
|
||||
constexpr size_t DB_UPDATE = 0x0004;
|
||||
constexpr size_t DB_CLEAN = 0x0008;
|
||||
constexpr size_t DB_REMOVE = 0x0010;
|
||||
constexpr size_t DB_PATTERN = 0x0020;
|
||||
|
||||
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 ) {
|
||||
string &language, string &pattern, size_t &db_flags,
|
||||
string &db_pattern, char_t *optional, int &i ) {
|
||||
switch ( c ) {
|
||||
case 's':
|
||||
show = optional;
|
||||
@ -56,7 +63,7 @@ int handleArgument( char_t c, string &show, std::set< int > &seasons_num,
|
||||
change_dir = false;
|
||||
break;
|
||||
case 'p':
|
||||
path = string( optional );
|
||||
path = optional;
|
||||
i++;
|
||||
// if path provided, assume it's correct
|
||||
change_dir = false;
|
||||
@ -87,6 +94,26 @@ int handleArgument( char_t c, string &show, std::set< int > &seasons_num,
|
||||
pattern = optional;
|
||||
i++;
|
||||
break;
|
||||
case 'a':
|
||||
db_flags |= DB_ADD;
|
||||
break;
|
||||
case 'r':
|
||||
db_flags |= DB_REFRESH;
|
||||
break;
|
||||
case 'u':
|
||||
db_flags |= DB_UPDATE;
|
||||
break;
|
||||
case 'd':
|
||||
db_pattern = optional;
|
||||
db_flags |= DB_PATTERN;
|
||||
i++;
|
||||
break;
|
||||
case '2':
|
||||
db_flags |= DB_CLEAN;
|
||||
break;
|
||||
case '3':
|
||||
db_flags |= DB_REMOVE;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
@ -118,14 +145,26 @@ string getOptions( const char_t *option ) {
|
||||
return L"1";
|
||||
else if ( !wcscmp( option, L"--help" ) )
|
||||
return L"h";
|
||||
else if ( !wcscmp( option, L"--db-add" ) )
|
||||
return L"a";
|
||||
else if ( !wcscmp( option, L"--db-refresh" ) )
|
||||
return L"r";
|
||||
else if ( !wcscmp( option, L"--db-update" ) )
|
||||
return L"u";
|
||||
else if ( !wcscmp( option, L"--db-name-pattern" ) )
|
||||
return L"d";
|
||||
else if ( !wcscmp( option, L"--db-clean" ) )
|
||||
return L"2";
|
||||
else if ( !wcscmp( option, L"--db-remove" ) )
|
||||
return L"3";
|
||||
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 ) {
|
||||
bool &linux, bool &trust, size_t &db_flags,
|
||||
string &db_pattern, const int argc, char_t **argv ) {
|
||||
string options{};
|
||||
char_t *optional;
|
||||
for ( auto i = 1; i < argc; i++ ) {
|
||||
@ -137,9 +176,9 @@ int parseCommandLine( string &show, std::set< int > &seasons_num, string &path,
|
||||
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 );
|
||||
auto res = handleArgument( x, show, seasons_num, change_dir, path,
|
||||
trust, linux, language, pattern,
|
||||
db_flags, db_pattern, optional, i );
|
||||
if ( res != 0 )
|
||||
return res;
|
||||
}
|
||||
@ -152,17 +191,24 @@ int parseCommandLine( string &show, std::set< int > &seasons_num, string &path,
|
||||
// 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 ) {
|
||||
bool &linux, bool &trust, size_t &db_flags,
|
||||
string &db_pattern, 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' },
|
||||
{ "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' },
|
||||
{ "show", required_argument, 0, 's' },
|
||||
{ "season", required_argument, 0, 'n' },
|
||||
{ "correct-path", no_argument, 0, 'c' },
|
||||
{ "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' },
|
||||
{ "db-add", no_argument, 0, 'a' },
|
||||
{ "db-refresh", no_argument, 0, 'r' },
|
||||
{ "db-update", no_argument, 0, 'u' },
|
||||
{ "db-name-pattern", required_argument, 0, 'd' },
|
||||
{ "db-clean", no_argument, 0, '2' },
|
||||
{ "db-remove", required_argument, 0, '3' },
|
||||
{ "help", no_argument, 0, 'h' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@ -170,12 +216,13 @@ int parseCommandLine( string &show, std::set< int > &seasons_num, string &path,
|
||||
|
||||
while ( 1 ) {
|
||||
int option_index{ 0 };
|
||||
auto c = getopt_long( argc, argv, "s:n:cp:txl:01:h", long_options,
|
||||
auto c = getopt_long( argc, argv, "s:n:cp:txl:01:arud23h", long_options,
|
||||
&option_index );
|
||||
if ( c == -1 )
|
||||
break;
|
||||
auto res = handleArgument( c, show, seasons_num, change_dir, path,
|
||||
trust, linux, language, pattern, optarg, i );
|
||||
trust, linux, language, pattern, db_flags,
|
||||
db_pattern, optarg, i );
|
||||
if ( res != 0 )
|
||||
return res;
|
||||
}
|
||||
@ -207,15 +254,17 @@ int main
|
||||
bool change_dir{ true };
|
||||
bool linux{ false };
|
||||
bool trust{ false };
|
||||
size_t db_flags{};
|
||||
string path{ TEXT( "." ) };
|
||||
string language{ TEXT( "en" ) };
|
||||
string pattern{ TEXT( "%filename - %epname" ) };
|
||||
string db_pattern{};
|
||||
Curl c;
|
||||
|
||||
{
|
||||
auto tmp =
|
||||
parseCommandLine( show, seasons_num, path, change_dir, language,
|
||||
pattern, linux, trust, argc, argv );
|
||||
auto tmp = parseCommandLine( show, seasons_num, path, change_dir,
|
||||
language, pattern, linux, trust, db_flags,
|
||||
db_pattern, argc, argv );
|
||||
if ( tmp == -1 )
|
||||
return 1;
|
||||
else if ( tmp == 1 )
|
||||
@ -241,6 +290,40 @@ int main
|
||||
change_dir = true;
|
||||
}
|
||||
|
||||
if ( !db_pattern.empty() ) {
|
||||
changeDBPattern( db_pattern );
|
||||
}
|
||||
|
||||
if ( db_flags & DB_REMOVE && db_flags & DB_ADD ) {
|
||||
cerr << "You can't remove and add at the same time" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( db_flags & DB_REMOVE ) {
|
||||
removeFromDB( FSLib::canonical( path ) );
|
||||
}
|
||||
|
||||
if ( db_flags & DB_ADD ) {
|
||||
addToDB( show, path, language, linux, c );
|
||||
cout << "Added to database" << std::endl;
|
||||
}
|
||||
if ( db_flags & DB_REFRESH ) {
|
||||
refreshDB( linux, c );
|
||||
cout << "Refreshed database" << std::endl;
|
||||
}
|
||||
if ( db_flags & DB_UPDATE ) {
|
||||
updateDB( linux, c );
|
||||
cout << "Updated database" << std::endl;
|
||||
}
|
||||
if ( db_flags & DB_CLEAN ) {
|
||||
cleanDB();
|
||||
cout << "Database cleaned" << std::endl;
|
||||
}
|
||||
|
||||
// if db operations happened don't continue
|
||||
if ( db_flags )
|
||||
return 0;
|
||||
|
||||
while ( change_dir ) {
|
||||
if ( !FSLib::isDirectory( path ) ) {
|
||||
cout << "This directory doesn't exist, please insert a correct "
|
||||
|
75
progress.cpp
Normal file
75
progress.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
#include "progress.hpp"
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <conio.h>
|
||||
#include <windows.h>
|
||||
#include <winuser.h>
|
||||
|
||||
#define cout std::wcout
|
||||
using string = std::wstring;
|
||||
|
||||
#else // UNIX
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#define cout std::cout
|
||||
#define TEXT( a ) a
|
||||
using string = std::string;
|
||||
|
||||
#endif // UNIX
|
||||
|
||||
size_t getTermWidth() {
|
||||
#ifdef WIN32
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
|
||||
GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &csbi );
|
||||
return csbi.srWindow.Right - csbi.srWindow.Left + 1;
|
||||
#else
|
||||
struct winsize w;
|
||||
ioctl( 0, TIOCGWINSZ, &w );
|
||||
|
||||
return w.ws_col;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
void home( size_t /*UNUSED*/ ) {
|
||||
static HANDLE h = NULL;
|
||||
while ( !h )
|
||||
h = GetStdHandle( STD_OUTPUT_HANDLE );
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
GetConsoleScreenBufferInfo( h, &info );
|
||||
COORD c = { 0, info.dwCursorPosition.Y - 1 };
|
||||
SetConsoleCursorPosition( h, c );
|
||||
}
|
||||
#else
|
||||
void home( size_t width ) {
|
||||
cout << "\x1b[" << width << "D";
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t getNum( size_t width, int perc ) {
|
||||
return ( width * perc ) / 100;
|
||||
}
|
||||
|
||||
void ProgressBar::print( int perc ) {
|
||||
auto width = getTermWidth();
|
||||
home( width );
|
||||
auto count = getNum( width - 7, perc );
|
||||
cout << "[" << string( count, TEXT( '=' ) ).c_str();
|
||||
if ( perc != 100 ) {
|
||||
int wc = width - 8 - count;
|
||||
if ( wc < 0 )
|
||||
wc = 0;
|
||||
cout << ">" << string( wc, TEXT( ' ' ) ).c_str();
|
||||
}
|
||||
cout << "] ";
|
||||
if ( perc / 10 == 0 )
|
||||
cout << " ";
|
||||
else if ( perc / 100 == 0 )
|
||||
cout << " ";
|
||||
cout << perc << "%" << std::flush;
|
||||
}
|
8
progress.hpp
Normal file
8
progress.hpp
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef PROGRESS_HPP
|
||||
#define PROGRESS_HPP
|
||||
|
||||
namespace ProgressBar {
|
||||
void print(int perc);
|
||||
};
|
||||
|
||||
#endif
|
259
sqlitepp.hpp
Normal file
259
sqlitepp.hpp
Normal file
@ -0,0 +1,259 @@
|
||||
#ifndef SQLITEPP
|
||||
#define SQLITEPP
|
||||
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
#else
|
||||
|
||||
#include "sqlite3.h"
|
||||
#include <codecvt>
|
||||
#include <shlobj.h>
|
||||
|
||||
std::string _w_2_8( const std::wstring &wstring ) {
|
||||
std::wstring_convert< std::codecvt_utf8_utf16< wchar_t > > wconv;
|
||||
return wconv.to_bytes( wstring );
|
||||
}
|
||||
|
||||
std::wstring _8_2_w( const std::string &utf8 ) {
|
||||
std::wstring_convert< std::codecvt_utf8_utf16< wchar_t > > wconv;
|
||||
return wconv.from_bytes( utf8 );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace SQLite {
|
||||
|
||||
constexpr size_t OPEN_READONLY = 0x00000001;
|
||||
constexpr size_t OPEN_READWRITE = 0x00000002;
|
||||
constexpr size_t OPEN_CREATE = 0x00000004;
|
||||
constexpr size_t OPEN_URI = 0x00000040;
|
||||
constexpr size_t OPEN_MEMORY = 0x00000080;
|
||||
constexpr size_t OPEN_NOMUTEX = 0x00008000;
|
||||
constexpr size_t OPEN_FULLMUTEX = 0x00010000;
|
||||
constexpr size_t OPEN_SHAREDCACHE = 0x00020000;
|
||||
constexpr size_t OPEN_PRIVATECACHE = 0x00040000;
|
||||
|
||||
class Database {
|
||||
public:
|
||||
Database() {}
|
||||
|
||||
Database( const std::string &file, size_t options ) {
|
||||
open( file, options );
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
Database( const std::wstring &file, size_t options ) {
|
||||
open( file, options );
|
||||
}
|
||||
#endif
|
||||
|
||||
~Database() {
|
||||
close();
|
||||
}
|
||||
|
||||
void open( const std::string &file, size_t options ) {
|
||||
if ( sqlite3_open_v2( file.c_str(), &db, options, nullptr ) ) {
|
||||
throw std::runtime_error( "Could not open database " + file );
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
void open( const std::wstring &file, size_t options ) {
|
||||
if ( sqlite3_open_v2( _w_2_8( file ).c_str(), &db, options,
|
||||
nullptr ) ) {
|
||||
throw std::runtime_error( "Could not open database " +
|
||||
_w_2_8( file ) );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// execute command without output
|
||||
void exec( const std::string &command ) {
|
||||
char *errMsg = nullptr;
|
||||
int rc = sqlite3_exec( db, command.c_str(), nullptr, nullptr, &errMsg );
|
||||
if ( rc )
|
||||
throw std::runtime_error( "\"" + command +
|
||||
"\" resulted in an error:\n" + errMsg );
|
||||
sqlite3_free( errMsg );
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
void exec( const std::wstring &command ) {
|
||||
char *errMsg = nullptr;
|
||||
int rc = sqlite3_exec( db, _w_2_8( command ).c_str(), nullptr, nullptr,
|
||||
&errMsg );
|
||||
if ( rc )
|
||||
throw std::runtime_error( "\"" + _w_2_8( command ) +
|
||||
"\" resulted in an error:\n" + errMsg );
|
||||
sqlite3_free( errMsg );
|
||||
}
|
||||
#endif
|
||||
|
||||
// execute command that should only output 1 result
|
||||
void exec( const std::string &command, std::string &output ) {
|
||||
char *errMsg = nullptr;
|
||||
int rc = sqlite3_exec( db, command.c_str(), insert_val_s,
|
||||
static_cast< void * >( &output ), &errMsg );
|
||||
if ( rc )
|
||||
throw std::runtime_error( "\"" + command +
|
||||
"\" resulted in an error:\n" + errMsg );
|
||||
sqlite3_free( errMsg );
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
void exec( const std::wstring &command, std::wstring &output ) {
|
||||
char *errMsg = nullptr;
|
||||
int rc = sqlite3_exec( db, _w_2_8( command ).c_str(), insert_val_ws,
|
||||
static_cast< void * >( &output ), &errMsg );
|
||||
if ( rc )
|
||||
throw std::runtime_error( "\"" + _w_2_8( command ) +
|
||||
"\" resulted in an error:\n" + errMsg );
|
||||
sqlite3_free( errMsg );
|
||||
}
|
||||
#endif
|
||||
|
||||
// didn't work with set for some reason, so only vector is allowed
|
||||
void exec( const std::string &command,
|
||||
std::vector< std::unordered_map< std::string, std::string > >
|
||||
&object ) {
|
||||
char *errMsg = nullptr;
|
||||
int rc = sqlite3_exec( db, command.c_str(), insert_col_val,
|
||||
static_cast< void * >( &object ), &errMsg );
|
||||
if ( rc )
|
||||
throw std::runtime_error( "\"" + command +
|
||||
"\" resulted in an error:\n" + errMsg );
|
||||
sqlite3_free( errMsg );
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
// didn't work with set for some reason, so only vector is allowed
|
||||
void exec( const std::wstring &command,
|
||||
std::vector< std::unordered_map< std::wstring, std::wstring > >
|
||||
&object ) {
|
||||
char *errMsg = nullptr;
|
||||
int rc = sqlite3_exec( db, _w_2_8( command ).c_str(), insert_col_val_w,
|
||||
static_cast< void * >( &object ), &errMsg );
|
||||
if ( rc )
|
||||
throw std::runtime_error( "\"" + _w_2_8( command ) +
|
||||
"\" resulted in an error:\n" + errMsg );
|
||||
sqlite3_free( errMsg );
|
||||
}
|
||||
#endif
|
||||
|
||||
// execute command with output and store output in object (store only
|
||||
// values) object can by any container as long as it's template is
|
||||
// 'std::string'
|
||||
template < typename V > void exec( const std::string &command, V &object ) {
|
||||
char *errMsg = nullptr;
|
||||
int rc = sqlite3_exec( db, command.c_str(), insert_val< V >,
|
||||
static_cast< void * >( &object ), &errMsg );
|
||||
if ( rc )
|
||||
throw std::runtime_error( "\"" + command +
|
||||
"\" resulted in an error:\n" + errMsg );
|
||||
sqlite3_free( errMsg );
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
template < typename V >
|
||||
void exec( const std::wstring &command, V &object ) {
|
||||
char *errMsg = nullptr;
|
||||
int rc = sqlite3_exec( db, _w_2_8( command ).c_str(), insert_val_w< V >,
|
||||
static_cast< void * >( &object ), &errMsg );
|
||||
if ( rc )
|
||||
throw std::runtime_error( "\"" + _w_2_8( command ) +
|
||||
"\" resulted in an error:\n" + errMsg );
|
||||
sqlite3_free( errMsg );
|
||||
}
|
||||
#endif
|
||||
|
||||
void close() {
|
||||
sqlite3_close( db );
|
||||
}
|
||||
|
||||
private:
|
||||
sqlite3 *db;
|
||||
|
||||
static int insert_col_val( void *d, int argc, char **argv,
|
||||
char **azColName ) {
|
||||
auto &data = *static_cast<
|
||||
std::vector< std::unordered_map< std::string, std::string > > * >(
|
||||
d );
|
||||
std::unordered_map< std::string, std::string > buffer;
|
||||
for ( int i = 0; i < argc; i++ ) {
|
||||
// insert all columns and values into 'data'
|
||||
buffer[azColName[i]] = argv[i] ? argv[i] : "";
|
||||
}
|
||||
data.insert( data.end(), std::move( buffer ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
static int insert_col_val_w( void *d, int argc, char **argv,
|
||||
char **azColName ) {
|
||||
auto &data = *static_cast<
|
||||
std::vector< std::unordered_map< std::wstring, std::wstring > > * >(
|
||||
d );
|
||||
std::unordered_map< std::wstring, std::wstring > buffer;
|
||||
for ( int i = 0; i < argc; i++ ) {
|
||||
// insert all columns and values into 'data'
|
||||
buffer[_8_2_w( azColName[i] )] = argv[i] ? _8_2_w( argv[i] ) : L"";
|
||||
}
|
||||
data.insert( data.end(), std::move( buffer ) );
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int insert_val_s( void *d, int argc, char **argv,
|
||||
char ** /*UNUSED*/ ) {
|
||||
auto &data = *static_cast< std::string * >( d );
|
||||
if ( argc > 0 ) {
|
||||
data = argv[0] ? argv[0] : "";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
static int insert_val_ws( void *d, int argc, char **argv,
|
||||
char ** /*UNUSED*/ ) {
|
||||
auto &data = *static_cast< std::wstring * >( d );
|
||||
if ( argc > 0 ) {
|
||||
data = argv[0] ? _8_2_w( argv[0] ) : L"";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
template < typename V >
|
||||
static int insert_val( void *d, int argc, char **argv,
|
||||
char ** /*UNUSED*/ ) {
|
||||
auto &data = *static_cast< V * >( d );
|
||||
for ( int i = 0; i < argc; i++ ) {
|
||||
// insert all values into 'data'
|
||||
data.insert( data.end(), argv[i] ? argv[i] : "" );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
template < typename V >
|
||||
static int insert_val_w( void *d, int argc, char **argv,
|
||||
char ** /*UNUSED*/ ) {
|
||||
auto &data = *static_cast< V * >( d );
|
||||
for ( int i = 0; i < argc; i++ ) {
|
||||
// insert all values into 'data'
|
||||
data.insert( data.end(), argv[i] ? _8_2_w( argv[i] ) : L"" );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace SQLite
|
||||
|
||||
#endif
|
@ -208,7 +208,7 @@ getRenamedFiles( const string &show, int season, string url,
|
||||
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 ) {
|
||||
std::set< string > const *files_ptr, bool print ) {
|
||||
if ( url.empty() )
|
||||
url = getDefUrl( show, language, c );
|
||||
|
||||
@ -224,20 +224,22 @@ void singleSeason( const string &path, string &show, int season, string url,
|
||||
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 ( print ) {
|
||||
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;
|
||||
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();
|
||||
|
@ -33,7 +33,8 @@ getRenamedFiles( const string &show, int season, string url,
|
||||
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 );
|
||||
std::set< string > const *files = nullptr,
|
||||
bool print = true );
|
||||
void multipleSeasons( const string &path, string &show,
|
||||
const std::set< int > seasons, const string &language,
|
||||
const string &pattern, const bool &linux,
|
||||
|
@ -37,9 +37,20 @@ bool FSLib::exists( const string &path ) {
|
||||
}
|
||||
|
||||
string FSLib::canonical( const string &path ) {
|
||||
char_t *full_path = new char_t[MAX_PATH];
|
||||
char_t *canonical_path = new char_t[MAX_PATH];
|
||||
|
||||
auto failed = !PathCanonicalizeW( canonical_path, path.c_str() );
|
||||
auto failed = !GetFullPathName( path.c_str(), MAX_PATH, full_path, NULL );
|
||||
|
||||
if ( failed ) {
|
||||
delete[] canonical_path;
|
||||
delete[] full_path;
|
||||
return string();
|
||||
}
|
||||
|
||||
failed = !PathCanonicalizeW( canonical_path, full_path );
|
||||
|
||||
delete[] full_path;
|
||||
|
||||
if ( failed ) {
|
||||
delete[] canonical_path;
|
||||
|
Loading…
Reference in New Issue
Block a user