-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
fef15a6
commit 4db424b
Showing
4 changed files
with
240 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
#include "config.hpp" | ||
|
||
#include <CLI/CLI.hpp> | ||
/* Copyright (C) 2023 Patrick Ziegler <zipat@proton.me> | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#include <spdlog/spdlog.h> | ||
#include <toml.hpp> | ||
|
||
#include <mediacopier/version.hpp> | ||
|
||
#include <filesystem> | ||
#include <fstream> | ||
|
||
namespace fs = std::filesystem; | ||
|
||
constexpr static const char* DEFAULT_PATTERN = "%Y/%W/IMG_%Y%m%d_%H%M%S"; | ||
constexpr static const char* PERSISTENT_CONFIG = ".mediacopier"; | ||
|
||
std::pair<Config::ParseResult, int> Config::parseArgs(int argc, char *argv[]) noexcept | ||
{ | ||
CLI::App app{mediacopier::MEDIACOPIER_PROJECT_NAME}; | ||
app.set_version_flag("-v,--version", mediacopier::MEDIACOPIER_VERSION); | ||
|
||
auto copyapp = app.add_subcommand("copy", "Copy some files"); | ||
copyapp->callback([this]() { cmd = Command::Copy; }); | ||
copyapp->add_option("inputDir", inputDir)->required()->check(CLI::ExistingDirectory); | ||
copyapp->add_option("outputDir", outputDir)->required(); | ||
copyapp->add_option("-p,--pattern", pattern); | ||
|
||
auto moveapp = app.add_subcommand("move", "Move some files"); | ||
moveapp->callback([this]() { cmd = Command::Move; }); | ||
moveapp->add_option("inputDir", inputDir)->required()->check(CLI::ExistingDirectory); | ||
moveapp->add_option("outputDir", outputDir)->required(); | ||
moveapp->add_option("-p,--pattern", pattern); | ||
|
||
int ret = 0; | ||
try { | ||
app.parse(argc, argv); | ||
return {ParseResult::Continue, ret}; | ||
} catch(const CLI::Success &err) { | ||
// printing help message or version info | ||
ret = app.exit(err); | ||
return {ParseResult::Break, ret}; | ||
} catch(const CLI::ParseError &err) { | ||
ret = app.exit(err); | ||
return {ParseResult::Break, ret}; | ||
} | ||
} | ||
|
||
void Config::loadPersistentConfig() noexcept | ||
{ | ||
auto persistentConfigFile = outputDir / PERSISTENT_CONFIG; | ||
if (!fs::exists(persistentConfigFile)) { | ||
return; | ||
} | ||
try { | ||
const auto data = toml::parse(persistentConfigFile); | ||
if (pattern.empty()) { | ||
pattern = toml::find<std::string>(data, "pattern"); | ||
} | ||
} catch (const std::exception& err) { | ||
spdlog::error("Failed to parse config: " + std::string{err.what()}); | ||
} | ||
} | ||
|
||
void Config::storePersistentConfig() const noexcept | ||
{ | ||
if (!fs::exists(outputDir)) { | ||
return; | ||
} | ||
auto persistentConfigFile = outputDir / PERSISTENT_CONFIG; | ||
toml::value lastRun{{"pattern", pattern}}; | ||
std::ofstream out{persistentConfigFile}; | ||
out << "# this file is updated on every run of mediacopier" | ||
<< ", manual changes might be lost\n" << lastRun; | ||
} | ||
|
||
void Config::finalize() noexcept | ||
{ | ||
if (pattern.empty()) { | ||
pattern = DEFAULT_PATTERN; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
/* Copyright (C) 2023 Patrick Ziegler <zipat@proton.me> | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#include <filesystem> | ||
|
||
struct Config | ||
{ | ||
enum class Command { | ||
Copy, | ||
Move | ||
}; | ||
|
||
enum class ParseResult { | ||
Continue, | ||
Break | ||
}; | ||
|
||
std::pair<ParseResult, int> parseArgs(int argc, char *argv[]) noexcept; | ||
void loadPersistentConfig() noexcept; | ||
void storePersistentConfig() const noexcept; | ||
void finalize() noexcept; | ||
|
||
Command cmd = Command::Copy; | ||
std::filesystem::path inputDir; | ||
std::filesystem::path outputDir; | ||
std::string pattern; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,38 +1,112 @@ | ||
#include <CLI/CLI.hpp> | ||
/* Copyright (C) 2023 Patrick Ziegler <zipat@proton.me> | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#include <iostream> | ||
#include <mediacopier/file_info_factory.hpp> | ||
#include <mediacopier/file_register.hpp> | ||
#include <mediacopier/operation_copy_jpeg.hpp> | ||
#include <mediacopier/operation_move_jpeg.hpp> | ||
|
||
int main(int argc, char** argv) { | ||
CLI::App app{"App description"}; | ||
//argv = app.ensure_utf8(argv); | ||
#include <range/v3/view/filter.hpp> | ||
#include <range/v3/view/transform.hpp> | ||
#include <range/v3/iterator_range.hpp> | ||
|
||
app.set_version_flag("-v,--version", "1.0.0"); | ||
#include <spdlog/spdlog.h> | ||
|
||
std::string pattern = "default"; | ||
std::string filename = "default file"; | ||
std::string command = "none"; | ||
bool slim = false; | ||
#include <atomic> | ||
#include <csignal> | ||
|
||
auto copyapp = app.add_subcommand("copy", "Copy some files"); | ||
copyapp->add_option("-p,--pattern", pattern, "A help string"); | ||
copyapp->callback([&command]() { command = "copy"; }); | ||
auto opt = copyapp->add_option("filename", filename); | ||
opt->required(); | ||
#include "config.hpp" | ||
|
||
auto moveapp = app.add_subcommand("move", "Move some files"); | ||
moveapp->add_option("-p,--pattern", pattern, "A help string"); | ||
namespace fs = std::filesystem; | ||
namespace mc = mediacopier; | ||
|
||
auto simapp = app.add_subcommand("simulate", "Do nothing, just simulate what would happen"); | ||
simapp->add_option("-p,--pattern", pattern, "A help string"); | ||
static volatile std::atomic<bool> operationCancelled(false); | ||
|
||
auto guiapp = app.add_subcommand("gui"); | ||
guiapp->add_flag("--slim", slim, "Instantiate the slim version"); | ||
auto valid_media_files(const fs::path& path) | ||
{ | ||
static auto is_regular_file = [](const fs::directory_entry& path) { | ||
return fs::is_regular_file(path); | ||
}; | ||
static auto is_valid = [](const mc::FileInfoPtr& file) { | ||
return file != nullptr; | ||
}; | ||
return ranges::make_iterator_range( | ||
fs::recursive_directory_iterator(path), | ||
fs::recursive_directory_iterator()) | ||
| ranges::views::filter(is_regular_file) | ||
| ranges::views::transform(mc::to_file_info_ptr) | ||
| ranges::views::filter(is_valid); | ||
} | ||
|
||
template <typename Operation> | ||
auto exec(const Config& config) -> void | ||
{ | ||
// register callback for graceful shutdown via CTRL-C | ||
std::signal(SIGINT, [](int) -> void { | ||
operationCancelled.store(true); | ||
}); | ||
|
||
spdlog::info("Checking input directory.."); | ||
auto reg = mc::FileRegister{config.outputDir, config.pattern}; | ||
std::optional<fs::path> dest; | ||
|
||
for (auto file : valid_media_files(config.inputDir)) { | ||
if (operationCancelled.load()) { | ||
spdlog::warn("Operation was cancelled.."); | ||
break; | ||
} | ||
try { | ||
if ((dest = reg.add(file)).has_value()) { | ||
spdlog::info("Processing: {} -> {}", | ||
file->path().string(), | ||
dest.value().string()); | ||
Operation op(dest.value()); | ||
file->accept(op); | ||
} | ||
} catch (const std::exception& err) { | ||
spdlog::error(err.what()); | ||
} | ||
} | ||
|
||
spdlog::info("Removing duplicates in destination directory.."); | ||
reg.removeDuplicates(); | ||
|
||
spdlog::info("Done"); | ||
std::signal(SIGINT, SIG_DFL); | ||
} | ||
|
||
int main(int argc, char *argv[]) | ||
{ | ||
Config config; | ||
const auto& [res, ret] = config.parseArgs(argc, argv); | ||
if (res != Config::ParseResult::Continue) { | ||
return ret; | ||
} | ||
config.loadPersistentConfig(); | ||
config.finalize(); | ||
|
||
CLI11_PARSE(app, argc, argv); | ||
switch (config.cmd) { | ||
case Config::Command::Copy: | ||
exec<mediacopier::FileOperationCopyJpeg>(config); | ||
break; | ||
case Config::Command::Move: | ||
exec<mediacopier::FileOperationMoveJpeg>(config); | ||
break; | ||
} | ||
|
||
std::cout << pattern << std::endl | ||
<< filename << std::endl | ||
<< command << std::endl | ||
<< slim << std::endl; | ||
config.storePersistentConfig(); | ||
return 0; | ||
} |