@@ -1,236 +0,0 @@
2− * Copyright 2013 Canonical Ltd.
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU Lesser General Public License as published by
6− * the Free Software Foundation; version 3.
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU Lesser General Public License for more details.
13− * You should have received a copy of the GNU Lesser General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
16− * Authors: Jussi Pakkanen <jussi.pakkanen@canonical.com>
17− * Pawel Stolowski <pawel.stolowski@canonical.com>
20−#include "albumartprovider.h"
22−#include <QNetworkAccessManager>
24−#include <QNetworkRequest>
25−#include <QNetworkReply>
27−#include <QTemporaryFile>
31−#include <QStringList>
36−#include <QtConcurrent>
40−const std::string AlbumArtProvider::DEFAULT_ALBUM_ART = "/usr/share/unity/icons/album_missing.png";
41−const std::string AlbumArtProvider::UNITY_LENS_SCHEMA = "com.canonical.Unity.Lenses";
43−static QByteArray download(QString url) {
44− QScopedPointer<QNetworkAccessManager> am(new QNetworkAccessManager);
45− QNetworkReply *reply = am->get(QNetworkRequest(QUrl(url)));
47− QObject::connect(am.data(), &QNetworkAccessManager::finished, &loop, &QEventLoop::quit);
50− if (reply->error() != QNetworkReply::NoError) {
51− qWarning() << "Error downloading from the network:" << reply->errorString();
54− return reply->readAll();
57−AlbumArtProvider::AlbumArtProvider()
58− : QQuickImageProvider(QQmlImageProviderBase::Image, QQmlImageProviderBase::ForceAsynchronousImageLoading),
61− auto schemas = g_settings_list_schemas();
63− for (int i = 0; schemas[i]; i++) {
64− if (g_strcmp0(schemas[i], UNITY_LENS_SCHEMA.c_str()) == 0) {
65− m_settings = g_settings_new(UNITY_LENS_SCHEMA.c_str());
70− if (m_settings == nullptr) {
71− qWarning() << "Missing" << QString::fromStdString(UNITY_LENS_SCHEMA) << "schema";
75−AlbumArtProvider::~AlbumArtProvider()
78− g_object_unref(m_settings);
81−std::string AlbumArtProvider::get_lastfm_url(const albuminfo &ai) {
82− QString artist = QString::fromStdString(ai.artist);
83− QString album = QString::fromStdString(ai.album);
84− // audioscrobbler wants it without any / (as it would break the URL)
88− /// @todo: this is the old API which will probably get axed at some point in the future
89− /// The new 2.0 API requires an API key, but supports JSON output, etc, so switching
90− /// to it should be done ASAP.
91− QString request = QString("http://ws.audioscrobbler.com/1.0/album/%1/%2/info.xml").arg(artist)
94− QFuture<QByteArray> future = QtConcurrent::run(download, request);
95− QByteArray arr = future.result();
96− if(arr.size() == 0) {
102− tmp.open(QIODevice::ReadOnly);
103− query.bindVariable("reply", &tmp);
104− query.setQuery("doc($reply)/album/coverart/large[1]/text()");
106− query.evaluateTo(&image);
107− image = image.trimmed();
109− // return empty if last.fm tries to offer their default
111− if (image.contains("catalogue/noimage")) {
115− return image.toStdString();
118−bool AlbumArtProvider::download_and_store(const std::string &image_url, const std::string &output_file) {
119− QString url = QString::fromStdString(image_url);
120− QString fileName = QString::fromStdString(output_file);
121− QFuture<QByteArray> future = QtConcurrent::run(download, url);
122− QByteArray arr = future.result();
123− if (arr.size() == 0) {
126− QFile file(fileName);
127− if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
128− qWarning() << "Could not open file for writing:" << file.errorString();
131− if (file.write(arr) == -1){
132− qWarning() << "Could not write the image:" << file.error();
139−void AlbumArtProvider::fix_format(const std::string &fname) {
140− // MediaArtSpec requires jpg. Convert to it if necessary.
141− FILE *f = fopen(fname.c_str(), "r");
144− unsigned char buf[2];
145− fread(buf, 1, 2, f);
147− if(buf[0] == 0xff && buf[1] == 0xd8) {
150− QImage im(fname.c_str());
151− im.save(fname.c_str(), "JPEG");
154−std::string AlbumArtProvider::get_image(const std::string &artist, const std::string &album) {
157− info.artist = artist;
160− if(info.album.empty() || info.artist.empty()) {
161− return DEFAULT_ALBUM_ART;
163− if(cache.has_art(info.artist, info.album)) {
164− // Image may have expired from cache between these two lines.
165− // It might expire before we return. C'est la vie.
166− return cache.get_art_file(info.artist, info.album);
169− if (m_settings != nullptr && g_strcmp0(g_settings_get_string(m_settings, "remote-content-search"), "all") !=0) {
170− qDebug() << "Remote content disabled";
171− return DEFAULT_ALBUM_ART;
174− std::string image_url = get_lastfm_url(info);
175− if(image_url.empty()) {
176− return DEFAULT_ALBUM_ART;
178− QTemporaryFile tempFile;
180− tempFile.setAutoRemove(true);
181− QString fname = tempFile.fileName();
182− std::string tmpname = fname.toUtf8().data();
184− if(!download_and_store(image_url, tmpname)) {
185− return DEFAULT_ALBUM_ART;
187− fix_format(tmpname.c_str());
189− if(!f.open(QIODevice::ReadWrite)) {
190− return DEFAULT_ALBUM_ART;
192− QByteArray arr = f.readAll();
195− cache.add_art(info.artist, info.album, arr.data(), arr.size());
197− std::string res = cache.get_art_file(info.artist, info.album);
199− return DEFAULT_ALBUM_ART;
203− return DEFAULT_ALBUM_ART;
206−QImage AlbumArtProvider::requestImage(const QString &id, QSize *realSize, const QSize &requestedSize) {
207− Q_UNUSED(requestedSize)
209− QUrlQuery query(id);
210− if (!query.hasQueryItem(QStringLiteral("artist")) || !query.hasQueryItem(QStringLiteral("album"))) {
211− qWarning() << "Invalid albumart uri:" << id;
212− return QImage(QString::fromStdString(DEFAULT_ALBUM_ART));
214− const QString artist = query.queryItemValue(QStringLiteral("artist"), QUrl::FullyEncoded);
215− const QString album = query.queryItemValue(QStringLiteral("album"), QUrl::FullyEncoded);
217− std::string tgt_path;
219− tgt_path = get_image(artist.toStdString(), album.toStdString());
220− if(!tgt_path.empty()) {
222− image.load(QString::fromStdString(tgt_path));
223− // FIXME: Rescale to requested size preserving aspect.
224− *realSize = image.size();
227− } catch(std::exception &e) {
228− qDebug() << "Album art loader failed: " << e.what();
230− qDebug() << "Unknown error when generating image.";
233− QImage fallback(QString::fromStdString(DEFAULT_ALBUM_ART));
234− *realSize = fallback.size();