- Show podcast coves in toolbar, queue, and info view.

- Show podcast description in info view.
- Only show cover in toolbar cover tooltip.
Issue #1556
This commit is contained in:
Craig Drummond
2019-12-05 16:01:39 +00:00
committed by Craig Drummond
parent e10350842d
commit 2d8566d743
9 changed files with 89 additions and 42 deletions

View File

@@ -54,10 +54,13 @@
40. Categorized view is reported to crash (#1530), so disable by default. Pass
-DENABLE_CATEGORIZED_VIEW=ON to cmake to re-enable.
41. Add 'aac' and 'libfdk_aac' as supported encoders.
42. Custom playqueue background is not workig with Qt 5.12 onwards, so
disabled for now.
42. Custom playqueue background is not working with Qt 5.12 onwards, so
disabled for now. (#1554)
43. Convert podcast descriptions to plain text, trim whitespace, and limit to
1000 characters.
44. Show podcast coves in toolbar, queue, and info view.
45. Show podcast description in info view.
46. Only show cover in toolbar cover tooltip.
2.3.3
-----

View File

@@ -23,6 +23,7 @@
#include "onlineview.h"
#include "gui/covers.h"
#include "online/podcastservice.h"
OnlineView::OnlineView(QWidget *p)
: View(p)
@@ -40,12 +41,13 @@ void OnlineView::update(const Song &song, bool force)
needToUpdate=true;
return;
}
setHeader(song.describe());
Covers::Image cImg=Covers::self()->requestImage(song, true);
setHeader(currentSong.describe().replace("<b>", "").replace("</b>", ""));
QString descr = PodcastService::self()->episodeDescr(song);
Covers::Image cImg = Covers::self()->requestImage(song, true);
if (!cImg.img.isNull()) {
setHtml(createPicTag(cImg.img, cImg.fileName));
setHtml(createPicTag(cImg.img, cImg.fileName)+(descr.isEmpty() ? QString() : ("<br>"+descr)));
} else {
setHtml(QString());
setHtml(descr.isEmpty() ? QString() : descr);
}
}
}

View File

@@ -29,6 +29,7 @@
#include "song.h"
#if !defined CANTATA_NO_UI_FUNCTIONS
#include "online/onlineservice.h"
#include "online/podcastservice.h"
#endif
#include <QStringList>
#include <QSet>
@@ -825,6 +826,12 @@ QString Song::filePath(const QString &base) const
QString Song::describe() const
{
#if !defined CANTATA_NO_UI_FUNCTIONS
if (OnlineSvrTrack==type && PodcastService::constName==onlineService()) {
return title;
}
#endif
QString albumText=album.isEmpty() ? name() : displayAlbum(album, Song::albumYear(*this));
if (title.isEmpty()) {

View File

@@ -57,6 +57,8 @@ Song & OnlineService::encode(Song &song)
add(json, "track", song.track);
add(json, "disc", song.disc);
add(json, "service", song.onlineService());
add(json, "imgcache", song.extraField(Song::OnlineImageCacheName));
add(json, "imgurl", song.extraField(Song::OnlineImageUrl));
song.file=Utils::addHashParam(QUrl(song.file).toEncoded(), constSongDetails, QJsonDocument(json).toJson(QJsonDocument::Compact));
return song;
}
@@ -84,6 +86,8 @@ bool OnlineService::decode(Song &song)
if (obj.contains("track")) song.track=obj["track"].toInt();
if (obj.contains("disc")) song.track=obj["disc"].toInt();
song.setIsFromOnlineService(obj["service"].toString());
if (obj.contains("imgcache")) song.setExtraField(Song::OnlineImageCacheName, obj["imgcache"].toString());
if (obj.contains("imgurl")) song.setExtraField(Song::OnlineImageUrl, obj["imgurl"].toString());
song.type=Song::OnlineSvrTrack;
song.file=Utils::removeHash(song.file);
return true;

View File

@@ -49,9 +49,8 @@ OnlineServicesPage::OnlineServicesPage(QWidget *p)
SoundCloudService *soundcloud=new SoundCloudService(this);
addPage(soundcloud->name(), soundcloud->icon(), soundcloud->title(), soundcloud->descr(), new OnlineSearchWidget(soundcloud, this));
podcast=new PodcastService(this);
addPage(podcast->name(), podcast->icon(), podcast->title(), podcast->descr(), new PodcastWidget(podcast, this));
connect(podcast, SIGNAL(error(QString)), this, SIGNAL(error(QString)));
addPage(PodcastService::self()->name(), PodcastService::self()->icon(), PodcastService::self()->title(), PodcastService::self()->descr(), new PodcastWidget(PodcastService::self(), this));
connect(PodcastService::self(), SIGNAL(error(QString)), this, SIGNAL(error(QString)));
Configuration config(metaObject()->className());
load(config);
@@ -65,12 +64,12 @@ OnlineServicesPage::~OnlineServicesPage()
bool OnlineServicesPage::isDownloading()
{
return podcast->isDownloading();
return PodcastService::self()->isDownloading();
}
void OnlineServicesPage::cancelAll()
{
podcast->cancelAll();
PodcastService::self()->cancelAll();
}
#include "moc_onlineservicespage.cpp"

View File

@@ -27,8 +27,6 @@
#include "onlineservice.h"
#include "widgets/multipagewidget.h"
class PodcastService;
class OnlineServicesPage : public MultiPageWidget
{
Q_OBJECT
@@ -44,9 +42,6 @@ public:
Q_SIGNALS:
void error(const QString &msg);
private:
PodcastService *podcast;
};
#endif

View File

@@ -24,6 +24,7 @@
#include "podcastservice.h"
#include "podcastsettingsdialog.h"
#include "rssparser.h"
#include "support/globalstatic.h"
#include "support/utils.h"
#include "support/monoicon.h"
#include "gui/settings.h"
@@ -48,6 +49,8 @@
#include <QTextDocument>
#include <stdio.h>
GLOBAL_STATIC(PodcastService, instance)
static QString encodeName(const QString &name)
{
QString n=name;
@@ -214,8 +217,10 @@ Song PodcastService::Episode::toSong() const
Song song;
song.title=name;
song.file=url.toString();
song.artist=parent->name;
song.album=parent->name;
song.time=duration;
song.setExtraField(Song::OnlineImageUrl, parent->imageUrl.toString());
song.setExtraField(Song::OnlineImageCacheName, parent->imageFile);
if (!localFile.isEmpty()) {
song.setLocalPath(localFile);
}
@@ -411,8 +416,8 @@ const Song & PodcastService::Podcast::coverSong()
return song;
}
PodcastService::PodcastService(QObject *p)
: ActionModel(p)
PodcastService::PodcastService()
: ActionModel(nullptr)
, downloadJob(nullptr)
, rssUpdateTimer(nullptr)
{
@@ -438,6 +443,44 @@ QString PodcastService::descr() const
return tr("Subscribe to RSS feeds");
}
bool PodcastService::episodeCover(const Song &s, QImage &img, QString &imgFilename) const
{
if ((s.isFromOnlineService() && s.onlineService()==constName) || isPodcastFile(s.file)) {
QString path=s.decodedPath();
if (path.isEmpty()) {
path=s.file;
}
for (Podcast *podcast: podcasts) {
for (Episode *episode: podcast->episodes) {
if (episode->url==path || episode->localFile==path) {
imgFilename = podcast->imageFile;
img = QImage(imgFilename);
return true;
}
}
}
}
return false;
}
QString PodcastService::episodeDescr(const Song &s) const
{
if ((s.isFromOnlineService() && s.onlineService()==constName) || isPodcastFile(s.file)) {
QString path=s.decodedPath();
if (path.isEmpty()) {
path=s.file;
}
for (Podcast *podcast: podcasts) {
for (Episode *episode: podcast->episodes) {
if (episode->url==path || episode->localFile==path) {
return episode->descr.replace("<p><br></p>", "");
}
}
}
}
return QString();
}
int PodcastService::rowCount(const QModelIndex &index) const
{
if (index.column()>0) {
@@ -1343,6 +1386,7 @@ void PodcastService::currentMpdSong(const Song &s)
idx=createIndex(podcasts.indexOf(podcast), 0, (void *)podcast);
emit dataChanged(idx, idx);
}
return;
}
}

