Use new argument parser API
This commit is contained in:
parent
f6e9368792
commit
72621f7ad8
|
@ -6,7 +6,7 @@ set(META_APP_NAME "Tag Editor")
|
|||
set(META_APP_CATEGORIES "Utility;Audio;Video;")
|
||||
set(META_APP_AUTHOR "Martchus")
|
||||
set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}")
|
||||
set(META_APP_DESCRIPTION "A tageditor with Qt GUI and command line interface. Supports MP4 (iTunes), ID3, Vorbis, Opus and Matroska.")
|
||||
set(META_APP_DESCRIPTION "A tageditor with Qt GUI and command line interface. Supports MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska.")
|
||||
set(META_VERSION_MAJOR 1)
|
||||
set(META_VERSION_MINOR 4)
|
||||
set(META_VERSION_PATCH 1)
|
||||
|
@ -130,6 +130,10 @@ set(ICON_FILES
|
|||
resources/icons/hicolor/scalable/apps/${META_PROJECT_NAME}.svg
|
||||
)
|
||||
|
||||
set(DOC_FILES
|
||||
README.md
|
||||
)
|
||||
|
||||
# find c++utilities
|
||||
find_package(c++utilities 3.3.0 REQUIRED)
|
||||
use_cpp_utilities()
|
||||
|
|
|
@ -30,26 +30,29 @@ namespace Cli {
|
|||
SetTagInfoArgs::SetTagInfoArgs(Argument &filesArg, Argument &verboseArg) :
|
||||
filesArg(filesArg),
|
||||
verboseArg(verboseArg),
|
||||
docTitleArg("doc-title", "d", "specifies the document title (has no affect if not supported by the container)"),
|
||||
removeOtherFieldsArg("remove-other-fields", nullptr, "if present ALL unspecified tag fields will be removed (to remove a specific field use eg. \"album=\")"),
|
||||
treatUnknownFilesAsMp3FilesArg("treat-unknown-as-mp3", nullptr, "if present unknown files will be treatet as MP3 files"),
|
||||
id3v1UsageArg("id3v1-usage", nullptr, "specifies the ID3v1 usage (only used when already present by default); only relevant when dealing with MP3 files (or files treated as such)"),
|
||||
id3v2UsageArg("id3v2-usage", nullptr, "specifies the ID3v2 usage (always used by default); only relevant when dealing with MP3 files (or files treated as such)"),
|
||||
mergeMultipleSuccessiveTagsArg("merge-successive-tags", nullptr, "if present multiple successive ID3v2 tags will be merged"),
|
||||
id3v2VersionArg("id3v2-version", nullptr, "forces a specific ID3v2 version to be used; only relevant when ID3v2 is used"),
|
||||
encodingArg("encoding", nullptr, "specifies the preferred encoding"),
|
||||
removeTargetsArg("remove-targets", nullptr, "removes all tags with the specified targets (which must be separated by \",\")"),
|
||||
attachmentsArg("attachments", nullptr, "specifies attachments to be added/updated/removed (multiple attachments must be separated by \",\""),
|
||||
removeExistingAttachmentsArg("remove-existing-attachments", "ra", "specifies names/IDs of existing attachments to be removed"),
|
||||
minPaddingArg("min-padding", nullptr, "specifies the minimum padding before the media data"),
|
||||
maxPaddingArg("max-padding", nullptr, "specifies the maximum padding before the media data"),
|
||||
prefPaddingArg("preferred-padding", nullptr, "specifies the preferred padding before the media data"),
|
||||
tagPosArg("tag-pos", nullptr, "specifies the preferred tag position"),
|
||||
forceTagPosArg("force-tag-pos", nullptr, "forces the specified tag postion to be used even if it requires the file to be rewritten"),
|
||||
indexPosArg("index-pos", nullptr, "specifies the preferred index position"),
|
||||
forceIndexPosArg("force-index-pos", nullptr, "forces the specified index postion to be used even if it requires the file to be rewritten"),
|
||||
forceRewriteArg("force-rewrite", nullptr, "forces the file to rewritten from the scratch"),
|
||||
setTagInfoArg("set-tag-info", "set", "sets the values of all specified tag fields")
|
||||
docTitleArg("doc-title", 'd', "specifies the document title (has no affect if not supported by the container)"),
|
||||
removeOtherFieldsArg("remove-other-fields", '\0', "if present ALL unspecified tag fields will be removed (to remove a specific field use eg. \"album=\")"),
|
||||
treatUnknownFilesAsMp3FilesArg("treat-unknown-as-mp3", '\0', "if present unknown files will be treatet as MP3 files"),
|
||||
id3v1UsageArg("id3v1-usage", '\0', "specifies the ID3v1 usage (only used when already present by default); only relevant when dealing with MP3 files (or files treated as such)"),
|
||||
id3v2UsageArg("id3v2-usage", '\0', "specifies the ID3v2 usage (always used by default); only relevant when dealing with MP3 files (or files treated as such)"),
|
||||
mergeMultipleSuccessiveTagsArg("merge-successive-tags", '\0', "if present multiple successive ID3v2 tags will be merged"),
|
||||
id3v2VersionArg("id3v2-version", '\0', "forces a specific ID3v2 version to be used; only relevant when ID3v2 is used"),
|
||||
encodingArg("encoding", '\0', "specifies the preferred encoding"),
|
||||
removeTargetsArg("remove-targets", '\0', "removes all tags with the specified targets (which must be separated by \",\")"),
|
||||
attachmentsArg("attachments", '\0', "specifies attachments to be added/updated/removed (multiple attachments must be separated by \",\""),
|
||||
removeExistingAttachmentsArg("remove-existing-attachments", 'r', "specifies names/IDs of existing attachments to be removed"),
|
||||
minPaddingArg("min-padding", '\0', "specifies the minimum padding before the media data"),
|
||||
maxPaddingArg("max-padding", '\0', "specifies the maximum padding before the media data"),
|
||||
prefPaddingArg("preferred-padding", '\0', "specifies the preferred padding before the media data"),
|
||||
tagPosValueArg("value", 'v', "specifies the position, either front, back or current"),
|
||||
forceTagPosArg("force", 'f', "forces the specified position even if the file to be rewritten"),
|
||||
tagPosArg("tag-pos", '\0', "specifies the preferred tag position"),
|
||||
indexPosValueArg("value", 'v', "specifies the position, either front, back or current"),
|
||||
forceIndexPosArg("force", 'f', "forces the specified position even if the file to be rewritten"),
|
||||
indexPosArg("index-pos", '\0', "specifies the preferred index position"),
|
||||
forceRewriteArg("force-rewrite", '\0', "forces the file to rewritten from the scratch"),
|
||||
valuesArg("fields", 'n', "specifies the values to be set"),
|
||||
setTagInfoArg("set", 's', "sets the values of all specified tag fields")
|
||||
{
|
||||
docTitleArg.setCombinable(true);
|
||||
docTitleArg.setRequiredValueCount(-1);
|
||||
|
@ -85,20 +88,23 @@ SetTagInfoArgs::SetTagInfoArgs(Argument &filesArg, Argument &verboseArg) :
|
|||
prefPaddingArg.setRequiredValueCount(1);
|
||||
prefPaddingArg.setValueNames({"preferred padding in byte"});
|
||||
prefPaddingArg.setCombinable(true);
|
||||
tagPosArg.setRequiredValueCount(1);
|
||||
tagPosValueArg.setRequiredValueCount(1);
|
||||
forceTagPosArg.setCombinable(true);
|
||||
tagPosArg.setValueNames({"front/back/current"});
|
||||
tagPosArg.setCombinable(true);
|
||||
tagPosArg.setSecondaryArguments({&forceTagPosArg});
|
||||
indexPosArg.setRequiredValueCount(1);
|
||||
tagPosArg.setSubArguments({&tagPosValueArg, &forceTagPosArg});
|
||||
indexPosValueArg.setRequiredValueCount(1);
|
||||
forceIndexPosArg.setCombinable(true);
|
||||
indexPosArg.setValueNames({"front/back/current"});
|
||||
indexPosArg.setCombinable(true);
|
||||
indexPosArg.setSecondaryArguments({&forceIndexPosArg});
|
||||
indexPosArg.setSubArguments({&indexPosValueArg, &forceIndexPosArg});
|
||||
forceRewriteArg.setCombinable(true);
|
||||
valuesArg.setValueNames({"title=foo", "album=bar", "cover=/path/to/file"});
|
||||
valuesArg.setRequiredValueCount(-1);
|
||||
valuesArg.setImplicit(true);
|
||||
setTagInfoArg.setDenotesOperation(true);
|
||||
setTagInfoArg.setCallback(std::bind(Cli::setTagInfo, _1, std::cref(*this)));
|
||||
setTagInfoArg.setRequiredValueCount(-1);
|
||||
setTagInfoArg.setValueNames({"title=foo", "album=bar", "cover=/path/to/file"});
|
||||
setTagInfoArg.setSecondaryArguments({&filesArg, &docTitleArg, &removeOtherFieldsArg, &treatUnknownFilesAsMp3FilesArg, &id3v1UsageArg, &id3v2UsageArg,
|
||||
setTagInfoArg.setSubArguments({&valuesArg, &filesArg, &docTitleArg, &removeOtherFieldsArg, &treatUnknownFilesAsMp3FilesArg, &id3v1UsageArg, &id3v2UsageArg,
|
||||
&mergeMultipleSuccessiveTagsArg, &id3v2VersionArg, &encodingArg, &removeTargetsArg, &attachmentsArg,
|
||||
&removeExistingAttachmentsArg, &minPaddingArg, &maxPaddingArg, &prefPaddingArg, &tagPosArg,
|
||||
&indexPosArg, &forceRewriteArg, &verboseArg});
|
||||
|
@ -114,86 +120,92 @@ int main(int argc, char *argv[])
|
|||
QT_CONFIG_ARGUMENTS qtConfigArgs;
|
||||
HelpArgument helpArg(parser);
|
||||
// verbose option
|
||||
Argument verboseArg("verbose", "v", "be verbose");
|
||||
Argument verboseArg("verbose", 'v', "be verbose");
|
||||
verboseArg.setCombinable(true);
|
||||
// recursive option
|
||||
Argument recursiveArg("recursive", "r", "includes subdirectories");
|
||||
Argument recursiveArg("recursive", 'r', "includes subdirectories");
|
||||
// input/output file/files
|
||||
Argument filesArg("files", "f", "specifies the path of the file(s) to be opened");
|
||||
filesArg.setValueNames({"path 1", "path 2"});
|
||||
filesArg.setRequiredValueCount(-1);
|
||||
filesArg.setRequired(false);
|
||||
filesArg.setImplicit(true);
|
||||
qtConfigArgs.qtWidgetsGuiArg().addSecondaryArgument(&filesArg);
|
||||
Argument fileArg("file", "if", "specifies the path of the input file");
|
||||
Argument fileArg("file", 'f', "specifies the path of the file to be opened");
|
||||
fileArg.setValueNames({"path"});
|
||||
fileArg.setRequiredValueCount(1);
|
||||
fileArg.setRequired(true);
|
||||
Argument outputFileArg("output-file", "of", "specifies the path of the output file");
|
||||
fileArg.setCombinable(true);
|
||||
Argument defaultFileArg(fileArg);
|
||||
defaultFileArg.setImplicit(true);
|
||||
Argument filesArg("files", 'f', "specifies the path of the file(s) to be opened");
|
||||
filesArg.setValueNames({"path 1", "path 2"});
|
||||
filesArg.setRequiredValueCount(-1);
|
||||
filesArg.setCombinable(true);
|
||||
Argument outputFileArg("output-file", 'o', "specifies the path of the output file");
|
||||
outputFileArg.setValueNames({"path"});
|
||||
outputFileArg.setRequiredValueCount(1);
|
||||
outputFileArg.setRequired(true);
|
||||
outputFileArg.setCombinable(true);
|
||||
// print field names
|
||||
Argument printFieldNamesArg("print-field-names", nullptr, "prints available field names");
|
||||
Argument printFieldNamesArg("print-field-names", '\0', "prints available field names");
|
||||
printFieldNamesArg.setCallback(Cli::printFieldNames);
|
||||
// display general file info
|
||||
Argument displayFileInfoArg("display-file-info", "info", "displays general file information");
|
||||
Argument displayFileInfoArg("display-file-info", 'i', "displays general file information");
|
||||
displayFileInfoArg.setDenotesOperation(true);
|
||||
displayFileInfoArg.setCallback(std::bind(Cli::displayFileInfo, _1, std::cref(filesArg), std::cref(verboseArg)));
|
||||
displayFileInfoArg.setSecondaryArguments({&filesArg, &verboseArg});
|
||||
displayFileInfoArg.setSubArguments({&filesArg, &verboseArg});
|
||||
// display tag info
|
||||
Argument displayTagInfoArg("display-tag-info", "get", "displays the values of all specified tag fields (displays all fields if none specified)");
|
||||
Argument fieldsArg("fields", 'n', "specifies the field names to be displayed");
|
||||
fieldsArg.setValueNames({"title", "album", "artist", "trackpos"});
|
||||
fieldsArg.setRequiredValueCount(-1);
|
||||
fieldsArg.setImplicit(true);
|
||||
Argument displayTagInfoArg("get", 'g', "displays the values of all specified tag fields (displays all fields if none specified)");
|
||||
displayTagInfoArg.setDenotesOperation(true);
|
||||
displayTagInfoArg.setCallback(std::bind(Cli::displayTagInfo, _1, std::cref(filesArg), std::cref(verboseArg)));
|
||||
displayTagInfoArg.setRequiredValueCount(-1);
|
||||
displayTagInfoArg.setValueNames({"title", "album", "artist", "trackpos"});
|
||||
displayTagInfoArg.setSecondaryArguments({&filesArg, &verboseArg});
|
||||
displayTagInfoArg.setSubArguments({&fieldsArg, &filesArg, &verboseArg});
|
||||
// set tag info
|
||||
Cli::SetTagInfoArgs setTagInfoArgs(filesArg, verboseArg);
|
||||
// extract cover
|
||||
Argument extractFieldArg("extract", "ext", "extracts the specified field from the specified file");
|
||||
extractFieldArg.setRequiredValueCount(1);
|
||||
extractFieldArg.setValueNames({"field"});
|
||||
extractFieldArg.setSecondaryArguments({&fileArg, &outputFileArg, &verboseArg});
|
||||
Argument fieldArg("fields", 'n', "specifies the field to be extracted");
|
||||
fieldArg.setValueNames({"field name"});
|
||||
fieldArg.setRequiredValueCount(1);
|
||||
fieldArg.setImplicit(true);
|
||||
Argument extractFieldArg("extract", 'e', "extracts the specified field from the specified file");
|
||||
extractFieldArg.setSubArguments({&fieldArg, &fileArg, &outputFileArg, &verboseArg});
|
||||
extractFieldArg.setDenotesOperation(true);
|
||||
extractFieldArg.setCallback(std::bind(Cli::extractField, _1, std::cref(fileArg), std::cref(outputFileArg), std::cref(verboseArg)));
|
||||
// file info
|
||||
Argument validateArg("validate", "c", "validates the file integrity as accurately as possible; the structure of the file will be parsed completely");
|
||||
validateArg.setDenotesOperation(true);
|
||||
Argument validateArg("validate", 'c', "validates the file integrity as accurately as possible; the structure of the file will be parsed completely");
|
||||
validateArg.setCombinable(true);
|
||||
Argument genInfoArg("html-info", nullptr, "generates technical information about the specified file as HTML document");
|
||||
Argument genInfoArg("html-info", '\0', "generates technical information about the specified file as HTML document");
|
||||
genInfoArg.setDenotesOperation(true);
|
||||
genInfoArg.setSecondaryArguments({&fileArg, &validateArg, &outputFileArg});
|
||||
genInfoArg.setSubArguments({&fileArg, &validateArg, &outputFileArg});
|
||||
genInfoArg.setCallback(std::bind(Cli::generateFileInfo, _1, std::cref(fileArg), std::cref(outputFileArg), std::cref(validateArg)));
|
||||
// remove backup files
|
||||
Argument remBackupFilesArg("remove-backup-files", nullptr, "removes all files with \".bak\" suffix in the given directory and in subdirectories if recursive option is present");
|
||||
Argument directoryArg("directory", 'd', "specifies the directory");
|
||||
directoryArg.setRequiredValueCount(1);
|
||||
directoryArg.setValueNames({"path"});
|
||||
directoryArg.setImplicit(true);
|
||||
Argument remBackupFilesArg("remove-backup-files", '\0', "removes all files with \".bak\" suffix in the given directory and in subdirectories if recursive option is present");
|
||||
remBackupFilesArg.setDenotesOperation(true);
|
||||
remBackupFilesArg.setCallback(std::bind(Cli::removeBackupFiles, _1, std::cref(recursiveArg)));
|
||||
remBackupFilesArg.setValueNames({"directory"});
|
||||
remBackupFilesArg.setRequiredValueCount(1);
|
||||
remBackupFilesArg.setSecondaryArguments({&recursiveArg});
|
||||
remBackupFilesArg.setSubArguments({&directoryArg, &recursiveArg});
|
||||
// renaming utility
|
||||
Argument renamingUtilityArg("renaming-utility", nullptr, "launches the renaming utility instead of the main GUI");
|
||||
Argument renamingUtilityArg("renaming-utility", '\0', "launches the renaming utility instead of the main GUI");
|
||||
renamingUtilityArg.setCombinable(true);
|
||||
// set arguments to parser
|
||||
qtConfigArgs.qtWidgetsGuiArg().addSecondaryArgument(&filesArg);
|
||||
qtConfigArgs.qtWidgetsGuiArg().addSecondaryArgument(&renamingUtilityArg);
|
||||
parser.setMainArguments({&printFieldNamesArg, &displayFileInfoArg, &displayTagInfoArg, &setTagInfoArgs.setTagInfoArg, &extractFieldArg, &genInfoArg, &remBackupFilesArg, &qtConfigArgs.qtWidgetsGuiArg(), &helpArg});
|
||||
qtConfigArgs.qtWidgetsGuiArg().setAbbreviation('\0');
|
||||
qtConfigArgs.qtWidgetsGuiArg().addSubArgument(&defaultFileArg);
|
||||
qtConfigArgs.qtWidgetsGuiArg().addSubArgument(&renamingUtilityArg);
|
||||
parser.setMainArguments({&qtConfigArgs.qtWidgetsGuiArg(), &printFieldNamesArg, &displayFileInfoArg, &displayTagInfoArg, &setTagInfoArgs.setTagInfoArg, &extractFieldArg, &genInfoArg, &remBackupFilesArg, &helpArg});
|
||||
// parse given arguments
|
||||
try {
|
||||
parser.parseArgs(argc, argv);
|
||||
if(qtConfigArgs.areQtGuiArgsPresent()) {
|
||||
#ifdef GUI_QTWIDGETS
|
||||
return QtGui::runWidgetsGui(argc, argv, qtConfigArgs, filesArg.values().empty() ? QString() : QString::fromLocal8Bit(filesArg.values().front().data()), renamingUtilityArg.isPresent());
|
||||
return QtGui::runWidgetsGui(argc, argv, qtConfigArgs, defaultFileArg.isPresent() && !defaultFileArg.values().empty() ? QString::fromLocal8Bit(defaultFileArg.values().front()) : QString(), renamingUtilityArg.isPresent());
|
||||
#else
|
||||
CMD_UTILS_START_CONSOLE;
|
||||
cout << "Application has not been build with Qt widgets GUI support." << endl;
|
||||
cerr << "Application has not been build with Qt widgets GUI support." << endl;
|
||||
#endif
|
||||
}
|
||||
} catch(const Failure &ex) {
|
||||
CMD_UTILS_START_CONSOLE;
|
||||
cout << "Unable to parse arguments. " << ex.what() << "\nSee --help for available commands." << endl;
|
||||
cerr << "Unable to parse arguments. " << ex.what() << "\nSee --help for available commands." << endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -151,7 +151,7 @@ void printNotifications(const MediaFileInfo &fileInfo, const char *head = nullpt
|
|||
printNotifications(notifications, head, beVerbose);
|
||||
}
|
||||
|
||||
void printFieldNames(const StringVector ¶meterValues)
|
||||
void printFieldNames(const std::vector<const char *> ¶meterValues)
|
||||
{
|
||||
CMD_UTILS_START_CONSOLE;
|
||||
VAR_UNUSED(parameterValues)
|
||||
|
@ -160,7 +160,7 @@ void printFieldNames(const StringVector ¶meterValues)
|
|||
"recordlabel cover composer rating description" << endl;
|
||||
}
|
||||
|
||||
void removeBackupFiles(const StringVector ¶meterValues, const Argument &recursiveArg)
|
||||
void removeBackupFiles(const std::vector<const char *> ¶meterValues, const Argument &recursiveArg)
|
||||
{
|
||||
CMD_UTILS_START_CONSOLE;
|
||||
QDir dir(QString::fromStdString(parameterValues.at(0)));
|
||||
|
@ -173,11 +173,11 @@ TagUsage parseUsageDenotation(const Argument &usageArg, TagUsage defaultUsage)
|
|||
{
|
||||
if(usageArg.isPresent()) {
|
||||
const auto &val = usageArg.values().front();
|
||||
if(val == "never") {
|
||||
if(!strcmp(val, "never")) {
|
||||
return TagUsage::Never;
|
||||
} else if(val == "keepexisting") {
|
||||
} else if(!strcmp(val, "keepexisting")) {
|
||||
return TagUsage::KeepExisting;
|
||||
} else if(val == "always") {
|
||||
} else if(!strcmp(val, "always")) {
|
||||
return TagUsage::Always;
|
||||
} else {
|
||||
cout << "Warning: The specified tag usage \"" << val << "\" is invalid and will be ignored." << endl;
|
||||
|
@ -190,15 +190,15 @@ TagTextEncoding parseEncodingDenotation(const Argument &encodingArg, TagTextEnco
|
|||
{
|
||||
if(encodingArg.isPresent()) {
|
||||
const auto &val = encodingArg.values().front();
|
||||
if(val == "utf8") {
|
||||
if(!strcmp(val, "utf8")) {
|
||||
return TagTextEncoding::Utf8;
|
||||
} else if(val == "latin1") {
|
||||
} else if(!strcmp(val, "latin1")) {
|
||||
return TagTextEncoding::Latin1;
|
||||
} else if(val == "utf16be") {
|
||||
} else if(!strcmp(val, "utf16be")) {
|
||||
return TagTextEncoding::Utf16BigEndian;
|
||||
} else if(val == "utf16le") {
|
||||
} else if(!strcmp(val, "utf16le")) {
|
||||
return TagTextEncoding::Utf16LittleEndian;
|
||||
} else if(val == "auto") {
|
||||
} else if(!strcmp(val, "auto")) {
|
||||
} else {
|
||||
cout << "Warning: The specified encoding \"" << val << "\" is invalid and will be ignored." << endl;
|
||||
}
|
||||
|
@ -210,11 +210,11 @@ ElementPosition parsePositionDenotation(const Argument &posArg, ElementPosition
|
|||
{
|
||||
if(posArg.isPresent()) {
|
||||
const auto &val = posArg.values().front();
|
||||
if(val == "front") {
|
||||
if(!strcmp(val, "front")) {
|
||||
return ElementPosition::BeforeData;
|
||||
} else if(val == "back") {
|
||||
} else if(!strcmp(val, "back")) {
|
||||
return ElementPosition::AfterData;
|
||||
} else if(val == "keep") {
|
||||
} else if(!strcmp(val, "keep")) {
|
||||
return ElementPosition::Keep;
|
||||
} else {
|
||||
cout << "Warning: The specified position \"" << val << "\" is invalid and will be ignored." << endl;
|
||||
|
@ -227,8 +227,8 @@ uint64 parseUInt64(const Argument &arg, uint64 defaultValue)
|
|||
{
|
||||
if(arg.isPresent()) {
|
||||
try {
|
||||
if(startsWith<string>(arg.values().front(), "0x")) {
|
||||
return stringToNumber<decltype(parseUInt64(arg, defaultValue))>(arg.values().front().substr(2), 16);
|
||||
if(*arg.values().front() == '0' && *(arg.values().front() + 1) == 'x') {
|
||||
return stringToNumber<decltype(parseUInt64(arg, defaultValue))>(arg.values().front() + 2, 16);
|
||||
} else {
|
||||
return stringToNumber<decltype(parseUInt64(arg, defaultValue))>(arg.values().front());
|
||||
}
|
||||
|
@ -284,20 +284,21 @@ bool applyTargetConfiguration(TagTarget &target, const std::string &configStr)
|
|||
}
|
||||
}
|
||||
|
||||
vector<FieldDenotation> parseFieldDenotations(const StringVector &fieldDenotations, bool readOnly)
|
||||
vector<FieldDenotation> parseFieldDenotations(const std::vector<const char *> &fieldDenotations, bool readOnly)
|
||||
{
|
||||
vector<FieldDenotation> fields;
|
||||
fields.reserve(fieldDenotations.size());
|
||||
TagType currentTagType = TagType::Unspecified;
|
||||
TagTarget currentTagTarget;
|
||||
for(const string &fieldDenotationString : fieldDenotations) {
|
||||
for(const char *fieldDenotationString : fieldDenotations) {
|
||||
// check for tag or target specifier
|
||||
if(strncmp(fieldDenotationString.c_str(), "tag:", 4) == 0) {
|
||||
if(fieldDenotationString.size() == 4) {
|
||||
const auto fieldDenotationLen = strlen(fieldDenotationString);
|
||||
if(strncmp(fieldDenotationString, "tag:", 4) == 0) {
|
||||
if(fieldDenotationLen == 4) {
|
||||
cout << "Warning: The \"tag\"-specifier has been used with no value(s) and hence is ignored. Possible values are: id3,id3v1,id3v2,itunes,vorbis,matroska,all" << endl;
|
||||
} else {
|
||||
TagType tagType = TagType::Unspecified;
|
||||
for(const auto &part : splitString(fieldDenotationString.substr(4), ",", EmptyPartsTreat::Omit)) {
|
||||
for(const auto &part : splitString(fieldDenotationString + 4, ",", EmptyPartsTreat::Omit)) {
|
||||
if(part == "id3v1") {
|
||||
tagType |= TagType::Id3v1Tag;
|
||||
} else if(part == "id3v2") {
|
||||
|
@ -326,8 +327,8 @@ vector<FieldDenotation> parseFieldDenotations(const StringVector &fieldDenotatio
|
|||
continue;
|
||||
}
|
||||
// read field name
|
||||
auto equationPos = fieldDenotationString.find('=');
|
||||
auto fieldName = equationPos != string::npos ? fieldDenotationString.substr(0, equationPos) : fieldDenotationString;
|
||||
const auto equationPos = strchr(fieldDenotationString, '=');
|
||||
auto fieldName = equationPos ? string(fieldDenotationString, static_cast<size_t>(equationPos - fieldDenotationString)) : fieldDenotationString;
|
||||
// field name might denote increment ("+") or path disclosure (">")
|
||||
auto fieldNamePos = fieldName.size();
|
||||
DenotationType type = DenotationType::Normal;
|
||||
|
@ -354,7 +355,7 @@ vector<FieldDenotation> parseFieldDenotations(const StringVector &fieldDenotatio
|
|||
cout << "Warning: Ignoring field denotation \"" << fieldDenotationString << "\" because no field name has been specified." << endl;
|
||||
continue;
|
||||
} else if(++fieldNamePos < fieldName.size()) {
|
||||
fieldName = fieldName.substr(0, fieldNamePos);
|
||||
fieldName = string(fieldName, fieldNamePos);
|
||||
}
|
||||
// parse the denoted filed
|
||||
KnownField field;
|
||||
|
@ -424,11 +425,11 @@ vector<FieldDenotation> parseFieldDenotations(const StringVector &fieldDenotatio
|
|||
fieldDenotation.type = type;
|
||||
fieldDenotation.tagType = currentTagType;
|
||||
fieldDenotation.tagTarget = currentTagTarget;
|
||||
if(equationPos != string::npos) {
|
||||
if(equationPos) {
|
||||
if(readOnly) {
|
||||
cout << "Warning: Specified value for \"" << fieldName << "\" will be ignored." << endl;
|
||||
} else {
|
||||
fieldDenotation.values.emplace_back(make_pair(mult == 1 ? fieldDenotation.values.size() : fileIndex, QString::fromLocal8Bit(fieldDenotationString.data() + equationPos + 1)));
|
||||
fieldDenotation.values.emplace_back(make_pair(mult == 1 ? fieldDenotation.values.size() : fileIndex, QString::fromLocal8Bit(equationPos + 1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -569,7 +570,7 @@ bool AttachmentInfo::next(AbstractContainer *container)
|
|||
return true;
|
||||
}
|
||||
|
||||
void generateFileInfo(const StringVector ¶meterValues, const Argument &inputFileArg, const Argument &outputFileArg, const Argument &validateArg)
|
||||
void generateFileInfo(const std::vector<const char *> ¶meterValues, const Argument &inputFileArg, const Argument &outputFileArg, const Argument &validateArg)
|
||||
{
|
||||
CMD_UTILS_START_CONSOLE;
|
||||
VAR_UNUSED(parameterValues)
|
||||
|
@ -581,7 +582,7 @@ void generateFileInfo(const StringVector ¶meterValues, const Argument &input
|
|||
inputFileInfo.parseEverything();
|
||||
cout << "Saving file info of \"" << inputFileArg.values().front() << "\" ..." << endl;
|
||||
NotificationList origNotify;
|
||||
QFile file(QString::fromLocal8Bit(outputFileArg.values().front().c_str()));
|
||||
QFile file(QString::fromLocal8Bit(outputFileArg.values().front()));
|
||||
if(file.open(QFile::WriteOnly) && file.write(HtmlInfo::generateInfo(inputFileInfo, origNotify)) && file.flush()) {
|
||||
cout << "File information has been saved to \"" << outputFileArg.values().front() << "\"." << endl;
|
||||
} else {
|
||||
|
@ -639,10 +640,10 @@ void printProperty(const char *propName, const intType value, const char *suffix
|
|||
}
|
||||
}
|
||||
|
||||
void displayFileInfo(const StringVector &, const Argument &filesArg, const Argument &verboseArg)
|
||||
void displayFileInfo(const std::vector<const char *> &, const Argument &filesArg, const Argument &verboseArg)
|
||||
{
|
||||
CMD_UTILS_START_CONSOLE;
|
||||
if(!filesArg.valueCount()) {
|
||||
if(filesArg.values().empty()) {
|
||||
cout << "Error: No files have been specified." << endl;
|
||||
return;
|
||||
}
|
||||
|
@ -766,10 +767,10 @@ void displayFileInfo(const StringVector &, const Argument &filesArg, const Argum
|
|||
}
|
||||
}
|
||||
|
||||
void displayTagInfo(const StringVector ¶meterValues, const Argument &filesArg, const Argument &verboseArg)
|
||||
void displayTagInfo(const std::vector<const char *> ¶meterValues, const Argument &filesArg, const Argument &verboseArg)
|
||||
{
|
||||
CMD_UTILS_START_CONSOLE;
|
||||
if(!filesArg.valueCount()) {
|
||||
if(filesArg.values().empty()) {
|
||||
cout << "Error: No files have been specified." << endl;
|
||||
return;
|
||||
}
|
||||
|
@ -864,10 +865,10 @@ void displayTagInfo(const StringVector ¶meterValues, const Argument &filesAr
|
|||
}
|
||||
}
|
||||
|
||||
void setTagInfo(const StringVector ¶meterValues, const SetTagInfoArgs &args)
|
||||
void setTagInfo(const std::vector<const char *> ¶meterValues, const SetTagInfoArgs &args)
|
||||
{
|
||||
CMD_UTILS_START_CONSOLE;
|
||||
if(!args.setTagInfoArg.valueCount()) {
|
||||
if(args.setTagInfoArg.values().empty()) {
|
||||
cout << "Error: No files have been specified." << endl;
|
||||
return;
|
||||
}
|
||||
|
@ -888,7 +889,7 @@ void setTagInfo(const StringVector ¶meterValues, const SetTagInfoArgs &args)
|
|||
targetsToRemove.emplace_back();
|
||||
bool validRemoveTargetsSpecified = false;
|
||||
for(const auto &targetDenotation : args.removeTargetsArg.values()) {
|
||||
if(targetDenotation == ",") {
|
||||
if(!strcmp(targetDenotation, ",")) {
|
||||
if(validRemoveTargetsSpecified) {
|
||||
targetsToRemove.emplace_back();
|
||||
}
|
||||
|
@ -906,7 +907,7 @@ void setTagInfo(const StringVector ¶meterValues, const SetTagInfoArgs &args)
|
|||
if(id3v2Version < 1 || id3v2Version > 4) {
|
||||
throw ConversionException();
|
||||
}
|
||||
} catch (ConversionException &) {
|
||||
} catch (const ConversionException &) {
|
||||
id3v2Version = 3;
|
||||
cout << "Warning: The specified ID3v2 version \"" << args.id3v2VersionArg.values().front() << "\" is invalid and will be ingored." << endl;
|
||||
}
|
||||
|
@ -1041,36 +1042,35 @@ void setTagInfo(const StringVector ¶meterValues, const SetTagInfoArgs &args)
|
|||
}
|
||||
// add/update/remove attachments explicitely
|
||||
AttachmentInfo currentInfo;
|
||||
for(const auto &value : args.attachmentsArg.values()) {
|
||||
const auto *data = value.data();
|
||||
if(value == ",") {
|
||||
for(const char *value : args.attachmentsArg.values()) {
|
||||
if(!strcmp(value, ",")) {
|
||||
attachmentsModified |= currentInfo.next(container);
|
||||
} else if(value == "add") {
|
||||
} else if(!strcmp(value, "add")) {
|
||||
currentInfo.action = AttachmentAction::Add;
|
||||
} else if(value == "update-by-id") {
|
||||
} else if(!strcmp(value, "update-by-id")) {
|
||||
currentInfo.action = AttachmentAction::UpdateById;
|
||||
} else if(value == "update-by-name") {
|
||||
} else if(!strcmp(value, "update-by-name")) {
|
||||
currentInfo.action = AttachmentAction::UpdateByName;
|
||||
} else if(value == "remove-by-id") {
|
||||
} else if(!strcmp(value, "remove-by-id")) {
|
||||
currentInfo.action = AttachmentAction::RemoveById;
|
||||
} else if(value == "remove-by-name") {
|
||||
} else if(!strcmp(value, "remove-by-name")) {
|
||||
currentInfo.action = AttachmentAction::RemoveByName;
|
||||
} else if(!strncmp(data, "id=", 3)) {
|
||||
} else if(!strncmp(value, "id=", 3)) {
|
||||
try {
|
||||
currentInfo.id = stringToNumber<uint64, string>(data + 3);
|
||||
currentInfo.id = stringToNumber<uint64, string>(value + 3);
|
||||
} catch(const ConversionException &) {
|
||||
container->addNotification(NotificationType::Warning, "The specified attachment ID \"" + string(data + 3) + "\" is invalid.", context);
|
||||
container->addNotification(NotificationType::Warning, "The specified attachment ID \"" + string(value + 3) + "\" is invalid.", context);
|
||||
}
|
||||
} else if(!strncmp(data, "path=", 5)) {
|
||||
currentInfo.path = data + 5;
|
||||
} else if(!strncmp(data, "name=", 5)) {
|
||||
currentInfo.name = data + 5;
|
||||
} else if(!strncmp(data, "mime=", 5)) {
|
||||
currentInfo.mime = data + 5;
|
||||
} else if(!strncmp(data, "desc=", 5)) {
|
||||
currentInfo.desc = data + 5;
|
||||
} else if(!strncmp(value, "path=", 5)) {
|
||||
currentInfo.path = value + 5;
|
||||
} else if(!strncmp(value, "name=", 5)) {
|
||||
currentInfo.name = value + 5;
|
||||
} else if(!strncmp(value, "mime=", 5)) {
|
||||
currentInfo.mime = value + 5;
|
||||
} else if(!strncmp(value, "desc=", 5)) {
|
||||
currentInfo.desc = value + 5;
|
||||
} else {
|
||||
container->addNotification(NotificationType::Warning, "The attachment specification \"" + value + "\" is invalid and will be ignored.", context);
|
||||
container->addNotification(NotificationType::Warning, "The attachment specification \"" + string(value) + "\" is invalid and will be ignored.", context);
|
||||
}
|
||||
}
|
||||
attachmentsModified |= currentInfo.next(container);
|
||||
|
@ -1105,7 +1105,7 @@ void setTagInfo(const StringVector ¶meterValues, const SetTagInfoArgs &args)
|
|||
}
|
||||
}
|
||||
|
||||
void extractField(const StringVector ¶meterValues, const Argument &inputFileArg, const Argument &outputFileArg, const Argument &verboseArg)
|
||||
void extractField(const std::vector<const char *> ¶meterValues, const Argument &inputFileArg, const Argument &outputFileArg, const Argument &verboseArg)
|
||||
{
|
||||
CMD_UTILS_START_CONSOLE;
|
||||
const auto fields = parseFieldDenotations(parameterValues, true);
|
||||
|
|
|
@ -8,10 +8,7 @@
|
|||
#include <vector>
|
||||
|
||||
namespace ApplicationUtilities {
|
||||
|
||||
typedef std::vector<std::string> StringVector;
|
||||
class Argument;
|
||||
|
||||
}
|
||||
|
||||
namespace Cli {
|
||||
|
@ -35,21 +32,24 @@ struct SetTagInfoArgs
|
|||
ApplicationUtilities::Argument minPaddingArg;
|
||||
ApplicationUtilities::Argument maxPaddingArg;
|
||||
ApplicationUtilities::Argument prefPaddingArg;
|
||||
ApplicationUtilities::Argument tagPosArg;
|
||||
ApplicationUtilities::Argument tagPosValueArg;
|
||||
ApplicationUtilities::Argument forceTagPosArg;
|
||||
ApplicationUtilities::Argument indexPosArg;
|
||||
ApplicationUtilities::Argument tagPosArg;
|
||||
ApplicationUtilities::Argument indexPosValueArg;
|
||||
ApplicationUtilities::Argument forceIndexPosArg;
|
||||
ApplicationUtilities::Argument indexPosArg;
|
||||
ApplicationUtilities::Argument forceRewriteArg;
|
||||
ApplicationUtilities::Argument valuesArg;
|
||||
ApplicationUtilities::Argument setTagInfoArg;
|
||||
};
|
||||
|
||||
void printFieldNames(const ApplicationUtilities::StringVector ¶meterValues);
|
||||
void displayFileInfo(const ApplicationUtilities::StringVector &, const ApplicationUtilities::Argument &filesArg, const ApplicationUtilities::Argument &verboseArg);
|
||||
void generateFileInfo(const ApplicationUtilities::StringVector ¶meterValues, const ApplicationUtilities::Argument &inputFileArg, const ApplicationUtilities::Argument &outputFileArg, const ApplicationUtilities::Argument &validateArg);
|
||||
void displayTagInfo(const ApplicationUtilities::StringVector ¶meterValues, const ApplicationUtilities::Argument &filesArg, const ApplicationUtilities::Argument &verboseArg);
|
||||
void setTagInfo(const ApplicationUtilities::StringVector ¶meterValues, const Cli::SetTagInfoArgs &args);
|
||||
void extractField(const ApplicationUtilities::StringVector ¶meterValues, const ApplicationUtilities::Argument &inputFileArg, const ApplicationUtilities::Argument &outputFileArg, const ApplicationUtilities::Argument &verboseArg);
|
||||
void removeBackupFiles(const ApplicationUtilities::StringVector ¶meterValues, const ApplicationUtilities::Argument &recursiveArg);
|
||||
void printFieldNames(const std::vector<const char *> ¶meterValues);
|
||||
void displayFileInfo(const std::vector<const char *> &, const ApplicationUtilities::Argument &filesArg, const ApplicationUtilities::Argument &verboseArg);
|
||||
void generateFileInfo(const std::vector<const char *> ¶meterValues, const ApplicationUtilities::Argument &inputFileArg, const ApplicationUtilities::Argument &outputFileArg, const ApplicationUtilities::Argument &validateArg);
|
||||
void displayTagInfo(const std::vector<const char *> ¶meterValues, const ApplicationUtilities::Argument &filesArg, const ApplicationUtilities::Argument &verboseArg);
|
||||
void setTagInfo(const std::vector<const char *> ¶meterValues, const Cli::SetTagInfoArgs &args);
|
||||
void extractField(const std::vector<const char *> ¶meterValues, const ApplicationUtilities::Argument &inputFileArg, const ApplicationUtilities::Argument &outputFileArg, const ApplicationUtilities::Argument &verboseArg);
|
||||
void removeBackupFiles(const std::vector<const char *> ¶meterValues, const ApplicationUtilities::Argument &recursiveArg);
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue