Compare commits

...

4 Commits

Author SHA1 Message Date
Blue 3971a5b662
pthreads for compatibility 2023-10-20 18:12:26 -03:00
Blue 2cce5f52f0
build scenario changes 2023-10-20 17:39:27 -03:00
Blue 5c3a4a592e
encoding settings 2023-10-13 16:10:08 -03:00
Blue 03e7f29d84
regex for additional files copying 2023-10-12 22:00:16 -03:00
15 changed files with 360 additions and 79 deletions

View File

@ -1,5 +1,9 @@
# Changelog # Changelog
## MLC 1.3.3 (October 13, 2023)
- Regex to specify non-music files to copy
- Encoding settings (VBR/CBR, encoding quality, output quality)
## MLC 1.3.2 (October 10, 2023) ## MLC 1.3.2 (October 10, 2023)
- A release purely for CI - A release purely for CI

View File

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.5) cmake_minimum_required(VERSION 3.5)
project( project(
mlc mlc
VERSION 1.3.212 VERSION 1.3.3
DESCRIPTION "Media Library Compiler: rips your media library to a lossy compilation" DESCRIPTION "Media Library Compiler: rips your media library to a lossy compilation"
LANGUAGES CXX LANGUAGES CXX
) )
@ -25,24 +25,25 @@ message("Compilation options: " ${COMPILE_OPTIONS})
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(PkgConfig REQUIRED)
find_package(FLAC REQUIRED) find_package(FLAC REQUIRED)
find_package(JPEG REQUIRED) find_package(JPEG REQUIRED)
find_package(LAME REQUIRED)
find_package(TAGLIB REQUIRED)
find_package(Threads REQUIRED)
pkg_check_modules(LAME REQUIRED IMPORTED_TARGET lame) add_executable(${PROJECT_NAME})
pkg_check_modules(TAGLIB REQUIRED IMPORTED_TARGET taglib)
add_executable(mlc)
target_compile_options(${PROJECT_NAME} PRIVATE ${COMPILE_OPTIONS}) target_compile_options(${PROJECT_NAME} PRIVATE ${COMPILE_OPTIONS})
add_subdirectory(src) add_subdirectory(src)
target_link_libraries(mlc target_link_libraries(${PROJECT_NAME}
FLAC::FLAC FLAC::FLAC
PkgConfig::LAME LAME::LAME
JPEG::JPEG JPEG::JPEG
PkgConfig::TAGLIB TAGLIB::TAGLIB
Threads::Threads
) )
install(TARGETS mlc RUNTIME DESTINATION bin) install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION bin)

23
cmake/FindFLAC.cmake Normal file
View File

@ -0,0 +1,23 @@
find_path(FLAC_INCLUDE_DIR FLAC/stream_decoder.h)
find_library(FLAC_LIBRARIES FLAC NAMES flac)
if(FLAC_INCLUDE_DIR AND FLAC_LIBRARIES)
set(FLAC_FOUND TRUE)
endif()
if(FLAC_FOUND)
add_library(FLAC::FLAC SHARED IMPORTED)
set_target_properties(FLAC::FLAC PROPERTIES
IMPORTED_LOCATION "${FLAC_LIBRARIES}"
INTERFACE_INCLUDE_DIRECTORIES "${FLAC_INCLUDE_DIR}/FLAC"
INTERFACE_LINK_LIBRARIES "${FLAC_LIBRARIES}"
)
if (NOT FLAC_FIND_QUIETLY)
message(STATUS "Found FLAC includes: ${FLAC_INCLUDE_DIR}/FLAC")
message(STATUS "Found FLAC library: ${FLAC_LIBRARIES}")
endif ()
else()
if (FLAC_FIND_REQUIRED)
message(FATAL_ERROR "Could NOT find FLAC development files")
endif ()
endif()

View File

