Commit 6ed029b3 authored by Ralf Engels's avatar Ralf Engels
Browse files

GPodder Improvements Patch Rev2

GPodder Improvements Patch Rev2

Use Solid::Networking::status() to prevent offline running of any
procedure that requests data from gpodder.net. Fixed some typos in
ChangeLog. Added some extra verifications, to see if suggested podcasts is
ready for use in GpodderServiceModel.

GPodder Improvements Patch Rev1

Put messages to show that gpodder service failed to get data from
gpodder.net. Done some cleanup and added some comments.

GPodder Service improvements

Full status synchronisation implemented. Cleanup and some refactoring.
GPodder Provider saves podcast subscriptions changes if the user closes
amarok before a expected synchronisation to end, so as to synchronize them
in the next start. Forcing GPodderService to verify if the username and
password is not empty before creating a mygpo::ApiRequest. Solved some
problems related to the KWallet use in GPodderService.

Courtesy: Lucas Gomes

FEATURE: 104335
FIXED-IN: 2.7
parent cba53ab9
......@@ -250,7 +250,7 @@ PlaylistsByProviderProxy::slotProviderAdded( Playlists::PlaylistProvider *provid
itemData.insert( Qt::DecorationRole, provider->icon() );
itemData.insert( PlaylistBrowserNS::PlaylistBrowserModel::ActionRole,
QVariant::fromValue( provider->providerActions() ) );
itemData.insert( PlaylistBrowserNS::PlaylistBrowserModel::ByLineRole, i18n( "No playlists" ) );
itemData.insert( PlaylistBrowserNS::PlaylistBrowserModel::ProviderRole,
QVariant::fromValue<Playlists::PlaylistProvider*>( provider ) );
RowData rowData;
......
......@@ -64,7 +64,7 @@ PlaylistBrowserNS::PodcastModel::destroy()
PlaylistBrowserNS::PodcastModel::PodcastModel()
: PlaylistBrowserModel( PlaylistManager::PodcastChannel )
, m_setNewAction( 0 )
, m_setNewAction( 0 )
{
s_instance = this;
m_setNewAction = new QAction( KIcon( "rating" ),
......@@ -238,7 +238,6 @@ PlaylistBrowserNS::PodcastModel::data( const QModelIndex &idx, int role ) const
case IsEpisodeColumn:
return bool( pmc->podcastType() == Podcasts::EpisodeType );
}
break;
}
......@@ -250,7 +249,7 @@ PlaylistBrowserNS::PodcastModel::data( const QModelIndex &idx, int role ) const
break;
}
case ByLineRole:
case PlaylistBrowserModel::ByLineRole:
{
if( idx.column() == PlaylistBrowserModel::ProviderColumn )
{
......@@ -282,12 +281,10 @@ PlaylistBrowserNS::PodcastModel::data( const QModelIndex &idx, int role ) const
bool
PlaylistBrowserNS::PodcastModel::setData( const QModelIndex &idx, const QVariant &value, int role )
{
DEBUG_BLOCK
//TODO: implement setNew.
return PlaylistBrowserModel::setData( idx, value, role );
}
int
......@@ -432,7 +429,12 @@ PlaylistBrowserNS::PodcastModel::slotSetNew( bool newState )
foreach( Podcasts::PodcastEpisodePtr episode, episodes )
{
if( !episode.isNull() )
{
episode->setNew( action->isChecked() );
if( action->isChecked() )
emit episodeMarkedAsNew( episode );
}
}
}
......
......@@ -76,6 +76,9 @@ class PodcastModel : public PlaylistBrowserModel
return Qt::MoveAction | Qt::CopyAction;
}
signals:
void episodeMarkedAsNew( Podcasts::PodcastEpisodePtr );
public slots:
void addPodcast();
void refreshPodcasts();
......
......@@ -1107,6 +1107,8 @@ SqlPodcastProvider::deleteDownloadedEpisode( Podcasts::SqlPodcastEpisodePtr epis
KIO::del( episode->localUrl(), KIO::HideProgressInfo );
episode->setLocalUrl( KUrl() );
emit episodeDeleted( Podcasts::PodcastEpisodePtr::dynamicCast( episode ) );
}
Podcasts::SqlPodcastChannelPtr
......@@ -1553,6 +1555,8 @@ SqlPodcastProvider::downloadResult( KJob *job )
if( sqlChannel->writeTags() )
sqlEpisode->writeTagsToFile();
//TODO: force a redraw of the view so the icon can be updated in the PlaylistBrowser
emit episodeDownloaded( Podcasts::PodcastEpisodePtr::dynamicCast( sqlEpisode ) );
}
else
{
......
......@@ -41,20 +41,22 @@ namespace Podcasts {
/**
@author Bart Cerneels <bart.cerneels@kde.org>
*/
class SqlPodcastProvider : public Podcasts::PodcastProvider
class AMAROK_CORE_EXPORT SqlPodcastProvider : public Podcasts::PodcastProvider
{
Q_OBJECT
public:
SqlPodcastProvider();
~SqlPodcastProvider();
virtual ~SqlPodcastProvider();
bool possiblyContainsTrack( const KUrl &url ) const;
Meta::TrackPtr trackForUrl( const KUrl &url );
//TrackProvider methods
virtual bool possiblyContainsTrack( const KUrl &url ) const;
virtual Meta::TrackPtr trackForUrl( const KUrl &url );
QString prettyName() const { return i18n("Local Podcasts"); }
KIcon icon() const { return KIcon( "server-database" ); }
//PlaylistProvider methods
virtual QString prettyName() const { return i18n("Local Podcasts"); }
virtual KIcon icon() const { return KIcon( "server-database" ); }
Playlists::PlaylistList playlists();
virtual Playlists::PlaylistList playlists();
//PlaylistProvider methods
virtual QList<QAction *> providerActions();
......@@ -66,20 +68,20 @@ class SqlPodcastProvider : public Podcasts::PodcastProvider
virtual void addPodcast( const KUrl &url );
Podcasts::PodcastChannelPtr addChannel( Podcasts::PodcastChannelPtr channel );
Podcasts::PodcastEpisodePtr addEpisode( Podcasts::PodcastEpisodePtr episode );
virtual Podcasts::PodcastChannelPtr addChannel( Podcasts::PodcastChannelPtr channel );
virtual Podcasts::PodcastEpisodePtr addEpisode( Podcasts::PodcastEpisodePtr episode );
Podcasts::PodcastChannelList channels();
virtual Podcasts::PodcastChannelList channels();
QList<QAction *> episodeActions( Podcasts::PodcastEpisodeList );
QList<QAction *> channelActions( Podcasts::PodcastChannelList );
virtual QList<QAction *> episodeActions( Podcasts::PodcastEpisodeList );
virtual QList<QAction *> channelActions( Podcasts::PodcastChannelList );
void completePodcastDownloads();
virtual void completePodcastDownloads();
//SqlPodcastProvider specific methods
Podcasts::SqlPodcastChannelPtr podcastChannelForId( int podcastChannelDbId );
virtual Podcasts::SqlPodcastChannelPtr podcastChannelForId( int podcastChannelDbId );
KUrl baseDownloadDir() const { return m_baseDownloadDir; }
virtual KUrl baseDownloadDir() const { return m_baseDownloadDir; }
public slots:
void updateAll();
......@@ -108,6 +110,10 @@ class SqlPodcastProvider : public Podcasts::PodcastProvider
signals:
void totalPodcastDownloadProgress( int progress );
//SqlPodcastProvider signals
void episodeDownloaded( Podcasts::PodcastEpisodePtr );
void episodeDeleted( Podcasts::PodcastEpisodePtr );
private slots:
void channelImageReady( Podcasts::PodcastChannelPtr, QImage );
void podcastImageFetcherDone( PodcastImageFetcher * );
......
......@@ -21,7 +21,11 @@
#include "core/support/Debug.h"
GpodderPodcastRequestHandler::GpodderPodcastRequestHandler( mygpo::PodcastListPtr podcasts, QModelIndex parentItem,
GpodderServiceModel *model ) : QObject( model ), m_podcasts( podcasts ), m_parentItem( parentItem ), m_model( model )
GpodderServiceModel *model )
: QObject( model )
, m_podcasts( podcasts )
, m_parentItem( parentItem )
, m_model( model )
{
}
......
......@@ -39,7 +39,7 @@ public slots:
private:
mygpo::PodcastListPtr m_podcasts;
QModelIndex m_parentItem;
GpodderServiceModel *m_model;
GpodderServiceModel *m_model;
};
#endif /* GPODDERPODCASTREQUESTHANDLER_H_ */
This diff is collapsed.
......@@ -48,8 +48,11 @@ public:
GpodderProvider( const QString& username, const QString& devicename, ApiRequest *apiRequest );
~GpodderProvider();
//TrackProvider methods
bool possiblyContainsTrack( const KUrl &url ) const;
Meta::TrackPtr trackForUrl( const KUrl &url );
//PodcastProvider methods
/** Special function to get an episode for a given guid.
*
* note: this functions is required because KUrl does not preserve every possible guids.
......@@ -118,10 +121,14 @@ private slots:
const KUrl &toUrl );
void urlResolveFinished( KJob * );
void slotEpisodeDownloaded( Podcasts::PodcastEpisodePtr episode );
void slotEpisodeDeleted( Podcasts::PodcastEpisodePtr episode );
void slotEpisodeMarkedAsNew( Podcasts::PodcastEpisodePtr episode );
private:
ApiRequest *m_apiRequest;
const QString m_username;
const QString m_devicename;
const QString m_deviceName;
PodcastChannelList m_channels;
KIO::TransferJob *m_resolveUrlJob;
......@@ -144,21 +151,32 @@ private:
void updateLocalPodcasts( const QList< QPair<QUrl,QUrl> > updatedUrls );
KConfigGroup gpodderActionsConfig() const;
void loadEpisodeActions();
void saveEpisodeActions();
void loadCachedEpisodeActions();
void saveCachedEpisodeActions();
KConfigGroup gpodderPodcastsConfig() const;
void loadCachedPodcastsChanges();
void saveCachedPodcastsChanges();
QAction *m_removeAction;
QAction *m_removeAction; //remove a subscription
//Lists of podcasts to be added or removed from gpodder.net
QList<QUrl> m_addList;
QList<QUrl> m_removeList;
KUrl resolvedPodcastUrl( const PodcastEpisodePtr episode );
QMap<KUrl,KUrl> m_redirectionUrlMap;
QQueue<QUrl> m_channelsToRequestActions;
QQueue<GpodderPodcastChannelPtr> m_channelsToAdd;
QMap<KIO::TransferJob *,GpodderPodcastChannelPtr> m_resolvedPodcasts;
//Used as a temporary container for podcasts with already urls resolved
//before adding them to m_channels
QQueue<GpodderPodcastChannelPtr> m_resolvedChannelsToBeAdded;
QMap<QUrl,EpisodeActionPtr> m_episodeStatusMap;
QMap<QUrl,EpisodeActionPtr> m_uploadEpisodeStatusMap;
QMap<KIO::TransferJob *,GpodderPodcastChannelPtr> m_resolvedPodcasts;
QTimer *m_timerGenerateEpisodeAction;
QTimer *m_timerGeneratePlayAction;
QTimer *m_timerSynchronizeStatus;
QTimer *m_timerSynchronizeSubscriptions;
......
......@@ -118,6 +118,7 @@ GpodderServiceFactory::createGpodderService()
GpodderService::GpodderService( GpodderServiceFactory *parent, const QString &name )
: ServiceBase( name, parent, false )
, m_inited( false )
, m_apiRequest( 0 )
, m_podcastProvider( 0 )
, m_proxyModel( 0 )
, m_subscribeButton( 0 )
......@@ -138,23 +139,54 @@ GpodderService::~GpodderService()
{
DEBUG_BLOCK
delete m_podcastProvider;
delete m_apiRequest;
if( m_podcastProvider )
{
//Remove the provider
The::playlistManager()->removeProvider( m_podcastProvider );
delete m_podcastProvider;
}
if ( m_apiRequest )
delete m_apiRequest;
}
//This Method should only contain the most necessary things for initilazing the Service
void
GpodderService::init()
{
DEBUG_BLOCK
GpodderServiceConfig config;
if( config.enableProvider() )
const QString &username = config.username();
const QString &password = config.password();
if ( m_apiRequest )
delete m_apiRequest;
//We have to check this here too, since KWallet::openWallet() doesn't
//guarantee that it will always return a wallet.
//Notice that LastFm service does the same verification.
if ( !config.isDataLoaded() )
{
m_apiRequest = new mygpo::ApiRequest( config.username(), config.password(), The::networkAccessManager() );
enableGpodderProvider( config.username() );
debug() << "Failed to read gpodder credentials.";
m_apiRequest = new mygpo::ApiRequest( The::networkAccessManager() );
}
else
m_apiRequest = new mygpo::ApiRequest( The::networkAccessManager() );
{
if( config.enableProvider() )
{
m_apiRequest = new mygpo::ApiRequest( username,
password,
The::networkAccessManager() );
if( m_podcastProvider )
delete m_podcastProvider;
enableGpodderProvider( username );
}
else
m_apiRequest = new mygpo::ApiRequest( The::networkAccessManager() );
}
m_serviceready = true;
m_inited = true;
......@@ -231,10 +263,10 @@ GpodderService::subscribe()
QModelIndex index = m_proxyModel->mapToSource( m_selectionModel->currentIndex() );
GpodderTreeItem *treeItem = static_cast<GpodderTreeItem*>( index.internalPointer() );
if( GpodderPodcastTreeItem *pcastTreeItem = qobject_cast<GpodderPodcastTreeItem*>( treeItem ) )
if( GpodderPodcastTreeItem *podcastTreeItem = qobject_cast<GpodderPodcastTreeItem*>( treeItem ) )
{
Podcasts::PodcastProvider *podcastProvider = The::playlistManager()->defaultPodcasts();
KUrl kUrl( pcastTreeItem->podcast()->url() );
KUrl kUrl( podcastTreeItem->podcast()->url() );
podcastProvider->addPodcast( kUrl );
}
}
......@@ -244,9 +276,15 @@ GpodderService::enableGpodderProvider( const QString &username )
{
DEBUG_BLOCK
debug() << "Enabling GpodderProvider";
QString deviceName = QLatin1String( "amarok-" ) % QHostInfo::localHostName();
debug() << QString( "Enabling GpodderProvider( Username: %1 - Device: %1 )" )
.arg( username )
.arg( deviceName );
m_podcastProvider = new Podcasts::GpodderProvider( username, deviceName, m_apiRequest );
//Add the gpodder's provider to the playlist manager
The::playlistManager()->addProvider( m_podcastProvider, PlaylistManager::PodcastChannel );
delete m_podcastProvider;
QString device = QLatin1String( "amarok-" ) % QHostInfo::localHostName();
m_podcastProvider = new Podcasts::GpodderProvider( username, device, m_apiRequest );
}
......@@ -31,23 +31,16 @@
#include <QLabel>
GpodderServiceConfig::GpodderServiceConfig()
: m_askDiag( 0 )
: m_username( "" )
, m_password( "" )
, m_enableProvider( false )
, m_ignoreWallet( false )
, m_isDataLoaded( false )
, m_askDiag( 0 )
, m_wallet( 0 )
{
DEBUG_BLOCK
KConfigGroup config = KGlobal::config()->group( configSectionName() );
// we only want to load the wallet if the user has enabled features that require a user/pass
bool synchronise = config.readEntry( "synchronise", false );
if( synchronise )
{
// open wallet unless explicitly told not to
if( !( config.readEntry( "ignoreWallet", QString() ) == "yes" ) )
m_wallet = KWallet::Wallet::openWallet( KWallet::Wallet::NetworkWallet(), 0, KWallet::Wallet::Synchronous );
}
load();
}
......@@ -65,10 +58,17 @@ GpodderServiceConfig::~GpodderServiceConfig()
void
GpodderServiceConfig::load()
{
DEBUG_BLOCK
debug() << "Load config";
KConfigGroup config = KGlobal::config()->group( configSectionName() );
m_enableProvider = config.readEntry( "enableProvider", false );
m_ignoreWallet = config.readEntry( "ignoreWallet", false );
//We only want to load the wallet if the user has enabled features that require a user/pass
tryToOpenWallet();
if( m_wallet )
{
if( !m_wallet->hasFolder( "Amarok" ) )
......@@ -78,57 +78,73 @@ GpodderServiceConfig::load()
// can remove at some point in the future, post-2.2
m_wallet->setFolder( "Amarok" );
if( m_wallet->readPassword( "gpodder_password", m_password ) > 0 )
if( m_wallet->readPassword( "gpodder_password", m_password ) != 0 )
debug() << "Failed to read gpodder.net password from kwallet!";
QByteArray rawUsername;
if( m_wallet->readEntry( "gpodder_username", rawUsername ) > 0 )
debug() << "failed to read gpodder.net username from kwallet.. :(";
else
m_username = QString::fromUtf8( rawUsername );
{
QByteArray rawUsername;
if( m_wallet->readEntry( "gpodder_username", rawUsername ) != 0 )
debug() << "Failed to read gpodder.net username from kwallet.. :(";
else
m_username = QString::fromUtf8( rawUsername );
}
}
else if( config.readEntry( "ignoreWallet", QString() ) != "no" )
else if( m_ignoreWallet )
{
m_username = config.readEntry( "username", QString() );
m_password = config.readEntry( "password", QString() );
}
m_enableProvider = config.readEntry( "enableProvider", false );
m_synchronise = config.readEntry( "synchronise", false );
else
debug() << "Failed to load the data.";
m_isDataLoaded = !( m_username.isEmpty() || m_password.isEmpty() );
}
void
GpodderServiceConfig::save()
{
DEBUG_BLOCK
debug() << "Save config";
KConfigGroup config = KGlobal::config()->group( configSectionName() );
config.writeEntry( "enableProvider", m_enableProvider );
config.writeEntry( "synchronise", m_synchronise );
config.writeEntry( "ignoreWallet", m_ignoreWallet );
//Whenever this function is called, we'll assume the user wants to
//change something, so blow away the subscription timestamp key
config.writeEntry( "subscriptionTimestamp", 0 );
if ( !m_wallet && config.readEntry( "ignoreWallet", QString() ) != "yes" )
askAboutMissingKWallet();
//Maybe the wallet had already closed or m_enableProvider and m_ignoreWallet
//could had changed also. So we try to reopen the wallet if it's not open.
tryToOpenWallet();
if( m_wallet )
{
m_wallet->setFolder( "Amarok" );
if( m_wallet->writePassword( "gpodder_password", m_password ) > 0 )
debug() << "Failed to save gpodder.net pw to kwallet!";
if( m_wallet->writeEntry( "gpodder_username", m_username.toUtf8() ) > 0 )
if( m_wallet->writeEntry( "gpodder_username", m_username.toUtf8() ) != 0 )
debug() << "Failed to save gpodder.net username to kwallet!";
if( m_wallet->writePassword( "gpodder_password", m_password ) != 0 )
debug() << "Failed to save gpodder.net pw to kwallet!";
}
else if( config.readEntry( "ignoreWallet", QString() ) == "yes" )
else if( m_ignoreWallet )
{
config.writeEntry( "username", m_username );
config.writeEntry( "password", m_password );
}
else
{
debug() << "Could not access the wallet to save the gpodder.net credentials";
if( m_enableProvider )
{
debug() << "Couldnt access the wallet to save the gpodder.net credentials";
askAboutMissingKWallet();
}
else
debug() << "There isn't valid credentials to be saved";
}
config.sync();
......@@ -153,6 +169,28 @@ GpodderServiceConfig::askAboutMissingKWallet()
m_askDiag->exec();
}
void GpodderServiceConfig::tryToOpenWallet()
{
DEBUG_BLOCK
//We only want to load the wallet if the user has enabled features
//that require a user/pass
if( ( m_enableProvider ) && ( !m_ignoreWallet ) )
{
debug() << "Opening wallet";
//Open wallet unless explicitly told not to
m_wallet = KWallet::Wallet::openWallet(
KWallet::Wallet::NetworkWallet(),
0, KWallet::Wallet::Synchronous );
}
else
{
debug() << "The wallet was ignored or is not needed.";
m_wallet = 0;
}
}
void
GpodderServiceConfig::reset()
{
......@@ -161,7 +199,7 @@ GpodderServiceConfig::reset()
m_username = "";
m_password = "";
m_enableProvider = false;
m_synchronise = false;
m_ignoreWallet = false;
}
void
......@@ -169,11 +207,15 @@ GpodderServiceConfig::textDialogYes() //SLOT
{
DEBUG_BLOCK
KConfigGroup config = KGlobal::config()->group( configSectionName() );
if ( !m_ignoreWallet )
{
KConfigGroup config = KGlobal::config()->group( configSectionName() );
config.writeEntry( "ignoreWallet", "yes" );
m_ignoreWallet = true;
config.writeEntry( "ignoreWallet ", m_ignoreWallet );
config.sync();
config.sync();
}
}
void
......@@ -181,11 +223,15 @@ GpodderServiceConfig::textDialogNo() //SLOT
{
DEBUG_BLOCK
KConfigGroup config = KGlobal::config()->group( configSectionName() );
if ( m_ignoreWallet )
{
KConfigGroup config = KGlobal::config()->group( configSectionName() );
config.writeEntry( "ignoreWallet", "no" );
m_ignoreWallet = false;
config.writeEntry( "ignoreWallet ", m_ignoreWallet );
config.sync();
config.sync();
}
}
#include "GpodderServiceConfig.moc"
......@@ -51,18 +51,25 @@ public:
bool enableProvider() { return m_enableProvider; }
void setEnableProvider( bool enableProvider ) { m_enableProvider = enableProvider; }
bool ignoreWallet() { return m_ignoreWallet; }
void setIgnoreWallet( bool ignoreWallet ) { m_ignoreWallet = ignoreWallet; }
bool isDataLoaded() { return m_isDataLoaded; }
private slots:
void textDialogYes();
void textDialogNo();
private:
void askAboutMissingKWallet();
void tryToOpenWallet();
QString m_username;
QString m_password;
bool m_enableProvider; //enables PodcastProvider if correct LoginData given
bool m_synchronise;
bool m_enableProvider; //Enables PodcastProvider if correct LoginData given
bool m_ignoreWallet;
bool m_isDataLoaded;
KDialog *m_askDiag;
KWallet::Wallet *m_wallet;
};
......