From 511d0feb7ca7c83d8b64e458fef8882a045c55fa Mon Sep 17 00:00:00 2001 From: "craig.p.drummond" Date: Thu, 26 Sep 2013 18:03:28 +0000 Subject: [PATCH] Extract, and store, podcast publication date - and use this to sort --- models/musiclibraryitempodcast.cpp | 23 ++++++----------------- models/musiclibraryitempodcast.h | 2 +- models/musiclibraryproxymodel.cpp | 12 +++++++++++- mpd/song.h | 2 ++ online/podcastservice.cpp | 8 ++++++-- online/rssparser.cpp | 16 ++++++++++++++++ online/rssparser.h | 3 +++ 7 files changed, 45 insertions(+), 21 deletions(-) diff --git a/models/musiclibraryitempodcast.cpp b/models/musiclibraryitempodcast.cpp index d490e6f0d..38e43c9c6 100644 --- a/models/musiclibraryitempodcast.cpp +++ b/models/musiclibraryitempodcast.cpp @@ -49,6 +49,7 @@ static QLatin1String constImageAttribute("img"); static QLatin1String constRssAttribute("rss"); static QLatin1String constEpisodeTag("episode"); static QLatin1String constNameAttribute("name"); +static QLatin1String constDateAttribute("date"); static QLatin1String constUrlAttribute("url"); static QLatin1String constTimeAttribute("time"); static QLatin1String constPlayedAttribute("played"); @@ -93,7 +94,6 @@ bool MusicLibraryItemPodcast::load() return false; } - int track=0; QFile file(m_fileName); QtIOCompressor compressor(&file); compressor.setStreamFormat(QtIOCompressor::GzipFormat); @@ -124,10 +124,10 @@ bool MusicLibraryItemPodcast::load() Song s; s.title=name; s.file=url; - s.track=++track; s.artist=m_itemData; s.setPlayed(constTrue==attributes.value(constPlayedAttribute).toString()); s.setPodcastImage(m_imageFile); + s.setPodcastPublishedDate(attributes.value(constDateAttribute).toString()); QString time=attributes.value(constTimeAttribute).toString(); s.time=time.isEmpty() ? 0 : time.toUInt(); MusicLibraryItemSong *song=new MusicLibraryItemSong(s, this); @@ -163,16 +163,15 @@ bool MusicLibraryItemPodcast::loadRss(QNetworkReply *dev) m_itemData=ch.name; m_unplayedEpisodeCount=ch.episodes.count(); - int track=0; foreach (const RssParser::Episode &ep, ch.episodes) { Song s; s.title=ep.name; s.file=ep.url.toString(); // ???? - s.track=++track; s.artist=m_itemData; s.time=ep.duration; s.setPlayed(false); s.setPodcastImage(m_imageFile); + s.setPodcastPublishedDate(ep.publicationDate.toString(Qt::ISODate)); MusicLibraryItemSong *song=new MusicLibraryItemSong(s, this); m_childItems.append(song); } @@ -209,6 +208,9 @@ bool MusicLibraryItemPodcast::save() if (s.hasbeenPlayed()) { writer.writeAttribute(constPlayedAttribute, constTrue); } + if (!s.podcastPublishedDate().isEmpty()) { + writer.writeAttribute(constDateAttribute, s.podcastPublishedDate()); + } writer.writeEndElement(); } writer.writeEndElement(); @@ -313,19 +315,6 @@ void MusicLibraryItemPodcast::removeFiles() } } -void MusicLibraryItemPodcast::updateTrackNumbers() -{ - quint16 track=0; - resetRows(); - m_unplayedEpisodeCount=0; - foreach (MusicLibraryItem *i, m_childItems) { - static_cast(i)->setTrack(++track); - if (!static_cast(i)->song().hasbeenPlayed()) { - m_unplayedEpisodeCount++; - } - } -} - void MusicLibraryItemPodcast::setPlayed(MusicLibraryItemSong *song) { if (!song->song().hasbeenPlayed()) { diff --git a/models/musiclibraryitempodcast.h b/models/musiclibraryitempodcast.h index 635028532..b83e62c85 100644 --- a/models/musiclibraryitempodcast.h +++ b/models/musiclibraryitempodcast.h @@ -62,7 +62,7 @@ public: void clearImage(); const QUrl & rssUrl() const { return m_rssUrl; } void removeFiles(); - void updateTrackNumbers(); + void setUnplayedCount(quint32 upc) { m_unplayedEpisodeCount=upc; } quint32 unplayedEpisodes() const { return m_unplayedEpisodeCount; } void setPlayed(MusicLibraryItemSong *song); void addAll(MusicLibraryItemPodcast *other); diff --git a/models/musiclibraryproxymodel.cpp b/models/musiclibraryproxymodel.cpp index 39276d065..76210e966 100644 --- a/models/musiclibraryproxymodel.cpp +++ b/models/musiclibraryproxymodel.cpp @@ -141,8 +141,18 @@ bool MusicLibraryProxyModel::lessThan(const QModelIndex &left, const QModelIndex if (left.row()<0 || right.row()<0) { return left.row()<0; } + if (static_cast(left.internalPointer())->itemType() == MusicLibraryItem::Type_Song) { - return static_cast(left.internalPointer())->song()(right.internalPointer())->song(); + MusicLibraryItemSong *l=static_cast(left.internalPointer()); + MusicLibraryItemSong *r=static_cast(right.internalPointer()); + + if (l->parentItem()->itemType() == MusicLibraryItem::Type_Podcast) { + int compare=QString::compare(l->song().podcastPublishedDate(), r->song().podcastPublishedDate()); + if (0!=compare) { + return compare>0; + } + } + return l->song()song(); } else if (static_cast(left.internalPointer())->itemType() == MusicLibraryItem::Type_Album) { return MusicLibraryItemAlbum::lessThan(static_cast(left.internalPointer()), static_cast(right.internalPointer())); } else if (static_cast(left.internalPointer())->itemType() == MusicLibraryItem::Type_Artist) { diff --git a/mpd/song.h b/mpd/song.h index dc93eb413..5aa39ea08 100644 --- a/mpd/song.h +++ b/mpd/song.h @@ -129,6 +129,8 @@ struct Song void setPlayed(bool p) { id=p ? 1 : 0; } void setPodcastImage(const QString &i) { genre=i; } const QString & podcastImage() const { return genre; } + void setPodcastPublishedDate(const QString &pd) { composer=pd; } + const QString & podcastPublishedDate() const { return composer; } // podcast/soundcloud functions... void setIsFromOnlineService(const QString &service); diff --git a/online/podcastservice.cpp b/online/podcastservice.cpp index efb7345af..c51602afe 100644 --- a/online/podcastservice.cpp +++ b/online/podcastservice.cpp @@ -271,7 +271,9 @@ void PodcastService::jobFinished() QSet playedSongs; foreach (MusicLibraryItem *i, orig->childItems()) { MusicLibraryItemSong *song=static_cast(i); - origSongs.insert(song->file()); + if (!song->song().podcastPublishedDate().isEmpty()) { + origSongs.insert(song->file()); + } if (song->song().hasbeenPlayed()) { playedSongs.insert(song->file()); } @@ -295,12 +297,13 @@ void PodcastService::jobFinished() orig->addAll(podcast); endInsertRows(); } - orig->updateTrackNumbers(); // Restore played status... + quint32 played=0; foreach (MusicLibraryItem *i, orig->childItems()) { MusicLibraryItemSong *song=static_cast(i); if (playedSongs.contains(song->file())) { + played++; orig->setPlayed(song); playedSongs.remove(song->file()); if (playedSongs.isEmpty()) { @@ -309,6 +312,7 @@ void PodcastService::jobFinished() } } + orig->setUnplayedCount(orig->childCount()-played); orig->save(); emitNeedToSort(); } diff --git a/online/rssparser.cpp b/online/rssparser.cpp index e8df8957c..5406e71c9 100644 --- a/online/rssparser.cpp +++ b/online/rssparser.cpp @@ -53,6 +53,20 @@ static void consumeCurrentElement(QXmlStreamReader &reader) } } +static QDateTime parseRfc822DateTime(const QString& text) +{ + // This sucks but we need it because some podcasts don't quite follow the + // spec properly - they might have 1-digit hour numbers for example. + + QRegExp re("([a-zA-Z]{3}),? (\\d{1,2}) ([a-zA-Z]{3}) (\\d{4}) (\\d{1,2}):(\\d{1,2}):(\\d{1,2})"); + if (-1==re.indexIn(text)) { + return QDateTime(); + } + + return QDateTime(QDate::fromString(QString("%1 %2 %3 %4").arg(re.cap(1), re.cap(3), re.cap(2), re.cap(4)), Qt::TextDate), + QTime(re.cap(5).toInt(), re.cap(6).toInt(), re.cap(7).toInt())); +} + static QUrl parseImage(QXmlStreamReader &reader) { QUrl url; @@ -96,6 +110,8 @@ static Episode parseEpisode(QXmlStreamReader &reader) ep.url=QUrl::fromEncoded(reader.attributes().value(QLatin1String("url")).toString().toLatin1()); } consumeCurrentElement(reader); + } else if (QLatin1String("pubDate")==name) { + ep.publicationDate=parseRfc822DateTime(reader.readElementText()); } else { consumeCurrentElement(reader); } diff --git a/online/rssparser.h b/online/rssparser.h index 888b99788..8bb186ecb 100644 --- a/online/rssparser.h +++ b/online/rssparser.h @@ -27,6 +27,8 @@ #include #include #include +#include +#include class QIODevice; @@ -37,6 +39,7 @@ struct Episode { Episode() : duration(0) { } QString name; + QDateTime publicationDate; unsigned int duration; QUrl url; };