Changeset View
Changeset View
Standalone View
Standalone View
host/mprisplugin.cpp
Show All 23 Lines | |||||
24 | #include "mprisplugin.h" | 24 | #include "mprisplugin.h" | ||
25 | 25 | | |||
26 | #include <QCoreApplication> | 26 | #include <QCoreApplication> | ||
27 | #include <QDBusConnection> | 27 | #include <QDBusConnection> | ||
28 | #include <QDBusObjectPath> | 28 | #include <QDBusObjectPath> | ||
29 | #include <QDebug> | 29 | #include <QDebug> | ||
30 | #include <QImageReader> | 30 | #include <QImageReader> | ||
31 | 31 | | |||
32 | #include <limits> | ||||
33 | | ||||
32 | #include "mprisroot.h" | 34 | #include "mprisroot.h" | ||
33 | #include "mprisplayer.h" | 35 | #include "mprisplayer.h" | ||
34 | 36 | | |||
35 | #include "settings.h" | 37 | #include "settings.h" | ||
36 | 38 | | |||
37 | #include <unistd.h> // getppid | 39 | #include <unistd.h> // getppid | ||
38 | 40 | | |||
39 | static const QString s_serviceName = QStringLiteral("org.mpris.MediaPlayer2.plasma-browser-integration"); | 41 | static const QString s_serviceName = QStringLiteral("org.mpris.MediaPlayer2.plasma-browser-integration"); | ||
42 | static const int s_maxThumbnailSize = 512; | ||||
40 | 43 | | |||
41 | MPrisPlugin::MPrisPlugin(QObject *parent) | 44 | MPrisPlugin::MPrisPlugin(QObject *parent) | ||
42 | : AbstractBrowserPlugin(QStringLiteral("mpris"), 1, parent) | 45 | : AbstractBrowserPlugin(QStringLiteral("mpris"), 1, parent) | ||
43 | , m_root(new MPrisRoot(this)) | 46 | , m_root(new MPrisRoot(this)) | ||
44 | , m_player(new MPrisPlayer(this)) | 47 | , m_player(new MPrisPlayer(this)) | ||
45 | , m_playbackStatus(QStringLiteral("Stopped")) | 48 | , m_playbackStatus(QStringLiteral("Stopped")) | ||
46 | , m_loopStatus(QStringLiteral("None")) | 49 | , m_loopStatus(QStringLiteral("None")) | ||
47 | { | 50 | { | ||
▲ Show 20 Lines • Show All 398 Lines • ▼ Show 20 Line(s) | |||||
446 | void MPrisPlugin::processMetadata(const QJsonObject &data) | 449 | void MPrisPlugin::processMetadata(const QJsonObject &data) | ||
447 | { | 450 | { | ||
448 | m_title = data.value(QStringLiteral("title")).toString(); | 451 | m_title = data.value(QStringLiteral("title")).toString(); | ||
449 | m_artist = data.value(QStringLiteral("artist")).toString(); | 452 | m_artist = data.value(QStringLiteral("artist")).toString(); | ||
450 | m_album = data.value(QStringLiteral("album")).toString(); | 453 | m_album = data.value(QStringLiteral("album")).toString(); | ||
451 | 454 | | |||
452 | // for simplicity we just use the biggest artwork it offers, perhaps we could limit it to some extent | 455 | // for simplicity we just use the biggest artwork it offers, perhaps we could limit it to some extent | ||
453 | // TODO download/cache artwork somewhere | 456 | // TODO download/cache artwork somewhere | ||
454 | QSize biggest; | 457 | qreal best = std::numeric_limits<qreal>::max(); | ||
458 | | ||||
455 | QUrl artworkUrl; | 459 | QUrl artworkUrl; | ||
456 | const QJsonArray &artwork = data.value(QStringLiteral("artwork")).toArray(); | 460 | const QJsonArray &artwork = data.value(QStringLiteral("artwork")).toArray(); | ||
457 | 461 | | |||
458 | const auto &supportedImageMimes = QImageReader::supportedMimeTypes(); | 462 | const auto &supportedImageMimes = QImageReader::supportedMimeTypes(); | ||
459 | 463 | | |||
460 | for (auto it = artwork.constBegin(), end = artwork.constEnd(); it != end; ++it) { | 464 | for (auto it = artwork.constBegin(), end = artwork.constEnd(); it != end; ++it) { | ||
461 | const QJsonObject &item = it->toObject(); | 465 | const QJsonObject &item = it->toObject(); | ||
462 | 466 | | |||
463 | const QUrl url = QUrl(item.value(QStringLiteral("src")).toString()); | 467 | const QUrl url = QUrl(item.value(QStringLiteral("src")).toString()); | ||
464 | if (!url.isValid()) { | 468 | if (!url.isValid()) { | ||
465 | continue; | 469 | continue; | ||
466 | } | 470 | } | ||
467 | 471 | | |||
468 | // why is this named "sizes" when it's just a string and the examples don't mention how one could specify multiple? | 472 | const QString type = item.value(QStringLiteral("type")).toString(); | ||
469 | // also, how on Earth could a single image src have multiple sizes? ... | 473 | if (!type.isEmpty() && !supportedImageMimes.contains(type.toUtf8())) { | ||
470 | // spec says this is a space-separated list of sizes for ... some reason | 474 | continue; | ||
475 | } | ||||
476 | | ||||
477 | // Sizes is a space-separated list of width x height pairs separated by X or x | ||||
fvogt: AFAICT this will not work as expected in cases such as 1920x1080 followed by 256x256. | |||||
471 | const QString sizeString = item.value(QStringLiteral("sizes")).toString(); | 478 | const QString sizeString = item.value(QStringLiteral("sizes")).toString(); | ||
479 | QStringList sizes = sizeString.split(QLatin1Char(' '), QString::SkipEmptyParts); | ||||
480 | // Sizes is optional, treat anything without a size as lowest priority so it is still used if neccessary | ||||
481 | if (sizes.isEmpty()) { | ||||
482 | sizes = QStringList{QStringLiteral("1x1")}; | ||||
483 | } | ||||
484 | | ||||
485 | for (const QString &size : sizes) { | ||||
472 | QSize actualSize; | 486 | QSize actualSize; | ||
473 | 487 | | |||
474 | // now parse the size... | 488 | // now parse the size... | ||
475 | const auto &sizeParts = sizeString.splitRef(QLatin1Char('x')); | 489 | const QVector<QStringRef> sizeSegments = size.splitRef(QLatin1Char('x'), QString::SkipEmptyParts, Qt::CaseInsensitive); | ||
Why change this line? With auto it was easier to read, just the & should be removed for clarity. Now it also accepts `xx42xx42xx" as valid size, while it didn't before. fvogt: Why change this line? With auto it was easier to read, just the `&` should be removed for… | |||||
476 | if (sizeParts.count() == 2) { | 490 | if (sizeSegments.count() == 2) { | ||
477 | const int width = sizeParts.first().toInt(); | 491 | const int width = sizeSegments.first().toInt(); | ||
478 | const int height = sizeParts.last().toInt(); | 492 | const int height = sizeSegments.last().toInt(); | ||
479 | if (width <= 0 || height <= 0) { | 493 | if (width > 0 && height > 0) { | ||
480 | continue; | | |||
481 | } | | |||
482 | | ||||
483 | actualSize = QSize(width, height); | 494 | actualSize = QSize(width, height); | ||
484 | } | 495 | } | ||
496 | } | ||||
485 | 497 | | |||
486 | const QString type = item.value(QStringLiteral("type")).toString(); | 498 | auto dist = std::numeric_limits<qreal>::max() - 1; | ||
That's still equal to std::numeric_limits<qreal>::max() due to lacking precision. fvogt: That's still equal to `std::numeric_limits<qreal>::max()` due to lacking precision. | |||||
487 | if (!type.isEmpty() && !supportedImageMimes.contains(type.toUtf8())) { | 499 | | ||
488 | continue; | 500 | if (!actualSize.isEmpty()) { | ||
501 | // Tries to find a thumbnail closest to 512x512 in size. | ||||
502 | // Unfortunately we don't know at what size it will be displayed but this should be fair enough. | ||||
503 | const auto targetSamples = s_maxThumbnailSize * s_maxThumbnailSize; | ||||
504 | const auto xscale = (1.0 * s_maxThumbnailSize) / actualSize.width(); | ||||
505 | const auto yscale = (1.0 * s_maxThumbnailSize) / actualSize.height(); | ||||
506 | auto sampleScale = std::min(1.0, std::min(xscale, yscale)); | ||||
507 | | ||||
508 | const auto effectiveSamples = actualSize.width() * actualSize.height() * sampleScale * sampleScale; | ||||
509 | | ||||
510 | dist = targetSamples - effectiveSamples; | ||||
This algorithm only looks at the aspect ratio of the image, not the resolution. For 4096x4096, 1024x1024 and 512x512 you'll get the same effectiveSamples value, so it will load huge thumbnails again. fvogt: This algorithm only looks at the aspect ratio of the image, not the resolution. For 4096x4096… | |||||
489 | } | 511 | } | ||
490 | 512 | | |||
491 | if (!biggest.isValid() || (actualSize.width() >= biggest.width() && actualSize.height() >= biggest.height())) { | 513 | if (dist < best) { | ||
492 | artworkUrl = url; | 514 | artworkUrl = url; | ||
493 | biggest = actualSize; | 515 | best = dist; | ||
516 | } | ||||
494 | } | 517 | } | ||
495 | } | 518 | } | ||
496 | 519 | | |||
497 | m_artworkUrl = artworkUrl; | 520 | m_artworkUrl = artworkUrl; | ||
498 | 521 | | |||
499 | emitPropertyChange(m_player, "Metadata"); | 522 | emitPropertyChange(m_player, "Metadata"); | ||
500 | } | 523 | } | ||
501 | 524 | | |||
▲ Show 20 Lines • Show All 86 Lines • Show Last 20 Lines |
AFAICT this will not work as expected in cases such as 1920x1080 followed by 256x256.