File indexing completed on 2024-05-05 04:48:17
0001 /**************************************************************************************** 0002 * Copyright (c) 2007-2009 Bart Cerneels <bart.cerneels@kde.org> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify it under * 0005 * the terms of the GNU General Public License as published by the Free Software * 0006 * Foundation; either version 2 of the License, or (at your option) any later * 0007 * version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0010 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0011 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0012 * * 0013 * You should have received a copy of the GNU General Public License along with * 0014 * this program. If not, see <http://www.gnu.org/licenses/>. * 0015 ****************************************************************************************/ 0016 0017 #ifndef PODCASTMETA_H 0018 #define PODCASTMETA_H 0019 0020 #include "core/amarokcore_export.h" 0021 #include "core/meta/Meta.h" 0022 #include "core/playlists/Playlist.h" 0023 #include "core/support/Amarok.h" 0024 0025 #include <QDateTime> 0026 #include <QSharedData> 0027 #include <QString> 0028 #include <QStringList> 0029 #include <QTextStream> 0030 #include <QUrl> 0031 0032 #include <KLocalizedString> 0033 namespace Collections 0034 { 0035 class QueryMaker; 0036 } 0037 namespace Podcasts 0038 { 0039 class PodcastEpisode; 0040 class PodcastChannel; 0041 0042 class PodcastArtist; 0043 class PodcastAlbum; 0044 class PodcastComposer; 0045 class PodcastGenre; 0046 class PodcastYear; 0047 0048 typedef AmarokSharedPointer<PodcastEpisode> PodcastEpisodePtr; 0049 typedef AmarokSharedPointer<PodcastChannel> PodcastChannelPtr; 0050 0051 typedef QList<PodcastEpisodePtr> PodcastEpisodeList; 0052 typedef QList<PodcastChannelPtr> PodcastChannelList; 0053 0054 class AMAROKCORE_EXPORT PodcastMetaCommon 0055 { 0056 public: 0057 PodcastMetaCommon() {} 0058 virtual ~PodcastMetaCommon() {} 0059 0060 virtual QString title() const { return m_title;} 0061 virtual QString description() const { return m_description; } 0062 virtual QStringList keywords() const { return m_keywords; } 0063 virtual QString subtitle() const { return m_subtitle; } 0064 virtual QString summary() const { return m_summary; } 0065 virtual QString author() const { return m_author; } 0066 0067 virtual void setTitle( const QString &title ) { m_title = title; } 0068 virtual void setDescription( const QString &description ) { m_description = description; } 0069 virtual void setKeywords( const QStringList &keywords ) { m_keywords = keywords; } 0070 virtual void addKeyword( const QString &keyword ) { m_keywords << keyword; } 0071 virtual void setSubtitle( const QString &subtitle ) { m_subtitle = subtitle; } 0072 virtual void setSummary( const QString &summary ) { m_summary = summary; } 0073 virtual void setAuthor( const QString &author ) { m_author = author; } 0074 0075 protected: 0076 QString m_title; //the title 0077 QString m_description; //a longer description, with HTML markup 0078 QStringList m_keywords; // TODO: save to DB 0079 QString m_subtitle; //a short description 0080 QString m_summary; 0081 QString m_author; // TODO: save to DB 0082 }; 0083 0084 class AMAROKCORE_EXPORT PodcastEpisode : public PodcastMetaCommon, public Meta::Track 0085 { 0086 public: 0087 PodcastEpisode(); 0088 explicit PodcastEpisode( const PodcastChannelPtr &channel ); 0089 PodcastEpisode( const PodcastEpisodePtr &episode, const PodcastChannelPtr &channel ); 0090 0091 ~PodcastEpisode() override {} 0092 0093 // Meta::Base methods 0094 QString name() const override { return m_title; } 0095 0096 // Meta::Track Methods 0097 QUrl playableUrl() const override { return m_localUrl.isEmpty() ? m_url : m_localUrl; } 0098 QString prettyUrl() const override { return playableUrl().toDisplayString(); } 0099 QString uidUrl() const override { return m_url.url(); } 0100 QString notPlayableReason() const override; 0101 0102 Meta::AlbumPtr album() const override { return m_albumPtr; } 0103 Meta::ArtistPtr artist() const override { return m_artistPtr; } 0104 Meta::ComposerPtr composer() const override { return m_composerPtr; } 0105 Meta::GenrePtr genre() const override { return m_genrePtr; } 0106 Meta::YearPtr year() const override { return m_yearPtr; } 0107 0108 qreal bpm() const override { return -1.0; } 0109 0110 QString comment() const override { return QString(); } 0111 virtual void setComment( const QString &newComment ) { Q_UNUSED( newComment ); } 0112 qint64 length() const override { return m_duration * 1000; } 0113 int filesize() const override { return m_fileSize; } 0114 int sampleRate() const override { return 0; } 0115 int bitrate() const override { return 0; } 0116 int trackNumber() const override { return m_sequenceNumber; } 0117 virtual void setTrackNumber( int newTrackNumber ) { Q_UNUSED( newTrackNumber ); } 0118 int discNumber() const override { return 0; } 0119 virtual void setDiscNumber( int newDiscNumber ) { Q_UNUSED( newDiscNumber ); } 0120 virtual QString mimeType() const { return m_mimeType; } 0121 0122 QString type() const override 0123 { 0124 const QString fileName = playableUrl().fileName(); 0125 return Amarok::extension( fileName ); 0126 } 0127 0128 virtual void addMatchTo( Collections::QueryMaker* qm ) { Q_UNUSED( qm ); } 0129 bool inCollection() const override { return false; } 0130 QString cachedLyrics() const override { return QString(); } 0131 void setCachedLyrics( const QString &lyrics ) override { Q_UNUSED( lyrics ); } 0132 0133 bool operator==( const Meta::Track &track ) const override; 0134 0135 //PodcastMetaCommon methods 0136 void setTitle( const QString &title ) override { m_title = title; } 0137 0138 //PodcastEpisode methods 0139 virtual QUrl localUrl() const { return m_localUrl; } 0140 virtual QDateTime pubDate() const { return m_pubDate; } 0141 virtual int duration() const { return m_duration; } 0142 virtual QString guid() const { return m_guid; } 0143 virtual bool isNew() const { return m_isNew; } 0144 virtual int sequenceNumber() const { return m_sequenceNumber; } 0145 virtual PodcastChannelPtr channel() const { return m_channel; } 0146 0147 virtual void setLocalUrl( const QUrl &url ) { m_localUrl = url; } 0148 virtual void setFilesize( int fileSize ) { m_fileSize = fileSize; } 0149 virtual void setMimeType( const QString &mimeType ) { m_mimeType = mimeType; } 0150 virtual void setUidUrl( const QUrl &url ) { m_url = url; } 0151 virtual void setPubDate( const QDateTime &pubDate ) { m_pubDate = pubDate; } 0152 virtual void setDuration( int duration ) { m_duration = duration; } 0153 virtual void setGuid( const QString &guid ) { m_guid = guid; } 0154 virtual void setNew( bool isNew ) { m_isNew = isNew; } 0155 virtual void setSequenceNumber( int sequenceNumber ) { m_sequenceNumber = sequenceNumber; } 0156 virtual void setChannel( const PodcastChannelPtr &channel ) { m_channel = channel; } 0157 0158 protected: 0159 PodcastChannelPtr m_channel; 0160 0161 QString m_guid; //the GUID from the podcast feed 0162 QUrl m_url; //remote url of the file 0163 QUrl m_localUrl; //the localUrl, only valid if downloaded 0164 QString m_mimeType; //the mimetype of the enclosure 0165 QDateTime m_pubDate; //the pubDate from the feed 0166 int m_duration; //the playlength in seconds 0167 int m_fileSize; //the size tag from the enclosure 0168 int m_sequenceNumber; //number of the episode 0169 bool m_isNew; //listened to or not? 0170 0171 //data members 0172 Meta::AlbumPtr m_albumPtr; 0173 Meta::ArtistPtr m_artistPtr; 0174 Meta::ComposerPtr m_composerPtr; 0175 Meta::GenrePtr m_genrePtr; 0176 Meta::YearPtr m_yearPtr; 0177 }; 0178 0179 class AMAROKCORE_EXPORT PodcastChannel : public PodcastMetaCommon, public Playlists::Playlist 0180 { 0181 public: 0182 0183 enum FetchType 0184 { 0185 DownloadWhenAvailable = 0, 0186 StreamOrDownloadOnDemand 0187 }; 0188 0189 PodcastChannel() 0190 : PodcastMetaCommon() 0191 , Playlist() 0192 , m_image() 0193 , m_subscribeDate() 0194 , m_copyright() 0195 , m_autoScan( false ) 0196 , m_fetchType( DownloadWhenAvailable ) 0197 , m_purge( false ) 0198 , m_purgeCount( 0 ) 0199 { } 0200 0201 explicit PodcastChannel(const PodcastChannelPtr &channel ); 0202 ~PodcastChannel() override {} 0203 0204 //Playlist virtual methods 0205 QUrl uidUrl() const override { return m_url; } 0206 QString name() const override { return title(); } 0207 0208 int trackCount() const override { return m_episodes.count(); } 0209 Meta::TrackList tracks() override; 0210 void addTrack( const Meta::TrackPtr &track, int position = -1 ) override; 0211 0212 //PodcastMetaCommon methods 0213 // override this since it's ambiguous in PodcastMetaCommon and Playlist 0214 QString description() const override { return m_description; } 0215 0216 //PodcastChannel methods 0217 virtual QUrl url() const { return m_url; } 0218 virtual QUrl webLink() const { return m_webLink; } 0219 virtual bool hasImage() const { return !m_image.isNull(); } 0220 virtual QUrl imageUrl() const { return m_imageUrl; } 0221 virtual QImage image() const { return m_image; } 0222 virtual QString copyright() const { return m_copyright; } 0223 virtual QStringList labels() const { return m_labels; } 0224 virtual QDate subscribeDate() const { return m_subscribeDate; } 0225 0226 virtual void setUrl( const QUrl &url ) { m_url = url; } 0227 virtual void setWebLink( const QUrl &link ) { m_webLink = link; } 0228 // TODO: inform all albums with this channel of the changed image 0229 virtual void setImage( const QImage &image ) { m_image = image; } 0230 virtual void setImageUrl( const QUrl &imageUrl ) { m_imageUrl = imageUrl; } 0231 virtual void setCopyright( const QString ©right ) { m_copyright = copyright; } 0232 virtual void setLabels( const QStringList &labels ) { m_labels = labels; } 0233 virtual void addLabel( const QString &label ) { m_labels << label; } 0234 virtual void setSubscribeDate( const QDate &date ) { m_subscribeDate = date; } 0235 0236 virtual Podcasts::PodcastEpisodePtr addEpisode( const PodcastEpisodePtr &episode ); 0237 virtual PodcastEpisodeList episodes() const { return m_episodes; } 0238 0239 bool load( QTextStream &stream ) { Q_UNUSED( stream ); return false; } 0240 0241 //PodcastChannel Settings 0242 QUrl saveLocation() const { return m_directory; } 0243 bool autoScan() const { return m_autoScan; } 0244 FetchType fetchType() const { return m_fetchType; } 0245 bool hasPurge() const { return m_purge; } 0246 int purgeCount() const { return m_purgeCount; } 0247 0248 void setSaveLocation( const QUrl &url ) { m_directory = url; } 0249 void setAutoScan( bool autoScan ) { m_autoScan = autoScan; } 0250 void setFetchType( FetchType fetchType ) { m_fetchType = fetchType; } 0251 void setPurge( bool purge ) { m_purge = purge; } 0252 void setPurgeCount( int purgeCount ) { m_purgeCount = purgeCount; } 0253 0254 protected: 0255 QUrl m_url; 0256 QUrl m_webLink; 0257 QImage m_image; 0258 QUrl m_imageUrl; 0259 QStringList m_labels; 0260 QDate m_subscribeDate; 0261 QString m_copyright; 0262 QUrl m_directory; //the local directory to save the files in. 0263 bool m_autoScan; //should this channel be checked automatically? 0264 PodcastChannel::FetchType m_fetchType; //'download when available' or 'stream or download on demand' 0265 bool m_purge; //remove old episodes? 0266 int m_purgeCount; //how many episodes do we keep on disk? 0267 PodcastEpisodeList m_episodes; 0268 }; 0269 0270 // internal helper classes 0271 0272 class AMAROKCORE_EXPORT PodcastArtist : public Meta::Artist 0273 { 0274 public: 0275 explicit PodcastArtist( PodcastEpisode *episode ) 0276 : Meta::Artist() 0277 , episode( episode ) 0278 {} 0279 0280 Meta::TrackList tracks() override 0281 { 0282 return Meta::TrackList(); 0283 } 0284 0285 Meta::AlbumList albums() 0286 { 0287 return Meta::AlbumList(); 0288 } 0289 0290 QString name() const override 0291 { 0292 QString author; 0293 if( episode && episode->channel() ) 0294 author = episode->channel()->author(); 0295 0296 return author; 0297 } 0298 0299 bool operator==( const Meta::Artist &other ) const override 0300 { 0301 return name() == other.name(); 0302 } 0303 0304 PodcastEpisode const *episode; 0305 }; 0306 0307 class AMAROKCORE_EXPORT PodcastAlbum : public Meta::Album 0308 { 0309 public: 0310 explicit PodcastAlbum( PodcastEpisode *episode ) 0311 : Meta::Album() 0312 , episode( episode ) 0313 {} 0314 0315 /* Its all a little bit stupid. 0316 When the channel image (and also the album image) changes the album get's no indication. 0317 Also the CoverCache is not in amarokcorelib but in amaroklib. 0318 Why the PodcastAlbum is the only one with a concrete implementation in amarokcorelib is another question. 0319 0320 virtual ~PodcastAlbum() 0321 { CoverCache::invalidateAlbum( Meta::AlbumPtr(this) ); } 0322 */ 0323 0324 bool isCompilation() const override 0325 { 0326 return false; 0327 } 0328 0329 bool hasAlbumArtist() const override 0330 { 0331 return false; 0332 } 0333 0334 Meta::ArtistPtr albumArtist() const override 0335 { 0336 return Meta::ArtistPtr(); 0337 } 0338 0339 Meta::TrackList tracks() override 0340 { 0341 return Meta::TrackList(); 0342 } 0343 0344 QString name() const override 0345 { 0346 if( episode != nullptr ) 0347 { 0348 const QString albumName = episode->channel()->title(); 0349 return albumName; 0350 } 0351 else 0352 return QString(); 0353 } 0354 0355 QImage image( int size ) const override 0356 { 0357 // This is a little stupid. If Channel::setImage is called we don't Q_EMIT a MetaDataChanged or invalidate the cache 0358 QImage image = episode->channel()->image(); 0359 return image.scaledToHeight( size ); 0360 } 0361 0362 bool operator==( const Meta::Album &other ) const override 0363 { 0364 return name() == other.name(); 0365 } 0366 0367 PodcastEpisode const *episode; 0368 }; 0369 0370 class AMAROKCORE_EXPORT PodcastGenre : public Meta::Genre 0371 { 0372 public: 0373 explicit PodcastGenre( PodcastEpisode *episode ) 0374 : Meta::Genre() 0375 , episode( episode ) 0376 {} 0377 0378 Meta::TrackList tracks() override 0379 { 0380 return Meta::TrackList(); 0381 } 0382 0383 QString name() const override 0384 { 0385 const QString genreName = i18n( "Podcast" ); 0386 return genreName; 0387 } 0388 0389 bool operator==( const Meta::Genre &other ) const override 0390 { 0391 return name() == other.name(); 0392 } 0393 0394 PodcastEpisode const *episode; 0395 }; 0396 0397 class AMAROKCORE_EXPORT PodcastComposer : public Meta::Composer 0398 { 0399 public: 0400 explicit PodcastComposer( PodcastEpisode *episode ) 0401 : Meta::Composer() 0402 , episode( episode ) 0403 {} 0404 0405 Meta::TrackList tracks() override 0406 { 0407 return Meta::TrackList(); 0408 } 0409 0410 QString name() const override 0411 { 0412 if( episode != nullptr ) 0413 { 0414 const QString composer = episode->channel()->author(); 0415 return composer; 0416 } 0417 else 0418 return QString(); 0419 0420 } 0421 0422 bool operator==( const Meta::Composer &other ) const override 0423 { 0424 return name() == other.name(); 0425 } 0426 0427 PodcastEpisode const *episode; 0428 }; 0429 0430 class AMAROKCORE_EXPORT PodcastYear : public Meta::Year 0431 { 0432 public: 0433 explicit PodcastYear( PodcastEpisode *episode ) 0434 : Meta::Year() 0435 , episode( episode ) 0436 {} 0437 0438 Meta::TrackList tracks() override 0439 { 0440 return Meta::TrackList(); 0441 } 0442 0443 QString name() const override 0444 { 0445 if( episode != nullptr ) 0446 { 0447 const QString year = episode->pubDate().toString( QStringLiteral("yyyy") ); 0448 return year; 0449 } 0450 else 0451 return QString(); 0452 } 0453 0454 bool operator==( const Meta::Year &other ) const override 0455 { 0456 return name() == other.name(); 0457 } 0458 0459 PodcastEpisode const *episode; 0460 }; 0461 0462 } //namespace Podcasts 0463 0464 Q_DECLARE_METATYPE( Podcasts::PodcastMetaCommon* ) 0465 Q_DECLARE_METATYPE( Podcasts::PodcastEpisodePtr ) 0466 Q_DECLARE_METATYPE( Podcasts::PodcastEpisodeList ) 0467 Q_DECLARE_METATYPE( Podcasts::PodcastChannelPtr ) 0468 Q_DECLARE_METATYPE( Podcasts::PodcastChannelList ) 0469 0470 #endif