From a191aebd8a5863455084e76464927a002281dbdc Mon Sep 17 00:00:00 2001 From: Martchus Date: Sat, 5 Aug 2023 02:06:26 +0200 Subject: [PATCH] Allow basic use of db query via JavaScript --- cli/mediafileinfoobject.h | 2 +- dbquery/dbquery.cpp | 16 +++++++++ dbquery/dbquery.h | 13 ++++--- testfiles/set-tags.js | 72 +++++++++++++++++++++++++++++++-------- 4 files changed, 84 insertions(+), 19 deletions(-) diff --git a/cli/mediafileinfoobject.h b/cli/mediafileinfoobject.h index 593ef21..020a3ae 100644 --- a/cli/mediafileinfoobject.h +++ b/cli/mediafileinfoobject.h @@ -49,7 +49,7 @@ public Q_SLOTS: void diag(const QString &level, const QString &message, const QString &context = QString()); int exec(); - void exit(int retcode); + void exit(int retcode = 0); QJSValue readEnvironmentVariable(const QString &variable, const QJSValue &defaultValue = QJSValue()) const; QJSValue readDirectory(const QString &path); diff --git a/dbquery/dbquery.cpp b/dbquery/dbquery.cpp index ebd7150..b613a54 100644 --- a/dbquery/dbquery.cpp +++ b/dbquery/dbquery.cpp @@ -209,6 +209,14 @@ const QByteArray *QueryResultsModel::cover(const QModelIndex &index) const return nullptr; } +QByteArray QueryResultsModel::coverValue(const QModelIndex &index) const +{ + if (const auto *c = cover(index)) { + return *c; + } + return QByteArray(); +} + /*! * \brief Fetches the cover the specified \a index. * \returns @@ -240,6 +248,14 @@ const QString *QueryResultsModel::lyrics(const QModelIndex &index) const return nullptr; } +QString QueryResultsModel::lyricsValue(const QModelIndex &index) const +{ + if (const auto *l = lyrics(index)) { + return *l; + } + return QString(); +} + /*! * \brief Fetches the lyrics the specified \a index. * \returns diff --git a/dbquery/dbquery.h b/dbquery/dbquery.h index 8cd657b..3ae0484 100644 --- a/dbquery/dbquery.h +++ b/dbquery/dbquery.h @@ -42,6 +42,9 @@ struct SongDescription { class QueryResultsModel : public QAbstractTableModel { Q_OBJECT + Q_PROPERTY(QStringList errorList READ errorList) + Q_PROPERTY(bool areResultsAvailable READ areResultsAvailable) + Q_PROPERTY(bool isFetchingCover READ isFetchingCover) public: enum Column { @@ -68,11 +71,13 @@ public: int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; const QByteArray *cover(const QModelIndex &index) const; - virtual bool fetchCover(const QModelIndex &index); + Q_INVOKABLE QByteArray coverValue(const QModelIndex &index) const; + Q_INVOKABLE virtual bool fetchCover(const QModelIndex &index); const QString *lyrics(const QModelIndex &index) const; - virtual bool fetchLyrics(const QModelIndex &index); - virtual void abort(); - virtual QUrl webUrl(const QModelIndex &index); + Q_INVOKABLE QString lyricsValue(const QModelIndex &index) const; + Q_INVOKABLE virtual bool fetchLyrics(const QModelIndex &index); + Q_INVOKABLE virtual void abort(); + Q_INVOKABLE virtual QUrl webUrl(const QModelIndex &index); Q_SIGNALS: void resultsAvailable(); diff --git a/testfiles/set-tags.js b/testfiles/set-tags.js index 099a72f..8bbd340 100644 --- a/testfiles/set-tags.js +++ b/testfiles/set-tags.js @@ -21,7 +21,12 @@ function isString(value) { return typeof(value) === "string" || value instanceof String; } -function changeTagFields(file, tag) { +function waitFor(signal) { + signal.connect(() => { utility.exit(); }); + utility.exec(); +} + +function logTagInfo(file, tag) { // log tag type and supported fields const fields = tag.fields; utility.diag("debug", tag.type, "tag"); @@ -34,8 +39,10 @@ function changeTagFields(file, tag) { utility.diag("debug", content, key + " (" + value.type + ")"); } } +} - // apply fixes to main text fields +function applyFixesToMainFields(file, tag) { + const fields = tag.fields; for (const key of mainTextFields) { for (const value of fields[key]) { if (isString(value.content)) { @@ -45,27 +52,64 @@ function changeTagFields(file, tag) { } } } +} - // ensure personal fields are cleared +function clearPersonalFields(file, tag) { + const fields = tag.fields; for (const key of personalFields) { fields[key] = []; } +} - // set total number of tracks if not already assigned using the number of files in directory - const track = fields.track; - if (track.find(value => !value.content.total) !== undefined) { - const extension = file.extension; - const dirItems = utility.readDirectory(file.containingDirectory) || []; - const total = dirItems.filter(fileName => fileName.endsWith(extension)).length; - if (total) { - for (const value of track) { - value.content.total |= total; - } - } +function addTotalNumberOfTracks(file, tag) { + const track = tag.fields.track; + if (track.find(value => !value.content.total) === undefined) { + return; // skip if already assigned } + const extension = file.extension; + const dirItems = utility.readDirectory(file.containingDirectory) || []; + const total = dirItems.filter(fileName => fileName.endsWith(extension)).length; + if (!total) { + return; + } + for (const value of track) { + value.content.total |= total; + } +} +function addLyrics(file, tag) { + const fields = tag.fields; + if (fields.lyrics.length) { + return; // skip if already assigned + } + const firstTitle = fields.title?.[0]?.content; + const firstArtist = fields.artist?.[0]?.content; + if (!firstTitle || !firstArtist) { + return; + } + const lyricsModel = utility.queryMakeItPersonal({title: firstTitle, artist: firstArtist}); + if (!lyricsModel.areResultsAvailable) { + waitFor(lyricsModel.resultsAvailable); + } + if (!lyricsModel.fetchLyrics(lyricsModel.index(0, 0))) { + waitFor(lyricsModel.lyricsAvailable); + } + fields.lyrics = lyricsModel.lyricsValue(lyricsModel.index(0, 0)); +} + +function addMiscFields(file, tag) { // assume the number of disks is always one for now + const fields = tag.fields; if (!fields.disk.length) { fields.disk = "1/1"; } } + +function changeTagFields(file, tag) { + logTagInfo(file, tag); + applyFixesToMainFields(file, tag); + clearPersonalFields(file, tag); + addTotalNumberOfTracks(file, tag); + addMiscFields(file, tag); + addLyrics(file, tag); +}