help page, number of parallel tasts, source and destination now can be set up from config
This commit is contained in:
parent
0b268a7245
commit
e266008e11
@ -1,7 +1,8 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## MLC 1.3.0 (UNRELEASED)
|
## MLC 1.3.0 (October 09, 2023)
|
||||||
- Config file to control the process
|
- Config file to control the process
|
||||||
|
- First help page
|
||||||
- Program modes concept to implement config print and help
|
- Program modes concept to implement config print and help
|
||||||
|
|
||||||
## MLC 1.2.0 (August 11, 2023)
|
## MLC 1.2.0 (August 11, 2023)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
project(
|
project(
|
||||||
mlc
|
mlc
|
||||||
VERSION 1.2.0
|
VERSION 1.3.0
|
||||||
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
|
||||||
)
|
)
|
||||||
|
@ -7,6 +7,7 @@ This is a program for compilation of your loseless music library to lossy format
|
|||||||
- flac
|
- flac
|
||||||
- lame
|
- lame
|
||||||
- jpeg
|
- jpeg
|
||||||
|
- taglib
|
||||||
|
|
||||||
### Building
|
### Building
|
||||||
|
|
||||||
|
@ -29,4 +29,5 @@ target_sources(${PROJECT_NAME} PRIVATE ${SOURCES})
|
|||||||
add_subdirectory(logger)
|
add_subdirectory(logger)
|
||||||
|
|
||||||
make_includable(default.conf ${CMAKE_BINARY_DIR}/generated/default.conf)
|
make_includable(default.conf ${CMAKE_BINARY_DIR}/generated/default.conf)
|
||||||
|
make_includable(help ${CMAKE_BINARY_DIR}/generated/help)
|
||||||
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_BINARY_DIR})
|
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_BINARY_DIR})
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# This is a default autogenerated MLC config
|
# This is a default autogenerated MLC config
|
||||||
# The syntax goes like this:
|
# The syntax goes like this:
|
||||||
# key value
|
# key value
|
||||||
|
# Only the first occasion of the valid key value pair is taken to consideration
|
||||||
#
|
#
|
||||||
# Use # sign for comments
|
# Use # sign for comments
|
||||||
#
|
#
|
||||||
@ -15,9 +16,31 @@
|
|||||||
# if you wish to override ~/.config/mlc.conf file
|
# if you wish to override ~/.config/mlc.conf file
|
||||||
|
|
||||||
# Log level, regulates minimal message severity to be printed
|
# Log level, regulates minimal message severity to be printed
|
||||||
# Allowed values are: debug, info, minor, major, warning, error, fatal
|
# Allowed values are: [debug, info, minor, major, warning, error, fatal]
|
||||||
#level info
|
#level info
|
||||||
|
|
||||||
# Output type
|
# Output type
|
||||||
# Allowed values are: mp3 (more comming soon)
|
# Allowed values are: [mp3] (more comming soon)
|
||||||
#type mp3
|
#type mp3
|
||||||
|
|
||||||
|
# Source collection path
|
||||||
|
# This is a default path to your music collection source.
|
||||||
|
# It's usefull to set it when you always encode the same collection
|
||||||
|
# Leaving this empty (as it is by default) will make you always
|
||||||
|
# specify source in the command line
|
||||||
|
#source
|
||||||
|
|
||||||
|
# Destingation path
|
||||||
|
# This is a default path for your encoding destination
|
||||||
|
# It's usefull to set it when you often encode your collection
|
||||||
|
# to the same output
|
||||||
|
# Leaving this empty (as it is by default) will make you always
|
||||||
|
# specify destination in the command line
|
||||||
|
#destination
|
||||||
|
|
||||||
|
# Parallel tasks
|
||||||
|
# Defines how many threads are going to be started in parralel
|
||||||
|
# Allowed values are [0, 1, 2, 3 ...] etc
|
||||||
|
# If it's set to 0 - amount of threads is going to be
|
||||||
|
# as high as your processor can effectively handle
|
||||||
|
#parallel 0
|
||||||
|
42
src/help
Normal file
42
src/help
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
Usage:
|
||||||
|
mlc [action] [arguments] [flags]
|
||||||
|
|
||||||
|
Actions:
|
||||||
|
convert - converts music
|
||||||
|
config - prints default config
|
||||||
|
help - prints this page
|
||||||
|
|
||||||
|
Default action is `convert`, so it can be omitted
|
||||||
|
|
||||||
|
Arguments work only for `convert` action
|
||||||
|
first - collection source
|
||||||
|
second - collection destination
|
||||||
|
|
||||||
|
Flags:
|
||||||
|
-c (--config) <path>
|
||||||
|
- sets custom config instead of default one
|
||||||
|
|
||||||
|
-h (--help)
|
||||||
|
- sets action to help, and prints this page
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
`mlc ~/Music comile/latest`
|
||||||
|
- reads config file from `~/.config/mlc.conf`
|
||||||
|
- if there was not - creates default that changes nothing
|
||||||
|
- creates directory `conpile` in the CURRENT directory if it was not created before
|
||||||
|
- create `latest` directory in `compile` dirrectory if it was not created before
|
||||||
|
- searches for music in `~/Music` directory
|
||||||
|
- converts all music to `comile/latest` directory
|
||||||
|
- copies all other files found in `~/Music` to `comile/latest`
|
||||||
|
- any file name overlap will be overriden
|
||||||
|
|
||||||
|
`mlc config > myConfig.conf`
|
||||||
|
- prints default config to standard output
|
||||||
|
- unix operator `>` redirects output to a file `myConfig.conf`
|
||||||
|
|
||||||
|
`mlc rip -c myConfig.conf`
|
||||||
|
- reads file `myConfig.conf` from current directory
|
||||||
|
- if `myConfig.conf` has a valid `source` entry - uses it and uses `rip` as destination
|
||||||
|
- if `myConfig.conf` has a valid `destination` entry - uses it and uses `rip` as source
|
||||||
|
- if both present (don't do this way) - it depends on the order, who comes first - defines behaviour
|
||||||
|
- the rest is the same from the first example apart from default config
|
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
#include "iostream"
|
#include "iostream"
|
||||||
|
|
||||||
|
static const char* help =
|
||||||
|
#include "generated/help"
|
||||||
|
;
|
||||||
|
|
||||||
void printHelp() {
|
void printHelp() {
|
||||||
std::cout << "Sorry, there is no help yet. It will arrive one day... I hope" << std::endl;
|
std::cout << help << std::endl;
|
||||||
}
|
}
|
||||||
|
140
src/settings.cpp
140
src/settings.cpp
@ -4,15 +4,39 @@ static const char* defaultConfig =
|
|||||||
#include "generated/default.conf"
|
#include "generated/default.conf"
|
||||||
;
|
;
|
||||||
|
|
||||||
|
enum class Flag {
|
||||||
|
config,
|
||||||
|
help,
|
||||||
|
none
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Option {
|
||||||
|
level,
|
||||||
|
type,
|
||||||
|
source,
|
||||||
|
destination,
|
||||||
|
parallel,
|
||||||
|
_optionsSize
|
||||||
|
};
|
||||||
|
|
||||||
|
using Literals = std::array<std::string_view, 2>;
|
||||||
|
constexpr std::array<Literals, static_cast<int>(Flag::none)> flags({{
|
||||||
|
{"-c", "--config"},
|
||||||
|
{"-h", "--help"}
|
||||||
|
}});
|
||||||
|
|
||||||
constexpr std::array<std::string_view, Settings::_actionsSize> actions({
|
constexpr std::array<std::string_view, Settings::_actionsSize> actions({
|
||||||
"convert",
|
"convert",
|
||||||
"help",
|
"help",
|
||||||
"config"
|
"config"
|
||||||
});
|
});
|
||||||
|
|
||||||
constexpr std::array<std::string_view, Settings::_optionsSize> options({
|
constexpr std::array<std::string_view, static_cast<int>(Option::_optionsSize)> options({
|
||||||
"level",
|
"level",
|
||||||
"type"
|
"type",
|
||||||
|
"source",
|
||||||
|
"destination",
|
||||||
|
"parallel"
|
||||||
});
|
});
|
||||||
|
|
||||||
constexpr std::array<std::string_view, Settings::_typesSize> types({
|
constexpr std::array<std::string_view, Settings::_typesSize> types({
|
||||||
@ -23,6 +47,25 @@ bool is_space(char ch){
|
|||||||
return std::isspace(static_cast<unsigned char>(ch));
|
return std::isspace(static_cast<unsigned char>(ch));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Flag getFlag(const std::string_view arg) {
|
||||||
|
for (int i = 0; i < flags.size(); ++i) {
|
||||||
|
const Literals& lit = flags[i];
|
||||||
|
unsigned char dist = std::distance(lit.begin(), std::find(lit.begin(), lit.end(), arg));
|
||||||
|
if (dist < lit.size())
|
||||||
|
return static_cast<Flag>(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Flag::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
Option stringToOption(const std::string& source) {
|
||||||
|
unsigned char dist = std::distance(options.begin(), std::find(options.begin(), options.end(), source));
|
||||||
|
if (dist < static_cast<unsigned char>(Option::_optionsSize))
|
||||||
|
return static_cast<Option>(dist);
|
||||||
|
|
||||||
|
return Option::_optionsSize;
|
||||||
|
}
|
||||||
|
|
||||||
Settings::Settings(int argc, char ** argv):
|
Settings::Settings(int argc, char ** argv):
|
||||||
arguments(),
|
arguments(),
|
||||||
action(std::nullopt),
|
action(std::nullopt),
|
||||||
@ -38,16 +81,40 @@ Settings::Settings(int argc, char ** argv):
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Settings::parseArguments() {
|
void Settings::parseArguments() {
|
||||||
|
Flag flag = Flag::none;
|
||||||
for (int i = 0; i < arguments.size(); ++i) {
|
for (int i = 0; i < arguments.size(); ++i) {
|
||||||
const std::string_view& arg = arguments[i];
|
const std::string_view& arg = arguments[i];
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
Action act = stringToAction(stripFlags(arg));
|
Action act = stringToAction(arg);
|
||||||
if (act < _actionsSize) {
|
if (act < _actionsSize) {
|
||||||
action = act;
|
action = act;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (flag) {
|
||||||
|
case Flag::config:
|
||||||
|
configPath = arg;
|
||||||
|
flag = Flag::none;
|
||||||
|
continue;
|
||||||
|
case Flag::none:
|
||||||
|
flag = getFlag(arg);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (flag) {
|
||||||
|
case Flag::none:
|
||||||
|
break;
|
||||||
|
case Flag::help:
|
||||||
|
action = help;
|
||||||
|
flag = Flag::none;
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (getAction() == convert) {
|
if (getAction() == convert) {
|
||||||
if (!input.has_value()) {
|
if (!input.has_value()) {
|
||||||
input = arg;
|
input = arg;
|
||||||
@ -78,23 +145,23 @@ Settings::Type Settings::getType() const {
|
|||||||
|
|
||||||
std::string Settings::getInput() const {
|
std::string Settings::getInput() const {
|
||||||
if (input.has_value())
|
if (input.has_value())
|
||||||
return input.value();
|
return resolvePath(input.value());
|
||||||
else
|
else
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Settings::getOutput() const {
|
std::string Settings::getOutput() const {
|
||||||
if (output.has_value())
|
if (output.has_value())
|
||||||
return output.value();
|
return resolvePath(output.value());
|
||||||
else
|
else
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Settings::getConfigPath() const {
|
std::string Settings::getConfigPath() const {
|
||||||
if (configPath.has_value())
|
if (configPath.has_value())
|
||||||
return configPath.value();
|
return resolvePath(configPath.value());
|
||||||
else
|
else
|
||||||
return std::string(getenv("HOME")) + "/.config/mlc.conf";
|
return resolvePath("~/.config/mlc.conf");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Settings::isConfigDefault() const {
|
bool Settings::isConfigDefault() const {
|
||||||
@ -108,14 +175,11 @@ Logger::Severity Settings::getLogLevel() const {
|
|||||||
return Logger::Severity::info;
|
return Logger::Severity::info;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view Settings::stripFlags(const std::string_view& option) {
|
unsigned int Settings::getThreads() const {
|
||||||
if (option[0] == '-') {
|
if (threads.has_value())
|
||||||
if (option[1] == '-')
|
return threads.value();
|
||||||
return option.substr(2);
|
else
|
||||||
|
return 0;
|
||||||
return option.substr(1);
|
|
||||||
}
|
|
||||||
return option;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::strip(std::string& line) {
|
void Settings::strip(std::string& line) {
|
||||||
@ -159,26 +223,47 @@ void Settings::readConfigLine(const std::string& line) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
Option option = stringToOption(key);
|
Option option = stringToOption(key);
|
||||||
if (option == _optionsSize)
|
if (option == Option::_optionsSize)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case level: {
|
case Option::level: {
|
||||||
std::string lv;
|
std::string lv;
|
||||||
if (stream >> lv) {
|
if (!logLevel.has_value() && stream >> lv) {
|
||||||
Logger::Severity level = Logger::stringToSeverity(lv);
|
Logger::Severity level = Logger::stringToSeverity(lv);
|
||||||
if (level < Logger::Severity::_sevetirySize)
|
if (level < Logger::Severity::_sevetirySize)
|
||||||
logLevel = level;
|
logLevel = level;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case type: {
|
case Option::type: {
|
||||||
std::string lv;
|
std::string lv;
|
||||||
if (stream >> lv) {
|
if (!outputType.has_value() && stream >> lv) {
|
||||||
Type type = stringToType(lv);
|
Type type = stringToType(lv);
|
||||||
if (type < _typesSize)
|
if (type < _typesSize)
|
||||||
outputType = type;
|
outputType = type;
|
||||||
}
|
}
|
||||||
} break;
|
} 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case Option::destination: {
|
||||||
|
std::string path;
|
||||||
|
if (!output.has_value() && stream >> path)
|
||||||
|
output = path;
|
||||||
|
} break;
|
||||||
|
case Option::parallel: {
|
||||||
|
unsigned int count;
|
||||||
|
if (!threads.has_value() && stream >> count)
|
||||||
|
threads = count;
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -200,14 +285,6 @@ Settings::Action Settings::stringToAction(const std::string_view& source) {
|
|||||||
return _actionsSize;
|
return _actionsSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings::Option Settings::stringToOption(const std::string& source) {
|
|
||||||
unsigned char dist = std::distance(options.begin(), std::find(options.begin(), options.end(), source));
|
|
||||||
if (dist < _optionsSize)
|
|
||||||
return static_cast<Option>(dist);
|
|
||||||
|
|
||||||
return _optionsSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
Settings::Type Settings::stringToType(const std::string& source) {
|
Settings::Type Settings::stringToType(const std::string& source) {
|
||||||
unsigned char dist = std::distance(types.begin(), std::find(types.begin(), types.end(), source));
|
unsigned char dist = std::distance(types.begin(), std::find(types.begin(), types.end(), source));
|
||||||
if (dist < _typesSize)
|
if (dist < _typesSize)
|
||||||
@ -215,3 +292,10 @@ Settings::Type Settings::stringToType(const std::string& source) {
|
|||||||
|
|
||||||
return _typesSize;
|
return _typesSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Settings::resolvePath(const std::string& line) {
|
||||||
|
if (line.size() > 0 && line[0] == '~')
|
||||||
|
return getenv("HOME") + line.substr(1);
|
||||||
|
else
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
@ -28,12 +28,6 @@ public:
|
|||||||
_typesSize
|
_typesSize
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Option {
|
|
||||||
level,
|
|
||||||
type,
|
|
||||||
_optionsSize
|
|
||||||
};
|
|
||||||
|
|
||||||
Settings(int argc, char **argv);
|
Settings(int argc, char **argv);
|
||||||
|
|
||||||
std::string getInput() const;
|
std::string getInput() const;
|
||||||
@ -43,6 +37,7 @@ public:
|
|||||||
Logger::Severity getLogLevel() const;
|
Logger::Severity getLogLevel() const;
|
||||||
Type getType() const;
|
Type getType() const;
|
||||||
Action getAction() const;
|
Action getAction() const;
|
||||||
|
unsigned int getThreads() const;
|
||||||
|
|
||||||
bool readConfigFile();
|
bool readConfigFile();
|
||||||
void readConfigLine(const std::string& line);
|
void readConfigLine(const std::string& line);
|
||||||
@ -51,14 +46,13 @@ public:
|
|||||||
static Action stringToAction(const std::string& source);
|
static Action stringToAction(const std::string& source);
|
||||||
static Action stringToAction(const std::string_view& source);
|
static Action stringToAction(const std::string_view& source);
|
||||||
static Type stringToType(const std::string& source);
|
static Type stringToType(const std::string& source);
|
||||||
static Option stringToOption(const std::string& source);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void parseArguments();
|
void parseArguments();
|
||||||
|
|
||||||
static std::string_view stripFlags(const std::string_view& option);
|
|
||||||
static void strip(std::string& line);
|
static void strip(std::string& line);
|
||||||
static void stripComment(std::string& line);
|
static void stripComment(std::string& line);
|
||||||
|
static std::string resolvePath(const std::string& line);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::string_view> arguments;
|
std::vector<std::string_view> arguments;
|
||||||
@ -68,4 +62,5 @@ private:
|
|||||||
std::optional<std::string> output;
|
std::optional<std::string> output;
|
||||||
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;
|
||||||
};
|
};
|
||||||
|
@ -42,8 +42,11 @@ void TaskManager::start() {
|
|||||||
if (running)
|
if (running)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const uint32_t num_threads = std::thread::hardware_concurrency();
|
unsigned int amount = settings->getThreads();
|
||||||
for (uint32_t ii = 0; ii < num_threads; ++ii)
|
if (amount == 0)
|
||||||
|
amount = std::thread::hardware_concurrency();
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < amount; ++i)
|
||||||
threads.emplace_back(std::thread(&TaskManager::loop, this));
|
threads.emplace_back(std::thread(&TaskManager::loop, this));
|
||||||
|
|
||||||
running = true;
|
running = true;
|
||||||
|
Loading…
Reference in New Issue
Block a user