Space treatment, a bit more memory safe handling, exclude option, typo fixes
All checks were successful
MLC Release workflow / Archlinux (release) Successful in 1m35s

This commit is contained in:
Blue 2025-03-30 22:07:20 +03:00
parent ceab08a26d
commit bf88e05a13
Signed by: blue
GPG key ID: 9B203B252A63EE38
10 changed files with 111 additions and 73 deletions

View file

@ -6,11 +6,12 @@ namespace fs = std::filesystem;
static const std::string flac(".flac");
Collection::Collection(const std::filesystem::path& path, TaskManager* tm) :
Collection::Collection(const std::filesystem::path& path, const std::shared_ptr<TaskManager>& tm, const std::shared_ptr<Settings>& st):
path(path),
countMusical(0),
counted(false),
taskManager(tm)
taskManager(tm),
settings(st)
{}
Collection::~Collection()
@ -33,13 +34,16 @@ uint32_t Collection::countMusicFiles() const {
++countMusical;
} else if (fs::is_directory(path)) {
for (const fs::directory_entry& entry : fs::directory_iterator(path)) {
if (settings->isExcluded(entry.path()))
continue;
switch (entry.status().type()) {
case fs::file_type::regular:
if (isMusic(entry.path()))
++countMusical;
break;
case fs::file_type::directory: {
Collection collection(entry.path());
Collection collection(entry.path(), taskManager, settings);
countMusical += collection.countMusicFiles();
} break;
default:
@ -53,25 +57,24 @@ uint32_t Collection::countMusicFiles() const {
}
void Collection::convert(const std::string& outPath) {
if (taskManager == nullptr)
throw 6;
fs::path out = fs::absolute(outPath);
fs::create_directories(out);
out = fs::canonical(outPath);
for (const fs::directory_entry& entry : fs::directory_iterator(path)) {
fs::path sourcePath = entry.path();
if (settings->isExcluded(sourcePath))
continue;
switch (entry.status().type()) {
case fs::file_type::regular: {
fs::path sourcePath = entry.path();
if (isMusic(sourcePath))
taskManager->queueConvert(sourcePath, out / sourcePath.stem());
else
taskManager->queueCopy(sourcePath, out / sourcePath.filename());
} break;
case fs::file_type::directory: {
fs::path sourcePath = entry.path();
Collection collection(sourcePath, taskManager);
Collection collection(sourcePath, taskManager, settings);
fs::path::iterator itr = sourcePath.end();
--itr;
collection.convert(std::string(out / *itr));

View file

@ -3,14 +3,16 @@
#include <string>
#include <iostream>
#include <filesystem>
#include <memory>
#include "settings.h"
#include "flactomp3.h"
class TaskManager;
class Collection {
public:
Collection(const std::filesystem::path& path, TaskManager* tm = nullptr);
Collection(const std::filesystem::path& path, const std::shared_ptr<TaskManager>& tm, const std::shared_ptr<Settings>& st);
~Collection();
void list() const;
@ -24,6 +26,7 @@ private:
std::filesystem::path path;
mutable uint32_t countMusical;
mutable bool counted;
TaskManager* taskManager;
std::shared_ptr<TaskManager> taskManager;
std::shared_ptr<Settings> settings;
};

View file

@ -92,7 +92,15 @@
# Variable bitrate
# Switches on or off variable bitrate
# VBR files are usually smaller, but not supped to be worse
# VBR files are usually smaller, but not supposed to be worse
# in terms of quality. VBR files might be a bit more tricky for the player
# Allowed values are: [true, false]
#vbr true
# Exclude
# MLC renders any music file it finds in source directory
# UNLESS its path matches the following regex
# Allowed value is the regex without any additional syntax,
# for example: exclude [Ss]hamefull?\s[Ss]ong[Ss]
# If you don't want to exclude anything leave this option blank
#exclude

View file

@ -57,16 +57,16 @@ int main(int argc, char **argv) {
}
logger->setSeverity(settings->getLogLevel());
TaskManager taskManager(settings, logger);
taskManager.start();
std::shared_ptr<TaskManager> taskManager = std::make_shared<TaskManager>(settings, logger);
taskManager->start();
std::chrono::time_point start = std::chrono::system_clock::now();
Collection collection(input, &taskManager);
Collection collection(input, taskManager, settings);
collection.convert(output);
taskManager.wait();
taskManager->wait();
std::cout << std::endl;
taskManager.stop();
taskManager->stop();
std::chrono::time_point end = std::chrono::system_clock::now();
std::chrono::duration<double> seconds = end - start;

View file

@ -17,6 +17,7 @@ enum class Option {
destination,
parallel,
filesToCopy,
exclude,
encodingQuality,
outputQuality,
vbr,
@ -42,6 +43,7 @@ constexpr std::array<std::string_view, static_cast<int>(Option::_optionsSize)> o
"destination",
"parallel",
"filesToCopy",
"exclude",
"encodingQuality",
"outputQuality",
"vbr"
@ -264,69 +266,74 @@ void Settings::readConfigLine(const std::string& line) {
if (option == Option::_optionsSize)
return;
std::string value;
std::getline(stream >> std::ws, value);
strip(value);
if (value.empty())
return;
switch (option) {
case Option::level: {
std::string lv;
if (!logLevel.has_value() && stream >> lv) {
if (!logLevel.has_value() && std::istringstream(value) >> lv) {
Logger::Severity level = Logger::stringToSeverity(lv);
if (level < Logger::Severity::_severitySize)
logLevel = level;
}
} break;
case Option::type: {
std::string lv;
if (!outputType.has_value() && stream >> lv) {
Type type = stringToType(lv);
std::string tp;
if (!outputType.has_value() && std::istringstream(value) >> tp) {
Type type = stringToType(tp);
if (type < _typesSize)
outputType = type;
}
} break;
case Option::source: {
std::string path;
if (stream >> path) {
if (!input.has_value()) {
input = path;
} else if (!output.has_value()) {
output = input;
input = path;
}
if (!input.has_value()) {
input = value;
} else if (!output.has_value()) {
output = input;
input = value;
}
} break;
case Option::destination: {
std::string path;
if (!output.has_value() && stream >> path)
output = path;
if (!output.has_value())
output = value;
} break;
case Option::parallel: {
unsigned int count;
if (!threads.has_value() && stream >> count)
if (!threads.has_value() && std::istringstream(value) >> 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^";
if (!nonMusic.has_value()) {
if (value == "all")
value = "";
else if (value == "none")
value = "a^";
nonMusic = regex;
nonMusic = value;
}
} break;
case Option::exclude: {
if (!excluded.has_value())
excluded = value;
} break;
case Option::outputQuality: {
unsigned int value;
if (!outputQuality.has_value() && stream >> value)
outputQuality = std::clamp(value, minQuality, maxQuality);
unsigned int quality;
if (!outputQuality.has_value() && std::istringstream(value) >> quality)
outputQuality = std::clamp(quality, minQuality, maxQuality);
} break;
case Option::encodingQuality: {
unsigned int value;
if (!encodingQuality.has_value() && stream >> value)
encodingQuality = std::clamp(value, minQuality, maxQuality);
unsigned int quality;
if (!encodingQuality.has_value() && std::istringstream(value) >> quality)
encodingQuality = std::clamp(quality, minQuality, maxQuality);
} break;
case Option::vbr: {
bool value;
if (!vbr.has_value() && stream >> std::boolalpha >> value)
vbr = value;
bool vb;
if (!vbr.has_value() && std::istringstream(value) >> std::boolalpha >> vb)
vbr = vb;
} break;
default:
break;
@ -365,9 +372,16 @@ std::string Settings::resolvePath(const std::string& line) {
}
bool Settings::matchNonMusic(const std::string& fileName) const {
if (nonMusic.has_value())
return std::regex_search(fileName, nonMusic.value());
else
if (!nonMusic.has_value())
return true;
return std::regex_search(fileName, nonMusic.value());
}
bool Settings::isExcluded(const std::string& path) const {
if (!excluded.has_value())
return false;
return std::regex_search(path, excluded.value());
}

View file

@ -40,6 +40,7 @@ public:
Action getAction() const;
unsigned int getThreads() const;
bool matchNonMusic(const std::string& fileName) const;
bool isExcluded(const std::string& path) const;
unsigned char getEncodingQuality() const;
unsigned char getOutputQuality() const;
bool getVBR() const;
@ -69,6 +70,7 @@ private:
std::optional<std::string> configPath;
std::optional<unsigned int> threads;
std::optional<std::regex> nonMusic;
std::optional<std::regex> excluded;
std::optional<unsigned char> encodingQuality;
std::optional<unsigned char> outputQuality;
std::optional<bool> vbr;

View file

@ -22,6 +22,9 @@ TaskManager::~TaskManager() {
}
void TaskManager::queueConvert(const std::filesystem::path& source, const std::filesystem::path& destination) {
if (settings->isExcluded(source))
return;
std::unique_lock<std::mutex> lock(queueMutex);
jobs.emplace(Job::convert, source, destination);
@ -83,7 +86,7 @@ void TaskManager::loop() {
lock.lock();
++completeTasks;
printResilt(job, result);
printResult(job, result);
--busyThreads;
lock.unlock();
waitConditional.notify_all();
@ -138,7 +141,7 @@ TaskManager::JobResult TaskManager::execute(Job& job) {
}};
}
void TaskManager::printResilt(const TaskManager::Job& job, const TaskManager::JobResult& result) {
void TaskManager::printResult(const TaskManager::Job& job, const TaskManager::JobResult& result) {
std::string msg;
switch (job.type) {
case Job::copy:

View file

@ -36,7 +36,7 @@ public:
private:
void loop();
JobResult execute(Job& job);
void printResilt(const Job& job, const JobResult& result);
void printResult(const Job& job, const JobResult& result);
static JobResult mp3Job(const Job& job, const std::shared_ptr<Settings>& settings);
static JobResult copyJob(const Job& job, const std::shared_ptr<Settings>& settings);