Support showing unsupported fields when displaying tag info
This commit is contained in:
parent
3148873e09
commit
4edeaa1ab2
|
@ -11,8 +11,8 @@ set(META_APP_DESCRIPTION "A tageditor with Qt GUI and command line interface. Su
|
||||||
set(META_GUI_OPTIONAL true)
|
set(META_GUI_OPTIONAL true)
|
||||||
set(META_JS_SRC_DIR renamingutility)
|
set(META_JS_SRC_DIR renamingutility)
|
||||||
set(META_VERSION_MAJOR 3)
|
set(META_VERSION_MAJOR 3)
|
||||||
set(META_VERSION_MINOR 0)
|
set(META_VERSION_MINOR 1)
|
||||||
set(META_VERSION_PATCH 1)
|
set(META_VERSION_PATCH 0)
|
||||||
|
|
||||||
# add project files
|
# add project files
|
||||||
set(HEADER_FILES
|
set(HEADER_FILES
|
||||||
|
|
|
@ -164,8 +164,10 @@ int main(int argc, char *argv[])
|
||||||
fieldsArg.setImplicit(true);
|
fieldsArg.setImplicit(true);
|
||||||
OperationArgument displayTagInfoArg("get", 'g', "displays the values of all specified tag fields (displays all fields if none specified)",
|
OperationArgument displayTagInfoArg("get", 'g', "displays the values of all specified tag fields (displays all fields if none specified)",
|
||||||
PROJECT_NAME " get title album artist -f /some/dir/*.m4a");
|
PROJECT_NAME " get title album artist -f /some/dir/*.m4a");
|
||||||
displayTagInfoArg.setCallback(std::bind(Cli::displayTagInfo, std::cref(fieldsArg), std::cref(filesArg), std::cref(verboseArg)));
|
ConfigValueArgument showUnsupportedArg("show-unsupported", 'u', "shows unsupported fields (has only effect when no field names specified)");
|
||||||
displayTagInfoArg.setSubArguments({ &fieldsArg, &filesArg, &verboseArg });
|
displayTagInfoArg.setCallback(
|
||||||
|
std::bind(Cli::displayTagInfo, std::cref(fieldsArg), std::cref(showUnsupportedArg), std::cref(filesArg), std::cref(verboseArg)));
|
||||||
|
displayTagInfoArg.setSubArguments({ &fieldsArg, &showUnsupportedArg, &filesArg, &verboseArg });
|
||||||
// set tag info
|
// set tag info
|
||||||
Cli::SetTagInfoArgs setTagInfoArgs(filesArg, verboseArg);
|
Cli::SetTagInfoArgs setTagInfoArgs(filesArg, verboseArg);
|
||||||
// extract cover
|
// extract cover
|
||||||
|
|
|
@ -213,11 +213,27 @@ void printFieldName(const char *fieldName, size_t fieldNameLen)
|
||||||
{
|
{
|
||||||
cout << " " << fieldName;
|
cout << " " << fieldName;
|
||||||
// also write padding
|
// also write padding
|
||||||
|
if (fieldNameLen >= 18) {
|
||||||
|
// write at least one space
|
||||||
|
cout << ' ';
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (auto i = fieldNameLen; i < 18; ++i) {
|
for (auto i = fieldNameLen; i < 18; ++i) {
|
||||||
cout << ' ';
|
cout << ' ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void printTagValue(const TagValue &value)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
cout << value.toString(TagTextEncoding::Utf8);
|
||||||
|
} catch (const ConversionException &) {
|
||||||
|
// handle case when value can not be displayed as string
|
||||||
|
cout << "can't display as string (see --extract)";
|
||||||
|
}
|
||||||
|
cout << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
void printField(const FieldScope &scope, const Tag *tag, TagType tagType, bool skipEmpty)
|
void printField(const FieldScope &scope, const Tag *tag, TagType tagType, bool skipEmpty)
|
||||||
{
|
{
|
||||||
// write field name
|
// write field name
|
||||||
|
@ -243,13 +259,7 @@ void printField(const FieldScope &scope, const Tag *tag, TagType tagType, bool s
|
||||||
// print values
|
// print values
|
||||||
for (const auto &value : values) {
|
for (const auto &value : values) {
|
||||||
printFieldName(fieldName, fieldNameLen);
|
printFieldName(fieldName, fieldNameLen);
|
||||||
try {
|
printTagValue(*value);
|
||||||
cout << value->toString(TagTextEncoding::Utf8);
|
|
||||||
} catch (const ConversionException &) {
|
|
||||||
// handle case when value can not be displayed as string
|
|
||||||
cout << "can't display as string (see --extract)";
|
|
||||||
}
|
|
||||||
cout << '\n';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (const ConversionException &e) {
|
} catch (const ConversionException &e) {
|
||||||
|
@ -259,6 +269,41 @@ void printField(const FieldScope &scope, const Tag *tag, TagType tagType, bool s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename ConcreteTag> void printNativeFields(const Tag *tag)
|
||||||
|
{
|
||||||
|
const auto *const concreteTag = static_cast<const ConcreteTag *>(tag);
|
||||||
|
for (const auto &field : concreteTag->fields()) {
|
||||||
|
// skip all fields which are supported anyways
|
||||||
|
if (concreteTag->knownField(field.first) != KnownField::Invalid) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto fieldId(ConcreteTag::FieldType::fieldIdToString(field.first));
|
||||||
|
printFieldName(fieldId.data(), fieldId.size());
|
||||||
|
printTagValue(field.second.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printNativeFields(const Tag *tag)
|
||||||
|
{
|
||||||
|
switch (tag->type()) {
|
||||||
|
case TagType::Id3v2Tag:
|
||||||
|
printNativeFields<Id3v2Tag>(tag);
|
||||||
|
break;
|
||||||
|
case TagType::Mp4Tag:
|
||||||
|
printNativeFields<Mp4Tag>(tag);
|
||||||
|
break;
|
||||||
|
case TagType::MatroskaTag:
|
||||||
|
printNativeFields<MatroskaTag>(tag);
|
||||||
|
break;
|
||||||
|
case TagType::VorbisComment:
|
||||||
|
case TagType::OggVorbisComment:
|
||||||
|
printNativeFields<VorbisComment>(tag);
|
||||||
|
break;
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TimeSpanOutputFormat parseTimeSpanOutputFormat(const Argument &timeSpanFormatArg, TimeSpanOutputFormat defaultFormat)
|
TimeSpanOutputFormat parseTimeSpanOutputFormat(const Argument &timeSpanFormatArg, TimeSpanOutputFormat defaultFormat)
|
||||||
{
|
{
|
||||||
if (timeSpanFormatArg.isPresent()) {
|
if (timeSpanFormatArg.isPresent()) {
|
||||||
|
|
|
@ -279,7 +279,7 @@ inline void printProperty(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename NumberType, Traits::EnableIfAny<std::is_integral<NumberType>, std::is_floating_point<NumberType>>* = nullptr>
|
template <typename NumberType, Traits::EnableIfAny<std::is_integral<NumberType>, std::is_floating_point<NumberType>> * = nullptr>
|
||||||
inline void printProperty(
|
inline void printProperty(
|
||||||
const char *propName, const NumberType value, const char *suffix = nullptr, bool force = false, ApplicationUtilities::Indentation indentation = 4)
|
const char *propName, const NumberType value, const char *suffix = nullptr, bool force = false, ApplicationUtilities::Indentation indentation = 4)
|
||||||
{
|
{
|
||||||
|
@ -289,6 +289,7 @@ inline void printProperty(
|
||||||
}
|
}
|
||||||
|
|
||||||
void printField(const FieldScope &scope, const Tag *tag, TagType tagType, bool skipEmpty);
|
void printField(const FieldScope &scope, const Tag *tag, TagType tagType, bool skipEmpty);
|
||||||
|
void printNativeFields(const Tag *tag);
|
||||||
|
|
||||||
ChronoUtilities::TimeSpanOutputFormat parseTimeSpanOutputFormat(
|
ChronoUtilities::TimeSpanOutputFormat parseTimeSpanOutputFormat(
|
||||||
const ApplicationUtilities::Argument &usageArg, ChronoUtilities::TimeSpanOutputFormat defaultFormat);
|
const ApplicationUtilities::Argument &usageArg, ChronoUtilities::TimeSpanOutputFormat defaultFormat);
|
||||||
|
|
|
@ -301,7 +301,7 @@ void displayFileInfo(const ArgumentOccurrence &, const Argument &filesArg, const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void displayTagInfo(const Argument &fieldsArg, const Argument &filesArg, const Argument &verboseArg)
|
void displayTagInfo(const Argument &fieldsArg, const Argument &showUnsupportedArg, const Argument &filesArg, const Argument &verboseArg)
|
||||||
{
|
{
|
||||||
CMD_UTILS_START_CONSOLE;
|
CMD_UTILS_START_CONSOLE;
|
||||||
|
|
||||||
|
@ -325,29 +325,32 @@ void displayTagInfo(const Argument &fieldsArg, const Argument &filesArg, const A
|
||||||
fileInfo.parseTags(diag);
|
fileInfo.parseTags(diag);
|
||||||
cout << "Tag information for \"" << file << "\":\n";
|
cout << "Tag information for \"" << file << "\":\n";
|
||||||
const auto tags = fileInfo.tags();
|
const auto tags = fileInfo.tags();
|
||||||
if (!tags.empty()) {
|
if (tags.empty()) {
|
||||||
// iterate through all tags
|
cout << " - File has no (supported) tag information.\n";
|
||||||
for (const auto *tag : tags) {
|
continue;
|
||||||
// determine tag type
|
}
|
||||||
const TagType tagType = tag->type();
|
// iterate through all tags
|
||||||
// write tag name and target, eg. MP4/iTunes tag
|
for (const auto *tag : tags) {
|
||||||
cout << " - " << TextAttribute::Bold << tagName(tag) << TextAttribute::Reset << '\n';
|
// determine tag type
|
||||||
// iterate through fields specified by the user
|
const TagType tagType = tag->type();
|
||||||
if (fields.empty()) {
|
// write tag name and target, eg. MP4/iTunes tag
|
||||||
for (auto field = firstKnownField; field != KnownField::Invalid; field = nextKnownField(field)) {
|
cout << " - " << TextAttribute::Bold << tagName(tag) << TextAttribute::Reset << '\n';
|
||||||
printField(FieldScope(field), tag, tagType, true);
|
// iterate through fields specified by the user
|
||||||
}
|
if (fields.empty()) {
|
||||||
} else {
|
for (auto field = firstKnownField; field != KnownField::Invalid; field = nextKnownField(field)) {
|
||||||
for (const auto &fieldDenotation : fields) {
|
printField(FieldScope(field), tag, tagType, true);
|
||||||
const FieldScope &denotedScope = fieldDenotation.first;
|
}
|
||||||
if (denotedScope.tagType == TagType::Unspecified || (denotedScope.tagType | tagType) != TagType::Unspecified) {
|
if (showUnsupportedArg.isPresent()) {
|
||||||
printField(denotedScope, tag, tagType, false);
|
printNativeFields(tag);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
for (const auto &fieldDenotation : fields) {
|
||||||
|
const FieldScope &denotedScope = fieldDenotation.first;
|
||||||
|
if (denotedScope.tagType == TagType::Unspecified || (denotedScope.tagType | tagType) != TagType::Unspecified) {
|
||||||
|
printField(denotedScope, tag, tagType, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
cout << " - File has no (supported) tag information.\n";
|
|
||||||
}
|
}
|
||||||
} catch (const TagParser::Failure &) {
|
} catch (const TagParser::Failure &) {
|
||||||
cerr << Phrases::Error << "A parsing failure occured when reading the file \"" << file << "\"." << Phrases::EndFlush;
|
cerr << Phrases::Error << "A parsing failure occured when reading the file \"" << file << "\"." << Phrases::EndFlush;
|
||||||
|
|
|
@ -53,8 +53,8 @@ void displayFileInfo(const ApplicationUtilities::ArgumentOccurrence &, const App
|
||||||
const ApplicationUtilities::Argument &verboseArg);
|
const ApplicationUtilities::Argument &verboseArg);
|
||||||
void generateFileInfo(const ApplicationUtilities::ArgumentOccurrence &, const ApplicationUtilities::Argument &inputFileArg,
|
void generateFileInfo(const ApplicationUtilities::ArgumentOccurrence &, const ApplicationUtilities::Argument &inputFileArg,
|
||||||
const ApplicationUtilities::Argument &outputFileArg, const ApplicationUtilities::Argument &validateArg);
|
const ApplicationUtilities::Argument &outputFileArg, const ApplicationUtilities::Argument &validateArg);
|
||||||
void displayTagInfo(const ApplicationUtilities::Argument &fieldsArg, const ApplicationUtilities::Argument &filesArg,
|
void displayTagInfo(const ApplicationUtilities::Argument &fieldsArg, const ApplicationUtilities::Argument &showUnsupportedArg,
|
||||||
const ApplicationUtilities::Argument &verboseArg);
|
const ApplicationUtilities::Argument &filesArg, const ApplicationUtilities::Argument &verboseArg);
|
||||||
void setTagInfo(const Cli::SetTagInfoArgs &args);
|
void setTagInfo(const Cli::SetTagInfoArgs &args);
|
||||||
void extractField(const ApplicationUtilities::Argument &fieldArg, const ApplicationUtilities::Argument &attachmentArg,
|
void extractField(const ApplicationUtilities::Argument &fieldArg, const ApplicationUtilities::Argument &attachmentArg,
|
||||||
const ApplicationUtilities::Argument &inputFilesArg, const ApplicationUtilities::Argument &outputFileArg,
|
const ApplicationUtilities::Argument &inputFilesArg, const ApplicationUtilities::Argument &outputFileArg,
|
||||||
|
|
Loading…
Reference in New Issue