diff --git a/host/mprisplugin.cpp b/host/mprisplugin.cpp --- a/host/mprisplugin.cpp +++ b/host/mprisplugin.cpp @@ -29,14 +29,17 @@ #include #include +#include + #include "mprisroot.h" #include "mprisplayer.h" #include "settings.h" #include // getppid static const QString s_serviceName = QStringLiteral("org.mpris.MediaPlayer2.plasma-browser-integration"); +static const int s_maxThumbnailSize = 512; MPrisPlugin::MPrisPlugin(QObject *parent) : AbstractBrowserPlugin(QStringLiteral("mpris"), 1, parent) @@ -451,7 +454,8 @@ // for simplicity we just use the biggest artwork it offers, perhaps we could limit it to some extent // TODO download/cache artwork somewhere - QSize biggest; + qreal best = std::numeric_limits::max(); + QUrl artworkUrl; const QJsonArray &artwork = data.value(QStringLiteral("artwork")).toArray(); @@ -465,32 +469,51 @@ continue; } - // why is this named "sizes" when it's just a string and the examples don't mention how one could specify multiple? - // also, how on Earth could a single image src have multiple sizes? ... - // spec says this is a space-separated list of sizes for ... some reason - const QString sizeString = item.value(QStringLiteral("sizes")).toString(); - QSize actualSize; - - // now parse the size... - const auto &sizeParts = sizeString.splitRef(QLatin1Char('x')); - if (sizeParts.count() == 2) { - const int width = sizeParts.first().toInt(); - const int height = sizeParts.last().toInt(); - if (width <= 0 || height <= 0) { - continue; - } - - actualSize = QSize(width, height); - } - const QString type = item.value(QStringLiteral("type")).toString(); if (!type.isEmpty() && !supportedImageMimes.contains(type.toUtf8())) { continue; } - if (!biggest.isValid() || (actualSize.width() >= biggest.width() && actualSize.height() >= biggest.height())) { - artworkUrl = url; - biggest = actualSize; + // Sizes is a space-separated list of width x height pairs separated by X or x + const QString sizeString = item.value(QStringLiteral("sizes")).toString(); + QStringList sizes = sizeString.split(QLatin1Char(' '), QString::SkipEmptyParts); + // Sizes is optional, treat anything without a size as lowest priority so it is still used if neccessary + if (sizes.isEmpty()) { + sizes = QStringList{QStringLiteral("1x1")}; + } + + for (const QString &size : sizes) { + QSize actualSize; + + // now parse the size... + const QVector sizeSegments = size.splitRef(QLatin1Char('x'), QString::SkipEmptyParts, Qt::CaseInsensitive); + if (sizeSegments.count() == 2) { + const int width = sizeSegments.first().toInt(); + const int height = sizeSegments.last().toInt(); + if (width > 0 && height > 0) { + actualSize = QSize(width, height); + } + } + + auto dist = std::numeric_limits::max() - 1; + + if (!actualSize.isEmpty()) { + // Tries to find a thumbnail closest to 512x512 in size. + // Unfortunately we don't know at what size it will be displayed but this should be fair enough. + const auto targetSamples = s_maxThumbnailSize * s_maxThumbnailSize; + const auto xscale = (1.0 * s_maxThumbnailSize) / actualSize.width(); + const auto yscale = (1.0 * s_maxThumbnailSize) / actualSize.height(); + auto sampleScale = std::min(1.0, std::min(xscale, yscale)); + + const auto effectiveSamples = actualSize.width() * actualSize.height() * sampleScale * sampleScale; + + dist = targetSamples - effectiveSamples; + } + + if (dist < best) { + artworkUrl = url; + best = dist; + } } }