Allow renaming file via `set --script …`

This allows doing what the GUI renaming utilitiy does on the command-line.
If only renaming is wanted
This commit is contained in:
Martchus 2023-11-10 15:44:24 +01:00
parent b5f9158106
commit 72dcbbbd81
4 changed files with 47 additions and 8 deletions

View File

@ -369,12 +369,13 @@ Here are some Bash examples which illustrate getting and setting tag information
- The script needs to be ECMAScript as supported by the Qt framework. - 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 - 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. 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 - The script needs to export a `main()` function. This function is invoked for every file and
passed an object representing this file as first argument. 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 - 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. fixes and tries to fetch lyrics and cover art.
- The option `--pedantic debug` is not required but useful for debugging. You may also add - For debugging, the option `--pedantic debug` is very useful. You may also add
`--script-settings dryRun=1` and use that setting within the script as shown in the example. `--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. - 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. - 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. - Adding properties of unsupported fields manually does not work; those will just be ignored.
@ -394,6 +395,11 @@ 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 - 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 values as usual (via `--values`) then these values have precedence over values set by the
script. 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).
##### Further useful commands ##### Further useful commands
* Let the tag editor return with a non-zero exit code even if only non-fatal problems have been encountered * Let the tag editor return with a non-zero exit code even if only non-fatal problems have been encountered

View File

@ -494,6 +494,7 @@ public:
private: private:
static void addWarnings(Diagnostics &diag, const std::string &context, const QList<QQmlError> &warnings); static void addWarnings(Diagnostics &diag, const std::string &context, const QList<QQmlError> &warnings);
const SetTagInfoArgs &args;
int argc; int argc;
QCoreApplication app; QCoreApplication app;
Diagnostics diag; Diagnostics diag;
@ -510,7 +511,8 @@ private:
* - Logs status/problems directly in accordance with other parts of the CLI. * - Logs status/problems directly in accordance with other parts of the CLI.
*/ */
JavaScriptProcessor::JavaScriptProcessor(const SetTagInfoArgs &args) JavaScriptProcessor::JavaScriptProcessor(const SetTagInfoArgs &args)
: argc(0) : args(args)
, argc(0)
, app(argc, nullptr) , app(argc, nullptr)
, utility(new UtilityObject(&engine)) , utility(new UtilityObject(&engine))
{ {
@ -567,7 +569,7 @@ JavaScriptProcessor::JavaScriptProcessor(const SetTagInfoArgs &args)
*/ */
QJSValue JavaScriptProcessor::callMain(MediaFileInfo &mediaFileInfo, Diagnostics &diag) 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 fileInfoObjectValue = engine.newQObject(&fileInfoObject);
auto context = argsToString("executing JavaScript for ", mediaFileInfo.fileName()); auto context = argsToString("executing JavaScript for ", mediaFileInfo.fileName());
utility->setDiag(&context, &diag); utility->setDiag(&context, &diag);

View File

@ -20,6 +20,8 @@
#include <c++utilities/conversion/binaryconversion.h> #include <c++utilities/conversion/binaryconversion.h>
#include <c++utilities/conversion/conversionexception.h> #include <c++utilities/conversion/conversionexception.h>
#include <c++utilities/conversion/stringbuilder.h>
#include <c++utilities/io/path.h>
#include <qtutilities/misc/compat.h> #include <qtutilities/misc/compat.h>
@ -33,6 +35,7 @@
#include <QJSValueIterator> #include <QJSValueIterator>
#include <QRegularExpression> #include <QRegularExpression>
#include <filesystem>
#include <iostream> #include <iostream>
#include <limits> #include <limits>
#include <type_traits> #include <type_traits>
@ -558,11 +561,13 @@ 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) : QObject(parent)
, m_f(mediaFileInfo) , m_f(mediaFileInfo)
, m_diag(diag) , m_diag(diag)
, m_engine(engine) , m_engine(engine)
, m_quiet(quiet)
{ {
} }
@ -621,4 +626,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 } // namespace Cli

View File

@ -193,7 +193,8 @@ class MediaFileInfoObject : public QObject {
Q_PROPERTY(QList<TagObject *> tags READ tags) Q_PROPERTY(QList<TagObject *> tags READ tags)
public: 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);
~MediaFileInfoObject() override; ~MediaFileInfoObject() override;
TagParser::MediaFileInfo &fileInfo(); TagParser::MediaFileInfo &fileInfo();
@ -207,12 +208,14 @@ public:
public Q_SLOTS: public Q_SLOTS:
void applyChanges(); void applyChanges();
bool rename(const QString &newPath);
private: private:
TagParser::MediaFileInfo &m_f; TagParser::MediaFileInfo &m_f;
TagParser::Diagnostics &m_diag; TagParser::Diagnostics &m_diag;
QJSEngine *m_engine; QJSEngine *m_engine;
QList<TagObject *> m_tags; QList<TagObject *> m_tags;
bool m_quiet;
}; };
inline TagParser::MediaFileInfo &MediaFileInfoObject::fileInfo() inline TagParser::MediaFileInfo &MediaFileInfoObject::fileInfo()