Compare commits

...

24 Commits

Author SHA1 Message Date
Martchus 12620c5768 Ensure desktop file name is set when initializing GUI 2024-04-12 01:08:59 +02:00
Martchus 854bd13efc Update translations 2024-02-28 21:43:03 +01:00
Martchus 22aa2f0851 Handle TRACKTOTAL/DISCTOTAL/PARTTOTAL fields in Vorbis Comments
See the corresponding tagparser commit
2024-02-28 21:39:52 +01:00
Martchus abc80c24ff Mention key used for signing binaries in README 2024-02-07 19:25:15 +01:00
Martchus 6e66b6aa0b Make code in `runProcess` compile with Qt 5 2024-01-26 12:26:32 +01:00
Martchus 934b955837 Update copyright date 2024-01-23 00:27:34 +01:00
Martchus 959b0f0032 Allow running a sub process via the script API 2024-01-20 17:30:48 +01:00
Martchus d8f542d3e4 Update translations 2024-01-17 14:34:43 +01:00
Martchus a8281f323a Fix consistency issue when declaring/defining field mapping array 2024-01-17 14:34:30 +01:00
Martchus b3f576a354 Fix typo in README 2024-01-08 14:42:02 +01:00
Martchus c26d3e7be8 Fix indentation in `gui/entertargetdialog.ui` 2024-01-07 23:37:49 +01:00
Martchus 63ec653df5 Add and update tab-stops explicitly where default order is wrong 2024-01-07 23:36:27 +01:00
Martchus 2cd47777a3 Add mapping for "Publisher webpage" in CLI 2024-01-04 20:54:43 +01:00
Martchus 88989ff986 Extend script API; allow copying tags from other files 2023-12-30 03:06:58 +01:00
Martchus e1e979f9f5 Avoid use of `jq`-argument `--argjson` as it has been removed
Apprently `--slurpfile` is supposed to be used instead.
2023-12-29 18:08:25 +01:00
Martchus 04bd9563c0 Support "Publisher webpage field" 2023-12-29 17:27:55 +01:00
Martchus dd0bbd74c5 Update use of `albumArtist` in examples of renaming utility 2023-12-29 15:47:32 +01:00
Martchus f82bf04c66 State minimum required Windows 10 version 2023-11-18 21:42:26 +01:00
Martchus a87e431e04 Update outdated README section about DPI awareness under Windows 2023-11-18 21:28:11 +01:00
Martchus 72dcbbbd81 Allow renaming file via `set --script …`
This allows doing what the GUI renaming utilitiy does on the command-line.
If only renaming is wanted
2023-11-10 15:46:45 +01:00
Martchus b5f9158106 Bump patch version 2023-11-10 14:35:52 +01:00
Martchus f1b785337d Mention settings to improve performance 2023-10-31 21:25:25 +01:00
Martchus 09e2fe20f7 Mention Chocolatey package in README 2023-10-20 17:38:41 +02:00
Martchus c7df780281 Mention problem with antivirus software in README 2023-10-20 17:38:41 +02:00
33 changed files with 572 additions and 205 deletions

View File

@ -14,7 +14,7 @@ set(META_GUI_OPTIONAL true)
set(META_JS_SRC_DIR renamingutility)
set(META_VERSION_MAJOR 3)
set(META_VERSION_MINOR 9)
set(META_VERSION_PATCH 0)
set(META_VERSION_PATCH 1)
set(META_RELEASE_DATE "2023-09-05")
set(META_ADD_DEFAULT_CPP_UNIT_TEST_APPLICATION ON)
@ -204,7 +204,7 @@ if (WIDGETS_GUI OR QUICK_GUI)
endif ()
# find tagparser
find_package(tagparser${CONFIGURATION_PACKAGE_SUFFIX} 12.1.0 REQUIRED)
find_package(tagparser${CONFIGURATION_PACKAGE_SUFFIX} 12.2.0 REQUIRED)
use_tag_parser()
# enable experimental JSON export

View File