@ -1,20 +1,26 @@
#copied from here, thank you #copied from here, thank you
#https://github.com/sipwise/sems/blob/master/cmake/FindLame.cmake #https://github.com/sipwise/sems/blob/master/cmake/FindLame.cmake
FIND_PATH(LAME_INCLUDE_DIR lame/lame.h) find_path(LAME_INCLUDE_DIR lame/lame.h)
FIND_LIBRARY(LAME_LIBRARIES NAMES mp3lame) find_library(LAME_LIBRARIES lame NAMES mp3lame)
IF(LAME_INCLUDE_DIR AND LAME_LIBRARIES) if(LAME_INCLUDE_DIR AND LAME_LIBRARIES)
SET(LAME_FOUND TRUE) set(LAME_FOUND TRUE)
ENDIF(LAME_INCLUDE_DIR AND LAME_LIBRARIES) endif(LAME_INCLUDE_DIR AND LAME_LIBRARIES)
IF(LAME_FOUND) if(LAME_FOUND)
IF (NOT Lame_FIND_QUIETLY) add_library(LAME::LAME SHARED IMPORTED)
MESSAGE(STATUS "Found lame includes: ${LAME_INCLUDE_DIR}/lame/lame.h") set_target_properties(LAME::LAME PROPERTIES
MESSAGE(STATUS "Found lame library: ${LAME_LIBRARIES}") IMPORTED_LOCATION "${LAME_LIBRARIES}"
ENDIF (NOT Lame_FIND_QUIETLY) INTERFACE_INCLUDE_DIRECTORIES "${LAME_INCLUDE_DIR}/lame"
ELSE(LAME_FOUND) INTERFACE_LINK_LIBRARIES "${LAME_LIBRARIES}"
IF (Lame_FIND_REQUIRED) )
MESSAGE(FATAL_ERROR "Could NOT find lame development files") if (NOT Lame_FIND_QUIETLY)
ENDIF (Lame_FIND_REQUIRED) message(STATUS "Found lame includes: ${LAME_INCLUDE_DIR}/lame")
ENDIF(LAME_FOUND) message(STATUS "Found lame library: ${LAME_LIBRARIES}")
endif (NOT Lame_FIND_QUIETLY)
else(LAME_FOUND)
if (Lame_FIND_REQUIRED)
message(FATAL_ERROR "Could NOT find lame development files")
endif (Lame_FIND_REQUIRED)
endif(LAME_FOUND)

24
cmake/FindTAGLIB.cmake Normal file
View File

@ -0,0 +1,24 @@
find_path(TAGLIB_INCLUDE_DIR taglib/id3v2tag.h)
find_library(TAGLIB_LIBRARIES taglib NAMES TAGLIB tag)
if(TAGLIB_INCLUDE_DIR AND TAGLIB_LIBRARIES)
set(TAGLIB_FOUND TRUE)
endif()
if(TAGLIB_FOUND)
add_library(TAGLIB::TAGLIB SHARED IMPORTED)
set_target_properties(TAGLIB::TAGLIB PROPERTIES
IMPORTED_LOCATION "${TAGLIB_LIBRARIES}"
INTERFACE_INCLUDE_DIRECTORIES "${FLAC_INCLUDE_DIR}/taglib"
INTERFACE_LINK_LIBRARIES "${TAGLIB_LIBRARIES}"
)
if (NOT TAGLIB_FIND_QUIETLY)
message(STATUS "Found TAGLIB includes: ${FLAC_INCLUDE_DIR}/taglib")
message(STATUS "Found TAGLIB library: ${TAGLIB_LIBRARIES}")
endif ()
else()
if (TAGLIB_FIND_REQUIRED)
message(FATAL_ERROR "Could NOT find TAGLIB development files")
endif ()
endif()

View File

@ -1,6 +1,6 @@
# Maintainer: Yury Gubich <blue@macaw.me> # Maintainer: Yury Gubich <blue@macaw.me>
pkgname=mlc pkgname=mlc
pkgver=1.3.212 pkgver=1.3.3
pkgrel=1 pkgrel=1
pkgdesc="Media Library Compiler: rips your media library to a lossy compilation" pkgdesc="Media Library Compiler: rips your media library to a lossy compilation"
arch=('i686' 'x86_64') arch=('i686' 'x86_64')

