1 /****************************************************************************************
2  * Copyright (c) 2007 Bart Cerneels <bart.cerneels@kde.org>                             *
3  *                                                                                      *
4  * This program is free software; you can redistribute it and/or modify it under        *
5  * the terms of the GNU General Public License as published by the Free Software        *
6  * Foundation; either version 2 of the License, or (at your option) any later           *
7  * version.                                                                             *
8  *                                                                                      *
9  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
11  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
12  *                                                                                      *
13  * You should have received a copy of the GNU General Public License along with         *
14  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
15  ****************************************************************************************/
16 
17 #ifndef SQLPODCASTPROVIDER_H
18 #define SQLPODCASTPROVIDER_H
19 
20 #include "core/podcasts/PodcastProvider.h"
21 #include "core/podcasts/PodcastReader.h"
22 #include "SqlPodcastMeta.h"
23 
24 #include <QIcon>
25 
26 #include <KLocalizedString>
27 
28 class PodcastImageFetcher;
29 
30 class QDialog;
31 class QUrl;
32 class PodcastReader;
33 class QTimer;
34 
35 namespace Ui {
36     class SqlPodcastProviderSettingsWidget;
37 }
38 
39 namespace Podcasts {
40 
41 /**
42 	@author Bart Cerneels <bart.cerneels@kde.org>
43 */
44 class AMAROK_EXPORT SqlPodcastProvider : public Podcasts::PodcastProvider
45 {
46     Q_OBJECT
47     public:
48         SqlPodcastProvider();
49         ~SqlPodcastProvider() override;
50 
51         //TrackProvider methods
52         bool possiblyContainsTrack( const QUrl &url ) const override;
53         Meta::TrackPtr trackForUrl( const QUrl &url ) override;
54 
55         //PlaylistProvider methods
prettyName()56         QString prettyName() const override { return i18n("Local Podcasts"); }
icon()57         QIcon icon() const override { return QIcon::fromTheme( QStringLiteral("server-database") ); }
58 
59         Playlists::PlaylistList playlists() override;
60 
61         //PlaylistProvider methods
62         QActionList providerActions() override;
63         QActionList playlistActions( const Playlists::PlaylistList &playlists ) override;
64         QActionList trackActions( const QMultiHash<Playlists::PlaylistPtr, int> &playlistTracks ) override;
65 
66         //PodcastProvider methods
67         Podcasts::PodcastEpisodePtr episodeForGuid( const QString &guid ) override;
68 
69         void addPodcast( const QUrl &url ) override;
70 
71         Podcasts::PodcastChannelPtr addChannel( const Podcasts::PodcastChannelPtr &channel ) override;
72         Podcasts::PodcastEpisodePtr addEpisode( Podcasts::PodcastEpisodePtr episode ) override;
73 
74         Podcasts::PodcastChannelList channels() override;
75 
76         void completePodcastDownloads() override;
77 
78         //SqlPodcastProvider specific methods
79         virtual Podcasts::SqlPodcastChannelPtr podcastChannelForId( int podcastChannelDbId );
80 
baseDownloadDir()81         virtual QUrl baseDownloadDir() const { return m_baseDownloadDir; }
82 
83     public Q_SLOTS:
84         void updateAll() override;
85         void downloadEpisode( const Podcasts::PodcastEpisodePtr &episode );
86         void deleteDownloadedEpisode( const Podcasts::PodcastEpisodePtr &episode );
87 
88         void slotReadResult( PodcastReader *podcastReader );
89         void downloadEpisode( Podcasts::SqlPodcastEpisodePtr episode );
90         void deleteDownloadedEpisode( Podcasts::SqlPodcastEpisodePtr episode );
91 
92     private Q_SLOTS:
93         void downloadResult( KJob * );
94         void addData( KIO::Job *job, const QByteArray & data );
95         void redirected( KIO::Job *, const QUrl& );
96         void autoUpdate();
97         void slotDeleteDownloadedEpisodes();
98         void slotDownloadEpisodes();
99         void slotSetKeep();
100         void slotConfigureChannel();
101         void slotRemoveChannels();
102         void slotUpdateChannels();
103         void slotDownloadProgress( KJob *job, unsigned long percent );
104         void slotWriteTagsToFiles();
105         void slotConfigChanged();
106         void slotExportOpml();
107 
108     Q_SIGNALS:
109         void totalPodcastDownloadProgress( int progress );
110 
111         //SqlPodcastProvider signals
112         void episodeDownloaded( Podcasts::PodcastEpisodePtr );
113         void episodeDeleted( Podcasts::PodcastEpisodePtr );
114 
115     private Q_SLOTS:
116         void channelImageReady( Podcasts::PodcastChannelPtr, const QImage &);
117         void podcastImageFetcherDone( PodcastImageFetcher * );
118         void slotConfigureProvider();
119 
120         void slotStatusBarNewProgressOperation( KIO::TransferJob * job,
121                                                                const QString &description,
122                                                                Podcasts::PodcastReader* reader );
123         void slotStatusBarSorryMessage( const QString &message );
124         void slotOpmlWriterDone( int result );
125 
126     private:
127         void startTimer();
128         void configureProvider();
129         void configureChannel( Podcasts::SqlPodcastChannelPtr channel );
130         void updateSqlChannel( Podcasts::SqlPodcastChannelPtr channel );
131 
132         /** creates all the necessary tables, indexes etc. for the database */
133         void createTables() const;
134         void loadPodcasts();
135 
136         /** @arg string: a url, localUrl or guid in string form */
137         Podcasts::SqlPodcastEpisodePtr sqlEpisodeForString( const QString &string );
138 
139         void updateDatabase( int fromVersion, int toVersion );
140         void fetchImage( const Podcasts::SqlPodcastChannelPtr &channel );
141 
142         /** shows a modal dialog asking the user if he really wants to unsubscribe
143             and if he wants to keep the podcast media */
144         QPair<bool, bool> confirmUnsubscribe( Podcasts::SqlPodcastChannelPtr channel );
145 
146         /** remove the episodes in the list from the filesystem */
147         void deleteDownloadedEpisodes( Podcasts::SqlPodcastEpisodeList &episodes );
148 
149         void moveDownloadedEpisodes( Podcasts::SqlPodcastChannelPtr channel );
150 
151         /** Removes a podcast from the list. Will ask for confirmation to delete the episodes
152           * as well
153           */
154         void removeSubscription( Podcasts::SqlPodcastChannelPtr channel );
155 
156         void subscribe( const QUrl &url );
157         QFile* createTmpFile ( Podcasts::SqlPodcastEpisodePtr sqlEpisode );
158         void cleanupDownload( KJob *job, bool downloadFailed );
159 
160         /** returns true if the file that is downloaded by 'job' is already locally available */
161         bool checkEnclosureLocallyAvailable( KIO::Job *job );
162 
163         Podcasts::SqlPodcastChannelList m_channels;
164 
165         QTimer *m_updateTimer;
166         int m_autoUpdateInterval; //interval between autoupdate attempts in minutes
167         unsigned int m_updatingChannels;
168         unsigned int m_maxConcurrentUpdates;
169         Podcasts::SqlPodcastChannelList m_updateQueue;
170         QList<QUrl> m_subscribeQueue;
171 
172         struct PodcastEpisodeDownload {
173             Podcasts::SqlPodcastEpisodePtr episode;
174             QFile *tmpFile;
175             QString fileName;
176             bool finalNameReady;
177         };
178 
179         QHash<KJob *, struct PodcastEpisodeDownload> m_downloadJobMap;
180 
181         Podcasts::SqlPodcastEpisodeList m_downloadQueue;
182         int m_maxConcurrentDownloads;
183         int m_completedDownloads;
184 
185         QUrl m_baseDownloadDir;
186 
187         QDialog *m_providerSettingsDialog;
188         Ui::SqlPodcastProviderSettingsWidget *m_providerSettingsWidget;
189 
190         QList<QAction *> m_providerActions;
191 
192         QAction *m_configureChannelAction; //Configure a Channel
193         QAction *m_deleteAction; //delete a downloaded Episode
194         QAction *m_downloadAction;
195         QAction *m_keepAction;
196         QAction *m_removeAction; //remove a subscription
197         QAction *m_updateAction;
198         QAction *m_writeTagsAction; //write feed information to downloaded file
199 
200         PodcastImageFetcher *m_podcastImageFetcher;
201 };
202 
203 } //namespace Podcasts
204 
205 #endif
206