regex for additional files copying
This commit is contained in:
parent
eb85b71651
commit
03e7f29d84
@ -1,5 +1,8 @@
|
||||
# Changelog
|
||||
|
||||
## MLC 1.3.3 (UNRELEASED)
|
||||
- Regex to specify non-music files to copy
|
||||
|
||||
## MLC 1.3.2 (October 10, 2023)
|
||||
- A release purely for CI
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(
|
||||
mlc
|
||||
VERSION 1.3.212
|
||||
VERSION 1.3.3
|
||||
DESCRIPTION "Media Library Compiler: rips your media library to a lossy compilation"
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Maintainer: Yury Gubich <blue@macaw.me>
|
||||
pkgname=mlc
|
||||
pkgver=1.3.212
|
||||
pkgver=1.3.3
|
||||
pkgrel=1
|
||||
pkgdesc="Media Library Compiler: rips your media library to a lossy compilation"
|
||||
arch=('i686' 'x86_64')
|
||||
|
@ -6,22 +6,15 @@ namespace fs = std::filesystem;
|
||||
|
||||
static const std::string flac(".flac");
|
||||
|
||||
Collection::Collection(const std::string& path, TaskManager* tm) :
|
||||
path(fs::canonical(path)),
|
||||
countMusical(0),
|
||||
counted(false),
|
||||
taskManager(tm)
|
||||
{}
|
||||
|
||||
Collection::Collection(const std::filesystem::path& path, TaskManager* tm) :
|
||||
path(fs::canonical(path)),
|
||||
path(path),
|
||||
countMusical(0),
|
||||
counted(false),
|
||||
taskManager(tm)
|
||||
{}
|
||||
|
||||
Collection::~Collection() {
|
||||
}
|
||||
Collection::~Collection()
|
||||
{}
|
||||
|
||||
void Collection::list() const {
|
||||
if (fs::is_regular_file(path))
|
||||
@ -71,13 +64,10 @@ void Collection::convert(const std::string& outPath) {
|
||||
switch (entry.status().type()) {
|
||||
case fs::file_type::regular: {
|
||||
fs::path sourcePath = entry.path();
|
||||
fs::path dstPath = out / sourcePath.stem();
|
||||
if (isMusic(sourcePath))
|
||||
taskManager->queueJob(sourcePath, dstPath);
|
||||
taskManager->queueConvert(sourcePath, out / sourcePath.stem());
|
||||
else
|
||||
fs::copy_file(sourcePath, dstPath, fs::copy_options::overwrite_existing);
|
||||
|
||||
//std::cout << sourcePath << " => " << dstPath << std::endl;
|
||||
taskManager->queueCopy(sourcePath, out / sourcePath.filename());
|
||||
} break;
|
||||
case fs::file_type::directory: {
|
||||
fs::path sourcePath = entry.path();
|
||||
|
@ -10,7 +10,6 @@ class TaskManager;
|
||||
|
||||
class Collection {
|
||||
public:
|
||||
Collection(const std::string& path, TaskManager* tm = nullptr);
|
||||
Collection(const std::filesystem::path& path, TaskManager* tm = nullptr);
|
||||
~Collection();
|
||||
|
||||
|
@ -44,3 +44,10 @@
|
||||
# If it's set to 0 - amount of threads is going to be
|
||||
# as high as your processor can effectively handle
|
||||
#parallel 0
|
||||
|
||||
# Non music files
|
||||
# MLC copies any non-music file it finds in source directory
|
||||
# if it matches the following regex
|
||||
# Allowed value are: [all, none] or regex without any additional syntax,
|
||||
# for example: filesToCopy cover\.jpe?g
|
||||
#filesToCopy all
|
||||
|
@ -16,6 +16,7 @@ enum class Option {
|
||||
source,
|
||||
destination,
|
||||
parallel,
|
||||
filesToCopy,
|
||||
_optionsSize
|
||||
};
|
||||
|
||||
@ -36,7 +37,8 @@ constexpr std::array<std::string_view, static_cast<int>(Option::_optionsSize)> o
|
||||
"type",
|
||||
"source",
|
||||
"destination",
|
||||
"parallel"
|
||||
"parallel",
|
||||
"filesToCopy"
|
||||
});
|
||||
|
||||
constexpr std::array<std::string_view, Settings::_typesSize> types({
|
||||
@ -72,7 +74,10 @@ Settings::Settings(int argc, char ** argv):
|
||||
outputType(std::nullopt),
|
||||
input(std::nullopt),
|
||||
output(std::nullopt),
|
||||
logLevel(std::nullopt)
|
||||
logLevel(std::nullopt),
|
||||
configPath(std::nullopt),
|
||||
threads(std::nullopt),
|
||||
nonMusic(std::nullopt)
|
||||
{
|
||||
for (int i = 1; i < argc; ++i)
|
||||
arguments.push_back(argv[i]);
|
||||
@ -264,6 +269,17 @@ void Settings::readConfigLine(const std::string& line) {
|
||||
if (!threads.has_value() && stream >> count)
|
||||
threads = count;
|
||||
} break;
|
||||
case Option::filesToCopy: {
|
||||
std::string regex;
|
||||
if (!nonMusic.has_value() && stream >> regex) {
|
||||
if (regex == "all")
|
||||
regex = "";
|
||||
else if (regex == "none")
|
||||
regex = "a^";
|
||||
|
||||
nonMusic = regex;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -299,3 +315,11 @@ std::string Settings::resolvePath(const std::string& line) {
|
||||
else
|
||||
return line;
|
||||
}
|
||||
|
||||
bool Settings::matchNonMusic(const std::string& fileName) const {
|
||||
if (nonMusic.has_value())
|
||||
return std::regex_search(fileName, nonMusic.value());
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <functional>
|
||||
#include <cctype>
|
||||
#include <sstream>
|
||||
#include <regex>
|
||||
|
||||
#include "logger/logger.h"
|
||||
|
||||
@ -38,6 +39,7 @@ public:
|
||||
Type getType() const;
|
||||
Action getAction() const;
|
||||
unsigned int getThreads() const;
|
||||
bool matchNonMusic(const std::string& fileName) const;
|
||||
|
||||
bool readConfigFile();
|
||||
void readConfigLine(const std::string& line);
|
||||
@ -63,4 +65,5 @@ private:
|
||||
std::optional<Logger::Severity> logLevel;
|
||||
std::optional<std::string> configPath;
|
||||
std::optional<unsigned int> threads;
|
||||
std::optional<std::regex> nonMusic;
|
||||
};
|
||||
|
@ -21,9 +21,9 @@ TaskManager::TaskManager(const std::shared_ptr<Settings>& settings, const std::s
|
||||
TaskManager::~TaskManager() {
|
||||
}
|
||||
|
||||
void TaskManager::queueJob(const std::filesystem::path& source, const std::filesystem::path& destination) {
|
||||
void TaskManager::queueConvert(const std::filesystem::path& source, const std::filesystem::path& destination) {
|
||||
std::unique_lock<std::mutex> lock(queueMutex);
|
||||
jobs.emplace(source, destination);
|
||||
jobs.emplace(Job::convert, source, destination);
|
||||
|
||||
++maxTasks;
|
||||
logger->setStatusMessage(std::to_string(completeTasks) + "/" + std::to_string(maxTasks));
|
||||
@ -32,6 +32,19 @@ void TaskManager::queueJob(const std::filesystem::path& source, const std::files
|
||||
loopConditional.notify_one();
|
||||
}
|
||||
|
||||
void TaskManager::queueCopy(const std::filesystem::path& source, const std::filesystem::path& destination) {
|
||||
if (!settings->matchNonMusic(source.filename()))
|
||||
return;
|
||||
|
||||
std::unique_lock<std::mutex> lock(queueMutex);
|
||||
jobs.emplace(Job::copy, source, destination);
|
||||
++maxTasks;
|
||||
logger->setStatusMessage(std::to_string(completeTasks) + "/" + std::to_string(maxTasks));
|
||||
|
||||
lock.unlock();
|
||||
loopConditional.notify_one();
|
||||
}
|
||||
|
||||
bool TaskManager::busy() const {
|
||||
std::lock_guard lock(queueMutex);
|
||||
return !jobs.empty();
|
||||
@ -61,28 +74,16 @@ void TaskManager::loop() {
|
||||
if (terminate)
|
||||
return;
|
||||
|
||||
std::pair<std::string, std::string> pair = jobs.front();
|
||||
Job job = jobs.front();
|
||||
++busyThreads;
|
||||
jobs.pop();
|
||||
lock.unlock();
|
||||
|
||||
JobResult result;
|
||||
switch (settings->getType()) {
|
||||
case Settings::mp3:
|
||||
result = mp3Job(pair.first, pair.second + ".mp3", settings->getLogLevel());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
JobResult result = execute(job);
|
||||
|
||||
lock.lock();
|
||||
++completeTasks;
|
||||
logger->printNested(
|
||||
result.first ? "Encoding complete but there are messages about it" : "Encoding failed!",
|
||||
{"Source: \t" + pair.first, "Destination: \t" + pair.second},
|
||||
result.second,
|
||||
std::to_string(completeTasks) + "/" + std::to_string(maxTasks)
|
||||
);
|
||||
printResilt(job, result);
|
||||
--busyThreads;
|
||||
lock.unlock();
|
||||
waitConditional.notify_all();
|
||||
@ -118,14 +119,72 @@ unsigned int TaskManager::getCompleteTasks() const {
|
||||
return completeTasks;
|
||||
}
|
||||
|
||||
TaskManager::JobResult TaskManager::execute(const Job& job) {
|
||||
switch (job.type) {
|
||||
case Job::copy:
|
||||
return copyJob(job, settings->getLogLevel());
|
||||
case Job::convert:
|
||||
switch (settings->getType()) {
|
||||
case Settings::mp3:
|
||||
return mp3Job(job, settings->getLogLevel());
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return {false, {
|
||||
{Logger::Severity::error, "Unknown job type: " + std::to_string(job.type)}
|
||||
}};
|
||||
}
|
||||
|
||||
void TaskManager::printResilt(const TaskManager::Job& job, const TaskManager::JobResult& result) {
|
||||
std::string msg;
|
||||
switch (job.type) {
|
||||
case Job::copy:
|
||||
if (result.first)
|
||||
msg = "File copy complete, but there are messages about it:";
|
||||
else
|
||||
msg = "File copy failed!";
|
||||
break;
|
||||
case Job::convert:
|
||||
if (result.first)
|
||||
msg = "Encoding complete but there are messages about it:";
|
||||
else
|
||||
msg = "Encoding failed!";
|
||||
break;
|
||||
}
|
||||
|
||||
logger->printNested(
|
||||
msg,
|
||||
{"Source: \t" + job.source.string(), "Destination: \t" + job.destination.string()},
|
||||
result.second,
|
||||
std::to_string(completeTasks) + "/" + std::to_string(maxTasks)
|
||||
);
|
||||
}
|
||||
|
||||
TaskManager::JobResult TaskManager::mp3Job(
|
||||
const std::filesystem::path& source,
|
||||
const std::filesystem::path& destination,
|
||||
const TaskManager::Job& job,
|
||||
Logger::Severity logLevel)
|
||||
{
|
||||
FLACtoMP3 convertor(logLevel);
|
||||
convertor.setInputFile(source);
|
||||
convertor.setOutputFile(destination);
|
||||
convertor.setInputFile(job.source);
|
||||
convertor.setOutputFile(job.destination.string() + ".mp3");
|
||||
bool result = convertor.run();
|
||||
return {result, convertor.getHistory()};
|
||||
}
|
||||
|
||||
TaskManager::JobResult TaskManager::copyJob(const TaskManager::Job& job, Logger::Severity logLevel) {
|
||||
(void)(logLevel);
|
||||
bool success = std::filesystem::copy_file(
|
||||
job.source,
|
||||
job.destination,
|
||||
std::filesystem::copy_options::overwrite_existing
|
||||
);
|
||||
|
||||
return {success, {}};
|
||||
}
|
||||
|
||||
TaskManager::Job::Job(Type type, const std::filesystem::path& source, std::filesystem::path destination):
|
||||
type(type),
|
||||
source(source),
|
||||
destination(destination) {}
|
||||
|
@ -18,13 +18,15 @@
|
||||
#include "logger/printer.h"
|
||||
|
||||
class TaskManager {
|
||||
typedef std::pair<bool, std::list<Logger::Message>> JobResult;
|
||||
using JobResult = std::pair<bool, std::list<Logger::Message>>;
|
||||
struct Job;
|
||||
public:
|
||||
TaskManager(const std::shared_ptr<Settings>& settings, const std::shared_ptr<Printer>& logger);
|
||||
~TaskManager();
|
||||
|
||||
void start();
|
||||
void queueJob(const std::filesystem::path& source, const std::filesystem::path& destination);
|
||||
void queueConvert(const std::filesystem::path& source, const std::filesystem::path& destination);
|
||||
void queueCopy(const std::filesystem::path& source, const std::filesystem::path& destination);
|
||||
void stop();
|
||||
bool busy() const;
|
||||
void wait();
|
||||
@ -33,7 +35,11 @@ public:
|
||||
|
||||
private:
|
||||
void loop();
|
||||
static JobResult mp3Job(const std::filesystem::path& source, const std::filesystem::path& destination, Logger::Severity logLevel);
|
||||
JobResult execute(const Job& job);
|
||||
void printResilt(const Job& job, const JobResult& result);
|
||||
static JobResult mp3Job(const Job& job, Logger::Severity logLevel);
|
||||
static JobResult copyJob(const Job& job, Logger::Severity logLevel);
|
||||
|
||||
private:
|
||||
std::shared_ptr<Settings> settings;
|
||||
std::shared_ptr<Printer> logger;
|
||||
@ -46,7 +52,17 @@ private:
|
||||
std::condition_variable loopConditional;
|
||||
std::condition_variable waitConditional;
|
||||
std::vector<std::thread> threads;
|
||||
std::queue<std::pair<std::filesystem::path, std::filesystem::path>> jobs;
|
||||
std::queue<Job> jobs;
|
||||
|
||||
};
|
||||
|
||||
struct TaskManager::Job {
|
||||
enum Type {
|
||||
copy,
|
||||
convert
|
||||
};
|
||||
Job(Type type, const std::filesystem::path& source, std::filesystem::path destination);
|
||||
Type type;
|
||||
std::filesystem::path source;
|
||||
std::filesystem::path destination;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user