Merge branch 'refs/heads/cli'

This commit is contained in:
Martchus 2015-10-14 19:50:08 +02:00
commit a60bbe532a
5 changed files with 82 additions and 15 deletions

View File

@ -95,4 +95,4 @@ add "CONFIG+=forcewebkit" to the qmake arguments.
- Use padding to prevent rewriting the entire file to save tags.
- Support more tag formats (EXIF, PDF metadata, ...).
- Set tag information concurrently if multiple files have been specified.
- Extracting/adding/removing attachments via CLI.
- Do tests with Matroska files which have multiple segments.

View File

@ -68,6 +68,10 @@ int main(int argc, char *argv[])
displayTagInfoArg.setValueNames({"title", "album", "artist", "trackpos"});
displayTagInfoArg.setSecondaryArguments({&filesArg, &verboseArg});
// set tag info
Argument docTitleArg("doc-title", "d", "specifies the document title (has no affect if not supported by the container)");
docTitleArg.setCombinable(true);
docTitleArg.setRequiredValueCount(-1);
docTitleArg.setValueNames({"title of first segment", "title of second segment"});
Argument removeOtherFieldsArg("remove-other-fields", string(), "if present ALL unspecified tag fields will be removed (to remove a specific field use eg. \"album=\")");
removeOtherFieldsArg.setCombinable(true);
Argument treatUnknownFilesAsMp3FilesArg("treat-unknown-as-mp3", string(), "if present unknown files will be treatet as MP3 files");
@ -102,10 +106,10 @@ int main(int argc, char *argv[])
removeExistingAttachmentsArg.setCombinable(true);
Argument setTagInfoArg("set-tag-info", "set", "sets the values of all specified tag fields");
setTagInfoArg.setDenotesOperation(true);
setTagInfoArg.setCallback(std::bind(Cli::setTagInfo, _1, std::cref(filesArg), std::cref(removeOtherFieldsArg), std::cref(treatUnknownFilesAsMp3FilesArg), std::cref(id3v1UsageArg), std::cref(id3v2UsageArg), std::cref(mergeMultipleSuccessiveTagsArg), std::cref(id3v2VersionArg), std::cref(encodingArg), std::cref(removeTargetsArg), std::cref(attachmentsArg), std::cref(removeExistingAttachmentsArg), std::cref(verboseArg)));
setTagInfoArg.setCallback(std::bind(Cli::setTagInfo, _1, std::cref(filesArg), std::cref(docTitleArg), std::cref(removeOtherFieldsArg), std::cref(treatUnknownFilesAsMp3FilesArg), std::cref(id3v1UsageArg), std::cref(id3v2UsageArg), std::cref(mergeMultipleSuccessiveTagsArg), std::cref(id3v2VersionArg), std::cref(encodingArg), std::cref(removeTargetsArg), std::cref(attachmentsArg), std::cref(removeExistingAttachmentsArg), std::cref(verboseArg)));
setTagInfoArg.setRequiredValueCount(-1);
setTagInfoArg.setValueNames({"title=foo", "album=bar", "cover=/path/to/file"});
setTagInfoArg.setSecondaryArguments({&filesArg, &removeOtherFieldsArg, &treatUnknownFilesAsMp3FilesArg, &id3v1UsageArg, &id3v2UsageArg, &mergeMultipleSuccessiveTagsArg, &id3v2VersionArg, &encodingArg, &removeTargetsArg, &attachmentsArg, &removeExistingAttachmentsArg, &verboseArg});
setTagInfoArg.setSecondaryArguments({&filesArg, &docTitleArg, &removeOtherFieldsArg, &treatUnknownFilesAsMp3FilesArg, &id3v1UsageArg, &id3v2UsageArg, &mergeMultipleSuccessiveTagsArg, &id3v2VersionArg, &encodingArg, &removeTargetsArg, &attachmentsArg, &removeExistingAttachmentsArg, &verboseArg});
// extract cover
Argument extractFieldArg("extract", "ext", "extracts the specified field from the specified file");
extractFieldArg.setRequiredValueCount(1);

View File

