Add support for adding podcast episodes to the playlist

This commit is contained in:
David Sansome 2012-03-10 23:39:09 +00:00
parent c204dd31fb
commit 19a971c7cd
6 changed files with 132 additions and 2 deletions

View File

@ -244,6 +244,7 @@ set(SOURCES
podcasts/podcastepisode.cpp
podcasts/podcastinfowidget.cpp
podcasts/podcastservice.cpp
podcasts/podcastservicemodel.cpp
podcasts/podcastsettingspage.cpp
podcasts/podcastparser.cpp
podcasts/podcastupdater.cpp
@ -498,6 +499,7 @@ set(HEADERS
podcasts/podcastdownloader.h
podcasts/podcastinfowidget.h
podcasts/podcastservice.h
podcasts/podcastservicemodel.h
podcasts/podcastsettingspage.h
podcasts/podcastupdater.h
podcasts/podcasturlloader.h

View File

@ -15,12 +15,16 @@
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "podcast.h"
#include "podcastepisode.h"
#include "core/logging.h"
#include "core/timeconstants.h"
#include "core/utilities.h"
#include <QDataStream>
#include <QDateTime>
#include <QFile>
#include <QFileInfo>
const QStringList PodcastEpisode::kColumns = QStringList()
<< "podcast_id" << "title" << "description" << "author"
@ -143,3 +147,29 @@ void PodcastEpisode::BindToQuery(QSqlQuery* query) const {
query->bindValue(":extra", extra);
}
Song PodcastEpisode::ToSong(const Podcast& podcast) const {
Song ret;
ret.set_valid(true);
ret.set_title(title());
ret.set_artist(author());
ret.set_length_nanosec(kNsecPerSec * duration_secs());
ret.set_year(publication_date().date().year());
ret.set_comment(description());
if (downloaded() && QFile::exists(local_url().toLocalFile())) {
ret.set_url(local_url());
} else {
ret.set_url(url());
}
ret.set_basefilename(QFileInfo(ret.url().path()).fileName());
// Use information from the podcast if it's set
if (podcast.is_valid()) {
ret.set_album(podcast.title());
ret.set_art_automatic(podcast.ImageUrlLarge().toString());
}
return ret;
}

View File

@ -18,11 +18,15 @@
#ifndef PODCASTEPISODE_H
#define PODCASTEPISODE_H
#include "core/song.h"
#include <QSharedDataPointer>
#include <QSqlQuery>
#include <QUrl>
#include <QVariantMap>
class Podcast;
class PodcastEpisode {
public:
PodcastEpisode();
@ -38,6 +42,8 @@ public:
void InitFromQuery(const QSqlQuery& query);
void BindToQuery(QSqlQuery* query) const;
Song ToSong(const Podcast& podcast) const;
int database_id() const;
int podcast_database_id() const;
const QString& title() const;

View File

@ -19,6 +19,7 @@
#include "podcastbackend.h"
#include "podcastdownloader.h"
#include "podcastservice.h"
#include "podcastservicemodel.h"
#include "podcastupdater.h"
#include "core/application.h"
#include "core/logging.h"
@ -49,7 +50,7 @@ PodcastService::PodcastService(Application* app, InternetModel* parent)
use_pretty_covers_(true),
icon_loader_(new StandardItemIconLoader(app->album_cover_loader(), this)),
backend_(app->podcast_backend()),
model_(new QStandardItemModel(this)),
model_(new PodcastServiceModel(this)),
proxy_(new PodcastSortProxyModel(this)),
context_menu_(NULL),
root_(NULL)
@ -160,10 +161,12 @@ void PodcastService::UpdateEpisodeText(QStandardItem* item,
QFont font;
QIcon icon;
// Unlistened episodes are bold
if (!episode.listened()) {
font.setBold(true);
}
// Downloaded episodes get an icon
if (episode.downloaded()) {
if (downloaded_icon_.isNull()) {
downloaded_icon_ = IconLoader::Load("document-save");
@ -171,6 +174,7 @@ void PodcastService::UpdateEpisodeText(QStandardItem* item,
icon = downloaded_icon_;
}
// Queued or downloading episodes get icons, tooltips, and maybe a title.
switch (state) {
case PodcastDownloader::Queued:
if (queued_icon_.isNull()) {
@ -186,7 +190,7 @@ void PodcastService::UpdateEpisodeText(QStandardItem* item,
}
icon = downloading_icon_;
tooltip = tr("Downloading (%1%)...").arg(percent);
title = QString("[ %1% ] %2").arg(QString::number(percent), episode.title());
title = QString("[ %1% ] %2").arg(QString::number(percent), episode.title());
break;
case PodcastDownloader::Finished:
@ -215,6 +219,7 @@ QStandardItem* PodcastService::CreatePodcastItem(const Podcast& podcast) {
item->setIcon(default_icon_);
item->setData(Type_Podcast, InternetModel::Role_Type);
item->setData(QVariant::fromValue(podcast), Role_Podcast);
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsSelectable);
UpdatePodcastText(item, unlistened_count);
// Load the podcast's image if it has one
@ -232,6 +237,8 @@ QStandardItem* PodcastService::CreatePodcastEpisodeItem(const PodcastEpisode& ep
item->setText(episode.title());
item->setData(Type_Episode, InternetModel::Role_Type);
item->setData(QVariant::fromValue(episode), Role_Episode);
item->setData(InternetModel::PlayBehaviour_UseSongLoader, InternetModel::Role_PlayBehaviour);
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsSelectable);
UpdateEpisodeText(item);

View File

@ -0,0 +1,53 @@
/* This file is part of Clementine.
Copyright 2012, David Sansome <me@davidsansome.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "podcastservice.h"
#include "podcastservicemodel.h"
#include "playlist/songmimedata.h"
PodcastServiceModel::PodcastServiceModel(QObject* parent)
: QStandardItemModel(parent)
{
}
QMimeData* PodcastServiceModel::mimeData(const QModelIndexList& indexes) const {
SongMimeData* data = new SongMimeData;
QList<QUrl> urls;
foreach (const QModelIndex& index, indexes) {
QVariant episode_variant = index.data(PodcastService::Role_Episode);
if (!episode_variant.isValid())
continue;
PodcastEpisode episode(episode_variant.value<PodcastEpisode>());
// Get the podcast from the index's parent
Podcast podcast;
QVariant podcast_variant = index.parent().data(PodcastService::Role_Podcast);
if (podcast_variant.isValid()) {
podcast = podcast_variant.value<Podcast>();
}
Song song = episode.ToSong(podcast);
data->songs << song;
urls << song.url();
}
data->setUrls(urls);
return data;
}

View File

@ -0,0 +1,32 @@
/* This file is part of Clementine.
Copyright 2012, David Sansome <me@davidsansome.com>
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PODCASTSERVICEMODEL_H
#define PODCASTSERVICEMODEL_H
#include <QStandardItemModel>
class PodcastServiceModel : public QStandardItemModel {
Q_OBJECT
public:
PodcastServiceModel(QObject* parent = 0);
QMimeData* mimeData(const QModelIndexList& indexes) const;
};
#endif // PODCASTSERVICEMODEL_H