changed logging concept, reworked task manager
This commit is contained in:
parent
6c7356598a
commit
0b268a7245
@ -1,5 +1,9 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## MLC 1.3.0 (UNRELEASED)
|
||||||
|
- Config file to control the process
|
||||||
|
- Program modes concept to implement config print and help
|
||||||
|
|
||||||
## MLC 1.2.0 (August 11, 2023)
|
## MLC 1.2.0 (August 11, 2023)
|
||||||
- Better way of handling tags using TagLib
|
- Better way of handling tags using TagLib
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
cmake_minimum_required(VERSION 3.0)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
project(
|
project(
|
||||||
mlc
|
mlc
|
||||||
VERSION 1.2.0
|
VERSION 1.2.0
|
||||||
|
@ -12,7 +12,6 @@ set(SOURCES
|
|||||||
flactomp3.cpp
|
flactomp3.cpp
|
||||||
collection.cpp
|
collection.cpp
|
||||||
taskmanager.cpp
|
taskmanager.cpp
|
||||||
loggable.cpp
|
|
||||||
settings.cpp
|
settings.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -22,11 +21,12 @@ set(HEADERS
|
|||||||
flactomp3.h
|
flactomp3.h
|
||||||
collection.h
|
collection.h
|
||||||
taskmanager.h
|
taskmanager.h
|
||||||
loggable.h
|
|
||||||
settings.h
|
settings.h
|
||||||
)
|
)
|
||||||
|
|
||||||
target_sources(${PROJECT_NAME} PRIVATE ${SOURCES})
|
target_sources(${PROJECT_NAME} PRIVATE ${SOURCES})
|
||||||
|
|
||||||
|
add_subdirectory(logger)
|
||||||
|
|
||||||
make_includable(default.conf ${CMAKE_BINARY_DIR}/generated/default.conf)
|
make_includable(default.conf ${CMAKE_BINARY_DIR}/generated/default.conf)
|
||||||
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_BINARY_DIR})
|
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_BINARY_DIR})
|
||||||
|
@ -13,8 +13,8 @@ const std::map<std::string, std::string> textIdentificationReplacements({
|
|||||||
{"PUBLISHER", "TPUB"}
|
{"PUBLISHER", "TPUB"}
|
||||||
});
|
});
|
||||||
|
|
||||||
FLACtoMP3::FLACtoMP3(Severity severity, uint8_t size) :
|
FLACtoMP3::FLACtoMP3(Logger::Severity severity, uint8_t size) :
|
||||||
Loggable(severity),
|
logger(severity),
|
||||||
inPath(),
|
inPath(),
|
||||||
outPath(),
|
outPath(),
|
||||||
decoder(FLAC__stream_decoder_new()),
|
decoder(FLAC__stream_decoder_new()),
|
||||||
@ -72,7 +72,7 @@ bool FLACtoMP3::run() {
|
|||||||
float MBytes = (float)fileSize / 1024 / 1024;
|
float MBytes = (float)fileSize / 1024 / 1024;
|
||||||
std::string strMBytes = std::to_string(MBytes);
|
std::string strMBytes = std::to_string(MBytes);
|
||||||
strMBytes = strMBytes.substr(0, strMBytes.find(".") + 3) + " MiB";
|
strMBytes = strMBytes.substr(0, strMBytes.find(".") + 3) + " MiB";
|
||||||
log(info, "resulting file size: " + strMBytes);
|
logger.info("resulting file size: " + strMBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
@ -110,13 +110,13 @@ bool FLACtoMP3::initializeOutput() {
|
|||||||
output = fopen(outPath.c_str(), "w+b");
|
output = fopen(outPath.c_str(), "w+b");
|
||||||
if (output == 0) {
|
if (output == 0) {
|
||||||
output = nullptr;
|
output = nullptr;
|
||||||
log(fatal, "Error opening file " + outPath);
|
logger.fatal("Error opening file " + outPath);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = lame_init_params(encoder);
|
int ret = lame_init_params(encoder);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
log(fatal, "Error initializing LAME parameters. Code = " + std::to_string(ret));
|
logger.fatal("Error initializing LAME parameters. Code = " + std::to_string(ret));
|
||||||
fclose(output);
|
fclose(output);
|
||||||
output = nullptr;
|
output = nullptr;
|
||||||
return false;
|
return false;
|
||||||
@ -143,9 +143,9 @@ void FLACtoMP3::processInfo(const FLAC__StreamMetadata_StreamInfo& info) {
|
|||||||
lame_set_in_samplerate(encoder, info.sample_rate);
|
lame_set_in_samplerate(encoder, info.sample_rate);
|
||||||
lame_set_num_channels(encoder, info.channels);
|
lame_set_num_channels(encoder, info.channels);
|
||||||
flacMaxBlockSize = info.max_blocksize;
|
flacMaxBlockSize = info.max_blocksize;
|
||||||
log(Loggable::info, "sample rate: " + std::to_string(info.sample_rate));
|
logger.info("sample rate: " + std::to_string(info.sample_rate));
|
||||||
log(Loggable::info, "channels: " + std::to_string(info.channels));
|
logger.info("channels: " + std::to_string(info.channels));
|
||||||
log(Loggable::info, "bits per sample: " + std::to_string(info.bits_per_sample));
|
logger.info("bits per sample: " + std::to_string(info.bits_per_sample));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FLACtoMP3::processTags(const FLAC__StreamMetadata_VorbisComment& tags) {
|
void FLACtoMP3::processTags(const FLAC__StreamMetadata_VorbisComment& tags) {
|
||||||
@ -156,7 +156,7 @@ void FLACtoMP3::processTags(const FLAC__StreamMetadata_VorbisComment& tags) {
|
|||||||
std::string_view comm((const char*)entry.entry);
|
std::string_view comm((const char*)entry.entry);
|
||||||
std::string_view::size_type ePos = comm.find("=");
|
std::string_view::size_type ePos = comm.find("=");
|
||||||
if (ePos == std::string_view::npos) {
|
if (ePos == std::string_view::npos) {
|
||||||
log(warning, "couldn't understand tag (" + std::string(comm) + "), symbol '=' is missing, skipping");
|
logger.warn("couldn't understand tag (" + std::string(comm) + "), symbol '=' is missing, skipping");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
std::string key(comm.substr(0, ePos));
|
std::string key(comm.substr(0, ePos));
|
||||||
@ -174,17 +174,17 @@ void FLACtoMP3::processTags(const FLAC__StreamMetadata_VorbisComment& tags) {
|
|||||||
TagLib::ID3v2::TextIdentificationFrame* frame = new TagLib::ID3v2::TextIdentificationFrame(itr->second.c_str());
|
TagLib::ID3v2::TextIdentificationFrame* frame = new TagLib::ID3v2::TextIdentificationFrame(itr->second.c_str());
|
||||||
frame->setText(value);
|
frame->setText(value);
|
||||||
customFrames.push_back(frame);
|
customFrames.push_back(frame);
|
||||||
log(debug, "tag \"" + key + "\" was remapped to \"" + itr->second + "\"");
|
logger.debug("tag \"" + key + "\" was remapped to \"" + itr->second + "\"");
|
||||||
} else {
|
} else {
|
||||||
success = props.insert(key, TagLib::String(value, TagLib::String::UTF8));
|
success = props.insert(key, TagLib::String(value, TagLib::String::UTF8));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
log(warning, "couldn't understand tag (" + key + "), skipping");
|
logger.warn("couldn't understand tag (" + key + "), skipping");
|
||||||
}
|
}
|
||||||
TagLib::StringList unsupported = props.unsupportedData();
|
TagLib::StringList unsupported = props.unsupportedData();
|
||||||
for (const TagLib::String& key : unsupported)
|
for (const TagLib::String& key : unsupported)
|
||||||
log(minor, "tag \"" + key.to8Bit() + "\", is not supported, probably won't display well");
|
logger.minor("tag \"" + key.to8Bit() + "\", is not supported, probably won't display well");
|
||||||
|
|
||||||
id3v2tag.setProperties(props);
|
id3v2tag.setProperties(props);
|
||||||
|
|
||||||
@ -195,13 +195,13 @@ void FLACtoMP3::processTags(const FLAC__StreamMetadata_VorbisComment& tags) {
|
|||||||
|
|
||||||
void FLACtoMP3::processPicture(const FLAC__StreamMetadata_Picture& picture) {
|
void FLACtoMP3::processPicture(const FLAC__StreamMetadata_Picture& picture) {
|
||||||
if (downscaleAlbumArt && picture.data_length > LAME_MAXALBUMART) {
|
if (downscaleAlbumArt && picture.data_length > LAME_MAXALBUMART) {
|
||||||
log(info, "embeded album art is too big (" + std::to_string(picture.data_length) + " bytes), rescaling");
|
logger.info("embeded album art is too big (" + std::to_string(picture.data_length) + " bytes), rescaling");
|
||||||
log(debug, "mime type is " + std::string(picture.mime_type));
|
logger.debug("mime type is " + std::string(picture.mime_type));
|
||||||
if (picture.mime_type == jpeg) {
|
if (picture.mime_type == jpeg) {
|
||||||
if (scaleJPEG(picture))
|
if (scaleJPEG(picture))
|
||||||
log(debug, "successfully rescaled album art");
|
logger.debug("successfully rescaled album art");
|
||||||
else
|
else
|
||||||
log(warning, "failed to rescale album art");
|
logger.warn("failed to rescale album art");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//auch, sorry for copying so much, but I haven't found a way around it yet
|
//auch, sorry for copying so much, but I haven't found a way around it yet
|
||||||
@ -220,7 +220,7 @@ bool FLACtoMP3::scaleJPEG(const FLAC__StreamMetadata_Picture& picture) {
|
|||||||
int rc = jpeg_read_header(&dinfo, TRUE);
|
int rc = jpeg_read_header(&dinfo, TRUE);
|
||||||
|
|
||||||
if (rc != 1) {
|
if (rc != 1) {
|
||||||
log(Loggable::error, "error reading jpeg header");
|
logger.error("error reading jpeg header");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
TagLib::ByteVector vector (picture.data_length + 1024 * 4); //I allocate a little bit more not to corrupt someone else's the memory
|
TagLib::ByteVector vector (picture.data_length + 1024 * 4); //I allocate a little bit more not to corrupt someone else's the memory
|
||||||
@ -251,7 +251,7 @@ bool FLACtoMP3::scaleJPEG(const FLAC__StreamMetadata_Picture& picture) {
|
|||||||
while (dinfo.output_scanline < dinfo.output_height) {
|
while (dinfo.output_scanline < dinfo.output_height) {
|
||||||
if (mem_size + rowSize > vector.size()) {
|
if (mem_size + rowSize > vector.size()) {
|
||||||
vector.resize(vector.size() + rowSize);
|
vector.resize(vector.size() + rowSize);
|
||||||
log(Loggable::major, "allocated memory for resising the image wasn't enougth, resising");
|
logger.major("allocated memory for resising the image wasn't enougth, resising");
|
||||||
}
|
}
|
||||||
jpeg_read_scanlines(&dinfo, &row, 1);
|
jpeg_read_scanlines(&dinfo, &row, 1);
|
||||||
jpeg_write_scanlines(&cinfo, &row, 1);
|
jpeg_write_scanlines(&cinfo, &row, 1);
|
||||||
@ -297,11 +297,11 @@ bool FLACtoMP3::flush() {
|
|||||||
outputBufferSize
|
outputBufferSize
|
||||||
);
|
);
|
||||||
while (nwrite == -1) { //-1 is returned when there was not enough space in the given buffer
|
while (nwrite == -1) { //-1 is returned when there was not enough space in the given buffer
|
||||||
log(major, std::to_string(outputBufferSize) + " bytes in the output buffer wasn't enough");;
|
logger.major(std::to_string(outputBufferSize) + " bytes in the output buffer wasn't enough");;
|
||||||
outputBufferSize = outputBufferSize * 2;
|
outputBufferSize = outputBufferSize * 2;
|
||||||
delete[] outputBuffer;
|
delete[] outputBuffer;
|
||||||
outputBuffer = new uint8_t[outputBufferSize];
|
outputBuffer = new uint8_t[outputBufferSize];
|
||||||
log(major, "allocating " + std::to_string(outputBufferSize) + " bytes");
|
logger.major("allocating " + std::to_string(outputBufferSize) + " bytes");
|
||||||
|
|
||||||
nwrite = lame_encode_buffer_interleaved(
|
nwrite = lame_encode_buffer_interleaved(
|
||||||
encoder,
|
encoder,
|
||||||
@ -318,10 +318,10 @@ bool FLACtoMP3::flush() {
|
|||||||
return actuallyWritten == 1;
|
return actuallyWritten == 1;
|
||||||
} else {
|
} else {
|
||||||
if (nwrite == 0) {
|
if (nwrite == 0) {
|
||||||
log(minor, "encoding flush encoded 0 bytes, skipping write");
|
logger.minor("encoding flush encoded 0 bytes, skipping write");
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
log(fatal, "encoding flush failed. Code = : " + std::to_string(nwrite));
|
logger.fatal("encoding flush failed. Code = : " + std::to_string(nwrite));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -359,15 +359,15 @@ FLAC__StreamDecoderWriteStatus FLACtoMP3::write(
|
|||||||
// }
|
// }
|
||||||
FLACtoMP3* self = static_cast<FLACtoMP3*>(client_data);
|
FLACtoMP3* self = static_cast<FLACtoMP3*>(client_data);
|
||||||
if (frame->header.channels != 2) {
|
if (frame->header.channels != 2) {
|
||||||
self->log(fatal, "ERROR: This frame contains " + std::to_string(frame->header.channels) + " channels (should be 2)");
|
self->logger.fatal("ERROR: This frame contains " + std::to_string(frame->header.channels) + " channels (should be 2)");
|
||||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||||
}
|
}
|
||||||
if (buffer[0] == NULL) {
|
if (buffer[0] == NULL) {
|
||||||
self->log(fatal, "ERROR: buffer [0] is NULL");
|
self->logger.fatal("ERROR: buffer [0] is NULL");
|
||||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||||
}
|
}
|
||||||
if (buffer[1] == NULL) {
|
if (buffer[1] == NULL) {
|
||||||
self->log(fatal, "ERROR: buffer [1] is NULL");
|
self->logger.fatal("ERROR: buffer [1] is NULL");
|
||||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,7 +383,7 @@ void FLACtoMP3::error(const FLAC__StreamDecoder* decoder, FLAC__StreamDecoderErr
|
|||||||
(void)decoder;
|
(void)decoder;
|
||||||
FLACtoMP3* self = static_cast<FLACtoMP3*>(client_data);
|
FLACtoMP3* self = static_cast<FLACtoMP3*>(client_data);
|
||||||
std::string errText(FLAC__StreamDecoderErrorStatusString[status]);
|
std::string errText(FLAC__StreamDecoderErrorStatusString[status]);
|
||||||
self->log(Loggable::error, "Got error callback: " + errText);
|
self->logger.error("Got error callback: " + errText);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FLACtoMP3::attachPictureFrame(const FLAC__StreamMetadata_Picture& picture, const TagLib::ByteVector& bytes) {
|
void FLACtoMP3::attachPictureFrame(const FLAC__StreamMetadata_Picture& picture, const TagLib::ByteVector& bytes) {
|
||||||
@ -395,91 +395,91 @@ void FLACtoMP3::attachPictureFrame(const FLAC__StreamMetadata_Picture& picture,
|
|||||||
switch (picture.type) {
|
switch (picture.type) {
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::Other);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::Other);
|
||||||
log(info, "attached picture is described as \"other\"");
|
logger.info("attached picture is described as \"other\"");
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::FileIcon);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::FileIcon);
|
||||||
log(info, "attached picture is a standard file icon");
|
logger.info("attached picture is a standard file icon");
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::OtherFileIcon);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::OtherFileIcon);
|
||||||
log(info, "attached picture is apparently not so standard file icon...");
|
logger.info("attached picture is apparently not so standard file icon...");
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover);
|
||||||
log(info, "attached picture is a front album cover");
|
logger.info("attached picture is a front album cover");
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::BackCover);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::BackCover);
|
||||||
log(info, "attached picture is an back album cover");
|
logger.info("attached picture is an back album cover");
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_LEAFLET_PAGE:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_LEAFLET_PAGE:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::LeafletPage);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::LeafletPage);
|
||||||
log(info, "attached picture is a leflet from the album");
|
logger.info("attached picture is a leflet from the album");
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::Media);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::Media);
|
||||||
log(info, "attached picture is probably an imadge of an album CD");
|
logger.info("attached picture is probably an imadge of an album CD");
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_LEAD_ARTIST:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_LEAD_ARTIST:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::LeadArtist);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::LeadArtist);
|
||||||
log(info, "attached picture is an image of the lead artist");
|
logger.info("attached picture is an image of the lead artist");
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_ARTIST:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_ARTIST:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::Artist);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::Artist);
|
||||||
log(info, "attached picture is an image the artist");
|
logger.info("attached picture is an image the artist");
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_CONDUCTOR:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_CONDUCTOR:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::Conductor);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::Conductor);
|
||||||
log(info, "attached picture is an image the conductor");
|
logger.info("attached picture is an image the conductor");
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_BAND:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_BAND:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::Band);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::Band);
|
||||||
log(info, "attached picture is an image of the band");
|
logger.info("attached picture is an image of the band");
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_COMPOSER:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_COMPOSER:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::Composer);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::Composer);
|
||||||
log(info, "attached picture is an image of composer");
|
logger.info("attached picture is an image of composer");
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_LYRICIST:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_LYRICIST:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::Lyricist);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::Lyricist);
|
||||||
log(info, "attached picture is an image of the lyricist");
|
logger.info("attached picture is an image of the lyricist");
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_RECORDING_LOCATION:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_RECORDING_LOCATION:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::RecordingLocation);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::RecordingLocation);
|
||||||
log(info, "attached picture is an image recording location");
|
logger.info("attached picture is an image recording location");
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_RECORDING:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_RECORDING:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::DuringRecording);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::DuringRecording);
|
||||||
log(info, "attached picture is an image of the process of the recording");
|
logger.info("attached picture is an image of the process of the recording");
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_PERFORMANCE:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_PERFORMANCE:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::DuringPerformance);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::DuringPerformance);
|
||||||
log(info, "attached picture is an image of process of the performance");
|
logger.info("attached picture is an image of process of the performance");
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_VIDEO_SCREEN_CAPTURE:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_VIDEO_SCREEN_CAPTURE:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::MovieScreenCapture);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::MovieScreenCapture);
|
||||||
log(info, "attached picture is an frame from a movie");
|
logger.info("attached picture is an frame from a movie");
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_FISH:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_FISH:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::ColouredFish);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::ColouredFish);
|
||||||
log(info, "attached picture is ... a bright large colo(u?)red fish...? o_O");
|
logger.info("attached picture is ... a bright large colo(u?)red fish...? o_O");
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_ILLUSTRATION:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_ILLUSTRATION:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::Illustration);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::Illustration);
|
||||||
log(info, "attached picture is an track related illustration");
|
logger.info("attached picture is an track related illustration");
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_BAND_LOGOTYPE:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_BAND_LOGOTYPE:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::BandLogo);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::BandLogo);
|
||||||
log(info, "attached picture is a band logo");
|
logger.info("attached picture is a band logo");
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_PUBLISHER_LOGOTYPE:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_PUBLISHER_LOGOTYPE:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::PublisherLogo);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::PublisherLogo);
|
||||||
log(info, "attached picture is a publisher logo");
|
logger.info("attached picture is a publisher logo");
|
||||||
break;
|
break;
|
||||||
case FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED:
|
case FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED:
|
||||||
frame->setType(TagLib::ID3v2::AttachedPictureFrame::Other);
|
frame->setType(TagLib::ID3v2::AttachedPictureFrame::Other);
|
||||||
log(info, "attached picture is something unknown, so, I would assume it's \"other\"");
|
logger.info("attached picture is something unknown, so, I would assume it's \"other\"");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,11 +487,14 @@ void FLACtoMP3::attachPictureFrame(const FLAC__StreamMetadata_Picture& picture,
|
|||||||
float KBytes = (float)sizeBytes / 1024;
|
float KBytes = (float)sizeBytes / 1024;
|
||||||
std::string strKBytes = std::to_string(KBytes);
|
std::string strKBytes = std::to_string(KBytes);
|
||||||
strKBytes = strKBytes.substr(0, strKBytes.find(".") + 3) + " KiB";
|
strKBytes = strKBytes.substr(0, strKBytes.find(".") + 3) + " KiB";
|
||||||
log(info, "attached picture size: " + strKBytes);
|
logger.info("attached picture size: " + strKBytes);
|
||||||
|
|
||||||
std::string description = frame->description().to8Bit();
|
std::string description = frame->description().to8Bit();
|
||||||
if (description.size() > 0)
|
if (description.size() > 0)
|
||||||
log(info, "attached picture has a description (b'cuz where else would you ever read it?): " + description);
|
logger.info("attached picture has a description (b'cuz where else would you ever read it?): " + description);
|
||||||
id3v2tag.addFrame(frame);
|
id3v2tag.addFrame(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::list<Logger::Message> FLACtoMP3::getHistory() const {
|
||||||
|
return logger.getHistory();
|
||||||
|
}
|
||||||
|
@ -10,17 +10,19 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "loggable.h"
|
#include "logger/accumulator.h"
|
||||||
|
|
||||||
class FLACtoMP3 : public Loggable {
|
class FLACtoMP3 {
|
||||||
public:
|
public:
|
||||||
FLACtoMP3(Severity severity = info, uint8_t size = 4);
|
FLACtoMP3(Logger::Severity severity = Logger::Severity::info, uint8_t size = 4);
|
||||||
~FLACtoMP3();
|
~FLACtoMP3();
|
||||||
|
|
||||||
void setInputFile(const std::string& path);
|
void setInputFile(const std::string& path);
|
||||||
void setOutputFile(const std::string& path);
|
void setOutputFile(const std::string& path);
|
||||||
bool run();
|
bool run();
|
||||||
|
|
||||||
|
std::list<Logger::Message> getHistory() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void processTags(const FLAC__StreamMetadata_VorbisComment& tags);
|
void processTags(const FLAC__StreamMetadata_VorbisComment& tags);
|
||||||
void processInfo(const FLAC__StreamMetadata_StreamInfo& info);
|
void processInfo(const FLAC__StreamMetadata_StreamInfo& info);
|
||||||
@ -41,6 +43,7 @@ private:
|
|||||||
);
|
);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Accumulator logger;
|
||||||
std::string inPath;
|
std::string inPath;
|
||||||
std::string outPath;
|
std::string outPath;
|
||||||
|
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
#include "loggable.h"
|
|
||||||
|
|
||||||
constexpr std::array<std::string_view, Loggable::_sevetirySize> levels({
|
|
||||||
"debug",
|
|
||||||
"info",
|
|
||||||
"minor",
|
|
||||||
"major",
|
|
||||||
"warning",
|
|
||||||
"error",
|
|
||||||
"fatal"
|
|
||||||
});
|
|
||||||
|
|
||||||
Loggable::Loggable(Loggable::Severity severity):
|
|
||||||
currentSeverity(severity),
|
|
||||||
history()
|
|
||||||
{}
|
|
||||||
|
|
||||||
Loggable::~Loggable()
|
|
||||||
{}
|
|
||||||
|
|
||||||
void Loggable::log(Loggable::Severity severity, const std::string& comment) const {
|
|
||||||
if (severity >= currentSeverity)
|
|
||||||
history.emplace_back(severity, comment);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::list<std::pair<Loggable::Severity, std::string>> Loggable::getHistory() const {
|
|
||||||
return history;
|
|
||||||
}
|
|
||||||
|
|
||||||
Loggable::Severity Loggable::stringToSeverity(const std::string& line) {
|
|
||||||
unsigned char dist = std::distance(levels.begin(), std::find(levels.begin(), levels.end(), line));
|
|
||||||
if (dist < _sevetirySize)
|
|
||||||
return static_cast<Severity>(dist);
|
|
||||||
|
|
||||||
return _sevetirySize;
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
#include <string>
|
|
||||||
#include <array>
|
|
||||||
#include <string_view>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
class Loggable {
|
|
||||||
public:
|
|
||||||
enum Severity {
|
|
||||||
debug,
|
|
||||||
info,
|
|
||||||
minor,
|
|
||||||
major,
|
|
||||||
warning,
|
|
||||||
error,
|
|
||||||
fatal,
|
|
||||||
_sevetirySize
|
|
||||||
};
|
|
||||||
typedef std::pair<Severity, std::string> Message;
|
|
||||||
|
|
||||||
Loggable(Severity severity);
|
|
||||||
~Loggable();
|
|
||||||
|
|
||||||
void log (Severity severity, const std::string& comment) const;
|
|
||||||
std::list<Message> getHistory() const;
|
|
||||||
|
|
||||||
static Severity stringToSeverity(const std::string& line);
|
|
||||||
|
|
||||||
private:
|
|
||||||
const Severity currentSeverity;
|
|
||||||
mutable std::list<Message> history;
|
|
||||||
};
|
|
13
src/logger/CMakeLists.txt
Normal file
13
src/logger/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
set(SOURCES
|
||||||
|
logger.cpp
|
||||||
|
printer.cpp
|
||||||
|
accumulator.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(HEADERS
|
||||||
|
logger.h
|
||||||
|
printer.h
|
||||||
|
accumulator.h
|
||||||
|
)
|
||||||
|
|
||||||
|
target_sources(${PROJECT_NAME} PRIVATE ${SOURCES})
|
33
src/logger/accumulator.cpp
Normal file
33
src/logger/accumulator.cpp
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#include "accumulator.h"
|
||||||
|
|
||||||
|
Accumulator::Accumulator(Severity severity):
|
||||||
|
severity(severity),
|
||||||
|
history()
|
||||||
|
{}
|
||||||
|
|
||||||
|
Logger::Severity Accumulator::getSeverity() const {
|
||||||
|
return severity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Accumulator::setSeverity(Severity severity) {
|
||||||
|
Accumulator::severity = severity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Accumulator::log(const std::list<Message>& comments, bool colored) const {
|
||||||
|
(void)(colored);
|
||||||
|
for (const Message& comment : comments)
|
||||||
|
if (comment.first >= Accumulator::severity)
|
||||||
|
history.emplace_back(comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Accumulator::log(Severity severity, const std::string& comment, bool colored) const {
|
||||||
|
(void)(colored);
|
||||||
|
if (severity < Accumulator::severity)
|
||||||
|
return;
|
||||||
|
|
||||||
|
history.emplace_back(severity, comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<Logger::Message> Accumulator::getHistory() const {
|
||||||
|
return history;
|
||||||
|
}
|
20
src/logger/accumulator.h
Normal file
20
src/logger/accumulator.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
class Accumulator : public Logger {
|
||||||
|
public:
|
||||||
|
Accumulator(Severity severity = Severity::info);
|
||||||
|
|
||||||
|
virtual void log(const std::list<Message>& comments, bool colored = true) const override;
|
||||||
|
virtual void log(Severity severity, const std::string& comment, bool colored = true) const override;
|
||||||
|
|
||||||
|
virtual Severity getSeverity() const override;
|
||||||
|
virtual void setSeverity(Severity severity) override;
|
||||||
|
|
||||||
|
std::list<Message> getHistory() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Severity severity;
|
||||||
|
mutable std::list<Message> history;
|
||||||
|
};
|
53
src/logger/logger.cpp
Normal file
53
src/logger/logger.cpp
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <string_view>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
constexpr std::array<std::string_view, static_cast<int>(Logger::Severity::_sevetirySize)> levels({
|
||||||
|
"debug",
|
||||||
|
"info",
|
||||||
|
"minor",
|
||||||
|
"major",
|
||||||
|
"warning",
|
||||||
|
"error",
|
||||||
|
"fatal"
|
||||||
|
});
|
||||||
|
|
||||||
|
Logger::~Logger() {}
|
||||||
|
|
||||||
|
void Logger::debug(const std::string& comment, bool colored) const {
|
||||||
|
log(Severity::debug, comment, colored);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::info(const std::string& comment, bool colored) const {
|
||||||
|
log(Severity::info, comment, colored);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::minor(const std::string& comment, bool colored) const {
|
||||||
|
log(Severity::minor, comment, colored);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::major(const std::string& comment, bool colored) const {
|
||||||
|
log(Severity::major, comment, colored);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::warn(const std::string& comment, bool colored) const {
|
||||||
|
log(Severity::warning, comment, colored);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::error(const std::string& comment, bool colored) const {
|
||||||
|
log(Severity::error, comment, colored);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::fatal(const std::string& comment, bool colored) const {
|
||||||
|
log(Severity::fatal, comment, colored);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::Severity Logger::stringToSeverity(const std::string& line) {
|
||||||
|
unsigned char dist = std::distance(levels.begin(), std::find(levels.begin(), levels.end(), line));
|
||||||
|
if (dist < static_cast<unsigned char>(Severity::_sevetirySize))
|
||||||
|
return static_cast<Severity>(dist);
|
||||||
|
|
||||||
|
return Severity::_sevetirySize;
|
||||||
|
}
|
36
src/logger/logger.h
Normal file
36
src/logger/logger.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Logger {
|
||||||
|
public:
|
||||||
|
enum class Severity {
|
||||||
|
debug,
|
||||||
|
info,
|
||||||
|
minor,
|
||||||
|
major,
|
||||||
|
warning,
|
||||||
|
error,
|
||||||
|
fatal,
|
||||||
|
_sevetirySize
|
||||||
|
};
|
||||||
|
using Message = std::pair<Severity, std::string>;
|
||||||
|
|
||||||
|
void debug(const std::string& comment, bool colored = true) const;
|
||||||
|
void info(const std::string& comment, bool colored = true) const;
|
||||||
|
void minor(const std::string& comment, bool colored = true) const;
|
||||||
|
void major(const std::string& comment, bool colored = true) const;
|
||||||
|
void warn(const std::string& comment, bool colored = true) const;
|
||||||
|
void error(const std::string& comment, bool colored = true) const;
|
||||||
|
void fatal(const std::string& comment, bool colored = true) const;
|
||||||
|
|
||||||
|
virtual ~Logger();
|
||||||
|
virtual void log(const std::list<Message>& comments, bool colored = true) const = 0;
|
||||||
|
virtual void log(Severity severity, const std::string& comment, bool colored = true) const = 0;
|
||||||
|
|
||||||
|
virtual void setSeverity(Severity severity) = 0;
|
||||||
|
virtual Severity getSeverity() const = 0;
|
||||||
|
|
||||||
|
static Severity stringToSeverity(const std::string& line);
|
||||||
|
};
|
135
src/logger/printer.cpp
Normal file
135
src/logger/printer.cpp
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
#include "printer.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <string_view>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
constexpr const std::array<std::string_view, static_cast<int>(Logger::Severity::_sevetirySize)> logSettings({
|
||||||
|
/*debug*/ "\e[90m",
|
||||||
|
/*info*/ "\e[32m",
|
||||||
|
/*minor*/ "\e[34m",
|
||||||
|
/*major*/ "\e[94m",
|
||||||
|
/*warning*/ "\e[33m",
|
||||||
|
/*error*/ "\e[31m",
|
||||||
|
/*fatal*/ "\e[91m"
|
||||||
|
});
|
||||||
|
|
||||||
|
constexpr const std::array<std::string_view, static_cast<int>(Logger::Severity::_sevetirySize)> logHeaders({
|
||||||
|
/*debug*/ "DEBUG: ",
|
||||||
|
/*info*/ "INFO: ",
|
||||||
|
/*minor*/ "MINOR: ",
|
||||||
|
/*major*/ "MAJOR: ",
|
||||||
|
/*warning*/ "WARNING: ",
|
||||||
|
/*error*/ "ERROR: ",
|
||||||
|
/*fatal*/ "FATAL: "
|
||||||
|
});
|
||||||
|
|
||||||
|
constexpr const std::string_view bold("\e[1m");
|
||||||
|
constexpr const std::string_view regular("\e[22m");
|
||||||
|
constexpr const std::string_view clearStyle("\e[0m");
|
||||||
|
constexpr const std::string_view clearLine("\e[2K\r");
|
||||||
|
|
||||||
|
Printer::Printer(Severity severity):
|
||||||
|
severity(severity),
|
||||||
|
mutex(),
|
||||||
|
status(std::nullopt)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Logger::Severity Printer::getSeverity() const {
|
||||||
|
return severity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Printer::setSeverity(Severity severity) {
|
||||||
|
Printer::severity = severity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Printer::setStatusMessage(const std::string& message) {
|
||||||
|
if (status.has_value())
|
||||||
|
std::cout << clearLine;
|
||||||
|
|
||||||
|
status = message;
|
||||||
|
std::cout << message << std::flush;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Printer::clearStatusMessage() {
|
||||||
|
if (status.has_value()) {
|
||||||
|
std::cout << clearLine << std::flush;
|
||||||
|
status = std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Printer::printNested(
|
||||||
|
const std::string& header,
|
||||||
|
const std::vector<std::string>& lines,
|
||||||
|
const std::list<Message>& comments,
|
||||||
|
const std::optional<std::string>& status
|
||||||
|
) {
|
||||||
|
std::lock_guard lock(mutex);
|
||||||
|
if (comments.size() > 0) {
|
||||||
|
if (status.has_value())
|
||||||
|
std::cout << clearLine;
|
||||||
|
|
||||||
|
std::cout << bold << header << clearStyle << "\n";
|
||||||
|
for (const std::string& line : lines)
|
||||||
|
std::cout << line << "\n";
|
||||||
|
|
||||||
|
for (const Message& msg : comments) {
|
||||||
|
if (msg.first >= severity) {
|
||||||
|
std::cout << '\t';
|
||||||
|
printMessage(msg, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status.has_value())
|
||||||
|
Printer::status = status;
|
||||||
|
|
||||||
|
finishPrint(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Printer::log(const std::list<Message>& comments, bool colored) const {
|
||||||
|
std::lock_guard lock(mutex);
|
||||||
|
|
||||||
|
bool changed = false;
|
||||||
|
for (const Message& msg : comments) {
|
||||||
|
if (msg.first >= severity) {
|
||||||
|
if (!changed && status.has_value())
|
||||||
|
std::cout << clearLine;
|
||||||
|
|
||||||
|
printMessage(msg, colored);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
finishPrint(colored);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Printer::log(Severity severity, const std::string& comment, bool colored) const {
|
||||||
|
if (severity < Printer::severity)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::lock_guard lock(mutex);
|
||||||
|
if (status.has_value())
|
||||||
|
std::cout << clearLine;
|
||||||
|
|
||||||
|
printMessage({severity, comment}, colored);
|
||||||
|
finishPrint(colored);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Printer::finishPrint(bool colored) const {
|
||||||
|
if (colored)
|
||||||
|
std::cout << clearStyle;
|
||||||
|
|
||||||
|
if (status.has_value())
|
||||||
|
std::cout << '\r' << status.value();
|
||||||
|
|
||||||
|
std::cout << std::flush;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Printer::printMessage(const Message& message, bool colored) const {
|
||||||
|
if (colored) {
|
||||||
|
int severity = static_cast<int>(message.first);
|
||||||
|
std::cout << logSettings[severity] << bold << logHeaders[severity] << regular;
|
||||||
|
}
|
||||||
|
std::cout << message.second << '\n';
|
||||||
|
}
|
38
src/logger/printer.h
Normal file
38
src/logger/printer.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
class Printer : public Logger {
|
||||||
|
public:
|
||||||
|
Printer(Severity severity = Severity::info);
|
||||||
|
|
||||||
|
virtual void log(const std::list<Message>& comments, bool colored = true) const override;
|
||||||
|
virtual void log(Severity severity, const std::string& comment, bool colored = true) const override;
|
||||||
|
|
||||||
|
virtual void setSeverity(Severity severity) override;
|
||||||
|
virtual Severity getSeverity() const override;
|
||||||
|
|
||||||
|
void setStatusMessage(const std::string& message);
|
||||||
|
void clearStatusMessage();
|
||||||
|
void printNested(
|
||||||
|
const std::string& header,
|
||||||
|
const std::vector<std::string>& lines = {},
|
||||||
|
const std::list<Message>& comments = {},
|
||||||
|
const std::optional<std::string>& status = std::nullopt
|
||||||
|
);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void printMessage(const Message& message, bool colored = false) const;
|
||||||
|
void finishPrint(bool colored = false) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::atomic<Severity> severity;
|
||||||
|
mutable std::mutex mutex;
|
||||||
|
std::optional<std::string> status;
|
||||||
|
};
|
29
src/main.cpp
29
src/main.cpp
@ -12,8 +12,10 @@
|
|||||||
#include "collection.h"
|
#include "collection.h"
|
||||||
#include "taskmanager.h"
|
#include "taskmanager.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "logger/logger.h"
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
std::shared_ptr<Printer> logger = std::make_shared<Printer>();
|
||||||
std::shared_ptr<Settings> settings = std::make_shared<Settings>(argc, argv);
|
std::shared_ptr<Settings> settings = std::make_shared<Settings>(argc, argv);
|
||||||
|
|
||||||
switch (settings->getAction()) {
|
switch (settings->getAction()) {
|
||||||
@ -42,20 +44,33 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskManager taskManager(settings);
|
std::string input = settings->getInput();
|
||||||
|
if (input.empty()) {
|
||||||
|
std::cout << "Input folder is not specified, quitting" << std::endl;
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string output = settings->getOutput();
|
||||||
|
if (output.empty()) {
|
||||||
|
std::cout << "Output folder is not specified, quitting" << std::endl;
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger->setSeverity(settings->getLogLevel());
|
||||||
|
TaskManager taskManager(settings, logger);
|
||||||
taskManager.start();
|
taskManager.start();
|
||||||
|
|
||||||
std::chrono::time_point start = std::chrono::system_clock::now();
|
std::chrono::time_point start = std::chrono::system_clock::now();
|
||||||
Collection collection(settings->getInput(), &taskManager);
|
Collection collection(input, &taskManager);
|
||||||
collection.convert(settings->getOutput());
|
collection.convert(output);
|
||||||
|
|
||||||
taskManager.printProgress();
|
|
||||||
taskManager.wait();
|
taskManager.wait();
|
||||||
|
std::cout << std::endl;
|
||||||
|
taskManager.stop();
|
||||||
|
|
||||||
std::chrono::time_point end = std::chrono::system_clock::now();
|
std::chrono::time_point end = std::chrono::system_clock::now();
|
||||||
std::chrono::duration<double> seconds = end - start;
|
std::chrono::duration<double> seconds = end - start;
|
||||||
std::cout << std::endl << "Encoding is done, it took " << seconds.count() << " seconds in total, enjoy!" << std::endl;
|
std::cout << "Encoding is done, it took " << seconds.count() << " seconds in total, enjoy!" << std::endl;
|
||||||
|
|
||||||
taskManager.stop();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ void Settings::parseArguments() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!output.has_value()) {
|
if (!output.has_value()) {
|
||||||
input = arg;
|
output = arg;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -101,11 +101,11 @@ bool Settings::isConfigDefault() const {
|
|||||||
return !configPath.has_value();
|
return !configPath.has_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
Loggable::Severity Settings::getLogLevel() const {
|
Logger::Severity Settings::getLogLevel() const {
|
||||||
if (logLevel.has_value())
|
if (logLevel.has_value())
|
||||||
return logLevel.value();
|
return logLevel.value();
|
||||||
else
|
else
|
||||||
return Loggable::info;
|
return Logger::Severity::info;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view Settings::stripFlags(const std::string_view& option) {
|
std::string_view Settings::stripFlags(const std::string_view& option) {
|
||||||
@ -166,8 +166,8 @@ void Settings::readConfigLine(const std::string& line) {
|
|||||||
case level: {
|
case level: {
|
||||||
std::string lv;
|
std::string lv;
|
||||||
if (stream >> lv) {
|
if (stream >> lv) {
|
||||||
Loggable::Severity level = Loggable::stringToSeverity(lv);
|
Logger::Severity level = Logger::stringToSeverity(lv);
|
||||||
if (level < Loggable::_sevetirySize)
|
if (level < Logger::Severity::_sevetirySize)
|
||||||
logLevel = level;
|
logLevel = level;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include "loggable.h"
|
#include "logger/logger.h"
|
||||||
|
|
||||||
class Settings {
|
class Settings {
|
||||||
public:
|
public:
|
||||||
@ -40,7 +40,7 @@ public:
|
|||||||
std::string getOutput() const;
|
std::string getOutput() const;
|
||||||
std::string getConfigPath() const;
|
std::string getConfigPath() const;
|
||||||
bool isConfigDefault() const;
|
bool isConfigDefault() const;
|
||||||
Loggable::Severity getLogLevel() const;
|
Logger::Severity getLogLevel() const;
|
||||||
Type getType() const;
|
Type getType() const;
|
||||||
Action getAction() const;
|
Action getAction() const;
|
||||||
|
|
||||||
@ -66,6 +66,6 @@ private:
|
|||||||
std::optional<Type> outputType;
|
std::optional<Type> outputType;
|
||||||
std::optional<std::string> input;
|
std::optional<std::string> input;
|
||||||
std::optional<std::string> output;
|
std::optional<std::string> output;
|
||||||
std::optional<Loggable::Severity> logLevel;
|
std::optional<Logger::Severity> logLevel;
|
||||||
std::optional<std::string> configPath;
|
std::optional<std::string> configPath;
|
||||||
};
|
};
|
||||||
|
@ -2,41 +2,19 @@
|
|||||||
|
|
||||||
#include "flactomp3.h"
|
#include "flactomp3.h"
|
||||||
|
|
||||||
constexpr const std::array<std::string_view, Loggable::fatal + 1> logSettings({
|
TaskManager::TaskManager(const std::shared_ptr<Settings>& settings, const std::shared_ptr<Printer>& logger):
|
||||||
/*debug*/ "\e[90m",
|
|
||||||
/*info*/ "\e[32m",
|
|
||||||
/*minor*/ "\e[34m",
|
|
||||||
/*major*/ "\e[94m",
|
|
||||||
/*warning*/ "\e[33m",
|
|
||||||
/*error*/ "\e[31m",
|
|
||||||
/*fatal*/ "\e[91m"
|
|
||||||
});
|
|
||||||
|
|
||||||
constexpr const std::array<std::string_view, Loggable::fatal + 1> logHeaders({
|
|
||||||
/*debug*/ "DEBUG: ",
|
|
||||||
/*info*/ "INFO: ",
|
|
||||||
/*minor*/ "MINOR: ",
|
|
||||||
/*major*/ "MAJOR: ",
|
|
||||||
/*warning*/ "WARNING: ",
|
|
||||||
/*error*/ "ERROR: ",
|
|
||||||
/*fatal*/ "FATAL: "
|
|
||||||
});
|
|
||||||
|
|
||||||
TaskManager::TaskManager(const std::shared_ptr<Settings>& settings):
|
|
||||||
settings(settings),
|
settings(settings),
|
||||||
|
logger(logger),
|
||||||
busyThreads(0),
|
busyThreads(0),
|
||||||
maxTasks(0),
|
maxTasks(0),
|
||||||
completeTasks(0),
|
completeTasks(0),
|
||||||
terminate(false),
|
terminate(false),
|
||||||
printMutex(),
|
running(false),
|
||||||
queueMutex(),
|
queueMutex(),
|
||||||
busyMutex(),
|
|
||||||
loopConditional(),
|
loopConditional(),
|
||||||
waitConditional(),
|
waitConditional(),
|
||||||
threads(),
|
threads(),
|
||||||
jobs(),
|
jobs()
|
||||||
boundLoopCondition(std::bind(&TaskManager::loopCondition, this)),
|
|
||||||
boundWaitCondition(std::bind(&TaskManager::waitCondition, this))
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,126 +22,107 @@ TaskManager::~TaskManager() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TaskManager::queueJob(const std::filesystem::path& source, const std::filesystem::path& destination) {
|
void TaskManager::queueJob(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(source, destination);
|
||||||
}
|
|
||||||
++maxTasks;
|
++maxTasks;
|
||||||
|
logger->setStatusMessage(std::to_string(completeTasks) + "/" + std::to_string(maxTasks));
|
||||||
|
|
||||||
|
lock.unlock();
|
||||||
loopConditional.notify_one();
|
loopConditional.notify_one();
|
||||||
waitConditional.notify_all();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TaskManager::busy() const {
|
bool TaskManager::busy() const {
|
||||||
bool result;
|
std::lock_guard lock(queueMutex);
|
||||||
{
|
return !jobs.empty();
|
||||||
std::unique_lock<std::mutex> lock(queueMutex);
|
|
||||||
result = !jobs.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskManager::start() {
|
void TaskManager::start() {
|
||||||
|
std::lock_guard lock(queueMutex);
|
||||||
|
if (running)
|
||||||
|
return;
|
||||||
|
|
||||||
const uint32_t num_threads = std::thread::hardware_concurrency();
|
const uint32_t num_threads = std::thread::hardware_concurrency();
|
||||||
for (uint32_t ii = 0; ii < num_threads; ++ii)
|
for (uint32_t ii = 0; ii < num_threads; ++ii)
|
||||||
threads.emplace_back(std::thread(&TaskManager::loop, this));
|
threads.emplace_back(std::thread(&TaskManager::loop, this));
|
||||||
|
|
||||||
|
running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskManager::loop() {
|
void TaskManager::loop() {
|
||||||
while (true) {
|
while (true) {
|
||||||
std::pair<std::string, std::string> pair;
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(queueMutex);
|
std::unique_lock<std::mutex> lock(queueMutex);
|
||||||
loopConditional.wait(lock, boundLoopCondition);
|
while (!terminate && jobs.empty())
|
||||||
|
loopConditional.wait(lock);
|
||||||
|
|
||||||
if (terminate)
|
if (terminate)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pair = jobs.front();
|
std::pair<std::string, std::string> pair = jobs.front();
|
||||||
++busyThreads;
|
++busyThreads;
|
||||||
waitConditional.notify_all();
|
|
||||||
jobs.pop();
|
jobs.pop();
|
||||||
}
|
lock.unlock();
|
||||||
|
|
||||||
JobResult result;
|
JobResult result;
|
||||||
switch (settings->getType()) {
|
switch (settings->getType()) {
|
||||||
case Settings::mp3:
|
case Settings::mp3:
|
||||||
result = mp3Job(pair.first, pair.second + ".mp3");
|
result = mp3Job(pair.first, pair.second + ".mp3", settings->getLogLevel());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lock.lock();
|
||||||
++completeTasks;
|
++completeTasks;
|
||||||
printProgress(result, pair.first, pair.second);
|
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)
|
||||||
|
);
|
||||||
--busyThreads;
|
--busyThreads;
|
||||||
|
lock.unlock();
|
||||||
waitConditional.notify_all();
|
waitConditional.notify_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TaskManager::loopCondition() const {
|
|
||||||
return !jobs.empty() || terminate;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TaskManager::waitCondition() const {
|
|
||||||
return busyThreads == 0 && !busy();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TaskManager::stop() {
|
void TaskManager::stop() {
|
||||||
{
|
std::unique_lock lock(queueMutex);
|
||||||
std::unique_lock<std::mutex> lock(queueMutex);
|
if (!running)
|
||||||
terminate = true;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
|
terminate = true;
|
||||||
|
|
||||||
|
lock.unlock();
|
||||||
loopConditional.notify_all();
|
loopConditional.notify_all();
|
||||||
for (std::thread& thread : threads)
|
for (std::thread& thread : threads)
|
||||||
thread.join();
|
thread.join();
|
||||||
|
|
||||||
|
lock.lock();
|
||||||
threads.clear();
|
threads.clear();
|
||||||
|
running = false;
|
||||||
|
logger->clearStatusMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskManager::wait() {
|
void TaskManager::wait() {
|
||||||
std::unique_lock<std::mutex> lock(busyMutex);
|
std::unique_lock lock(queueMutex);
|
||||||
waitConditional.wait(lock, boundWaitCondition);
|
while (busyThreads != 0 || !jobs.empty())
|
||||||
|
waitConditional.wait(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskManager::JobResult TaskManager::mp3Job(const std::filesystem::path& source, const std::filesystem::path& destination) {
|
unsigned int TaskManager::getCompleteTasks() const {
|
||||||
FLACtoMP3 convertor(Loggable::debug);
|
std::lock_guard lock(queueMutex);
|
||||||
|
return completeTasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskManager::JobResult TaskManager::mp3Job(
|
||||||
|
const std::filesystem::path& source,
|
||||||
|
const std::filesystem::path& destination,
|
||||||
|
Logger::Severity logLevel)
|
||||||
|
{
|
||||||
|
FLACtoMP3 convertor(logLevel);
|
||||||
convertor.setInputFile(source);
|
convertor.setInputFile(source);
|
||||||
convertor.setOutputFile(destination);
|
convertor.setOutputFile(destination);
|
||||||
bool result = convertor.run();
|
bool result = convertor.run();
|
||||||
return {result, convertor.getHistory()};
|
return {result, convertor.getHistory()};
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskManager::printProgress() const {
|
|
||||||
std::unique_lock<std::mutex> lock(printMutex);
|
|
||||||
std::cout << "\r" << completeTasks << "/" << maxTasks << std::flush;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TaskManager::printProgress(
|
|
||||||
const TaskManager::JobResult& result,
|
|
||||||
const std::filesystem::path& source,
|
|
||||||
const std::filesystem::path& destination) const
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(printMutex);
|
|
||||||
if (result.first) {
|
|
||||||
if (result.second.size() > 0) {
|
|
||||||
std::cout << "\r\e[1m" << "Encoding complete but there are messages about it" << "\e[0m" << std::endl;
|
|
||||||
printLog(result, source, destination);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
std::cout << "\r\e[1m" << "Encoding failed!" << "\e[0m" << std::endl;
|
|
||||||
printLog(result, source, destination);
|
|
||||||
}
|
|
||||||
std::cout << "\r" << completeTasks << "/" << maxTasks << std::flush;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TaskManager::printLog(
|
|
||||||
const TaskManager::JobResult& result,
|
|
||||||
const std::filesystem::path& source,
|
|
||||||
const std::filesystem::path& destination)
|
|
||||||
{
|
|
||||||
std::cout << "Source: \t" << source << std::endl;
|
|
||||||
std::cout << "Destination: \t" << destination << std::endl;
|
|
||||||
for (const Loggable::Message& msg : result.second) {
|
|
||||||
std::cout << "\t" << logSettings[msg.first] << "\e[1m" << logHeaders[msg.first] << "\e[22m" << msg.second << std::endl;
|
|
||||||
}
|
|
||||||
std::cout << "\e[0m" << std::endl;
|
|
||||||
}
|
|
||||||
|
@ -14,13 +14,13 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "loggable.h"
|
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "logger/printer.h"
|
||||||
|
|
||||||
class TaskManager {
|
class TaskManager {
|
||||||
typedef std::pair<bool, std::list<Loggable::Message>> JobResult;
|
typedef std::pair<bool, std::list<Logger::Message>> JobResult;
|
||||||
public:
|
public:
|
||||||
TaskManager(const std::shared_ptr<Settings>& settings);
|
TaskManager(const std::shared_ptr<Settings>& settings, const std::shared_ptr<Printer>& logger);
|
||||||
~TaskManager();
|
~TaskManager();
|
||||||
|
|
||||||
void start();
|
void start();
|
||||||
@ -28,30 +28,25 @@ public:
|
|||||||
void stop();
|
void stop();
|
||||||
bool busy() const;
|
bool busy() const;
|
||||||
void wait();
|
void wait();
|
||||||
void printProgress() const;
|
|
||||||
void printProgress(const JobResult& result, const std::filesystem::path& source, const std::filesystem::path& destination) const;
|
unsigned int getCompleteTasks() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loop();
|
void loop();
|
||||||
bool loopCondition() const;
|
static JobResult mp3Job(const std::filesystem::path& source, const std::filesystem::path& destination, Logger::Severity logLevel);
|
||||||
bool waitCondition() const;
|
|
||||||
static JobResult mp3Job(const std::filesystem::path& source, const std::filesystem::path& destination);
|
|
||||||
static void printLog(const JobResult& result, const std::filesystem::path& source, const std::filesystem::path& destination);
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<Settings> settings;
|
std::shared_ptr<Settings> settings;
|
||||||
std::atomic<uint32_t> busyThreads;
|
std::shared_ptr<Printer> logger;
|
||||||
std::atomic<uint32_t> maxTasks;
|
unsigned int busyThreads;
|
||||||
std::atomic<uint32_t> completeTasks;
|
unsigned int maxTasks;
|
||||||
|
unsigned int completeTasks;
|
||||||
bool terminate;
|
bool terminate;
|
||||||
mutable std::mutex printMutex;
|
bool running;
|
||||||
mutable std::mutex queueMutex;
|
mutable std::mutex queueMutex;
|
||||||
std::mutex busyMutex;
|
|
||||||
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<std::pair<std::filesystem::path, std::filesystem::path>> jobs;
|
||||||
std::function<bool()> boundLoopCondition;
|
|
||||||
std::function<bool()> boundWaitCondition;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user