2 * Copyright (C) 2016 The Qt Company Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "playlistwithmetadata.h"
19 #include <QtCore/QDebug>
20 #include <QtCore/QBuffer>
21 #include <QtGui/QImage>
22 #include <QtGui/QImageWriter>
23 #include <QtMultimedia/QMediaPlayer>
24 #include <QtMultimedia/QMediaMetaData>
26 class PlaylistWithMetadata::Private
29 Private(PlaylistWithMetadata *parent);
35 void loadMetadata(int row);
38 PlaylistWithMetadata *q;
41 QAbstractListModel *source;
42 QList<QMetaObject::Connection> connections;
44 QHash<QUrl, QString> title;
45 QHash<QUrl, QString> artist;
46 QHash<QUrl, QUrl> coverArt;
47 QHash<QUrl, qint64> duration;
48 QHash<QUrl, QMediaPlayer *> players;
51 PlaylistWithMetadata::Private::Private(PlaylistWithMetadata *parent)
57 void PlaylistWithMetadata::Private::disconnect()
60 for (const auto &connection : connections)
61 q->disconnect(connection);
66 void PlaylistWithMetadata::Private::connect()
69 connections.append(q->connect(source, &QAbstractListModel::rowsAboutToBeInserted, [&](const QModelIndex &parent, int first, int last) {
71 q->beginInsertRows(QModelIndex(), first, last);
73 connections.append(q->connect(source, &QAbstractListModel::rowsInserted, [&](const QModelIndex &parent, int first, int last) {
75 for (int i = first; i <= last; i++) {
81 connections.append(q->connect(source, &QAbstractListModel::rowsAboutToBeRemoved, [&](const QModelIndex &parent, int first, int last) {
83 q->beginRemoveRows(QModelIndex(), first, last);
85 connections.append(q->connect(source, &QAbstractListModel::rowsRemoved, [&](const QModelIndex &parent, int first, int last) {
87 for (int i = last; i >= first; --i) {
88 QUrl url = urls.at(i);
100 int count = source->rowCount();
102 q->beginInsertRows(QModelIndex(), 0, count);
103 for (int i = 0; i < count; i++) {
111 void PlaylistWithMetadata::Private::loadMetadata(int row)
113 QUrl url = source->data(source->index(row), Qt::UserRole + 1).toUrl();
114 QMediaPlayer *player = new QMediaPlayer(q);
116 players.insert(url, player);
117 q->connect(player, &QMediaPlayer::mediaStatusChanged, [this, url](QMediaPlayer::MediaStatus mediaStatus) {
118 switch (mediaStatus) {
119 case QMediaPlayer::NoMedia:
120 case QMediaPlayer::LoadedMedia: {
121 QMediaPlayer *player = players.take(url);
122 title.insert(url, player->metaData(QMediaMetaData::Title).toString());
123 artist.insert(url, player->metaData(QMediaMetaData::ContributingArtist).toString());
124 QVariant coverArtImage = player->metaData(QMediaMetaData::CoverArtImage);
125 if (coverArtImage.type() == QVariant::Image) {
126 QImage image = coverArtImage.value<QImage>();
128 QBuffer buffer(&data);
129 buffer.open(QBuffer::WriteOnly);
130 QImageWriter png(&buffer, "png");
131 if (png.write(image)) {
133 coverArt.insert(url, QUrl(QStringLiteral("data:image/png;base64,") + data.toBase64()));
136 duration.insert(url, player->duration());
137 QModelIndex index = q->index(urls.indexOf(url));
138 q->dataChanged(index, index, QVector<int>() << TitleRole << ArtistRole << CoverArtRole << DurationRole);
139 player->deleteLater();
146 player->setMedia(url);
149 PlaylistWithMetadata::PlaylistWithMetadata(QObject *parent)
150 : QAbstractListModel(parent)
151 , d(new Private(this))
155 PlaylistWithMetadata::~PlaylistWithMetadata()
160 int PlaylistWithMetadata::rowCount(const QModelIndex &parent) const
163 if (parent.isValid())
166 ret = d->source->rowCount(QModelIndex());
170 QVariant PlaylistWithMetadata::data(const QModelIndex &index, int role) const
173 if (!index.isValid())
175 int row = index.row();
176 if (row < 0 || rowCount() <= row)
178 QUrl url = d->urls.at(row);
181 ret = d->title.value(url);
182 if (ret.toString().isEmpty())
183 ret = QVariant(url.fileName());
186 ret = d->artist.value(url);
189 ret = d->coverArt.value(url);
195 ret = d->duration.value(url);
204 QHash<int, QByteArray> PlaylistWithMetadata::roleNames() const
207 {TitleRole, "title"},
208 {ArtistRole, "artist"},
209 {CoverArtRole, "coverArt"},
210 {SourceRole, "source"},
211 {DurationRole, "duration"}
215 QAbstractListModel *PlaylistWithMetadata::source() const
220 void PlaylistWithMetadata::setSource(QAbstractListModel *source)
222 if (d->source == source) return;
226 emit sourceChanged(source);