@ -93,6 +93,19 @@ much as possible, set the following in the GUI's "File layout" settings:
When using the CLI, you just need to add `--max-padding 429496729` to the CLI arguments (and avoid any of the other
arguments mentioned in previous sections).
### Improve performance
Editing big files (especially Matroska files) can take some time. To improve the performance, put the index at the
end of the file (CLI option `--index-pos back`) because then the size of the index will never have to be recalculated.
Also follow the advice from the "Backup/temporary files" section to force rewriting and to put the temporary directory
on the same filesystem as the file you are editing. Forcing a rewrite can improve the performance because then the tag
editor will not even try to see whether it could be avoided and can thus skip computations that can take a notable
time for big Matroska files.
Of course being able to avoid a rewrite would still be more optimal. Checkout the previous section for how to achieve
that. To improve performance further when avoiding a rewrite, put the tag at the end (CLI option `--tag-pos back`).
Then the tag editor will not even try to put tags at the front and can thus skip a few computations. (Avoiding a
rewrite is still not a good idea in general.)
## Download
### Source
See the release section on GitHub.
@ -129,12 +142,19 @@ See the release section on GitHub.
the package `libopengl0` is installed on Debian/Ubuntu)
* Supports X11 and Wayland (set the environment variable `QT_QPA_PLATFORM=xcb` to disable
native Wayland support if it does not work on your system)
* Binaries are signed with the GPG key
[`B9E36A7275FC61B464B67907E06FE8F53CDC6A4C`](https://keyserver.ubuntu.com/pks/lookup?search=B9E36A7275FC61B464B67907E06FE8F53CDC6A4C&fingerprint=on&op=index).
* Windows
* for binaries checkout the [release section on GitHub](https://github.com/Martchus/tageditor/releases)
* Windows SmartScreen will likely block the execution (you'll get a window saying "Windows protected your PC");
right click on the executable, select properties and tick the checkbox to allow the execution
* the Qt 6 based version is stable and preferable but only supports Windows 10 and newer
* Antivirus software often **wrongly** considers the executable harmful. This is a known problem. Please don't create
issues about it.
* the Qt 6 based version is stable and preferable but only supports Windows 10 version 1809 and newer
* the Qt 5 based version should still work on older versions down to Windows 7 although this is not regularly checked
* Binaries are signed with the GPG key
[`B9E36A7275FC61B464B67907E06FE8F53CDC6A4C`](https://keyserver.ubuntu.com/pks/lookup?search=B9E36A7275FC61B464B67907E06FE8F53CDC6A4C&fingerprint=on&op=index).
* there is also a [Chocolatey package](https://community.chocolatey.org/packages/tageditor) maintained by bcurran3
* for mingw-w64 PKGBUILDs checkout [my GitHub repository](https://github.com/Martchus/PKGBUILDs)
## Usage
@ -353,12 +373,14 @@ Here are some Bash examples which illustrate getting and setting tag information
- The script needs to be ECMAScript as supported by the Qt framework.
- This feature requires the tag editor to be configured with Qt QML as JavaScript provider at
compile time. Checkout the build instructions under "Building with Qt GUI" for details.
- The script needs to export a `main()` function. This function gets executed for every file and
passed an object representing this file as first argument.
- The script needs to export a `main()` function. This function is invoked for every file and
passed an object representing the current file as first argument.
- Checkout the file `testfiles/set-tags.js` in this repository for an example that applies basic
fixes and tries to fetch lyrics and cover art.
- The option `--pedantic debug` is not required but useful for debugging. You may also add
`--script-settings dryRun=1` and use that setting within the script as shown in the example.
fixes and tries to fetch lyrics and cover art when according settings are passed (e.g.
`--script-settings addCover=1 addLyrics=1`).
- For debugging, the option `--pedantic debug` is very useful. You may also add
`--script-settings dryRun=1` and check for that setting within the script as shown in the
mentioned example script.
- Common tag fields are exposed as object properties as shown in the mentioned example.
- Only properties for fields that are supported by the tag are added to the "fields" object.
- Adding properties of unsupported fields manually does not work; those will just be ignored.
@ -378,6 +400,16 @@ Here are some Bash examples which illustrate getting and setting tag information
- The script is executed before any other modifications are applied. So if you also specify
values as usual (via `--values`) then these values have precedence over values set by the
script.
- It is also possible to rename the file (via e.g. `file.rename(newPath)`). This will be done
immediately and also if `main()` returns a falsy value (so it is possible to only rename a
file without modifying it by returning a falsy value). If the specified path is relative, it
is interpreted relative to current directory of the file (and *not* to the current working
directory of the tag editor).
- It is also possible to open another file via `utility.openFile(path)`. This makes it possible
to copy tags over from another file, e.g. to insert tags back from original files that have
been lost when converting to a different format. The mentioned example script `set-tags.js`
also demonstrates this for covers and lyrics when according script settings are passed (e.g.
`--script-settings addCover=1 originalDir=… originalExt=…`).
##### Further useful commands
* Let the tag editor return with a non-zero exit code even if only non-fatal problems have been encountered
@ -521,11 +553,13 @@ by selecting the Fusion style.
---
Per monitor DPI awareness (v2) is not working out of the box but experimental support
[can be enabled](https://github.com/Martchus/syncthingtray#enable-experimental-support-for-windows-per-monitor-dpi-awareness-v2).
Tag Editor supports
[PMv2](https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows#per-monitor-and-per-monitor-v2-dpi-awareness)
out of the box as of Qt 6. You may tweak settings according to the
[Qt documentation](https://doc.qt.io/qt-6/highdpi.html#configuring-windows).
## Copyright notice and license
Copyright © 2015-2023 Marius Kittler
Copyright © 2015-2024 Marius Kittler
All code is licensed under [GPL-2-or-later](LICENSE).

View File

@ -209,6 +209,8 @@ const char *KnownFieldModel::fieldName(KnownField field)
return QT_TR_NOOP("License");
case KnownField::TermsOfUse:
return QT_TR_NOOP("Terms of use");
case KnownField::PublisherWebpage:
return QT_TR_NOOP("Publisher webpage");
default:
return "";
}
@ -327,6 +329,7 @@ KnownFieldModel::KnownFieldModel(QObject *parent, DefaultSelection defaultSelect
mkItem(KnownField::ProductionCopyright, Qt::Unchecked),
mkItem(KnownField::License, Qt::Unchecked),
mkItem(KnownField::TermsOfUse, Qt::Unchecked),
mkItem(KnownField::PublisherWebpage, Qt::Unchecked),
});
// clang-format on
}

View File

@ -85,6 +85,9 @@ SetTagInfoArgs::SetTagInfoArgs(Argument &filesArg, Argument &verboseArg, Argumen
, preserveModificationTimeArg("preserve-modification-time", '\0', "preserves the file's modification time")
, preserveMuxingAppArg("preserve-muxing-app", '\0', "preserves the file's muxing app meta-data value")
, preserveWritingAppArg("preserve-writing-app", '\0', "preserves the file's writing app meta-data value")
, preserveTotalFieldsArg("preserve-total-fields", '\0',
"preserves the TRACKTOTAL/DISCTOTAL/PARTTOTAL fields in Vorbis Comments (which are otherwise automatically included into the "
"TRACKNUMBER/DISCNUMBER/PARTNUMBER fields)")
, jsArg("script", 'j', "modifies tag fields via the specified JavaScript", { "path" })
, jsSettingsArg("script-settings", '\0', "passes settings to the JavaScript specified via --script", { "key=value" })
, setTagInfoArg("set", 's', "sets the specified tag information and attachments")
@ -142,7 +145,8 @@ SetTagInfoArgs::SetTagInfoArgs(Argument &filesArg, Argument &verboseArg, Argumen
&id3v2UsageArg, &id3InitOnCreateArg, &id3TransferOnRemovalArg, &mergeMultipleSuccessiveTagsArg, &id3v2VersionArg, &encodingArg,
&removeTargetArg, &addAttachmentArg, &updateAttachmentArg, &removeAttachmentArg, &removeExistingAttachmentsArg, &minPaddingArg,
&maxPaddingArg, &prefPaddingArg, &tagPosArg, &indexPosArg, &forceRewriteArg, &backupDirArg, &layoutOnlyArg, &preserveModificationTimeArg,
&preserveMuxingAppArg, &preserveWritingAppArg, &jsArg, &jsSettingsArg, &verboseArg, &pedanticArg, &quietArg, &outputFilesArg });
&preserveMuxingAppArg, &preserveWritingAppArg, &preserveTotalFieldsArg, &jsArg, &jsSettingsArg, &verboseArg, &pedanticArg, &quietArg,
&outputFilesArg });
}
} // namespace Cli

View File

@ -131,6 +131,7 @@ void restore()
= settings.value(QStringLiteral("preservemodificationtime"), v.tagPocessing.preserveModificationTime).toBool();
v.tagPocessing.preserveMuxingApp = settings.value(QStringLiteral("preservemuxingapp"), v.tagPocessing.preserveMuxingApp).toBool();
v.tagPocessing.preserveWritingApp = settings.value(QStringLiteral("preservewritingapp"), v.tagPocessing.preserveWritingApp).toBool();
v.tagPocessing.convertTotalFields = settings.value(QStringLiteral("converttotalfields"), v.tagPocessing.convertTotalFields).toBool();
settings.beginGroup(QStringLiteral("id3v1"));
switch (settings.value(QStringLiteral("usage"), 0).toInt()) {
case 1:
@ -270,6 +271,7 @@ void save()
settings.setValue(QStringLiteral("preservemodificationtime"), v.tagPocessing.preserveModificationTime);
settings.setValue(QStringLiteral("preservemuxingapp"), v.tagPocessing.preserveMuxingApp);
settings.setValue(QStringLiteral("preservewritingapp"), v.tagPocessing.preserveWritingApp);
settings.setValue(QStringLiteral("converttotalfields"), v.tagPocessing.convertTotalFields);
settings.beginGroup(QStringLiteral("id3v1"));
settings.setValue(QStringLiteral("usage"), static_cast<int>(v.tagPocessing.creationSettings.id3v1usage));
settings.endGroup();

View File

@ -82,6 +82,7 @@ struct TagProcessing {
bool preserveModificationTime = false;
bool preserveMuxingApp = false;
bool preserveWritingApp = false;
bool convertTotalFields = true;
TagParser::TagCreationSettings creationSettings;
FileLayout fileLayout;
};

View File

@ -8,7 +8,7 @@ using namespace TagParser;
namespace Cli {
namespace FieldMapping {
static constexpr auto fieldMapping = std::array<Mapping, 99>{ {
static constexpr auto fieldMapping = MappingType{ {
{ "Title", KnownField::Title },
{ "Album", KnownField::Album },
{ "Artist", KnownField::Artist },
@ -108,6 +108,7 @@ static constexpr auto fieldMapping = std::array<Mapping, 99>{ {
{ "ProductionCopyright", KnownField::ProductionCopyright },
{ "License", KnownField::License },
{ "TermsOfUse", KnownField::TermsOfUse },
{ "PublisherWebpage", KnownField::PublisherWebpage },
} };
const char *fieldDenotation(TagParser::KnownField knownField)
@ -142,7 +143,7 @@ TagParser::KnownField knownField(const char *fieldDenotation, std::size_t fieldD
return KnownField::Invalid;
}
const std::array<Mapping, 99> &mapping()
const MappingType &mapping()
{
return fieldMapping;
}

View File

@ -18,7 +18,8 @@ struct Mapping {
const char *fieldDenotation(TagParser::KnownField knownField);
TagParser::KnownField knownField(const char *fieldDenotation, std::size_t fieldDenotationSize);
const std::array<Mapping, 99> &mapping();
using MappingType = std::array<Mapping, 100>;
const MappingType &mapping();
} // namespace FieldMapping
} // namespace Cli

View File

@ -102,7 +102,7 @@ namespace Cli {
" purchasingdate recordinglocation compositionlocation composernationality\n" \
" playcounter measure tuning isrc mcdi isbn barcode catalognumber labelcode\n" \
" lccn imdb tmdb tvdb purchaseitem purchaseinfo purchaseowner purchaseprice\n" \
" purchasecurrency copyright productioncopyright license termsofuse"
" purchasecurrency copyright productioncopyright license termsofuse publisherwebpage"
#define TRACK_ATTRIBUTE_NAMES "name tracknumber enabled=yes enabled=no forced=yes forced=no default=yes default=no"
@ -391,7 +391,8 @@ void displayTagInfo(
// parse specified fields
const auto fields = parseFieldDenotations(fieldsArg, true);
MediaFileInfo fileInfo;
auto fileInfo = MediaFileInfo();
fileInfo.setFileHandlingFlags(fileInfo.fileHandlingFlags() | MediaFileHandlingFlags::ConvertTotalFields);
for (const char *file : filesArg.values()) {
Diagnostics diag;
AbortableProgressFeedback progress; // FIXME: actually use the progress object
@ -494,6 +495,7 @@ public:
private:
static void addWarnings(Diagnostics &diag, const std::string &context, const QList<QQmlError> &warnings);
const SetTagInfoArgs &args;
int argc;
QCoreApplication app;
Diagnostics diag;
@ -510,7 +512,8 @@ private:
* - Logs status/problems directly in accordance with other parts of the CLI.
*/
JavaScriptProcessor::JavaScriptProcessor(const SetTagInfoArgs &args)
: argc(0)
: args(args)
, argc(0)
, app(argc, nullptr)
, utility(new UtilityObject(&engine))
{
@ -567,7 +570,7 @@ JavaScriptProcessor::JavaScriptProcessor(const SetTagInfoArgs &args)
*/
QJSValue JavaScriptProcessor::callMain(MediaFileInfo &mediaFileInfo, Diagnostics &diag)
{
auto fileInfoObject = MediaFileInfoObject(mediaFileInfo, diag, &engine);
auto fileInfoObject = MediaFileInfoObject(mediaFileInfo, diag, &engine, args.quietArg.isPresent());
auto fileInfoObjectValue = engine.newQObject(&fileInfoObject);
auto context = argsToString("executing JavaScript for ", mediaFileInfo.fileName());
utility->setDiag(&context, &diag);
@ -707,6 +710,9 @@ void setTagInfo(const SetTagInfoArgs &args)
if (args.preserveWritingAppArg.isPresent()) {
fileInfo.setFileHandlingFlags(fileInfo.fileHandlingFlags() | MediaFileHandlingFlags::PreserveWritingApplication);
}
if (!args.preserveTotalFieldsArg.isPresent()) {
fileInfo.setFileHandlingFlags(fileInfo.fileHandlingFlags() | MediaFileHandlingFlags::ConvertTotalFields);
}
// set backup path
if (args.backupDirArg.isPresent()) {

View File

@ -50,6 +50,7 @@ struct SetTagInfoArgs {
CppUtilities::ConfigValueArgument preserveModificationTimeArg;
CppUtilities::ConfigValueArgument preserveMuxingAppArg;
CppUtilities::ConfigValueArgument preserveWritingAppArg;
CppUtilities::ConfigValueArgument preserveTotalFieldsArg;
CppUtilities::ConfigValueArgument jsArg;
CppUtilities::ConfigValueArgument jsSettingsArg;
CppUtilities::OperationArgument setTagInfoArg;

View File

@ -20,6 +20,9 @@
#include <c++utilities/conversion/binaryconversion.h>
#include <c++utilities/conversion/conversionexception.h>
#include <c++utilities/conversion/stringbuilder.h>
#include <c++utilities/io/path.h>
#include <c++utilities/tests/testutils.h>
#include <qtutilities/misc/compat.h>
@ -33,6 +36,7 @@
#include <QJSValueIterator>
#include <QRegularExpression>
#include <filesystem>
#include <iostream>
#include <limits>
#include <type_traits>
@ -56,6 +60,8 @@ constexpr auto nativeUtf16Encoding = TagParser::TagTextEncoding::
#endif
;
const std::string UtilityObject::s_defaultContext = std::string("executing JavaScript");
UtilityObject::UtilityObject(QJSEngine *engine)
: QObject(engine)
, m_engine(engine)
@ -83,9 +89,8 @@ void UtilityObject::diag(const QString &level, const QString &message, const QSt
{ QStringLiteral("information"), TagParser::DiagLevel::Information },
{ QStringLiteral("debug"), TagParser::DiagLevel::Debug },
});
static const auto defaultContext = std::string("executing JavaScript");
m_diag->emplace_back(mapping.value(level.toLower(), TagParser::DiagLevel::Debug), message.toStdString(),
context.isEmpty() ? (m_context ? *m_context : defaultContext) : context.toStdString());
context.isEmpty() ? (m_context ? *m_context : s_defaultContext) : context.toStdString());
}
int UtilityObject::exec()
@ -124,6 +129,65 @@ QJSValue UtilityObject::readFile(const QString &path)
return QJSValue();
}
QJSValue UtilityObject::openFile(const QString &path)
{
if (!m_diag) {
return QJSValue();
}
auto mediaFileInfo = std::make_unique<TagParser::MediaFileInfo>(path.toStdString());
auto feedback = TagParser::AbortableProgressFeedback();
try {
mediaFileInfo->open(true);
mediaFileInfo->parseEverything(*m_diag, feedback);
} catch (const std::exception &e) {
m_diag->emplace_back(TagParser::DiagLevel::Critical, CppUtilities::argsToString("Unable to open \"", mediaFileInfo->path(), "\": ", e.what()),
m_context ? *m_context : s_defaultContext);
return QJSValue();
}
auto mediaFileInfoObj = new MediaFileInfoObject(std::move(mediaFileInfo), *m_diag, m_engine, false, m_engine);
return m_engine->newQObject(mediaFileInfoObj);
}
QJSValue UtilityObject::runProcess(const QString &path, const QJSValue &args, int timeout)
{
auto res = m_engine->newObject();
#ifdef CPP_UTILITIES_HAS_EXEC_APP
auto pathUtf8 = path.toUtf8();
auto argsUtf8 = QByteArrayList();
auto argsUtf8Array = std::vector<const char *>();
if (args.isArray()) {
const auto size = args.property(QStringLiteral("length")).toUInt();
argsUtf8.reserve(size);
argsUtf8Array.reserve(static_cast<std::size_t>(size) + 2);
for (auto i = quint32(); i != size; ++i) {
argsUtf8.append(args.property(i).toString().toUtf8());
}
}
argsUtf8Array.emplace_back(pathUtf8.data());
for (const auto &argUtf8 : argsUtf8) {
argsUtf8Array.emplace_back(argUtf8.data());
}
argsUtf8Array.emplace_back(nullptr);
auto output = std::string(), errors = std::string();
try {
auto exitStatus = CppUtilities::execHelperAppInSearchPath(pathUtf8.data(), argsUtf8Array.data(), output, errors, false, timeout);
#ifndef CPP_UTILITIES_BOOST_PROCESS
if (WIFEXITED(exitStatus)) {
exitStatus = WEXITSTATUS(exitStatus);
res.setProperty(QStringLiteral("status"), exitStatus);
}
#else
res.setProperty(QStringLiteral("status"), exitStatus);
#endif
} catch (const std::runtime_error &e) {
res.setProperty(QStringLiteral("error"), QString::fromUtf8(e.what()));
}
res.setProperty(QStringLiteral("stdout"), QString::fromStdString(output));
res.setProperty(QStringLiteral("stderr"), QString::fromStdString(errors));
#endif
return res;
}
QString UtilityObject::formatName(const QString &str) const
{
return Utility::formatName(str);
@ -558,14 +622,23 @@ void TagObject::applyChanges()
}
}
MediaFileInfoObject::MediaFileInfoObject(TagParser::MediaFileInfo &mediaFileInfo, TagParser::Diagnostics &diag, QJSEngine *engine, QObject *parent)
MediaFileInfoObject::MediaFileInfoObject(
TagParser::MediaFileInfo &mediaFileInfo, TagParser::Diagnostics &diag, QJSEngine *engine, bool quiet, QObject *parent)
: QObject(parent)
, m_f(mediaFileInfo)
, m_diag(diag)
, m_engine(engine)
, m_quiet(quiet)
{
}
MediaFileInfoObject::MediaFileInfoObject(
std::unique_ptr<TagParser::MediaFileInfo> &&mediaFileInfo, TagParser::Diagnostics &diag, QJSEngine *engine, bool quiet, QObject *parent)
: MediaFileInfoObject(*mediaFileInfo.get(), diag, engine, quiet, parent)
{
m_f_owned = std::move(mediaFileInfo);
}
MediaFileInfoObject::~MediaFileInfoObject()
{
}
@ -575,11 +648,21 @@ QString MediaFileInfoObject::path() const
return QString::fromStdString(m_f.path());
}
bool MediaFileInfoObject::isPathRelative() const
{
return QFileInfo(path()).isRelative();
}
QString MediaFileInfoObject::name() const
{
return QString::fromStdString(m_f.fileName());
}
QString MediaFileInfoObject::nameWithoutExtension() const
{
return QString::fromStdString(m_f.fileName(true));
}
QString MediaFileInfoObject::extension() const
{
return QString::fromStdString(m_f.extension());
@ -621,4 +704,27 @@ void MediaFileInfoObject::applyChanges()
}
}
bool MediaFileInfoObject::rename(const QString &newPath)
{
const auto from = m_f.path();
const auto fromNative = std::filesystem::path(CppUtilities::makeNativePath(from));
const auto toRelUtf8 = newPath.toUtf8();
const auto toRelView = CppUtilities::PathStringView(toRelUtf8.data(), static_cast<std::size_t>(toRelUtf8.size()));
const auto toNative = fromNative.parent_path().append(CppUtilities::makeNativePath(toRelView));
const auto toView = CppUtilities::extractNativePath(toNative.native());
try {
m_f.stream().close();
std::filesystem::rename(fromNative, toNative);
m_f.reportPathChanged(toView);
m_f.stream().open(m_f.path(), std::ios_base::in | std::ios_base::out | std::ios_base::binary);
} catch (const std::runtime_error &e) {
m_diag.emplace_back(TagParser::DiagLevel::Critical, e.what(), CppUtilities::argsToString("renaming \"", from, "\" to \"", toView));
return false;
}
if (!m_quiet) {
std::cout << " - Renamed \"" << from << "\" to \"" << toView << "\"\n";
}
return true;
}
} // namespace Cli

View File

@ -54,6 +54,8 @@ public Q_SLOTS:
QJSValue readEnvironmentVariable(const QString &variable, const QJSValue &defaultValue = QJSValue()) const;
QJSValue readDirectory(const QString &path);
QJSValue readFile(const QString &path);
QJSValue openFile(const QString &path);
QJSValue runProcess(const QString &path, const QJSValue &args, int timeout = -1);
QString formatName(const QString &str) const;
QString fixUmlauts(const QString &str) const;
@ -63,13 +65,14 @@ public Q_SLOTS:
QJSValue queryMakeItPersonal(const QJSValue &songDescription);
QJSValue queryTekstowo(const QJSValue &songDescription);
QByteArray convertImage(const QByteArray &imageData, const QSize &maxSize, const QString &format);
QByteArray convertImage(const QByteArray &imageData, const QSize &maxSize, const QString &format = QString());
private:
static QtGui::SongDescription makeSongDescription(const QJSValue &obj);
QJSEngine *m_engine;
const std::string *m_context;
static const std::string s_defaultContext;
TagParser::Diagnostics *m_diag;
};
@ -186,19 +189,26 @@ inline TagParser::Tag &TagObject::tag()
class MediaFileInfoObject : public QObject {
Q_OBJECT
Q_PROPERTY(QString path READ path)
Q_PROPERTY(bool pathRelative READ isPathRelative)
Q_PROPERTY(QString name READ name)
Q_PROPERTY(QString nameWithoutExtension READ nameWithoutExtension)
Q_PROPERTY(QString extension READ extension)
Q_PROPERTY(QString containingDirectory READ containingDirectory)
Q_PROPERTY(QString savePath READ savePath WRITE setSavePath)
Q_PROPERTY(QList<TagObject *> tags READ tags)
public:
explicit MediaFileInfoObject(TagParser::MediaFileInfo &mediaFileInfo, TagParser::Diagnostics &diag, QJSEngine *engine, QObject *parent = nullptr);
explicit MediaFileInfoObject(
TagParser::MediaFileInfo &mediaFileInfo, TagParser::Diagnostics &diag, QJSEngine *engine, bool quiet, QObject *parent = nullptr);
explicit MediaFileInfoObject(std::unique_ptr<TagParser::MediaFileInfo> &&mediaFileInfo, TagParser::Diagnostics &diag, QJSEngine *engine,
bool quiet, QObject *parent = nullptr);
~MediaFileInfoObject() override;
TagParser::MediaFileInfo &fileInfo();
QString path() const;
bool isPathRelative() const;
QString name() const;
QString nameWithoutExtension() const;
QString extension() const;
QString containingDirectory() const;
QString savePath() const;
@ -207,12 +217,15 @@ public:
public Q_SLOTS:
void applyChanges();
bool rename(const QString &newPath);
private:
TagParser::MediaFileInfo &m_f;
std::unique_ptr<TagParser::MediaFileInfo> m_f_owned;
TagParser::Diagnostics &m_diag;
QJSEngine *m_engine;
QList<TagObject *> m_tags;
bool m_quiet;
};
inline TagParser::MediaFileInfo &MediaFileInfoObject::fileInfo()

View File

@ -73,6 +73,13 @@
</item>
</layout>
</widget>
<tabstops>
<tabstop>addPushButton</tabstop>
<tabstop>extractPushButton</tabstop>
<tabstop>restorePushButton</tabstop>
<tabstop>clearPushButton</tabstop>
<tabstop>treeView</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -382,6 +382,19 @@
<header location="global">qtutilities/widgets/clearspinbox.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>abortPushButton</tabstop>
<tabstop>searchPushButton</tabstop>
<tabstop>applyPushButton</tabstop>
<tabstop>trackSpinBox</tabstop>
<tabstop>titleLineEdit</tabstop>
<tabstop>albumLineEdit</tabstop>
<tabstop>artistLineEdit</tabstop>
<tabstop>fieldsListView</tabstop>
<tabstop>overrideCheckBox</tabstop>
<tabstop>autoInsertCheckBox</tabstop>
<tabstop>resultsTreeView</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -160,6 +160,16 @@
</item>
</layout>
</widget>
<tabstops>
<tabstop>insertTitleFromFilenameCheckBox</tabstop>
<tabstop>trimWhitespacesCheckBox</tabstop>
<tabstop>formatNamesCheckBox</tabstop>
<tabstop>fixUmlautsCheckBox</tabstop>
<tabstop>customSubstitutionGroupBox</tabstop>
<tabstop>regularExpressionLineEdit</tabstop>
<tabstop>replacementLineEdit</tabstop>
<tabstop>fieldsListView</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -60,6 +60,11 @@
<header location="global">qtutilities/widgets/clearlineedit.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>musicBrainzUrlLineEdit</tabstop>
<tabstop>lyricWikiUrlLineEdit</tabstop>
<tabstop>coverArtArchiveUrlLineEdit</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -189,7 +189,17 @@
<extends>QLineEdit</extends>
<header location="global">qtutilities/widgets/clearlineedit.h</header>
</customwidget>
</customwidgets>
</customwidgets>
<tabstops>
<tabstop>levelSpinBox</tabstop>
<tabstop>levelNameLineEdit</tabstop>
<tabstop>tracksListView</tabstop>
<tabstop>chaptersListView</tabstop>
<tabstop>editionsListView</tabstop>
<tabstop>attachmentsListView</tabstop>
<tabstop>abortPushButton</tabstop>
<tabstop>confirmPushButton</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -239,6 +239,20 @@ another position would prevent rewriting the entire file</string>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>forceRewriteCheckBox</tabstop>
<tabstop>minPaddingSpinBox</tabstop>
<tabstop>maxPaddingSpinBox</tabstop>
<tabstop>preferredPaddingSpinBox</tabstop>
<tabstop>tagPosBeforeDataRadioButton</tabstop>
<tabstop>tagPosAfterDataRadioButton</tabstop>
<tabstop>tagPosKeepRadioButton</tabstop>
<tabstop>tagPosForceCheckBox</tabstop>
<tabstop>indexPosBeforeDataRadioButton</tabstop>
<tabstop>indexPosAfterDataRadioButton</tabstop>
<tabstop>indexPosKeepRadioButton</tabstop>
<tabstop>indexPosForceCheckBox</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -169,6 +169,14 @@
</item>
</layout>
</widget>
<tabstops>
<tabstop>widthSpinBox</tabstop>
<tabstop>heightSpinBox</tabstop>
<tabstop>formatComboBox</tabstop>
<tabstop>aspectRatioComboBox</tabstop>
<tabstop>abortPushButton</tabstop>
<tabstop>confirmPushButton</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -7,12 +7,13 @@
#include "resources/config.h"
#include "resources/qtconfig.h"
#include <QApplication> // ensure QGuiApplication is defined before resources.h for desktop file name
#include <qtutilities/resources/importplugin.h>
#include <qtutilities/resources/qtconfigarguments.h>
#include <qtutilities/resources/resources.h>
#include <qtutilities/settingsdialog/qtsettings.h>
#include <QApplication>
#include <QMessageBox>
ENABLE_QT_RESOURCES_OF_STATIC_DEPENDENCIES

View File

@ -755,6 +755,19 @@
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>includeSubdirsCheckBox</tabstop>
<tabstop>pasteScriptPushButton</tabstop>
<tabstop>toggleScriptSourcePushButton</tabstop>
<tabstop>javaScriptPlainTextEdit</tabstop>
<tabstop>currentTreeView</tabstop>
<tabstop>previewTreeView</tabstop>
<tabstop>abortClosePushButton</tabstop>
<tabstop>generatePreviewPushButton</tabstop>
<tabstop>applyChangingsPushButton</tabstop>
<tabstop>scriptFilePathLineEdit</tabstop>
<tabstop>selectScriptFilePushButton</tabstop>
</tabstops>
<resources>
<include location="../resources/icons.qrc"/>
</resources>

View File

@ -360,6 +360,7 @@ bool TagProcessingGeneralOptionPage::apply()
settings.preserveModificationTime = ui()->preserveModificationTimeCheckBox->isChecked();
settings.preserveMuxingApp = ui()->preserveMuxingAppCheckBox->isChecked();
settings.preserveWritingApp = ui()->preserveWritingAppCheckBox->isChecked();
settings.convertTotalFields = ui()->convertTotalFieldsCheckBox->isChecked();
}
return true;
}
@ -397,6 +398,7 @@ void TagProcessingGeneralOptionPage::reset()
ui()->preserveModificationTimeCheckBox->setChecked(settings.preserveModificationTime);
ui()->preserveMuxingAppCheckBox->setChecked(settings.preserveMuxingApp);
ui()->preserveWritingAppCheckBox->setChecked(settings.preserveWritingApp);
ui()->convertTotalFieldsCheckBox->setChecked(settings.convertTotalFields);
}
}

View File

@ -835,6 +835,11 @@ bool TagEditorWidget::startParsing(const QString &path, bool forceRefresh)
m_currentDir = fileInfo.absolutePath();
m_fileName = fileInfo.fileName();
}
// set flags that are also important when parsing
auto &generalSettings = Settings::values().tagPocessing;
auto flags = m_fileInfo.fileHandlingFlags();
CppUtilities::modFlagEnum(flags, MediaFileHandlingFlags::ConvertTotalFields, generalSettings.convertTotalFields);
m_fileInfo.setFileHandlingFlags(flags);
// write diagnostics to m_diagReparsing if making results are available
m_makingResultsAvailable &= sameFile;
Diagnostics &diag = m_makingResultsAvailable ? m_diagReparsing : m_diag;
@ -1166,12 +1171,11 @@ bool TagEditorWidget::startSaving()
m_fileInfo.setMaxPadding(fileLayoutSettings.maxPadding);
m_fileInfo.setPreferredPadding(fileLayoutSettings.preferredPadding);
m_fileInfo.setBackupDirectory(settings.editor.backupDirectory);
if (generalSettings.preserveMuxingApp) {
m_fileInfo.setFileHandlingFlags(m_fileInfo.fileHandlingFlags() | MediaFileHandlingFlags::PreserveMuxingApplication);
}
if (generalSettings.preserveWritingApp) {
m_fileInfo.setFileHandlingFlags(m_fileInfo.fileHandlingFlags() | MediaFileHandlingFlags::PreserveWritingApplication);
}
auto flags = m_fileInfo.fileHandlingFlags();
CppUtilities::modFlagEnum(flags, MediaFileHandlingFlags::PreserveMuxingApplication, generalSettings.preserveMuxingApp);
CppUtilities::modFlagEnum(flags, MediaFileHandlingFlags::PreserveWritingApplication, generalSettings.preserveWritingApp);
CppUtilities::modFlagEnum(flags, MediaFileHandlingFlags::ConvertTotalFields, generalSettings.convertTotalFields);
m_fileInfo.setFileHandlingFlags(flags);
const auto startThread = [this, preserveModificationTime = settings.tagPocessing.preserveModificationTime] {
// define functions to show the saving progress and to actually applying the changes
auto showPercentage([this](AbortableProgressFeedback &progress) {

View File

@ -450,6 +450,7 @@ currently shown tag.</string>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>renamePushButton</tabstop>
<tabstop>tagSelectionComboBox</tabstop>
<tabstop>keepPreviousValuesPushButton</tabstop>
<tabstop>tagOptionsPushButton</tabstop>

View File

@ -159,6 +159,16 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="convertTotalFieldsCheckBox">
<property name="toolTip">
<string>Ensures fields usually holding values like &quot;3/15&quot; such as the track position are actually stored as such (and &lt;i&gt;not&lt;/i&gt; as two separate fields for the position and total values). This is required for the tag editor to support handling such separately stored total values at all. So far this only affects Vorbis Comments where it will convert the fields TRACKTOTAL/DISCTOTAL/PARTTOTAL to be included in the TRACKNUMBER/DISCNUMBER/PARTNUMBER fields.</string>
</property>
<property name="text">
<string>Convert total fields (see tooltip for details)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View File

@ -137,7 +137,7 @@ if (fileInfo.currentSuffix === "tmp") {
var fields = []
// get the artist (preferably album artist), remove invalid characters and add it to fields array
var artist = validFileName(tag.albumartist || tag.artist)
var artist = validFileName(tag.albumArtist || tag.artist)
if (includeArtist && !isPartOfCollection(tag) && notEmpty(artist)) {
fields.push(trailingBracketsStripped(firstValue(artist)))
}
@ -219,7 +219,7 @@ if (distDir) {
} else if (tag.comment.includes("single")) {
path.push("singles");
}
var artist = validDirectoryName(firstValue(tag.albumartist || tag.artist))
var artist = validDirectoryName(firstValue(tag.albumArtist || tag.artist))
if (isPartOfCollection(tag)) {
path.push(collectionsDir)
} else if (notEmpty(artist) && !isMiscFile(tag)) {

View File

@ -22,7 +22,7 @@ if (!fileInfo.hasAudioTracks && !fileInfo.hasVideoTracks) {
}
// make new filename
const fieldsToInclude = [tag.albumartist || tag.artist, tag.album, tag.trackPos || infoFromFileName.trackPos, tag.title || infoFromFileName.title]
const fieldsToInclude = [tag.albumArtist || tag.artist, tag.album, tag.trackPos || infoFromFileName.trackPos, tag.title || infoFromFileName.title]
let newName = ""
for (let field of fieldsToInclude) {
field = field.toString()

View File

@ -1,3 +1,5 @@
const fileCache = {};
export function isString(value) {
return typeof(value) === "string" || value instanceof String;
}
@ -13,10 +15,49 @@ export function logTagInfo(file, tag) {
utility.diag("debug", Object.keys(fields).sort().join(", "), "supported fields");
// log fields for debugging purposes
for (const [key, value] of Object.entries(fields)) {
const content = value.content;
if (content !== undefined && content != null && !(content instanceof ArrayBuffer)) {
utility.diag("debug", content, key + " (" + value.type + ")");
for (const [key, values] of Object.entries(fields)) {
for (const value of values) {
const content = value.content;
if (content !== undefined && content !== null && !(content instanceof ArrayBuffer)) {
utility.diag("debug", content, key + " (" + value.type + ")");
}
}
}
}
export function readFieldContents(file, fieldName) {
const values = [];
for (const tag of file.tags) {
if (tag.type === "ID3v1 tag") {
// due to its limitations ID3v1 tags may have truncated contents; so just ignore them
// for the sake of this script
continue;
}
for (const value of tag.fields[fieldName]) {
const content = value.content;
if (content !== undefined && content !== null) {
values.push(content);
}
}
if (values.length) {
// just return the contents from the first tag that has any for now
break;
}
}
return values;
}
export function cacheValue(cache, key, generator) {
const cachedValue = cache[key];
return cachedValue ? cachedValue : (cache[key] = generator());
}
export function openOriginalFile(file) {
const originalDir = settings.originalDir;
const originalExt = settings.originalExt || file.extension;
if (originalDir && file.pathRelative) {
const name = file.nameWithoutExtension;
const path = [originalDir, file.containingDirectory, name + originalExt].join("/");
return cacheValue(fileCache, path, () => utility.openFile(path));
}
}

View File

@ -1,26 +1,23 @@
import * as helpers from "helpers.js"
const lyricsCache = {};
const coverCache = {};
const albumColumn = 1;
export function queryLyrics(searchCriteria) {
return cacheValue(lyricsCache, searchCriteria.title + "_" + searchCriteria.artist, () => {
return helpers.cacheValue(lyricsCache, searchCriteria.title + "_" + searchCriteria.artist, () => {
utility.log(" - Querying lyrics for '" + searchCriteria.title + "' from '" + searchCriteria.artist + "' ...");
return queryLyricsFromProviders(["Tekstowo", "MakeItPersonal"], searchCriteria)
});
}
export function queryCover(searchCriteria) {
return cacheValue(coverCache, searchCriteria.album + "_" + searchCriteria.artist, () => {
return helpers.cacheValue(coverCache, searchCriteria.album + "_" + searchCriteria.artist, () => {
utility.log(" - Querying cover art for '" + searchCriteria.album + "' from '" + searchCriteria.artist + "' ...");
return queryCoverFromProvider("MusicBrainz", searchCriteria);
});
}
function cacheValue(cache, key, generator) {
const cachedValue = cache[key];
return cachedValue ? cachedValue : (cache[key] = generator());
}
function waitFor(signal) {
signal.connect(() => { utility.exit(); });
utility.exec();

View File

@ -57,11 +57,29 @@ function addTotalNumberOfTracks(file, tag) {
}
}
function addFieldFromOriginalFile(file, tag, fieldName) {
const originalFile = helpers.openOriginalFile(file);
if (!originalFile) {
return false;
}
utility.diag("debug", "Trying to take over " + fieldName + " from \"" + originalFile.path + "\".");
const contents = helpers.readFieldContents(originalFile, fieldName);
if (!contents.length) {
utility.diag("debug", "No " + fieldName + " found in original file.");
return false;
}
tag.fields[fieldName] = contents;
return true;
}
function addLyrics(file, tag) {
const fields = tag.fields;
if (fields.lyrics.length) {
return; // skip if already assigned
}
if (addFieldFromOriginalFile(file, tag, "lyrics")) {
return; // skip fetching via meta-data search if lyrics could be taken over from original file
}
const firstTitle = fields.title?.[0]?.content;
const firstArtist = fields.artist?.[0]?.content;
if (firstTitle && firstArtist) {
@ -74,6 +92,17 @@ function addCover(file, tag) {
if (fields.cover.length) {
return; // skip if already assigned
}
if (addFieldFromOriginalFile(file, tag, "cover")) {
// ensure the cover's resolution is below a certain size to avoid bloating the file
const convertedCovers = [];
const maxSizeInt = parseInt(settings.coverMaxSize || 512);
const maxSize = Qt.size(maxSizeInt, maxSizeInt);
for (const cover of fields.cover) {
convertedCovers.push(utility.convertImage(cover, maxSize));
}
fields.cover = convertedCovers;
return; // skip fetching via meta-data search if cover could be taken over from original file
}
const firstAlbum = fields.album?.[0]?.content?.replace(/ \(.*\)/, '');
const firstArtist = fields.artist?.[0]?.content;
if (firstAlbum && firstArtist) {

View File

@ -1164,12 +1164,12 @@ void CliTests::testJsonExport()
cout << "\nJSON export" << endl;
string stdout, stderr;
const auto file(testFilePath("matroska_wave1/test3.mkv"));
const auto expectedJsonPath(testFilePath("matroska_wave1-test3.json"));
const auto file = testFilePath("matroska_wave1/test3.mkv");
const auto expectedJson = readFile(testFilePath("matroska_wave1-test3.json"));
const char *const args[] = { "tageditor", "export", "--pretty", "-f", file.data(), nullptr };
TESTUTILS_ASSERT_EXEC(args);
const char *const jqArgs[]
= { "jq", "--argfile", "expected", expectedJsonPath.data(), "--argjson", "actual", stdout.data(), "-n", "$actual == $expected", nullptr };
= { "jq", "--argjson", "expected", expectedJson.data(), "--argjson", "actual", stdout.data(), "-n", "$actual == $expected", nullptr };
const auto *const logJsonExport = std::getenv(PROJECT_VARNAME_UPPER "_LOG_JQ_INVOCATION");
execHelperAppInSearchPath("jq", jqArgs, stdout, stderr, !logJsonExport || !std::strlen(logJsonExport));
CPPUNIT_ASSERT_EQUAL(""s, stderr);

View File

@ -1787,12 +1787,12 @@ another position would prevent rewriting the entire file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="571"/>
<location filename="../gui/settingsdialog.cpp" line="573"/>
<source>Minimum padding must be less or equal than maximum padding.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="637"/>
<location filename="../gui/settingsdialog.cpp" line="639"/>
<source>These options might be ignored if not supported by either the format or the implementation.</source>
<translation type="unfinished"></translation>
</message>
@ -2934,17 +2934,17 @@ Error in line %1: %3</source>
<translation></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="658"/>
<location filename="../gui/settingsdialog.cpp" line="660"/>
<source>Tag processing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="665"/>
<location filename="../gui/settingsdialog.cpp" line="667"/>
<source>Editor</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="673"/>
<location filename="../gui/settingsdialog.cpp" line="675"/>
<source>File browser</source>
<translation type="unfinished"></translation>
</message>
@ -3040,7 +3040,7 @@ currently shown tag.</source>
</message>
<message>
<location filename="../gui/tageditorwidget.ui" line="323"/>
<location filename="../gui/tageditorwidget.cpp" line="1341"/>
<location filename="../gui/tageditorwidget.cpp" line="1345"/>
<source>Abort</source>
<translation type="unfinished"></translation>
</message>
@ -3202,123 +3202,123 @@ currently shown tag.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="895"/>
<location filename="../gui/tageditorwidget.cpp" line="900"/>
<source>Unable to reload the file because the current process hasn&apos;t finished yet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="899"/>
<location filename="../gui/tageditorwidget.cpp" line="904"/>
<source>Currently is not file opened.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="921"/>
<location filename="../gui/tageditorwidget.cpp" line="926"/>
<source>Opening file - </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="934"/>
<location filename="../gui/tageditorwidget.cpp" line="939"/>
<source>There is no (supported) tag assigned.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="950"/>
<location filename="../gui/tageditorwidget.cpp" line="955"/>
<source>File could be parsed correctly.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="954"/>
<location filename="../gui/tageditorwidget.cpp" line="959"/>
<source>File couldn&apos;t be parsed correctly.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="963"/>
<location filename="../gui/tageditorwidget.cpp" line="968"/>
<source>There are warnings.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="967"/>
<location filename="../gui/tageditorwidget.cpp" line="972"/>
<source>No write access; the file has been opened in read-only mode.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="970"/>
<location filename="../gui/tageditorwidget.cpp" line="975"/>
<source>File format is not supported (an ID3 tag can be added anyways).</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="974"/>
<location filename="../gui/tageditorwidget.cpp" line="979"/>
<source>The file is composed of multiple segments. Dealing with such files has not been tested yet and might be broken.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1013"/>
<location filename="../gui/tageditorwidget.cpp" line="1018"/>
<source>The file %1 has been opened.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1033"/>
<location filename="../gui/tageditorwidget.cpp" line="1038"/>
<source>Unable to apply the entered tags to the file because the current process hasn&apos;t finished yet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1043"/>
<location filename="../gui/tageditorwidget.cpp" line="1048"/>
<source>No file has been opened, so tags can not be saved.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1060"/>
<location filename="../gui/tageditorwidget.cpp" line="1065"/>
<source>Saving tags ...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1075"/>
<location filename="../gui/tageditorwidget.cpp" line="1080"/>
<source>Unable to delete all tags from the file because the current process hasn&apos;t been finished yet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1085"/>
<location filename="../gui/tageditorwidget.cpp" line="1090"/>
<source>No file has been opened, so no tags can be deleted.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1089"/>
<location filename="../gui/tageditorwidget.cpp" line="1094"/>
<source>The selected file has no tag (at least no supported), so there is nothing to delete.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1094"/>
<location filename="../gui/tageditorwidget.cpp" line="1099"/>
<source>Do you really want to delete all tags from the file?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1103"/>
<location filename="../gui/tageditorwidget.cpp" line="1108"/>
<source>Don&apos;t show this message again</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1113"/>
<location filename="../gui/tageditorwidget.cpp" line="1118"/>
<source>Deletion aborted.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1124"/>
<location filename="../gui/tageditorwidget.cpp" line="1129"/>
<source>Deleting all tags ...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1141"/>
<location filename="../gui/tageditorwidget.cpp" line="1146"/>
<source>Unable to start saving process because there an other process hasn&apos;t finished yet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="870"/>
<location filename="../gui/tageditorwidget.cpp" line="1212"/>
<location filename="../gui/tageditorwidget.cpp" line="875"/>
<location filename="../gui/tageditorwidget.cpp" line="1216"/>
<source>unknown error</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<location filename="../gui/tageditorwidget.cpp" line="1271"/>
<location filename="../gui/tageditorwidget.cpp" line="1275"/>
<source>Saving has been canceled and there is/are %1 warning(s) </source>
<translation type="unfinished">
<numerusform></numerusform>
@ -3326,7 +3326,7 @@ currently shown tag.</source>
</translation>
</message>
<message numerus="yes">
<location filename="../gui/tageditorwidget.cpp" line="1274"/>
<location filename="../gui/tageditorwidget.cpp" line="1278"/>
<source>Saving has been canceled and there is/are %1 warning(s).</source>
<translation type="unfinished">
<numerusform></numerusform>
@ -3334,7 +3334,7 @@ currently shown tag.</source>
</translation>
</message>
<message numerus="yes">
<location filename="../gui/tageditorwidget.cpp" line="1282"/>
<location filename="../gui/tageditorwidget.cpp" line="1286"/>
<source>The tags have been saved, but there is/are %1 warning(s) </source>
<translation type="unfinished">
<numerusform></numerusform>
@ -3342,8 +3342,8 @@ currently shown tag.</source>
</translation>
</message>
<message numerus="yes">
<location filename="../gui/tageditorwidget.cpp" line="1272"/>
<location filename="../gui/tageditorwidget.cpp" line="1283"/>
<location filename="../gui/tageditorwidget.cpp" line="1276"/>
<location filename="../gui/tageditorwidget.cpp" line="1287"/>
<source>and %1 error(s).</source>
<translation type="unfinished">
<numerusform></numerusform>
@ -3351,32 +3351,32 @@ currently shown tag.</source>
</translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="881"/>
<location filename="../gui/tageditorwidget.cpp" line="886"/>
<source>The file is being parsed ...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="917"/>
<location filename="../gui/tageditorwidget.cpp" line="922"/>
<source>The file could not be opened because an IO error occurred: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="923"/>
<location filename="../gui/tageditorwidget.cpp" line="928"/>
<source>Tried to open file: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="959"/>
<location filename="../gui/tageditorwidget.cpp" line="964"/>
<source>Errors occurred.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1276"/>
<location filename="../gui/tageditorwidget.cpp" line="1280"/>
<source>Saving tags has been canceled.</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<location filename="../gui/tageditorwidget.cpp" line="1285"/>
<location filename="../gui/tageditorwidget.cpp" line="1289"/>
<source>The tags have been saved, but there is/are %1 warning(s).</source>
<translation type="unfinished">
<numerusform></numerusform>
@ -3384,133 +3384,133 @@ currently shown tag.</source>
</translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1290"/>
<location filename="../gui/tageditorwidget.cpp" line="1294"/>
<source>The tags have been saved.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1309"/>
<location filename="../gui/tageditorwidget.cpp" line="1313"/>
<source>The tags could not be saved. Checkout the info box for details.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1315"/>
<location filename="../gui/tageditorwidget.cpp" line="1319"/>
<source>Saving file - </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1317"/>
<location filename="../gui/tageditorwidget.cpp" line="1321"/>
<source>Tried to save file: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1336"/>
<location filename="../gui/tageditorwidget.cpp" line="1340"/>
<source>Automatic tag management</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1337"/>
<location filename="../gui/tageditorwidget.cpp" line="1341"/>
<source>The container format of the selected file is not supported. The file can be treated as MP3 file (an ID3 tag according to the settings will be created). This might break the file. Do you want to continue?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1340"/>
<location filename="../gui/tageditorwidget.cpp" line="1344"/>
<source>Treat file as MP3 file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1352"/>
<location filename="../gui/tageditorwidget.cpp" line="1356"/>
<source>The currently opened file changed on the disk.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1365"/>
<location filename="../gui/tageditorwidget.cpp" line="1369"/>
<source>Unable to close the file because the current process hasn&apos;t been finished yet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1377"/>
<location filename="../gui/tageditorwidget.cpp" line="1381"/>
<source>Closing file - </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1378"/>
<location filename="../gui/tageditorwidget.cpp" line="1382"/>
<source>Unable to close file: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1379"/>
<location filename="../gui/tageditorwidget.cpp" line="1383"/>
<source>Tried to close file: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1386"/>
<location filename="../gui/tageditorwidget.cpp" line="1390"/>
<source>The file has been closed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1393"/>
<location filename="../gui/tageditorwidget.cpp" line="1397"/>
<source>Unable to rename the file because the current process hasn&apos;t been finished yet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1399"/>
<location filename="../gui/tageditorwidget.cpp" line="1403"/>
<source>Renaming file - </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1400"/>
<location filename="../gui/tageditorwidget.cpp" line="1404"/>
<source>New file name:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1435"/>
<location filename="../gui/tageditorwidget.cpp" line="1439"/>
<source>Unable to rename file: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1436"/>
<location filename="../gui/tageditorwidget.cpp" line="1440"/>
<source>Tried to rename file: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1443"/>
<location filename="../gui/tageditorwidget.cpp" line="1447"/>
<source>The file has been renamed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1450"/>
<location filename="../gui/tageditorwidget.cpp" line="1454"/>
<source>Unable to save file information because the current process hasn&apos;t been finished yet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1454"/>
<location filename="../gui/tageditorwidget.cpp" line="1458"/>
<source>No file is opened.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1459"/>
<location filename="../gui/tageditorwidget.cpp" line="1463"/>
<source>No file information available.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1468"/>
<location filename="../gui/tageditorwidget.cpp" line="1472"/>
<source>Unable to open file &quot;%1&quot;.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1476"/>
<location filename="../gui/tageditorwidget.cpp" line="1480"/>
<source>Unable to write to file &quot;%1&quot;.
%2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1491"/>
<location filename="../gui/tageditorwidget.cpp" line="1495"/>
<source>Save file information - </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1493"/>
<location filename="../gui/tageditorwidget.cpp" line="1497"/>
<source>Unable to open file.</source>
<translation type="unfinished"></translation>
</message>
@ -3526,12 +3526,12 @@ currently shown tag.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1593"/>
<location filename="../gui/tageditorwidget.cpp" line="1597"/>
<source>A tag (with the selected target) already exists.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1589"/>
<location filename="../gui/tageditorwidget.cpp" line="1593"/>
<source>The tag can not be created.</source>
<translation type="unfinished"></translation>
</message>
@ -3541,42 +3541,42 @@ currently shown tag.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1310"/>
<location filename="../gui/tageditorwidget.cpp" line="1314"/>
<source>The tags could not be saved because an IO error occurred: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1579"/>
<location filename="../gui/tageditorwidget.cpp" line="1583"/>
<source>Unable to add a tag because the current process hasn&apos;t been finished yet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1583"/>
<location filename="../gui/tageditorwidget.cpp" line="1587"/>
<source>Unable to add a tag because no file is opened.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1616"/>
<location filename="../gui/tageditorwidget.cpp" line="1620"/>
<source>Unable to remove the tag because the current process hasn&apos;t been finished yet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1620"/>
<location filename="../gui/tageditorwidget.cpp" line="1624"/>
<source>Unable to remove the tag because no file is opened.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1680"/>
<location filename="../gui/tageditorwidget.cpp" line="1684"/>
<source>Unable to change the target because the current process hasn&apos;t been finished yet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1684"/>
<location filename="../gui/tageditorwidget.cpp" line="1688"/>
<source>Unable to change the target because no file is opened.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1688"/>
<location filename="../gui/tageditorwidget.cpp" line="1692"/>
<source>Can not change the target of the selected tag because the tag does not support targets.</source>
<translation type="unfinished"></translation>
</message>
@ -4671,6 +4671,16 @@ currently shown tag.</source>
<source>Preserve writing application</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tagprocessinggeneraloptionpage.ui" line="165"/>
<source>Ensures fields usually holding values like &quot;3/15&quot; such as the track position are actually stored as such (and &lt;i&gt;not&lt;/i&gt; as two separate fields for the position and total values). This is required for the tag editor to support handling such separately stored total values at all. So far this only affects Vorbis Comments where it will convert the fields TRACKTOTAL/DISCTOTAL/PARTTOTAL to be included in the TRACKNUMBER/DISCNUMBER/PARTNUMBER fields.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tagprocessinggeneraloptionpage.ui" line="168"/>
<source>Convert total fields (see tooltip for details)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tagprocessinggeneraloptionpage.ui" line="119"/>
<source>Enable automatic tag management (default)</source>
@ -5375,7 +5385,12 @@ Remarks
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../application/knownfieldmodel.cpp" line="348"/>
<location filename="../application/knownfieldmodel.cpp" line="213"/>
<source>Publisher webpage</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../application/knownfieldmodel.cpp" line="351"/>
<source>Field</source>
<translation type="unfinished"></translation>
</message>

View File

@ -1838,12 +1838,12 @@ another position would prevent rewriting the entire file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="571"/>
<location filename="../gui/settingsdialog.cpp" line="573"/>
<source>Minimum padding must be less or equal than maximum padding.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="637"/>
<location filename="../gui/settingsdialog.cpp" line="639"/>
<source>These options might be ignored if not supported by either the format or the implementation.</source>
<translation type="unfinished"></translation>
</message>
@ -3027,17 +3027,17 @@ Error in line %1: %3</source>
<translation></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="658"/>
<location filename="../gui/settingsdialog.cpp" line="660"/>
<source>Tag processing</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="665"/>
<location filename="../gui/settingsdialog.cpp" line="667"/>
<source>Editor</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/settingsdialog.cpp" line="673"/>
<location filename="../gui/settingsdialog.cpp" line="675"/>
<source>File browser</source>
<translation type="unfinished"></translation>
</message>
@ -3136,87 +3136,87 @@ Error in line %1: %3</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="899"/>
<location filename="../gui/tageditorwidget.cpp" line="904"/>
<source>Currently is not file opened.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="895"/>
<location filename="../gui/tageditorwidget.cpp" line="900"/>
<source>Unable to reload the file because the current process hasn&apos;t finished yet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="950"/>
<location filename="../gui/tageditorwidget.cpp" line="955"/>
<source>File could be parsed correctly.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="954"/>
<location filename="../gui/tageditorwidget.cpp" line="959"/>
<source>File couldn&apos;t be parsed correctly.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="963"/>
<location filename="../gui/tageditorwidget.cpp" line="968"/>
<source>There are warnings.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="967"/>
<location filename="../gui/tageditorwidget.cpp" line="972"/>
<source>No write access; the file has been opened in read-only mode.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="970"/>
<location filename="../gui/tageditorwidget.cpp" line="975"/>
<source>File format is not supported (an ID3 tag can be added anyways).</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="974"/>
<location filename="../gui/tageditorwidget.cpp" line="979"/>
<source>The file is composed of multiple segments. Dealing with such files has not been tested yet and might be broken.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="934"/>
<location filename="../gui/tageditorwidget.cpp" line="939"/>
<source>There is no (supported) tag assigned.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1013"/>
<location filename="../gui/tageditorwidget.cpp" line="1018"/>
<source>The file %1 has been opened.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1060"/>
<location filename="../gui/tageditorwidget.cpp" line="1065"/>
<source>Saving tags ...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1033"/>
<location filename="../gui/tageditorwidget.cpp" line="1038"/>
<source>Unable to apply the entered tags to the file because the current process hasn&apos;t finished yet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1094"/>
<location filename="../gui/tageditorwidget.cpp" line="1099"/>
<source>Do you really want to delete all tags from the file?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1124"/>
<location filename="../gui/tageditorwidget.cpp" line="1129"/>
<source>Deleting all tags ...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1085"/>
<location filename="../gui/tageditorwidget.cpp" line="1090"/>
<source>No file has been opened, so no tags can be deleted.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1075"/>
<location filename="../gui/tageditorwidget.cpp" line="1080"/>
<source>Unable to delete all tags from the file because the current process hasn&apos;t been finished yet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1141"/>
<location filename="../gui/tageditorwidget.cpp" line="1146"/>
<source>Unable to start saving process because there an other process hasn&apos;t finished yet.</source>
<translation type="unfinished"></translation>
</message>
@ -3236,32 +3236,32 @@ Error in line %1: %3</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="921"/>
<location filename="../gui/tageditorwidget.cpp" line="926"/>
<source>Opening file - </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1043"/>
<location filename="../gui/tageditorwidget.cpp" line="1048"/>
<source>No file has been opened, so tags can not be saved.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1089"/>
<location filename="../gui/tageditorwidget.cpp" line="1094"/>
<source>The selected file has no tag (at least no supported), so there is nothing to delete.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1103"/>
<location filename="../gui/tageditorwidget.cpp" line="1108"/>
<source>Don&apos;t show this message again</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1113"/>
<location filename="../gui/tageditorwidget.cpp" line="1118"/>
<source>Deletion aborted.</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<location filename="../gui/tageditorwidget.cpp" line="1271"/>
<location filename="../gui/tageditorwidget.cpp" line="1275"/>
<source>Saving has been canceled and there is/are %1 warning(s) </source>
<translation>
<numerusform>Saving has been canceled and there is %1 warning </numerusform>
@ -3269,7 +3269,7 @@ Error in line %1: %3</source>
</translation>
</message>
<message numerus="yes">
<location filename="../gui/tageditorwidget.cpp" line="1274"/>
<location filename="../gui/tageditorwidget.cpp" line="1278"/>
<source>Saving has been canceled and there is/are %1 warning(s).</source>
<translation>
<numerusform>Saving has been canceled and there is %1 warning.</numerusform>
@ -3277,7 +3277,7 @@ Error in line %1: %3</source>
</translation>
</message>
<message numerus="yes">
<location filename="../gui/tageditorwidget.cpp" line="1282"/>
<location filename="../gui/tageditorwidget.cpp" line="1286"/>
<source>The tags have been saved, but there is/are %1 warning(s) </source>
<translation>
<numerusform>The tags have been saved, but there is %1 warning</numerusform>
@ -3285,8 +3285,8 @@ Error in line %1: %3</source>
</translation>
</message>
<message numerus="yes">
<location filename="../gui/tageditorwidget.cpp" line="1272"/>
<location filename="../gui/tageditorwidget.cpp" line="1283"/>
<location filename="../gui/tageditorwidget.cpp" line="1276"/>
<location filename="../gui/tageditorwidget.cpp" line="1287"/>
<source>and %1 error(s).</source>
<translation>
<numerusform>and %1 error.</numerusform>
@ -3294,38 +3294,38 @@ Error in line %1: %3</source>
</translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="870"/>
<location filename="../gui/tageditorwidget.cpp" line="1212"/>
<location filename="../gui/tageditorwidget.cpp" line="875"/>
<location filename="../gui/tageditorwidget.cpp" line="1216"/>
<source>unknown error</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="881"/>
<location filename="../gui/tageditorwidget.cpp" line="886"/>
<source>The file is being parsed ...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="917"/>
<location filename="../gui/tageditorwidget.cpp" line="922"/>
<source>The file could not be opened because an IO error occurred: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="923"/>
<location filename="../gui/tageditorwidget.cpp" line="928"/>
<source>Tried to open file: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="959"/>
<location filename="../gui/tageditorwidget.cpp" line="964"/>
<source>Errors occurred.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1276"/>
<location filename="../gui/tageditorwidget.cpp" line="1280"/>
<source>Saving tags has been canceled.</source>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<location filename="../gui/tageditorwidget.cpp" line="1285"/>
<location filename="../gui/tageditorwidget.cpp" line="1289"/>
<source>The tags have been saved, but there is/are %1 warning(s).</source>
<translation>
<numerusform>The tags have been saved, but there is %1 warning.</numerusform>
@ -3333,133 +3333,133 @@ Error in line %1: %3</source>
</translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1290"/>
<location filename="../gui/tageditorwidget.cpp" line="1294"/>
<source>The tags have been saved.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1309"/>
<location filename="../gui/tageditorwidget.cpp" line="1313"/>
<source>The tags could not be saved. Checkout the info box for details.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1315"/>
<location filename="../gui/tageditorwidget.cpp" line="1319"/>
<source>Saving file - </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1317"/>
<location filename="../gui/tageditorwidget.cpp" line="1321"/>
<source>Tried to save file: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1336"/>
<location filename="../gui/tageditorwidget.cpp" line="1340"/>
<source>Automatic tag management</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1337"/>
<location filename="../gui/tageditorwidget.cpp" line="1341"/>
<source>The container format of the selected file is not supported. The file can be treated as MP3 file (an ID3 tag according to the settings will be created). This might break the file. Do you want to continue?</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1340"/>
<location filename="../gui/tageditorwidget.cpp" line="1344"/>
<source>Treat file as MP3 file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1352"/>
<location filename="../gui/tageditorwidget.cpp" line="1356"/>
<source>The currently opened file changed on the disk.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1365"/>
<location filename="../gui/tageditorwidget.cpp" line="1369"/>
<source>Unable to close the file because the current process hasn&apos;t been finished yet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1377"/>
<location filename="../gui/tageditorwidget.cpp" line="1381"/>
<source>Closing file - </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1378"/>
<location filename="../gui/tageditorwidget.cpp" line="1382"/>
<source>Unable to close file: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1379"/>
<location filename="../gui/tageditorwidget.cpp" line="1383"/>
<source>Tried to close file: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1386"/>
<location filename="../gui/tageditorwidget.cpp" line="1390"/>
<source>The file has been closed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1393"/>
<location filename="../gui/tageditorwidget.cpp" line="1397"/>
<source>Unable to rename the file because the current process hasn&apos;t been finished yet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1399"/>
<location filename="../gui/tageditorwidget.cpp" line="1403"/>
<source>Renaming file - </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1400"/>
<location filename="../gui/tageditorwidget.cpp" line="1404"/>
<source>New file name:</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1435"/>
<location filename="../gui/tageditorwidget.cpp" line="1439"/>
<source>Unable to rename file: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1436"/>
<location filename="../gui/tageditorwidget.cpp" line="1440"/>
<source>Tried to rename file: </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1443"/>
<location filename="../gui/tageditorwidget.cpp" line="1447"/>
<source>The file has been renamed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1450"/>
<location filename="../gui/tageditorwidget.cpp" line="1454"/>
<source>Unable to save file information because the current process hasn&apos;t been finished yet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1454"/>
<location filename="../gui/tageditorwidget.cpp" line="1458"/>
<source>No file is opened.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1459"/>
<location filename="../gui/tageditorwidget.cpp" line="1463"/>
<source>No file information available.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1468"/>
<location filename="../gui/tageditorwidget.cpp" line="1472"/>
<source>Unable to open file &quot;%1&quot;.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1476"/>
<location filename="../gui/tageditorwidget.cpp" line="1480"/>
<source>Unable to write to file &quot;%1&quot;.
%2</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1491"/>
<location filename="../gui/tageditorwidget.cpp" line="1495"/>
<source>Save file information - </source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1493"/>
<location filename="../gui/tageditorwidget.cpp" line="1497"/>
<source>Unable to open file.</source>
<translation type="unfinished"></translation>
</message>
@ -3475,52 +3475,52 @@ Error in line %1: %3</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1593"/>
<location filename="../gui/tageditorwidget.cpp" line="1597"/>
<source>A tag (with the selected target) already exists.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1589"/>
<location filename="../gui/tageditorwidget.cpp" line="1593"/>
<source>The tag can not be created.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1620"/>
<location filename="../gui/tageditorwidget.cpp" line="1624"/>
<source>Unable to remove the tag because no file is opened.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1616"/>
<location filename="../gui/tageditorwidget.cpp" line="1620"/>
<source>Unable to remove the tag because the current process hasn&apos;t been finished yet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1310"/>
<location filename="../gui/tageditorwidget.cpp" line="1314"/>
<source>The tags could not be saved because an IO error occurred: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1579"/>
<location filename="../gui/tageditorwidget.cpp" line="1583"/>
<source>Unable to add a tag because the current process hasn&apos;t been finished yet.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1583"/>
<location filename="../gui/tageditorwidget.cpp" line="1587"/>
<source>Unable to add a tag because no file is opened.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1684"/>
<location filename="../gui/tageditorwidget.cpp" line="1688"/>
<source>Unable to change the target because no file is opened.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1688"/>
<location filename="../gui/tageditorwidget.cpp" line="1692"/>
<source>Can not change the target of the selected tag because the tag does not support targets.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tageditorwidget.cpp" line="1680"/>
<location filename="../gui/tageditorwidget.cpp" line="1684"/>
<source>Unable to change the target because the current process hasn&apos;t been finished yet.</source>
<translation type="unfinished"></translation>
</message>
@ -3600,7 +3600,7 @@ currently shown tag.</source>
</message>
<message>
<location filename="../gui/tageditorwidget.ui" line="323"/>
<location filename="../gui/tageditorwidget.cpp" line="1341"/>
<location filename="../gui/tageditorwidget.cpp" line="1345"/>
<source>Abort</source>
<translation type="unfinished"></translation>
</message>
@ -4776,6 +4776,16 @@ currently shown tag.</source>
<source>Preserve writing application</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tagprocessinggeneraloptionpage.ui" line="165"/>
<source>Ensures fields usually holding values like &quot;3/15&quot; such as the track position are actually stored as such (and &lt;i&gt;not&lt;/i&gt; as two separate fields for the position and total values). This is required for the tag editor to support handling such separately stored total values at all. So far this only affects Vorbis Comments where it will convert the fields TRACKTOTAL/DISCTOTAL/PARTTOTAL to be included in the TRACKNUMBER/DISCNUMBER/PARTNUMBER fields.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tagprocessinggeneraloptionpage.ui" line="168"/>
<source>Convert total fields (see tooltip for details)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../gui/tagprocessinggeneraloptionpage.ui" line="119"/>
<source>Enable automatic tag management (default)</source>
@ -5498,7 +5508,12 @@ Remarks
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../application/knownfieldmodel.cpp" line="348"/>
<location filename="../application/knownfieldmodel.cpp" line="213"/>
<source>Publisher webpage</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../application/knownfieldmodel.cpp" line="351"/>
<source>Field</source>
<translation type="unfinished"></translation>
</message>