This commit is contained in:
zvon 2019-01-03 19:01:43 +01:00
parent e5c02be1e0
commit 49a490061e
6 changed files with 175 additions and 38 deletions

View File

@ -1,13 +1,16 @@
CC ?= clang
CXX ?= clang++
CFLAGS ?= -O2 -g -Wall -Wextra -std=c++17
CFLAGS ?= -O2 -g -Wall -Wextra -std=c++11
default: tv_rename
# using libc++ because libstdc++ has a bug in regex that causes seg fault with long lines
tv_rename: functions.o tv_rename.cpp
$(CXX) $(CFLAGS) -stdlib=libc++ -o tv_rename tv_rename.cpp functions.o -lcurl -lc++fs
tv_rename: functions.o filesystem.o tv_rename.cpp
$(CXX) $(CFLAGS) -stdlib=libc++ -o tv_rename tv_rename.cpp functions.o filesystem.o -lcurl
filesystem.o: filesystem.cpp
$(CXX) $(CFLAGS) -stdlib=libc++ -c filesystem.cpp
functions.o: functions.cpp
$(CXX) $(CFLAGS) -stdlib=libc++ -c functions.cpp

29
filesystem.cpp Normal file
View File

@ -0,0 +1,29 @@
#include "filesystem.hpp"
#include <sys/stat.h>
#include <stdlib.h>
#include <linux/limits.h>
bool FSLib::exists(const std::string &path) {
struct stat path_stat;
return stat( path.c_str(), &path_stat ) == 0;
}
bool FSLib::isDirectory(const std::string &path) {
struct stat path_stat;
stat( path.c_str(), &path_stat );
return S_ISDIR(path_stat.st_mode);
}
std::string FSLib::canonical(const std::string &path) {
char *canonical_path = static_cast<char *>(malloc(PATH_MAX));
if( realpath(path.c_str(), canonical_path) == nullptr )
return "";
std::string canonical_string{canonical_path};
free(canonical_path);
return canonical_string;
}
bool FSLib::rename(const std::string &file_a, const std::string &file_b) {
return ::rename( file_a.c_str(), file_b.c_str() ) == 0;
}

106
filesystem.hpp Normal file
View File

@ -0,0 +1,106 @@
#ifndef FSLIB_H
#define FSLIB_H
#include <string>
#include <dirent.h>
#include <string.h>
namespace FSLib{
bool exists(const std::string &path);
bool isDirectory(const std::string &path);
std::string canonical(const std::string &path);
bool rename(const std::string &file_a, const std::string &file_b);
class Directory {
public:
Directory(const std::string &path_) : dir_path(path_) {}
Directory() = delete;
Directory(const Directory &d) = default;
Directory(Directory &&d) = default;
class Iterator {
public:
Iterator( const Directory &d_ ) : d(opendir(d_.path())) {
current_entry = readdir(d);
}
Iterator( const Directory &d_, const struct dirent *current_entry_) : d(opendir(d_.path())), current_entry(current_entry_) {}
Iterator() = delete;
Iterator(const Iterator &i) = default;
Iterator(Iterator &&i) = default;
~Iterator() {
closedir(d);
}
std::string operator*() {
return current_entry->d_name;
}
Iterator &operator++() {
if( current_entry == nullptr )
return *this;
current_entry = readdir(d);
if( current_entry != nullptr && (!strcmp(current_entry->d_name, ".") || !strcmp(current_entry->d_name, "..")) )
operator++();
return *this;
}
Iterator operator++(int) {
Iterator ret(*this);
operator++();
return ret;
}
bool operator==(const Iterator &i_other) {
return i_other.current_entry == current_entry;
}
bool operator!=(const Iterator &i_other) {
return i_other.current_entry != current_entry;
}
private:
DIR *d;
const struct dirent *current_entry;
};
using iterator = Iterator;
using const_iterator = Iterator;
iterator begin() {
return Iterator(dir_path);
}
const_iterator begin() const {
return Iterator(dir_path);
}
const_iterator cbegin() const {
return begin();
}
iterator end() {
return Iterator(dir_path, nullptr);
}
const_iterator end() const {
return Iterator(dir_path, nullptr);
}
const_iterator cend() const {
return end();
}
const char *path() const {
return dir_path.c_str();
}
private:
std::string dir_path;
};
} //end FSLib
#endif

View File