View File

@ -6,23 +6,16 @@ namespace fs = std::filesystem;
static const std::string flac(".flac"); static const std::string flac(".flac");
Collection::Collection(const std::string& path, TaskManager* tm) : Collection::Collection(const std::filesystem::path& path, TaskManager* tm) :
path(fs::canonical(path)), path(path),
countMusical(0), countMusical(0),
counted(false), counted(false),
taskManager(tm) taskManager(tm)
{} {}
Collection::Collection(const std::filesystem::path& path, TaskManager* tm): Collection::~Collection()
path(fs::canonical(path)),
countMusical(0),
counted(false),
taskManager(tm)
{} {}
Collection::~Collection() {
}
void Collection::list() const { void Collection::list() const {
if (fs::is_regular_file(path)) if (fs::is_regular_file(path))
return; return;
@ -71,13 +64,10 @@ void Collection::convert(const std::string& outPath) {
switch (entry.status().type()) { switch (entry.status().type()) {
case fs::file_type::regular: { case fs::file_type::regular: {
fs::path sourcePath = entry.path(); fs::path sourcePath = entry.path();
fs::path dstPath = out / sourcePath.stem();
if (isMusic(sourcePath)) if (isMusic(sourcePath))
taskManager->queueJob(sourcePath, dstPath); taskManager->queueConvert(sourcePath, out / sourcePath.stem());
else else
fs::copy_file(sourcePath, dstPath, fs::copy_options::overwrite_existing); taskManager->queueCopy(sourcePath, out / sourcePath.filename());
//std::cout << sourcePath << " => " << dstPath << std::endl;
} break; } break;
case fs::file_type::directory: { case fs::file_type::directory: {
fs::path sourcePath = entry.path(); fs::path sourcePath = entry.path();

View File

@ -10,7 +10,6 @@ class TaskManager;
class Collection { class Collection {
public: public:
Collection(const std::string& path, TaskManager* tm = nullptr);
Collection(const std::filesystem::path& path, TaskManager* tm = nullptr); Collection(const std::filesystem::path& path, TaskManager* tm = nullptr);
~Collection(); ~Collection();

View File

@ -44,3 +44,55 @@
# If it's set to 0 - amount of threads is going to be # If it's set to 0 - amount of threads is going to be
# as high as your processor can effectively handle # as high as your processor can effectively handle
#parallel 0 #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
# Encoding quality
# Sets up encoding quality (NOT OUTPUT QUALITY)
# The higher quality the slower the encoding process
# 0 is the highest quality and slowest process
# 9 is the lowest quality and the fastest process fastest
# Allowed values are: [0, 1, 2, ... 9]
#encodingQuality 0
# Output quality
# Sets up output quality
# The higher quality the less information is lonst in compression
# 0 is the highest possible quality for selected mode and type and results in the biggest file
# 9 is the lowest quality but results in the smalest file
# Allowed values are [0, 1, 2, ... 9]
# For the constant bitrate modes (CBR) the following table is valid
# Quality | MP3 |
# --------+-----+--
# 0 | 320 |
# --------+-----+--
# 1 | 288 |
# --------+-----+--
# 2 | 256 |
# --------+-----+--
# 3 | 224 |
# --------+-----+--
# 4 | 192 |
# --------+-----+--
# 5 | 160 |
# --------+-----+--
# 6 | 128 |
# --------+-----+--
# 7 | 96 |
# --------+-----+--
# 8 | 64 |
# --------+-----+--
# 9 | 32 |
#outputQuality 0
# Variable bitrate
# Switches on or off variable bitrate
# VBR files are usually smaller, but not supped to be worse
# in terms of quality. VBR files might be a bit more tricky for the player
# Allowedvalues are: [true, false]
#vbr true

View File

@ -12,6 +12,18 @@ constexpr std::string_view jpeg ("image/jpeg");
const std::map<std::string, std::string> textIdentificationReplacements({ const std::map<std::string, std::string> textIdentificationReplacements({
{"PUBLISHER", "TPUB"} {"PUBLISHER", "TPUB"}
}); });
constexpr std::array<int, 10> bitrates({
320,
288,
256,
224,
192,
160,
128,
96,
64,
32
});
FLACtoMP3::FLACtoMP3(Logger::Severity severity, uint8_t size) : FLACtoMP3::FLACtoMP3(Logger::Severity severity, uint8_t size) :
logger(severity), logger(severity),
@ -46,7 +58,7 @@ bool FLACtoMP3::run() {
if (pcmCounter > 0) if (pcmCounter > 0)
flush(); flush();
int nwrite = lame_encode_flush(encoder, outputBuffer, pcmSize * 2); int nwrite = lame_encode_flush(encoder, outputBuffer, outputBufferSize);
fwrite((char*)outputBuffer, nwrite, 1, output); fwrite((char*)outputBuffer, nwrite, 1, output);
@ -98,9 +110,21 @@ void FLACtoMP3::setOutputFile(const std::string& path) {
outPath = path; outPath = path;
lame_set_VBR(encoder, vbr_default); }
lame_set_VBR_quality(encoder, 0);
lame_set_quality(encoder, 0); void FLACtoMP3::setParameters(unsigned char encodingQuality, unsigned char outputQuality, bool vbr) {
if (vbr) {
logger.info("Encoding to VBR with quality " + std::to_string(outputQuality));
lame_set_VBR(encoder, vbr_default);
lame_set_VBR_quality(encoder, outputQuality);
} else {
int bitrate = bitrates[outputQuality];
logger.info("Encoding to CBR " + std::to_string(bitrate));
lame_set_VBR(encoder, vbr_off);
lame_set_brate(encoder, bitrate);
}
lame_set_quality(encoder, encodingQuality);
} }
bool FLACtoMP3::initializeOutput() { bool FLACtoMP3::initializeOutput() {
@ -306,7 +330,7 @@ bool FLACtoMP3::flush() {
nwrite = lame_encode_buffer_interleaved( nwrite = lame_encode_buffer_interleaved(
encoder, encoder,
pcm, pcm,
pcmCounter, pcmCounter / 2,
outputBuffer, outputBuffer,
outputBufferSize outputBufferSize
); );

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <FLAC/stream_decoder.h> #include <stream_decoder.h>
#include <lame.h> #include <lame.h>
#include <jpeglib.h> #include <jpeglib.h>
#include <id3v2tag.h> #include <id3v2tag.h>
@ -8,6 +8,7 @@
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <map> #include <map>
#include <array>
#include <stdio.h> #include <stdio.h>
#include "logger/accumulator.h" #include "logger/accumulator.h"
@ -19,6 +20,7 @@ public:
void setInputFile(const std::string& path); void setInputFile(const std::string& path);
void setOutputFile(const std::string& path); void setOutputFile(const std::string& path);
void setParameters(unsigned char encodingQuality, unsigned char outputQuality, bool vbr);
bool run(); bool run();
std::list<Logger::Message> getHistory() const; std::list<Logger::Message> getHistory() const;

View File

@ -16,6 +16,10 @@ enum class Option {
source, source,
destination, destination,
parallel, parallel,
filesToCopy,
encodingQuality,
outputQuality,
vbr,
_optionsSize _optionsSize
}; };
@ -36,13 +40,20 @@ constexpr std::array<std::string_view, static_cast<int>(Option::_optionsSize)> o
"type", "type",
"source", "source",
"destination", "destination",
"parallel" "parallel",
"filesToCopy",
"encodingQuality",
"outputQuality",
"vbr"
}); });
constexpr std::array<std::string_view, Settings::_typesSize> types({ constexpr std::array<std::string_view, Settings::_typesSize> types({
"mp3" "mp3"
}); });
constexpr unsigned int maxQuality = 9;
constexpr unsigned int minQuality = 0;
bool is_space(char ch){ bool is_space(char ch){
return std::isspace(static_cast<unsigned char>(ch)); return std::isspace(static_cast<unsigned char>(ch));
} }
@ -72,7 +83,13 @@ Settings::Settings(int argc, char ** argv):
outputType(std::nullopt), outputType(std::nullopt),
input(std::nullopt), input(std::nullopt),
output(std::nullopt), output(std::nullopt),
logLevel(std::nullopt) logLevel(std::nullopt),
configPath(std::nullopt),
threads(std::nullopt),
nonMusic(std::nullopt),
encodingQuality(std::nullopt),
outputQuality(std::nullopt),
vbr(std::nullopt)
{ {
for (int i = 1; i < argc; ++i) for (int i = 1; i < argc; ++i)
arguments.push_back(argv[i]); arguments.push_back(argv[i]);
@ -182,6 +199,27 @@ unsigned int Settings::getThreads() const {
return 0; return 0;
} }
unsigned char Settings::getOutputQuality() const {
if (outputQuality.has_value())
return outputQuality.value();
else
return minQuality; //actually, it means max possible quality
}
unsigned char Settings::getEncodingQuality() const {
if (encodingQuality.has_value())
return encodingQuality.value();
else
return minQuality; //actually, it means max possible quality
}
bool Settings::getVBR() const {
if (vbr.has_value())
return vbr.value();
else
return true;
}
void Settings::strip(std::string& line) { void Settings::strip(std::string& line) {
line.erase(line.begin(), std::find_if(line.begin(), line.end(), std::not_fn(is_space))); line.erase(line.begin(), std::find_if(line.begin(), line.end(), std::not_fn(is_space)));
line.erase(std::find_if(line.rbegin(), line.rend(), std::not_fn(is_space)).base(), line.end()); line.erase(std::find_if(line.rbegin(), line.rend(), std::not_fn(is_space)).base(), line.end());
@ -264,6 +302,32 @@ void Settings::readConfigLine(const std::string& line) {
if (!threads.has_value() && stream >> count) if (!threads.has_value() && stream >> count)
threads = count; threads = count;
} break; } 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;
case Option::outputQuality: {
unsigned int value;
if (!outputQuality.has_value() && stream >> value)
outputQuality = std::clamp(value, minQuality, maxQuality);
} break;
case Option::encodingQuality: {
unsigned int value;
if (!encodingQuality.has_value() && stream >> value)
encodingQuality = std::clamp(value, minQuality, maxQuality);
} break;
case Option::vbr: {
bool value;
if (!vbr.has_value() && stream >> std::boolalpha >> value)
vbr = value;
} break;
default: default:
break; break;
} }
@ -299,3 +363,11 @@ std::string Settings::resolvePath(const std::string& line) {
else else
return line; return line;
} }
bool Settings::matchNonMusic(const std::string& fileName) const {
if (nonMusic.has_value())
return std::regex_search(fileName, nonMusic.value());
else
return true;
}

View File

@ -11,6 +11,7 @@
#include <functional> #include <functional>
#include <cctype> #include <cctype>
#include <sstream> #include <sstream>
#include <regex>
#include "logger/logger.h" #include "logger/logger.h"
@ -38,6 +39,10 @@ public:
Type getType() const; Type getType() const;
Action getAction() const; Action getAction() const;
unsigned int getThreads() const; unsigned int getThreads() const;
bool matchNonMusic(const std::string& fileName) const;
unsigned char getEncodingQuality() const;
unsigned char getOutputQuality() const;
bool getVBR() const;
bool readConfigFile(); bool readConfigFile();
void readConfigLine(const std::string& line); void readConfigLine(const std::string& line);
@ -63,4 +68,8 @@ private:
std::optional<Logger::Severity> logLevel; std::optional<Logger::Severity> logLevel;
std::optional<std::string> configPath; std::optional<std::string> configPath;
std::optional<unsigned int> threads; std::optional<unsigned int> threads;
std::optional<std::regex> nonMusic;
std::optional<unsigned char> encodingQuality;
std::optional<unsigned char> outputQuality;
std::optional<bool> vbr;
}; };

View File

@ -21,9 +21,9 @@ TaskManager::TaskManager(const std::shared_ptr<Settings>& settings, const std::s
TaskManager::~TaskManager() { 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); std::unique_lock<std::mutex> lock(queueMutex);
jobs.emplace(source, destination); jobs.emplace(Job::convert, source, destination);
++maxTasks; ++maxTasks;
logger->setStatusMessage(std::to_string(completeTasks) + "/" + std::to_string(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(); 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 { bool TaskManager::busy() const {
std::lock_guard lock(queueMutex); std::lock_guard lock(queueMutex);
return !jobs.empty(); return !jobs.empty();
@ -61,28 +74,16 @@ void TaskManager::loop() {
if (terminate) if (terminate)
return; return;
std::pair<std::string, std::string> pair = jobs.front(); Job job = jobs.front();
++busyThreads; ++busyThreads;
jobs.pop(); jobs.pop();
lock.unlock(); lock.unlock();
JobResult result; JobResult result = execute(job);
switch (settings->getType()) {
case Settings::mp3:
result = mp3Job(pair.first, pair.second + ".mp3", settings->getLogLevel());
break;
default:
break;
}
lock.lock(); lock.lock();
++completeTasks; ++completeTasks;
logger->printNested( printResilt(job, result);
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)
);
--busyThreads; --busyThreads;
lock.unlock(); lock.unlock();
waitConditional.notify_all(); waitConditional.notify_all();
@ -118,14 +119,72 @@ unsigned int TaskManager::getCompleteTasks() const {
return completeTasks; return completeTasks;
} }
TaskManager::JobResult TaskManager::mp3Job( TaskManager::JobResult TaskManager::execute(Job& job) {
const std::filesystem::path& source, switch (job.type) {
const std::filesystem::path& destination, case Job::copy:
Logger::Severity logLevel) return copyJob(job, settings);
{ case Job::convert:
FLACtoMP3 convertor(logLevel); switch (settings->getType()) {
convertor.setInputFile(source); case Settings::mp3:
convertor.setOutputFile(destination); job.destination.replace_extension("mp3");
return mp3Job(job, settings);
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 TaskManager::Job& job, const std::shared_ptr<Settings>& settings) {
FLACtoMP3 convertor(settings->getLogLevel());
convertor.setInputFile(job.source);
convertor.setOutputFile(job.destination);
convertor.setParameters(settings->getEncodingQuality(), settings->getOutputQuality(), settings->getVBR());
bool result = convertor.run(); bool result = convertor.run();
return {result, convertor.getHistory()}; return {result, convertor.getHistory()};
} }
TaskManager::JobResult TaskManager::copyJob(const TaskManager::Job& job, const std::shared_ptr<Settings>& settings) {
(void)(settings);
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) {}

View File

@ -18,13 +18,15 @@
#include "logger/printer.h" #include "logger/printer.h"
class TaskManager { class TaskManager {
typedef std::pair<bool, std::list<Logger::Message>> JobResult; using JobResult = std::pair<bool, std::list<Logger::Message>>;
struct Job;
public: public:
TaskManager(const std::shared_ptr<Settings>& settings, const std::shared_ptr<Printer>& logger); TaskManager(const std::shared_ptr<Settings>& settings, const std::shared_ptr<Printer>& logger);
~TaskManager(); ~TaskManager();
void start(); 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(); void stop();
bool busy() const; bool busy() const;
void wait(); void wait();
@ -33,7 +35,11 @@ public:
private: private:
void loop(); void loop();
static JobResult mp3Job(const std::filesystem::path& source, const std::filesystem::path& destination, Logger::Severity logLevel); JobResult execute(Job& job);
void printResilt(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);
private: private:
std::shared_ptr<Settings> settings; std::shared_ptr<Settings> settings;
std::shared_ptr<Printer> logger; std::shared_ptr<Printer> logger;
@ -46,7 +52,17 @@ private:
std::condition_variable loopConditional; std::condition_variable loopConditional;
std::condition_variable waitConditional; std::condition_variable waitConditional;
std::vector<std::thread> threads; 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;
};