View File

@@ -113,13 +113,17 @@ public:
static const QLatin1String constName;
PodcastService(QObject *p);
static PodcastService * self();
PodcastService();
~PodcastService() override { cancelAll(); }
Song & fixPath(Song &song) const;
QString name() const override;
QString title() const override;
QString descr() const override;
bool episodeCover(const Song &s, QImage &img, QString &imgFilename) const;
QString episodeDescr(const Song &s) const;
int rowCount(const QModelIndex &index = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override { Q_UNUSED(parent) return 1; }
bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;

View File

@@ -71,30 +71,19 @@ void CoverLabel::updateToolTip(bool isEvent)
setToolTip(QString());
return;
}
QString toolTip=QLatin1String("<table>");
const QImage &img=CurrentCover::self()->image();
toolTip+=tr("<tr><td align=\"right\"><b>Artist:</b></td><td>%1</td></tr>").arg(current.artist);
if (current.artist!=current.albumArtist()) {
toolTip+=tr("<tr><td align=\"right\"><b>Album artist:</b></td><td>%1</td></tr>").arg(current.albumArtist());
const QImage &img=CurrentCover::self()->image();
if (img.isNull()) {
return;
}
if (!current.composer().isEmpty()) {
toolTip+=tr("<tr><td align=\"right\"><b>Composer:</b></td><td>%1</td></tr>").arg(current.composer());
}
if (!current.performer().isEmpty() && current.performer()!=current.albumArtist()) {
toolTip+=tr("<tr><td align=\"right\"><b>Performer:</b></td><td>%1</td></tr>").arg(current.performer());
}
toolTip+=tr("<tr><td align=\"right\"><b>Album:</b></td><td>%1</td></tr>").arg(current.albumName());
toolTip+=tr("<tr><td align=\"right\"><b>Year:</b></td><td>%3</td></tr>").arg(QString::number(current.year));
toolTip+="</table>";
if (!img.isNull()) {
if (img.size().width()>Covers::constMaxSize.width() || img.size().height()>Covers::constMaxSize.height()) {
toolTip+=QString("<br/>%1").arg(View::encode(img.scaled(Covers::constMaxSize, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
} else if (CurrentCover::self()->fileName().isEmpty() || !QFile::exists(CurrentCover::self()->fileName())) {
toolTip+=QString("<br/>%1").arg(View::encode(img));
} else {
toolTip+=QString("<br/><img src=\"%1\"/>").arg(CurrentCover::self()->fileName());
}
QString toolTip;
if (img.size().width()>Covers::constMaxSize.width() || img.size().height()>Covers::constMaxSize.height()) {
toolTip=QString("<br/>%1").arg(View::encode(img.scaled(Covers::constMaxSize, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
} else if (CurrentCover::self()->fileName().isEmpty() || !QFile::exists(CurrentCover::self()->fileName())) {
toolTip=QString("<br/>%1").arg(View::encode(img));
} else {
toolTip=QString("<br/><img src=\"%1\"/>").arg(CurrentCover::self()->fileName());
}
setToolTip(toolTip);