@ -1,4 +1,5 @@
#include "functions.hpp"
#include "filesystem.hpp"
#include <iostream>
#include <curl/curl.h>
#include <stdlib.h>
@ -34,34 +35,32 @@ std::string Curl::execute(const std::string &url) {
return source;
}
void findSeason(std::set<std::experimental::filesystem::path> &files, int season, const std::string &path) {
namespace fs = std::experimental::filesystem;
void findSeason(std::set<std::string> &files, int season, const std::string &path) {
std::smatch match;
auto episode = std::regex("[sS][0]{0,2000}" + std::to_string(season) + "[eE][0-9]{1,2000}");
for( auto& p: fs::directory_iterator(path) ) {
if(fs::is_directory(p)) {
findSeason(files, season, p.path());
for( const auto& p: FSLib::Directory(path) ) {
if(FSLib::isDirectory(path + "/" + p)) {
findSeason(files, season, path + "/" + p);
continue;
}
std::string a = p.path().filename();
if( std::regex_search(a, episode) ) {
files.insert(p.path());
if( std::regex_search(p, episode) ) {
files.insert(path + "/" + p);
}
}
}
void iterateFS(std::set<int> &seasons, const std::string &path) {
namespace fs = std::experimental::filesystem;
std::smatch match;
auto episode = std::regex("[sS][0-9]{1,2000}[eE][0-9]{1,2000}");
for( auto& p: fs::directory_iterator(path) ) {
if(fs::is_directory(p)) {
iterateFS(seasons, p.path());
for( const auto& p: FSLib::Directory(path) ) {
if(FSLib::isDirectory(path + "/" + p)) {
iterateFS(seasons, path + "/" + p);
continue;
}
std::string a = p.path().filename();
if( std::regex_search(a, match, episode) ) {
a = match[0];
if( std::regex_search(p, match, episode) ) {
std::string a = match[0];
a = std::regex_replace(a, std::regex("[eE][0-9]{1,2000}"), "");
a = a.substr(1);
seasons.insert(std::stoi(a));
@ -70,7 +69,6 @@ void iterateFS(std::set<int> &seasons, const std::string &path) {
}
std::string getDefUrl( const std::string &show, const std::string &language, Curl &c ) {
using namespace std::string_literals;
auto search = std::regex_replace(show, std::regex(" "), "+");
auto source_code = c.execute("https://www.thetvdb.com/search?q=" + search + "&l=" + language);
auto series = std::regex("<td><a href=\"/series.*?</td>");

View File

@ -3,7 +3,6 @@
#include <string>
#include <set>
#include <experimental/filesystem>
#include <curl/curl.h>
class Curl {
@ -16,7 +15,7 @@ private:
};
std::string getDefUrl( const std::string &show, const std::string &language, Curl &c );
void findSeason(std::set<std::experimental::filesystem::path> &files, int season, const std::string &path);
void findSeason(std::set<std::string> &files, int season, const std::string &path);
void iterateFS(std::set<int> &seasons, const std::string &path);
void printHelp();

View File

@ -6,7 +6,7 @@
#include <set>
#include <string>
#include <sstream>
#include <filesystem>
#include "filesystem.hpp"
void singleSeason( const std::string &path, const std::string &show, int season, std::string url );
void multipleSeasons( const std::string &path, const std::string &show, const std::set<int> seasons );
@ -18,7 +18,6 @@ bool linux{false};
Curl c;
int main(int argc, char** argv) {
namespace fs = std::filesystem;
std::map<std::string, std::string> languages{
{"en", "English"}, {"sv", "Svenska"}, {"no", "Norsk"}, {"da", "Dansk"}, {"fi", "Suomeksi"},
{"nl", "Nederlands"}, {"de", "Deutsch"}, {"it", "Italiano"}, {"es", "Español"}, {"fr", "Français"},
@ -46,7 +45,7 @@ int main(int argc, char** argv) {
} else if ( !(strcmp("-sp", argv[x]) && strcmp("--show-path", argv[x])) ) {
path = std::string(argv[x+1]);
x++;
if( !fs::exists(fs::absolute(path)) )
if( !FSLib::isDirectory(path) )
change_dir = true;
} else if ( !(strcmp("-t", argv[x]) && strcmp("--trust", argv[x])) ) {
trust = true;
@ -73,13 +72,12 @@ int main(int argc, char** argv) {
}
while( change_dir ) {
auto abs = fs::absolute(path);
if( !fs::exists(abs) ) {
if( !FSLib::isDirectory(path) ) {
std::cout << "This directory doesn't exist, please insert a correct path: " << std::endl;
std::getline(std::cin, path);
continue;
}
std::cout << "Is this the right directory? " << fs::canonical(abs) << std::endl;
std::cout << "Is this the right directory? " << FSLib::canonical(path) << std::endl;
std::string response;
std::cin >> response;
std::cin.ignore(1,'\n');
@ -92,10 +90,8 @@ int main(int argc, char** argv) {
}
}
path = fs::absolute(path);
if( show.empty() ) {
show = std::regex_replace(fs::canonical(path).c_str(), std::regex(".*/"), "");
show = std::regex_replace(FSLib::canonical(path).c_str(), std::regex(".*/"), "");
std::cout << "Is this the right show name? " << show << std::endl;
std::string response;
std::cin >> response;
@ -155,16 +151,24 @@ void singleSeason( const std::string &path, const std::string &show, int season,
}
if( episodes.empty() )
return;
std::set<std::experimental::filesystem::path> files;
std::set<std::experimental::filesystem::path> renamed_files;
std::set<std::string> files;
std::set<std::string> renamed_files;
std::vector<std::string> renamed_episodes;
renamed_episodes.resize(episodes.size());
findSeason(files, season, path);
if( files.empty() )
return;
for( const auto &x : files ) {
std::string name = x.filename();
std::string dir = x.parent_path();
auto last = x.find_last_of("/");
std::string name;
std::string dir;
if( last == static_cast<size_t>(-1) ) {
name = x;
dir = ".";
} else {
name = x.substr(last+1);
dir = x.substr(0, last);
}
unsigned long num;
try {
num = std::stoi(std::regex_replace(name, std::regex(".*[sS][0]{0,2000}" + std::to_string(season) + "[eE]([0-9]{1,2000}).*"), "$1"));
@ -185,9 +189,8 @@ void singleSeason( const std::string &path, const std::string &show, int season,
}
}
auto orig = files.begin();
namespace fs = std::experimental::filesystem;
for(auto renamed = renamed_files.begin(); renamed != renamed_files.end(); ++renamed) {
std::cout << std::string((*orig).filename()) << " -> " << std::string((*renamed).filename()) << std::endl;
std::cout << *orig << " -> " << *renamed << std::endl;
++orig;
}
if( !trust ) {
@ -200,9 +203,8 @@ void singleSeason( const std::string &path, const std::string &show, int season,
return;
}
orig = files.begin();
namespace fs = std::experimental::filesystem;
for(auto renamed = renamed_files.begin(); renamed != renamed_files.end(); ++renamed) {
fs::rename(*orig, *renamed);
FSLib::rename(*orig, *renamed);
++orig;
}
}