diff options
Diffstat (limited to 'playlistwithmetadata.cpp')
-rw-r--r-- | playlistwithmetadata.cpp | 206 |
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); +} |