Allow setting covers of special types with description via CLI
See https://github.com/Martchus/tageditor/issues/64
This commit is contained in:
parent
8258a14089
commit
41fb2069f3
18
README.md
18
README.md
|
@ -270,6 +270,24 @@ Here are some Bash examples which illustrate getting and setting tag information
|
|||
**Note**: The *+* sign after the field name *track* which indicates that the field value should be increased after
|
||||
a file has been processed.
|
||||
|
||||
* Sets a cover of a special type with a description:
|
||||
```
|
||||
tageditor set cover=":front-cover" cover0="/path/to/back-cover.jpg:back-cover:The description" -f foo.mp3
|
||||
```
|
||||
|
||||
- The syntax is `path:cover-type:description`. The cover type and description are optional.
|
||||
- In this example the front cover is removed (by passing an empty path) and the back cover set to the specified
|
||||
file. Other cover types are not affected.
|
||||
- When specifying a cover without type, all existing covers are replaced and the new cover will be of the
|
||||
type "other".
|
||||
- To replace all existing covers when specifying a cover type
|
||||
use e.g. `… cover= cover0="/path/to/back-cover.jpg:back-cover"`.
|
||||
- The names of all cover types can be shown via `tageditor --print-field-names`.
|
||||
- The `0` after the 2nd `cover` is required. Otherwise the 2nd cover would only be set in the 2nd file (which
|
||||
is not even specified in this example).
|
||||
- This is only supported by the tag formats ID3v2 and Vorbis Comment. The type and description are ignored
|
||||
when dealing with a different format.
|
||||
|
||||
## Text encoding / unicode support
|
||||
1. It is possible to set the preferred encoding used *within* the tags via CLI option ``--encoding``
|
||||
and in the GUI settings.
|
||||
|
|
112
cli/helper.cpp
112
cli/helper.cpp
|
@ -28,6 +28,39 @@ using namespace Settings;
|
|||
|
||||
namespace Cli {
|
||||
|
||||
const std::vector<std::string_view> &id3v2CoverTypeNames()
|
||||
{
|
||||
static const auto t
|
||||
= std::vector<std::string_view>{ "other"sv, "file-icon"sv, "other-file-icon"sv, "front-cover"sv, "back-cover"sv, "leaflet-page"sv, "media"sv,
|
||||
"lead-performer"sv, "artist"sv, "conductor"sv, "band"sv, "composer"sv, "lyricist"sv, "recording-location"sv, "during-recording"sv,
|
||||
"during-performance"sv, "movie-screen-capture"sv, "bright-colored-fish"sv, "illustration"sv, "artist-logotype"sv, "publisher"sv };
|
||||
return t;
|
||||
}
|
||||
|
||||
CoverType id3v2CoverType(std::string_view coverName)
|
||||
{
|
||||
static const auto mapping = [] {
|
||||
const auto &names = id3v2CoverTypeNames();
|
||||
auto map = std::map<std::string_view, CoverType>();
|
||||
auto index = CoverType();
|
||||
for (const auto name : names) {
|
||||
map[name] = index++;
|
||||
}
|
||||
return map;
|
||||
}();
|
||||
if (const auto i = mapping.find(coverName); i != mapping.end()) {
|
||||
return i->second;
|
||||
} else {
|
||||
return invalidCoverType;
|
||||
}
|
||||
}
|
||||
|
||||
std::string_view id3v2CoverName(CoverType coverType)
|
||||
{
|
||||
const auto &names = id3v2CoverTypeNames();
|
||||
return coverType < names.size() ? names[coverType] : "?"sv;
|
||||
}
|
||||
|
||||
CppUtilities::TimeSpanOutputFormat timeSpanOutputFormat = TimeSpanOutputFormat::WithMeasures;
|
||||
|
||||
/*!
|
||||
|
@ -208,16 +241,16 @@ void printProperty(const char *propName, ElementPosition elementPosition, const
|
|||
}
|
||||
}
|
||||
|
||||
void printFieldName(const char *fieldName, size_t fieldNameLen)
|
||||
void printFieldName(std::string_view fieldName)
|
||||
{
|
||||
cout << " " << fieldName;
|
||||
// also write padding
|
||||
if (fieldNameLen >= 18) {
|
||||
if (fieldName.size() >= 18) {
|
||||
// write at least one space
|
||||
cout << ' ';
|
||||
return;
|
||||
}
|
||||
for (auto i = fieldNameLen; i < 18; ++i) {
|
||||
for (auto i = fieldName.size(); i < 18; ++i) {
|
||||
cout << ' ';
|
||||
}
|
||||
}
|
||||
|
@ -233,13 +266,30 @@ void printTagValue(const TagValue &value)
|
|||
cout << '\n';
|
||||
}
|
||||
|
||||
template <class TagType> static void printId3v2CoverValues(TagType *tag)
|
||||
{
|
||||
const auto &fields = tag->fields();
|
||||
const auto id = tag->fieldId(KnownField::Cover);
|
||||
for (auto range = fields.equal_range(id); range.first != range.second; ++range.first) {
|
||||
const auto &field = range.first->second;
|
||||
printFieldName(argsToString("Cover (", id3v2CoverName(static_cast<CoverType>(field.typeInfo())), ")"));
|
||||
printTagValue(field.value());
|
||||
}
|
||||
}
|
||||
|
||||
void printField(const FieldScope &scope, const Tag *tag, TagType tagType, bool skipEmpty)
|
||||
{
|
||||
// write field name
|
||||
const char *fieldName = scope.field.name();
|
||||
const auto fieldNameLen = strlen(fieldName);
|
||||
|
||||
const auto fieldName = std::string_view(scope.field.name());
|
||||
try {
|
||||
if (scope.field.knownFieldForTag(tag, tagType) == KnownField::Cover) {
|
||||
if (tagType == TagType::Id3v2Tag) {
|
||||
printId3v2CoverValues(static_cast<const Id3v2Tag *>(tag));
|
||||
} else {
|
||||
printId3v2CoverValues(static_cast<const VorbisComment *>(tag));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// parse field denotation
|
||||
const auto &values = scope.field.values(tag, tagType);
|
||||
|
||||
|
@ -255,20 +305,20 @@ void printField(const FieldScope &scope, const Tag *tag, TagType tagType, bool s
|
|||
|
||||
// print empty value (if not prevented)
|
||||
if (values.first.empty()) {
|
||||
printFieldName(fieldName, fieldNameLen);
|
||||
printFieldName(fieldName);
|
||||
cout << "none\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// print values
|
||||
for (const auto &value : values.first) {
|
||||
printFieldName(fieldName, fieldNameLen);
|
||||
printFieldName(fieldName);
|
||||
printTagValue(*value);
|
||||
}
|
||||
|
||||
} catch (const ConversionException &e) {
|
||||
// handle conversion error which might happen when parsing field denotation
|
||||
printFieldName(fieldName, fieldNameLen);
|
||||
printFieldName(fieldName);
|
||||
cout << "unable to parse - " << e.what() << '\n';
|
||||
}
|
||||
}
|
||||
|
@ -283,7 +333,7 @@ template <typename ConcreteTag> void printNativeFields(const Tag *tag)
|
|||
}
|
||||
|
||||
const auto fieldId(ConcreteTag::FieldType::fieldIdToString(field.first));
|
||||
printFieldName(fieldId.data(), fieldId.size());
|
||||
printFieldName(fieldId);
|
||||
printTagValue(field.second.value());
|
||||
}
|
||||
}
|
||||
|
@ -613,7 +663,7 @@ FieldDenotations parseFieldDenotations(const Argument &fieldsArg, bool readOnly)
|
|||
}
|
||||
|
||||
template <class ConcreteTag, TagType tagTypeMask = ConcreteTag::tagType>
|
||||
std::pair<std::vector<const TagValue *>, bool> valuesForNativeField(std::string_view idString, const Tag *tag, TagType tagType)
|
||||
static std::pair<std::vector<const TagValue *>, bool> valuesForNativeField(std::string_view idString, const Tag *tag, TagType tagType)
|
||||
{
|
||||
auto res = make_pair<std::vector<const TagValue *>, bool>({}, false);
|
||||
if (!(tagType & tagTypeMask)) {
|
||||
|
@ -625,7 +675,7 @@ std::pair<std::vector<const TagValue *>, bool> valuesForNativeField(std::string_
|
|||
}
|
||||
|
||||
template <class ConcreteTag, TagType tagTypeMask = ConcreteTag::tagType>
|
||||
bool setValuesForNativeField(std::string_view idString, Tag *tag, TagType tagType, const std::vector<TagValue> &values)
|
||||
static bool setValuesForNativeField(std::string_view idString, Tag *tag, TagType tagType, const std::vector<TagValue> &values)
|
||||
{
|
||||
if (!(tagType & tagTypeMask)) {
|
||||
return false;
|
||||
|
@ -633,20 +683,35 @@ bool setValuesForNativeField(std::string_view idString, Tag *tag, TagType tagTyp
|
|||
return static_cast<ConcreteTag *>(tag)->setValues(ConcreteTag::FieldType::fieldIdFromString(idString), values);
|
||||
}
|
||||
|
||||
inline FieldId::FieldId(
|
||||
std::string_view nativeField, const GetValuesForNativeFieldType &valuesForNativeField, const SetValuesForNativeFieldType &setValuesForNativeField)
|
||||
template <class ConcreteTag, TagType tagTypeMask = ConcreteTag::tagType>
|
||||
static KnownField knownFieldForNativeField(std::string_view idString, const Tag *tag, TagType tagType)
|
||||
{
|
||||
if (!(tagType & tagTypeMask)) {
|
||||
return KnownField::Invalid;
|
||||
}
|
||||
try {
|
||||
return static_cast<const ConcreteTag *>(tag)->knownField(ConcreteTag::FieldType::fieldIdFromString(idString));
|
||||
} catch (const ConversionException &) {
|
||||
return KnownField::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
inline FieldId::FieldId(std::string_view nativeField, GetValuesForNativeFieldType &&valuesForNativeField,
|
||||
SetValuesForNativeFieldType &&setValuesForNativeField, KnownFieldForNativeFieldType &&knownFieldForNativeField)
|
||||
: m_knownField(KnownField::Invalid)
|
||||
, m_nativeField(nativeField)
|
||||
, m_valuesForNativeField(valuesForNativeField)
|
||||
, m_setValuesForNativeField(setValuesForNativeField)
|
||||
, m_valuesForNativeField(std::move(valuesForNativeField))
|
||||
, m_setValuesForNativeField(std::move(setValuesForNativeField))
|
||||
, m_knownFieldForNativeField(std::move(knownFieldForNativeField))
|
||||
{
|
||||
}
|
||||
|
||||
/// \remarks This wrapper is required because specifying c'tor template args is not possible.
|
||||
template <class ConcreteTag, TagType tagTypeMask> FieldId FieldId::fromNativeField(std::string_view nativeFieldId)
|
||||
{
|
||||
return FieldId(nativeFieldId, bind(&valuesForNativeField<ConcreteTag, tagTypeMask>, nativeFieldId, _1, _2),
|
||||
bind(&setValuesForNativeField<ConcreteTag, tagTypeMask>, nativeFieldId, _1, _2, _3));
|
||||
return FieldId(nativeFieldId, std::bind(&valuesForNativeField<ConcreteTag, tagTypeMask>, nativeFieldId, _1, _2),
|
||||
std::bind(&setValuesForNativeField<ConcreteTag, tagTypeMask>, nativeFieldId, _1, _2, _3),
|
||||
std::bind(&knownFieldForNativeField<ConcreteTag, tagTypeMask>, nativeFieldId, _1, _2));
|
||||
}
|
||||
|
||||
FieldId FieldId::fromTagDenotation(const char *denotation, size_t denotationSize)
|
||||
|
@ -700,6 +765,15 @@ bool FieldId::setValues(Tag *tag, TagType tagType, const std::vector<TagValue> &
|
|||
}
|
||||
}
|
||||
|
||||
KnownField FieldId::knownFieldForTag(const Tag *tag, TagType tagType) const
|
||||
{
|
||||
if (!m_nativeField.empty()) {
|
||||
return m_knownFieldForNativeField(tag, tagType);
|
||||
} else {
|
||||
return m_knownField;
|
||||
}
|
||||
}
|
||||
|
||||
string tagName(const Tag *tag)
|
||||
{
|
||||
stringstream ss;
|
||||
|
|
23
cli/helper.h
23
cli/helper.h
|
@ -3,7 +3,9 @@
|
|||
|
||||
#include "../application/knownfieldmodel.h"
|
||||
|
||||
#include <tagparser/id3/id3v2tag.h>
|
||||
#include <tagparser/tag.h>
|
||||
#include <tagparser/vorbis/vorbiscomment.h>
|
||||
|
||||
#include <c++utilities/application/commandlineutils.h>
|
||||
#include <c++utilities/chrono/datetime.h>
|
||||
|
@ -13,6 +15,7 @@
|
|||
#include <c++utilities/misc/traits.h>
|
||||
|
||||
#include <functional>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
@ -44,11 +47,18 @@ CPP_UTILITIES_MARK_FLAG_ENUM_CLASS(TagParser, TagParser::TagType)
|
|||
|
||||
namespace Cli {
|
||||
|
||||
using CoverType = std::conditional_t<sizeof(typename Id3v2Tag::FieldType::TypeInfoType) >= sizeof(typename VorbisComment::FieldType::TypeInfoType),
|
||||
typename Id3v2Tag::FieldType::TypeInfoType, typename VorbisComment::FieldType::TypeInfoType>;
|
||||
constexpr auto invalidCoverType = std::numeric_limits<CoverType>::max();
|
||||
const std::vector<std::string_view> &id3v2CoverTypeNames();
|
||||
CoverType id3v2CoverType(std::string_view coverName);
|
||||
std::string_view id3v2CoverName(CoverType coverType);
|
||||
|
||||
class FieldId {
|
||||
friend struct std::hash<FieldId>;
|
||||
|
||||
public:
|
||||
FieldId(KnownField m_knownField = KnownField::Invalid, const char *denotation = nullptr, std::size_t denotationSize = 0);
|
||||
explicit FieldId(KnownField m_knownField = KnownField::Invalid, const char *denotation = nullptr, std::size_t denotationSize = 0);
|
||||
static FieldId fromTagDenotation(const char *denotation, std::size_t denotationSize);
|
||||
static FieldId fromTrackDenotation(const char *denotation, std::size_t denotationSize);
|
||||
bool operator==(const FieldId &other) const;
|
||||
|
@ -58,12 +68,14 @@ public:
|
|||
const std::string &denotation() const;
|
||||
std::pair<std::vector<const TagValue *>, bool> values(const Tag *tag, TagType tagType) const;
|
||||
bool setValues(Tag *tag, TagType tagType, const std::vector<TagValue> &values) const;
|
||||
KnownField knownFieldForTag(const Tag *tag, TagType tagType) const;
|
||||
|
||||
private:
|
||||
using GetValuesForNativeFieldType = std::function<std::pair<std::vector<const TagValue *>, bool>(const Tag *, TagType)>;
|
||||
using SetValuesForNativeFieldType = std::function<bool(Tag *, TagType, const std::vector<TagValue> &)>;
|
||||
FieldId(std::string_view nativeField, const GetValuesForNativeFieldType &valuesForNativeField,
|
||||
const SetValuesForNativeFieldType &setValuesForNativeField);
|
||||
using KnownFieldForNativeFieldType = std::function<KnownField(const Tag *, TagType)>;
|
||||
FieldId(std::string_view nativeField, GetValuesForNativeFieldType &&valuesForNativeField, SetValuesForNativeFieldType &&setValuesForNativeField,
|
||||
KnownFieldForNativeFieldType &&knownFieldForNativeField);
|
||||
template <class ConcreteTag, TagType tagTypeMask = ConcreteTag::tagType> static FieldId fromNativeField(std::string_view nativeFieldId);
|
||||
|
||||
KnownField m_knownField;
|
||||
|
@ -71,6 +83,7 @@ private:
|
|||
std::string m_nativeField;
|
||||
GetValuesForNativeFieldType m_valuesForNativeField;
|
||||
SetValuesForNativeFieldType m_setValuesForNativeField;
|
||||
KnownFieldForNativeFieldType m_knownFieldForNativeField;
|
||||
};
|
||||
|
||||
inline FieldId::FieldId(KnownField knownField, const char *denotation, std::size_t denotationSize)
|
||||
|
@ -105,7 +118,7 @@ inline const std::string &FieldId::denotation() const
|
|||
}
|
||||
|
||||
struct FieldScope {
|
||||
FieldScope(KnownField field = KnownField::Invalid, TagType tagType = TagType::Unspecified, TagTarget tagTarget = TagTarget());
|
||||
explicit FieldScope(KnownField field = KnownField::Invalid, TagType tagType = TagType::Unspecified, TagTarget tagTarget = TagTarget());
|
||||
bool operator==(const FieldScope &other) const;
|
||||
bool isTrack() const;
|
||||
|
||||
|
@ -150,7 +163,7 @@ inline FieldValue::FieldValue(DenotationType type, unsigned int fileIndex, const
|
|||
|
||||
class InterruptHandler {
|
||||
public:
|
||||
InterruptHandler(std::function<void()> handler);
|
||||
explicit InterruptHandler(std::function<void()> handler);
|
||||
~InterruptHandler();
|
||||
|
||||
private:
|
||||
|
|
|
@ -18,11 +18,13 @@
|
|||
#include <tagparser/abstracttrack.h>
|
||||
#include <tagparser/backuphelper.h>
|
||||
#include <tagparser/diagnostics.h>
|
||||
#include <tagparser/id3/id3v2tag.h>
|
||||
#include <tagparser/localehelper.h>
|
||||
#include <tagparser/mediafileinfo.h>
|
||||
#include <tagparser/progressfeedback.h>
|
||||
#include <tagparser/tag.h>
|
||||
#include <tagparser/tagvalue.h>
|
||||
#include <tagparser/vorbis/vorbiscomment.h>
|
||||
|
||||
#ifdef TAGEDITOR_JSON_EXPORT
|
||||
#include <reflective_rapidjson/json/reflector.h>
|
||||
|
@ -52,6 +54,7 @@
|
|||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
using namespace std;
|
||||
using namespace CppUtilities;
|
||||
|
@ -93,6 +96,9 @@ void printFieldNames(const ArgumentOccurrence &)
|
|||
" - Tag modifier: " TAG_MODIFIER "\n"
|
||||
" - Track modifier: track=id1,id2,id3,... track=all\n"
|
||||
" - Target modifier:\n " TARGET_MODIFIER "\n"
|
||||
"ID3v2 cover types:\n"
|
||||
<< joinStrings<std::remove_reference_t<decltype(id3v2CoverTypeNames())>, std::string>(id3v2CoverTypeNames(), "\n"sv, false, " - "sv, ""sv)
|
||||
<< '\n'
|
||||
<< flush;
|
||||
}
|
||||
|
||||
|
@ -379,6 +385,41 @@ void displayTagInfo(const Argument &fieldsArg, const Argument &showUnsupportedAr
|
|||
}
|
||||
}
|
||||
|
||||
template <class TagType>
|
||||
bool fieldPredicate(CoverType coverType, const std::pair<typename TagType::IdentifierType, typename TagType::FieldType> &pair)
|
||||
{
|
||||
return pair.second.isTypeInfoAssigned() ? (pair.second.typeInfo() == static_cast<typename TagType::FieldType::TypeInfoType>(coverType))
|
||||
: (coverType == 0);
|
||||
}
|
||||
|
||||
template <class TagType> static void setId3v2CoverValues(TagType *tag, std::vector<std::pair<TagValue, CoverType>> &&values)
|
||||
{
|
||||
auto &fields = tag->fields();
|
||||
const auto id = tag->fieldId(KnownField::Cover);
|
||||
const auto range = fields.equal_range(id);
|
||||
const auto first = range.first;
|
||||
|
||||
for (auto &[tagValue, coverType] : values) {
|
||||
// check whether there is already a tag value with the current index/type
|
||||
auto pair = find_if(first, range.second, std::bind(fieldPredicate<TagType>, coverType, placeholders::_1));
|
||||
if (pair != range.second) {
|
||||
// there is already a tag value with the current index/type
|
||||
// -> update this value
|
||||
pair->second.setValue(tagValue);
|
||||
// check whether there are more values with the current index/type assigned
|
||||
while ((pair = find_if(++pair, range.second, std::bind(fieldPredicate<TagType>, coverType, placeholders::_1))) != range.second) {
|
||||
// -> remove these values as we only support one value of a type in the same tag
|
||||
pair->second.setValue(TagValue());
|
||||
}
|
||||
} else if (!tagValue.isEmpty()) {
|
||||
using FieldType = typename TagType::FieldType;
|
||||
auto newField = FieldType(id, tagValue);
|
||||
newField.setTypeInfo(static_cast<typename FieldType::TypeInfoType>(coverType));
|
||||
fields.insert(std::pair(id, std::move(newField)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setTagInfo(const SetTagInfoArgs &args)
|
||||
{
|
||||
CMD_UTILS_START_CONSOLE;
|
||||
|
@ -603,7 +644,8 @@ void setTagInfo(const SetTagInfoArgs &args)
|
|||
continue;
|
||||
}
|
||||
// convert the values to TagValue
|
||||
vector<TagValue> convertedValues;
|
||||
auto convertedValues = std::vector<TagValue>();
|
||||
auto convertedValuesWithCoverType = std::vector<std::pair<TagValue, CoverType>>();
|
||||
for (const FieldValue *relevantDenotedValue : fieldDenotation.second.relevantValues) {
|
||||
// assign an empty TagValue to remove the field if denoted value is empty
|
||||
if (relevantDenotedValue->value.empty()) {
|
||||
|
@ -616,32 +658,72 @@ void setTagInfo(const SetTagInfoArgs &args)
|
|||
continue;
|
||||
}
|
||||
// add value from file
|
||||
const auto parts = splitStringSimple<std::vector<std::string_view>>(relevantDenotedValue->value, ":", 3);
|
||||
const auto path = parts.empty() ? std::string_view() : parts.front();
|
||||
try {
|
||||
// assume the file refers to a picture
|
||||
MediaFileInfo coverFileInfo(relevantDenotedValue->value);
|
||||
Diagnostics coverDiag;
|
||||
AbortableProgressFeedback coverProgress; // FIXME: actually use the progress object
|
||||
coverFileInfo.open(true);
|
||||
coverFileInfo.parseContainerFormat(coverDiag, coverProgress);
|
||||
auto buff = make_unique<char[]>(coverFileInfo.size());
|
||||
coverFileInfo.stream().seekg(static_cast<streamoff>(coverFileInfo.containerOffset()));
|
||||
coverFileInfo.stream().read(buff.get(), static_cast<streamoff>(coverFileInfo.size()));
|
||||
TagValue value(move(buff), coverFileInfo.size(), TagDataType::Picture);
|
||||
value.setMimeType(coverFileInfo.mimeType());
|
||||
convertedValues.emplace_back(move(value));
|
||||
auto value = TagValue();
|
||||
if (!path.empty()) {
|
||||
auto coverFileInfo = MediaFileInfo(path);
|
||||
auto coverDiag = Diagnostics();
|
||||
auto coverProgress = AbortableProgressFeedback(); // FIXME: actually use the progress object
|
||||
coverFileInfo.open(true);
|
||||
coverFileInfo.parseContainerFormat(coverDiag, coverProgress);
|
||||
auto buff = make_unique<char[]>(coverFileInfo.size());
|
||||
coverFileInfo.stream().seekg(static_cast<streamoff>(coverFileInfo.containerOffset()));
|
||||
coverFileInfo.stream().read(buff.get(), static_cast<streamoff>(coverFileInfo.size()));
|
||||
value = TagValue(std::move(buff), coverFileInfo.size(), TagDataType::Picture);
|
||||
value.setMimeType(coverFileInfo.mimeType());
|
||||
}
|
||||
if (parts.size() > 2) {
|
||||
value.setDescription(parts[2], TagTextEncoding::Utf8);
|
||||
}
|
||||
if (parts.size() > 1 && denotedScope.field.knownFieldForTag(tag, tagType) == KnownField::Cover
|
||||
&& (tagType == TagType::Id3v2Tag || tagType == TagType::VorbisComment)) {
|
||||
const auto coverType = id3v2CoverType(parts[1]);
|
||||
if (coverType == invalidCoverType) {
|
||||
diag.emplace_back(DiagLevel::Warning,
|
||||
argsToString("Specified cover type \"", parts[1], "\" is invalid. Ignoring the specified field/value."),
|
||||
context);
|
||||
} else {
|
||||
convertedValuesWithCoverType.emplace_back(std::pair(std::move(value), coverType));
|
||||
}
|
||||
} else {
|
||||
if (parts.size() > 1) {
|
||||
diag.emplace_back(DiagLevel::Warning,
|
||||
argsToString("Ignoring cover type \"", parts[1], "\" for ", tag->typeName(),
|
||||
". It is only supported by the cover field and the tag formats ID3v2 and Vorbis Comment."),
|
||||
context);
|
||||
}
|
||||
convertedValues.emplace_back(std::move(value));
|
||||
}
|
||||
} catch (const TagParser::Failure &) {
|
||||
diag.emplace_back(DiagLevel::Critical, "Unable to parse specified cover file.", context);
|
||||
} catch (const std::ios_base::failure &) {
|
||||
diag.emplace_back(DiagLevel::Critical, "An IO error occured when parsing the specified cover file.", context);
|
||||
} catch (const std::ios_base::failure &e) {
|
||||
diag.emplace_back(DiagLevel::Critical,
|
||||
argsToString("An IO error occured when parsing the specified cover file: ", e.what()), context);
|
||||
}
|
||||
}
|
||||
// finally set the values
|
||||
try {
|
||||
denotedScope.field.setValues(tag, tagType, convertedValues);
|
||||
if (!convertedValues.empty() || convertedValuesWithCoverType.empty()) {
|
||||
denotedScope.field.setValues(tag, tagType, convertedValues);
|
||||
}
|
||||
} catch (const ConversionException &e) {
|
||||
diag.emplace_back(DiagLevel::Critical,
|
||||
argsToString("Unable to parse denoted field ID \"", denotedScope.field.name(), "\": ", e.what()), context);
|
||||
}
|
||||
if (!convertedValuesWithCoverType.empty()) {
|
||||
switch (tagType) {
|
||||
case TagType::Id3v2Tag:
|
||||
setId3v2CoverValues(static_cast<Id3v2Tag *>(tag), std::move(convertedValuesWithCoverType));
|
||||
break;
|
||||
case TagType::VorbisComment:
|
||||
setId3v2CoverValues(static_cast<VorbisComment *>(tag), std::move(convertedValuesWithCoverType));
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue