aboutsummaryrefslogtreecommitdiffstats
path: root/playlistwithmetadata.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'playlistwithmetadata.cpp')
-rw-r--r--playlistwithmetadata.cpp206
1 files changed, 206 insertions, 0 deletions
diff --git a/playlistwithmetadata.cpp b/playlistwithmetadata.cpp
new file mode 100644
index 0000000..be6d9a1
--- /dev/null
+++ b/playlistwithmetadata.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2016 The Qt Company Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "playlistwithmetadata.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QBuffer>
+#include <QtGui/QImage>
+#include <QtGui/QImageWriter>
+#include <QtMultimedia/QMediaPlayer>
+#include <QtMultimedia/QMediaMetaData>
+
+class PlaylistWithMetadata::Private
+{
+public:
+ Private(PlaylistWithMetadata *parent);
+
+ void disconnect();
+ void connect();
+
+private:
+ void loadMetadata(int row);
+
+private:
+ PlaylistWithMetadata *q;
+
+public:
+ QAbstractListModel *source;
+ QList<QMetaObject::Connection> connections;
+ QList<QUrl> urls;
+ QHash<QUrl, QString> title;
+ QHash<QUrl, QString> artist;
+ QHash<QUrl, QUrl> coverArt;
+ QHash<QUrl, qint64> duration;
+ QHash<QUrl, QMediaPlayer *> players;
+};
+
+PlaylistWithMetadata::Private::Private(PlaylistWithMetadata *parent)
+ : q(parent)
+ , source(nullptr)
+{
+}
+
+void PlaylistWithMetadata::Private::disconnect()
+{
+ if (source) {
+ for (const auto &connection : connections)
+ q->disconnect(connection);
+ connections.clear();
+ }
+}
+
+void PlaylistWithMetadata::Private::connect()
+{
+ if (source) {
+ connections.append(q->connect(source, &QAbstractListModel::rowsAboutToBeInserted, [&](const QModelIndex &parent, int first, int last) {
+ Q_UNUSED(parent)
+ q->beginInsertRows(QModelIndex(), first, last);
+ }));
+ connections.append(q->connect(source, &QAbstractListModel::rowsInserted, [&](const QModelIndex &parent, int first, int last) {
+ Q_UNUSED(parent)
+ for (int i = first; i <= last; i++) {
+ loadMetadata(i);
+ }
+ q->endInsertRows();
+ }));
+
+ int count = source->rowCount();
+ if (count > 0) {
+ q->beginInsertRows(QModelIndex(), 0, count);
+ for (int i = 0; i < count; i++) {
+ loadMetadata(i);
+ }
+ q->endInsertRows();
+ }
+ }
+}
+
+void PlaylistWithMetadata::Private::loadMetadata(int row)
+{
+ QUrl url = source->data(source->index(row), Qt::UserRole + 1).toUrl();
+ QMediaPlayer *player = new QMediaPlayer(q);
+ urls.append(url);
+ players.insert(url, player);
+ q->connect(player, &QMediaPlayer::mediaStatusChanged, [this, url](QMediaPlayer::MediaStatus mediaStatus) {
+ switch (mediaStatus) {
+ case QMediaPlayer::NoMedia:
+ case QMediaPlayer::LoadedMedia: {
+ QMediaPlayer *player = players.take(url);
+ title.insert(url, player->metaData(QMediaMetaData::Title).toString());
+ artist.insert(url, player->metaData(QMediaMetaData::ContributingArtist).toString());
+ QVariant coverArtImage = player->metaData(QMediaMetaData::CoverArtImage);
+ if (coverArtImage.type() == QVariant::Image) {
+ QImage image = coverArtImage.value<QImage>();
+ QByteArray data;
+ QBuffer buffer(&data);
+ buffer.open(QBuffer::WriteOnly);
+ QImageWriter png(&buffer, "png");
+ if (png.write(image)) {
+ buffer.close();
+ coverArt.insert(url, QUrl(QStringLiteral("data:image/png;base64,") + data.toBase64()));
+ }
+ }
+ duration.insert(url, player->duration());
+ QModelIndex index = q->index(urls.indexOf(url));
+ q->dataChanged(index, index, QVector<int>() << TitleRole << ArtistRole << CoverArtRole << DurationRole);
+ player->deleteLater();
+ break; }
+ default:
+ break;
+ }
+
+ });
+ player->setMedia(url);
+}
+
+PlaylistWithMetadata::PlaylistWithMetadata(QObject *parent)
+ : QAbstractListModel(parent)
+ , d(new Private(this))
+{
+}
+
+PlaylistWithMetadata::~PlaylistWithMetadata()
+{
+ delete d;
+}
+
+int PlaylistWithMetadata::rowCount(const QModelIndex &parent) const
+{
+ int ret = 0;
+ if (parent.isValid())
+ return ret;
+ if (d->source)
+ ret = d->source->rowCount(QModelIndex());
+ return ret;
+}
+
+QVariant PlaylistWithMetadata::data(const QModelIndex &index, int role) const
+{
+ QVariant ret;
+ if (!index.isValid())
+ return ret;
+ int row = index.row();
+ if (row < 0 || rowCount() <= row)
+ return ret;
+ QUrl url = d->urls.at(row);
+ switch (role) {
+ case TitleRole:
+ ret = d->title.value(url);
+ break;
+ case ArtistRole:
+ ret = d->artist.value(url);
+ break;
+ case CoverArtRole:
+ ret = d->coverArt.value(url);
+ break;
+ case SourceRole:
+ ret = url;
+ break;
+ case DurationRole:
+ ret = d->duration.value(url);
+ break;
+ default:
+ qWarning() << role;
+ }
+
+ return ret;
+}
+
+QHash<int, QByteArray> PlaylistWithMetadata::roleNames() const
+{
+ return {
+ {TitleRole, "title"},
+ {ArtistRole, "artist"},
+ {CoverArtRole, "coverArt"},
+ {SourceRole, "source"},
+ {DurationRole, "duration"}
+ };
+}
+
+QAbstractListModel *PlaylistWithMetadata::source() const
+{
+ return d->source;
+}
+
+void PlaylistWithMetadata::setSource(QAbstractListModel *source)
+{
+ if (d->source == source) return;
+ d->disconnect();
+ d->source = source;
+ d->connect();
+ emit sourceChanged(source);
+}