@ -585,6 +585,20 @@ void printProperty(const char *propName, const string &value, const char *suffix
printProperty(propName, value.data(), suffix, intention);
}
void printProperty(const char *propName, TimeSpan timeSpan, const char *suffix = nullptr, size_t intention = 4)
{
if(!timeSpan.isNull()) {
printProperty(propName, timeSpan.toString(TimeSpanOutputFormat::WithMeasures), suffix, intention);
}
}
void printProperty(const char *propName, DateTime dateTime, const char *suffix = nullptr, size_t intention = 4)
{
if(!dateTime.isNull()) {
printProperty(propName, dateTime.toString(), suffix, intention);
}
}
template<typename intType>
void printProperty(const char *propName, const intType value, const char *suffix = nullptr, bool force = false, size_t intention = 4)
{
@ -611,6 +625,30 @@ void displayFileInfo(const StringVector &, const Argument &filesArg, const Argum
fileInfo.parseChapters();
cout << "Technical information for \"" << file << "\":" << endl;
cout << " Container format: " << fileInfo.containerFormatName() << endl;
{
if(const auto container = fileInfo.container()) {
size_t segmentIndex = 0;
for(const auto &title : container->titles()) {
if(segmentIndex) {
printProperty("Title", title + " (segment " + numberToString(++segmentIndex) + ")");
} else {
++segmentIndex;
printProperty("Title", title);
}
}
printProperty("Document type", container->documentType());
printProperty("Read version", container->readVersion());
printProperty("Version", container->version());
printProperty("Document read version", container->doctypeReadVersion());
printProperty("Document version", container->doctypeVersion());
printProperty("Duration", container->duration());
printProperty("Creation time", container->creationTime());
printProperty("Modification time", container->modificationTime());
}
if(fileInfo.paddingSize()) {
printProperty("Padding", dataSizeToString(fileInfo.paddingSize()));
}
}
{ // tracks
const auto tracks = fileInfo.tracks();
if(!tracks.empty()) {
@ -629,9 +667,7 @@ void displayFileInfo(const StringVector &, const Argument &filesArg, const Argum
if(track->size()) {
printProperty("Size", dataSizeToString(track->size(), true));
}
if(!track->duration().isNull()) {
printProperty("Duration", track->duration().toString(TimeSpanOutputFormat::WithMeasures));
}
printProperty("Duration", track->duration());
printProperty("FPS", track->fps());
if(track->channelConfigString()) {
printProperty("Channel config", track->channelConfigString());
@ -646,6 +682,8 @@ void displayFileInfo(const StringVector &, const Argument &filesArg, const Argum
printProperty("Sampling frequency", track->samplingFrequency(), "Hz");
printProperty("Extension sampling frequency", track->extensionSamplingFrequency(), "Hz");
printProperty("Sample count", track->sampleCount());
printProperty("Creation time", track->creationTime());
printProperty("Modification time", track->modificationTime());
cout << endl;
}
} else {
@ -794,10 +832,10 @@ void displayTagInfo(const StringVector &parameterValues, const Argument &filesAr
}
}
void setTagInfo(const StringVector &parameterValues, const Argument &filesArg, const Argument &removeOtherFieldsArg,
const Argument &treatUnknownFilesAsMp3FilesArg, const Argument &id3v1UsageArg, const Argument &id3v2UsageArg,
const Argument &mergeMultipleSuccessiveTagsArg, const Argument &id3v2VersionArg, const Argument &encodingArg,
const Argument &removeTargetsArg,
void setTagInfo(const StringVector &parameterValues, const Argument &filesArg, const Argument &docTitleArg,
const Argument &removeOtherFieldsArg, const Argument &treatUnknownFilesAsMp3FilesArg,
const Argument &id3v1UsageArg, const Argument &id3v2UsageArg, const Argument &mergeMultipleSuccessiveTagsArg,
const Argument &id3v2VersionArg, const Argument &encodingArg, const Argument &removeTargetsArg,
const Argument &attachmentsArg, const Argument &removeExistingAttachmentsArg, const Argument &verboseArg)
{
CMD_UTILS_START_CONSOLE;
@ -806,7 +844,7 @@ void setTagInfo(const StringVector &parameterValues, const Argument &filesArg, c
return;
}
auto fields = parseFieldDenotations(parameterValues, false);
if(fields.empty() && !attachmentsArg.valueCount()) {
if(fields.empty() && attachmentsArg.values().empty() && docTitleArg.values().empty()) {
cout << "Error: No fields/attachments have been specified." << endl;
return;
}
@ -875,6 +913,23 @@ void setTagInfo(const StringVector &parameterValues, const Argument &filesArg, c
// create new tags according to settings
fileInfo.createAppropriateTags(treatUnknownFilesAsMp3FilesArg.isPresent(), id3v1Usage, id3v2Usage, mergeMultipleSuccessiveTagsArg.isPresent(), !id3v2VersionArg.isPresent(), id3v2Version, requiredTargets);
auto container = fileInfo.container();
bool docTitleModified = false;
if(!docTitleArg.values().empty()) {
if(container) {
size_t segmentIndex = 0, segmentCount = container->titles().size();
for(const auto &newTitle : docTitleArg.values()) {
if(segmentIndex < segmentCount) {
container->setTitle(newTitle, segmentIndex);
docTitleModified = true;
} else {
cout << "Warning: The specified document title \"" << newTitle << "\" can not be set because the file has not that many segments or document titles are not supported." << endl;
}
++segmentIndex;
}
} else {
cout << "Warning: Setting the document title is not supported for the file." << endl;
}
}
fileInfo.tags(tags);
if(!tags.empty()) {
// iterate through all tags
@ -990,7 +1045,7 @@ void setTagInfo(const StringVector &parameterValues, const Argument &filesArg, c
// notification will be added by the file info automatically
}
}
if(!tags.empty() || attachmentsModified) {
if(!tags.empty() || docTitleModified || attachmentsModified) {
try {
// save parsing notifications because notifications of sub objects like tags, tracks, ... will be gone after applying changes
fileInfo.gatherRelatedNotifications(notifications);
@ -1001,6 +1056,8 @@ void setTagInfo(const StringVector &parameterValues, const Argument &filesArg, c
} catch(const ApplicationUtilities::Failure &) {
cout << "Error: Failed to apply changes." << endl;
}
} else {
cout << "Warning: No changed to be applied." << endl;
}
} catch(const ios_base::failure &) {
cout << "Error: An IO failure occured when reading/writing the file \"" << file << "\"." << endl;

View File

@ -18,7 +18,7 @@ void printFieldNames(const ApplicationUtilities::StringVector &parameterValues);
void displayFileInfo(const ApplicationUtilities::StringVector &, const ApplicationUtilities::Argument &filesArg, const ApplicationUtilities::Argument &verboseArg);
void generateFileInfo(const ApplicationUtilities::StringVector &parameterValues, const ApplicationUtilities::Argument &inputFileArg, const ApplicationUtilities::Argument &outputFileArg, const ApplicationUtilities::Argument &validateArg);
void displayTagInfo(const ApplicationUtilities::StringVector &parameterValues, const ApplicationUtilities::Argument &filesArg, const ApplicationUtilities::Argument &verboseArg);
void setTagInfo(const ApplicationUtilities::StringVector &parameterValues, const ApplicationUtilities::Argument &filesArg, const ApplicationUtilities::Argument &removeOtherFieldsArg, const ApplicationUtilities::Argument &treatUnknownFilesAsMp3FilesArg, const ApplicationUtilities::Argument &id3v1UsageArg, const ApplicationUtilities::Argument &id3v2UsageArg, const ApplicationUtilities::Argument &mergeMultipleSuccessiveTagsArg, const ApplicationUtilities::Argument &id3v2VersionArg, const ApplicationUtilities::Argument &encodingArg, const ApplicationUtilities::Argument &removeTargetsArg, const ApplicationUtilities::Argument &attachmentsArg, const ApplicationUtilities::Argument &removeExistingAttachmentsArg, const ApplicationUtilities::Argument &verboseArg);
void setTagInfo(const ApplicationUtilities::StringVector &parameterValues, const ApplicationUtilities::Argument &filesArg, const ApplicationUtilities::Argument &docTitleArg, const ApplicationUtilities::Argument &removeOtherFieldsArg, const ApplicationUtilities::Argument &treatUnknownFilesAsMp3FilesArg, const ApplicationUtilities::Argument &id3v1UsageArg, const ApplicationUtilities::Argument &id3v2UsageArg, const ApplicationUtilities::Argument &mergeMultipleSuccessiveTagsArg, const ApplicationUtilities::Argument &id3v2VersionArg, const ApplicationUtilities::Argument &encodingArg, const ApplicationUtilities::Argument &removeTargetsArg, const ApplicationUtilities::Argument &attachmentsArg, const ApplicationUtilities::Argument &removeExistingAttachmentsArg, const ApplicationUtilities::Argument &verboseArg);
void extractField(const ApplicationUtilities::StringVector &parameterValues, const ApplicationUtilities::Argument &inputFileArg, const ApplicationUtilities::Argument &outputFileArg, const ApplicationUtilities::Argument &verboseArg);
void removeBackupFiles(const ApplicationUtilities::StringVector &parameterValues, const ApplicationUtilities::Argument &recursiveArg);

View File

@ -640,8 +640,14 @@ QByteArray generateInfo(const MediaFileInfo &file, NotificationList &originalNot
res.append(mkExtendedSection(QStringLiteral("containerMore")));
}
if(container) {
if(!container->title().empty()) {
res.append(mkRow(QCoreApplication::translate("HtmlInfo", "Title"), qstr(container->title())));
size_t segmentIndex = 0;
for(const auto &title : container->titles()) {
if(segmentIndex) {
res.append(mkRow(QCoreApplication::translate("HtmlInfo", "Title (segment %1)").arg(++segmentIndex), qstr(title)));
} else {
++segmentIndex;
res.append(mkRow(QCoreApplication::translate("HtmlInfo", "Title"), qstr(title)));
}
}
if(container->version()) {
res.append(mkRow(QCoreApplication::translate("HtmlInfo", "Version"), QString::number(container->version())));