Version: 2.3.0 (using 4.4.1 (KDE 4.4.1), Kubuntu packages) Compiler: cc OS: Linux (i686) release 2.6.31-17-generic In "Podcasts" media source I right click on a podcast and select "Update channel". The episodes that are downloaded are added to the list even if they are already there, so every episode is there twice, three times etc. (depending on how many times do I click "Update channel". The same behaviour if I click "Update All". This bug was introduced in Amarok 2.3.0, in 2.2.x it was OK.
-> over to Podcasts and Bart
Does this happen with all channels or is there a specific one this happens with? Please paste the url of that channel here.
I tried it with these two podcasts: http://www2.rozhlas.cz/podcast/radiozurnal.rss http://downloads.bbc.co.uk/podcasts/worldservice/docarchive/rss.xml and it happens with both of them (no matter whether I update them one-by-one or "Update All")
*** Bug 231809 has been marked as a duplicate of this bug. ***
I can't reproduce this. There might be something wrong with your database. Is this a normal setup or do you use a MySQL server? Could you please run the next command in the script console and attach the result in a text file. Amarok.Collection.query( "SELECT id, title, url, guid FROM podcastepisodes WHERE channel = (SELECT id FROM podcastchannels WHERE url='http://www2.rozhlas.cz/podcast/radiozurnal.rss');" );
(In reply to comment #5) > I can't reproduce this. There might be something wrong with your database. Is > this a normal setup or do you use a MySQL server? > > Could you please run the next command in the script console and attach the > result in a text file. > > Amarok.Collection.query( "SELECT id, title, url, guid FROM podcastepisodes > WHERE channel = (SELECT id FROM podcastchannels WHERE > url='http://www2.rozhlas.cz/podcast/radiozurnal.rss');" ); I have the same problem with podcasts from NRK (http://nrk.no/podkast/), for example http://podkast.nrk.no/program/naturtelefonen.rss. I ran the above command substituting the url, but I don't konw how to copy the text from the script console.
(In reply to comment #6) > I have the same problem with podcasts from NRK (http://nrk.no/podkast/), for > example http://podkast.nrk.no/program/naturtelefonen.rss. I ran the above > command substituting the url, but I don't konw how to copy the text from the > script console. Select the line and Ctrl+C. Make sure to paste it in a text file and attach it here. The content will be to long to parse in a comment.
Created attachment 42228 [details] First run
Created attachment 42229 [details] Second run after another update of the podcast
It stopped doing after update to a newer version of Kubuntu package (now I have 2:2.3.0-0ubuntu1~karmic1~ppa2), so I'm not sure whether it was bug that was in Ubuntu package only or whether it was Amarok bug fixed by Ubuntu devs.
*** Bug 232032 has been marked as a duplicate of this bug. ***
commit d799a6ca67a3eb7ab0409948d40777ecdb70d745 Author: Bart Cerneels <bart.cerneels@kde.org> Date: Thu Mar 25 20:13:04 2010 +0100 Work around KUrl string parsing for guids. trackForUrl can not be used to query by guid because urls are not allowed to have non-latin characters, spaces, percent encoded entries, capitals, etc. So we'll use a function that doesn't take a KUrl. BUG:231230 diff --git a/src/collection/umscollection/podcasts/UmsPodcastProvider.cpp b/src/collection/umscollection/podcasts/UmsPodcastProvider.cpp index 3a8ce5b..7700a16 100644 --- a/src/collection/umscollection/podcasts/UmsPodcastProvider.cpp +++ b/src/collection/umscollection/podcasts/UmsPodcastProvider.cpp @@ -55,6 +55,13 @@ UmsPodcastProvider::trackForUrl( const KUrl &url ) return TrackPtr(); } +PodcastEpisodePtr +UmsPodcastProvider::episodeForGuid( const QString &guid ) +{ + Q_UNUSED( guid ) + return PodcastEpisodePtr(); +} + void UmsPodcastProvider::addPodcast( const KUrl &url ) { diff --git a/src/collection/umscollection/podcasts/UmsPodcastProvider.h b/src/collection/umscollection/podcasts/UmsPodcastProvider.h index 059ed45..f052769 100644 --- a/src/collection/umscollection/podcasts/UmsPodcastProvider.h +++ b/src/collection/umscollection/podcasts/UmsPodcastProvider.h @@ -36,6 +36,8 @@ class UmsPodcastProvider : public PodcastProvider virtual bool possiblyContainsTrack( const KUrl &url ) const; virtual Meta::TrackPtr trackForUrl( const KUrl &url ); + virtual Meta::PodcastEpisodePtr episodeForGuid( const QString &guid ); + virtual void addPodcast( const KUrl &url ); virtual Meta::PodcastChannelPtr addChannel( Meta::PodcastChannelPtr channel ); diff --git a/src/podcasts/PodcastProvider.h b/src/podcasts/PodcastProvider.h index 6bda936..d670ec1 100644 --- a/src/podcasts/PodcastProvider.h +++ b/src/podcasts/PodcastProvider.h @@ -41,6 +41,14 @@ class AMAROK_EXPORT PodcastProvider : public Amarok::TrackProvider, public Playl virtual bool possiblyContainsTrack( const KUrl &url ) const = 0; virtual Meta::TrackPtr trackForUrl( const KUrl &url ) = 0; + /** Special function to get an episode for a given guid. + * + * note: this functions is required because KUrl does not preserve every possible guids. + * This means we can not use trackForUrl(). + * Problematic guids contain non-latin characters, percent encoded parts, capitals, etc. + */ + virtual Meta::PodcastEpisodePtr episodeForGuid( const QString &guid ) = 0; + virtual void addPodcast( const KUrl &url ) = 0; virtual Meta::PodcastChannelPtr addChannel( Meta::PodcastChannelPtr channel ) = 0; diff --git a/src/podcasts/PodcastReader.cpp b/src/podcasts/PodcastReader.cpp index f609222..1722bd8 100644 --- a/src/podcasts/PodcastReader.cpp +++ b/src/podcasts/PodcastReader.cpp @@ -1149,15 +1149,18 @@ PodcastReader::endItem() m_item->setDescription( description ); } + Meta::PodcastEpisodePtr episode; QString guid = m_item->guid(); - bool useGuid = !guid.isEmpty() && - !guid.contains( "[A-Z]" ) && //KUrl only uses lowercase - !guid.startsWith( '/' ); //appends file:// - - const KUrl trackId( useGuid ? m_item->guid() : m_item->uidUrl() ); - Meta::PodcastEpisodePtr episode = Meta::PodcastEpisodePtr::dynamicCast( - m_podcastProvider->trackForUrl( trackId ) + if( guid.isEmpty() ) + { + episode = Meta::PodcastEpisodePtr::dynamicCast( + m_podcastProvider->trackForUrl( m_item->uidUrl() ) ); + } + else + { + episode = m_podcastProvider->episodeForGuid( guid ); + } //make sure that the episode is not a bogus match. The channel has to be correct. // See http://bugs.kde.org/show_bug.cgi?id=227515 diff --git a/src/podcasts/sql/SqlPodcastProvider.cpp b/src/podcasts/sql/SqlPodcastProvider.cpp index fa11604..a805867 100644 --- a/src/podcasts/sql/SqlPodcastProvider.cpp +++ b/src/podcasts/sql/SqlPodcastProvider.cpp @@ -170,47 +170,25 @@ SqlPodcastProvider::loadPodcasts() emit( updated() ); } -QString -SqlPodcastProvider::cleanUrlOrGuid( const KUrl &url ) +SqlPodcastEpisodePtr +SqlPodcastProvider::sqlEpisodeForString( const QString &string ) { - QString decodedUrl = QUrl::fromPercentEncoding( url.url().toUtf8() ); - return decodedUrl; -} + if( string.isEmpty() ) + return SqlPodcastEpisodePtr(); -bool -SqlPodcastProvider::possiblyContainsTrack( const KUrl &url ) const -{ SqlStorage *sqlStorage = CollectionManager::instance()->sqlStorage(); if( !sqlStorage ) - return false; - - QString command = "SELECT title FROM podcastepisodes WHERE guid='%1' OR url='%1' " - "OR localurl='%1';"; - command = command.arg( sqlStorage->escape( cleanUrlOrGuid( url ) ) ); - - QStringList dbResult = sqlStorage->query( command ); - return !dbResult.isEmpty(); -} - -Meta::TrackPtr -SqlPodcastProvider::trackForUrl( const KUrl &url ) -{ - if( url.isEmpty() ) - return TrackPtr(); - - SqlStorage *sqlStorage = CollectionManager::instance()->sqlStorage(); - if( !sqlStorage ) - return TrackPtr(); + return SqlPodcastEpisodePtr(); QString command = "SELECT id, url, channel, localurl, guid, " "title, subtitle, sequencenumber, description, mimetype, pubdate, " "duration, filesize, isnew FROM podcastepisodes " "WHERE guid='%1' OR url='%1' OR localurl='%1' ORDER BY id DESC;"; - command = command.arg( sqlStorage->escape( cleanUrlOrGuid( url ) ) ); + command = command.arg( sqlStorage->escape( string ) ); QStringList dbResult = sqlStorage->query( command ); if( dbResult.isEmpty() ) - return TrackPtr(); + return SqlPodcastEpisodePtr(); int episodeId = dbResult[0].toInt(); int channelId = dbResult[2].toInt(); @@ -229,23 +207,42 @@ SqlPodcastProvider::trackForUrl( const KUrl &url ) { error() << QString( "There is a track in the database with url/guid=%1 (%2) " "but there is no channel with dbId=%3 in our list!" ) - .arg( url.url() ).arg( episodeId ).arg( channelId ); - return TrackPtr(); + .arg( string ).arg( episodeId ).arg( channelId ); + return SqlPodcastEpisodePtr(); } Meta::SqlPodcastEpisodePtr episode; foreach( episode, channel->sqlEpisodes() ) - { if( episode->dbId() == episodeId ) - { - debug() << "found it!"; - return Meta::TrackPtr::dynamicCast( episode ); - } - } + return episode; //The episode was found in the database but it's channel didn't have it in it's list. //That probably is because it's beyond the purgecount limit. - episode = new Meta::SqlPodcastEpisode( dbResult.mid( 0, 14 ), channel ); + return SqlPodcastEpisodePtr( new SqlPodcastEpisode( dbResult.mid( 0, 14 ), channel ) ); +} + +bool +SqlPodcastProvider::possiblyContainsTrack( const KUrl &url ) const +{ + SqlStorage *sqlStorage = CollectionManager::instance()->sqlStorage(); + if( !sqlStorage ) + return false; + + QString command = "SELECT title FROM podcastepisodes WHERE guid='%1' OR url='%1' " + "OR localurl='%1';"; + command = command.arg( sqlStorage->escape( url.url() ) ); + + QStringList dbResult = sqlStorage->query( command ); + return !dbResult.isEmpty(); +} + +Meta::TrackPtr +SqlPodcastProvider::trackForUrl( const KUrl &url ) +{ + if( url.isEmpty() ) + return TrackPtr(); + + SqlPodcastEpisodePtr episode = sqlEpisodeForString( url.url() ); return Meta::TrackPtr::dynamicCast( episode ); } @@ -263,6 +260,12 @@ SqlPodcastProvider::playlists() return playlistList; } +Meta::PodcastEpisodePtr +SqlPodcastProvider::episodeForGuid( const QString &guid ) +{ + return PodcastEpisodePtr::dynamicCast( sqlEpisodeForString( guid ) ); +} + void SqlPodcastProvider::addPodcast( const KUrl &url ) { diff --git a/src/podcasts/sql/SqlPodcastProvider.h b/src/podcasts/sql/SqlPodcastProvider.h index d45c968..0bfb20b 100644 --- a/src/podcasts/sql/SqlPodcastProvider.h +++ b/src/podcasts/sql/SqlPodcastProvider.h @@ -50,6 +50,8 @@ class SqlPodcastProvider : public PodcastProvider Meta::PlaylistList playlists(); //PodcastProvider methods + virtual Meta::PodcastEpisodePtr episodeForGuid( const QString &guid ); + void addPodcast( const KUrl &url ); Meta::PodcastChannelPtr addChannel( Meta::PodcastChannelPtr channel ); @@ -114,9 +116,8 @@ class SqlPodcastProvider : public PodcastProvider void createTables() const; void loadPodcasts(); - /** return the url as a string. Removes percent encoding if it actually has a non-url guid. - */ - static QString cleanUrlOrGuid( const KUrl &url ); + /** @arg string: a url, localUrl or guid in string form */ + Meta::SqlPodcastEpisodePtr sqlEpisodeForString( const QString &string ); void updateDatabase( int fromVersion, int toVersion ); void fetchImage( Meta::SqlPodcastChannelPtr channel );
This has just been fixed by Bart: commit d799a6ca67a3eb7ab0409948d40777ecdb70d745 Author: Bart Cerneels <bart.cerneels@kde.org> Date: Thu Mar 25 20:13:04 2010 +0100 Work around KUrl string parsing for guids. trackForUrl can not be used to query by guid because urls are not allowed to have non-latin characters, spaces, percent encoded entries, capitals, etc. So we'll use a function that doesn't take a KUrl. BUG:231230 diff --git a/src/collection/umscollection/podcasts/UmsPodcastProvider.cpp b/src/collection/umscollection/podcasts/UmsPodcastProvider.cpp index 3a8ce5b..7700a16 100644 --- a/src/collection/umscollection/podcasts/UmsPodcastProvider.cpp +++ b/src/collection/umscollection/podcasts/UmsPodcastProvider.cpp @@ -55,6 +55,13 @@ UmsPodcastProvider::trackForUrl( const KUrl &url ) return TrackPtr(); } +PodcastEpisodePtr +UmsPodcastProvider::episodeForGuid( const QString &guid ) +{ + Q_UNUSED( guid ) + return PodcastEpisodePtr(); +} + void UmsPodcastProvider::addPodcast( const KUrl &url ) { diff --git a/src/collection/umscollection/podcasts/UmsPodcastProvider.h b/src/collection/umscollection/podcasts/UmsPodcastProvider.h index 059ed45..f052769 100644 --- a/src/collection/umscollection/podcasts/UmsPodcastProvider.h +++ b/src/collection/umscollection/podcasts/UmsPodcastProvider.h @@ -36,6 +36,8 @@ class UmsPodcastProvider : public PodcastProvider virtual bool possiblyContainsTrack( const KUrl &url ) const; virtual Meta::TrackPtr trackForUrl( const KUrl &url ); + virtual Meta::PodcastEpisodePtr episodeForGuid( const QString &guid ); + virtual void addPodcast( const KUrl &url ); virtual Meta::PodcastChannelPtr addChannel( Meta::PodcastChannelPtr channel ); diff --git a/src/podcasts/PodcastProvider.h b/src/podcasts/PodcastProvider.h index 6bda936..d670ec1 100644 --- a/src/podcasts/PodcastProvider.h +++ b/src/podcasts/PodcastProvider.h @@ -41,6 +41,14 @@ class AMAROK_EXPORT PodcastProvider : public Amarok::TrackProvider, public Playl virtual bool possiblyContainsTrack( const KUrl &url ) const = 0; virtual Meta::TrackPtr trackForUrl( const KUrl &url ) = 0; + /** Special function to get an episode for a given guid. + * + * note: this functions is required because KUrl does not preserve every possible guids. + * This means we can not use trackForUrl(). + * Problematic guids contain non-latin characters, percent encoded parts, capitals, etc. + */ + virtual Meta::PodcastEpisodePtr episodeForGuid( const QString &guid ) = 0; + virtual void addPodcast( const KUrl &url ) = 0; virtual Meta::PodcastChannelPtr addChannel( Meta::PodcastChannelPtr channel ) = 0; diff --git a/src/podcasts/PodcastReader.cpp b/src/podcasts/PodcastReader.cpp index f609222..1722bd8 100644 --- a/src/podcasts/PodcastReader.cpp +++ b/src/podcasts/PodcastReader.cpp @@ -1149,15 +1149,18 @@ PodcastReader::endItem() m_item->setDescription( description ); } + Meta::PodcastEpisodePtr episode; QString guid = m_item->guid(); - bool useGuid = !guid.isEmpty() && - !guid.contains( "[A-Z]" ) && //KUrl only uses lowercase - !guid.startsWith( '/' ); //appends file:// - - const KUrl trackId( useGuid ? m_item->guid() : m_item->uidUrl() ); - Meta::PodcastEpisodePtr episode = Meta::PodcastEpisodePtr::dynamicCast( - m_podcastProvider->trackForUrl( trackId ) + if( guid.isEmpty() ) + { + episode = Meta::PodcastEpisodePtr::dynamicCast( + m_podcastProvider->trackForUrl( m_item->uidUrl() ) ); + } + else + { + episode = m_podcastProvider->episodeForGuid( guid ); + } //make sure that the episode is not a bogus match. The channel has to be correct. // See http://bugs.kde.org/show_bug.cgi?id=227515 diff --git a/src/podcasts/sql/SqlPodcastProvider.cpp b/src/podcasts/sql/SqlPodcastProvider.cpp index fa11604..a805867 100644 --- a/src/podcasts/sql/SqlPodcastProvider.cpp +++ b/src/podcasts/sql/SqlPodcastProvider.cpp @@ -170,47 +170,25 @@ SqlPodcastProvider::loadPodcasts() emit( updated() ); } -QString -SqlPodcastProvider::cleanUrlOrGuid( const KUrl &url ) +SqlPodcastEpisodePtr +SqlPodcastProvider::sqlEpisodeForString( const QString &string ) { - QString decodedUrl = QUrl::fromPercentEncoding( url.url().toUtf8() ); - return decodedUrl; -} + if( string.isEmpty() ) + return SqlPodcastEpisodePtr(); -bool -SqlPodcastProvider::possiblyContainsTrack( const KUrl &url ) const -{ SqlStorage *sqlStorage = CollectionManager::instance()->sqlStorage(); if( !sqlStorage ) - return false; - - QString command = "SELECT title FROM podcastepisodes WHERE guid='%1' OR url='%1' " - "OR localurl='%1';"; - command = command.arg( sqlStorage->escape( cleanUrlOrGuid( url ) ) ); - - QStringList dbResult = sqlStorage->query( command ); - return !dbResult.isEmpty(); -} - -Meta::TrackPtr -SqlPodcastProvider::trackForUrl( const KUrl &url ) -{ - if( url.isEmpty() ) - return TrackPtr(); - - SqlStorage *sqlStorage = CollectionManager::instance()->sqlStorage(); - if( !sqlStorage ) - return TrackPtr(); + return SqlPodcastEpisodePtr(); QString command = "SELECT id, url, channel, localurl, guid, " "title, subtitle, sequencenumber, description, mimetype, pubdate, " "duration, filesize, isnew FROM podcastepisodes " "WHERE guid='%1' OR url='%1' OR localurl='%1' ORDER BY id DESC;"; - command = command.arg( sqlStorage->escape( cleanUrlOrGuid( url ) ) ); + command = command.arg( sqlStorage->escape( string ) ); QStringList dbResult = sqlStorage->query( command ); if( dbResult.isEmpty() ) - return TrackPtr(); + return SqlPodcastEpisodePtr(); int episodeId = dbResult[0].toInt(); int channelId = dbResult[2].toInt(); @@ -229,23 +207,42 @@ SqlPodcastProvider::trackForUrl( const KUrl &url ) { error() << QString( "There is a track in the database with url/guid=%1 (%2) " "but there is no channel with dbId=%3 in our list!" ) - .arg( url.url() ).arg( episodeId ).arg( channelId ); - return TrackPtr(); + .arg( string ).arg( episodeId ).arg( channelId ); + return SqlPodcastEpisodePtr(); } Meta::SqlPodcastEpisodePtr episode; foreach( episode, channel->sqlEpisodes() ) - { if( episode->dbId() == episodeId ) - { - debug() << "found it!"; - return Meta::TrackPtr::dynamicCast( episode ); - } - } + return episode; //The episode was found in the database but it's channel didn't have it in it's list. //That probably is because it's beyond the purgecount limit. - episode = new Meta::SqlPodcastEpisode( dbResult.mid( 0, 14 ), channel ); + return SqlPodcastEpisodePtr( new SqlPodcastEpisode( dbResult.mid( 0, 14 ), channel ) ); +} + +bool +SqlPodcastProvider::possiblyContainsTrack( const KUrl &url ) const +{ + SqlStorage *sqlStorage = CollectionManager::instance()->sqlStorage(); + if( !sqlStorage ) + return false; + + QString command = "SELECT title FROM podcastepisodes WHERE guid='%1' OR url='%1' " + "OR localurl='%1';"; + command = command.arg( sqlStorage->escape( url.url() ) ); + + QStringList dbResult = sqlStorage->query( command ); + return !dbResult.isEmpty(); +} + +Meta::TrackPtr +SqlPodcastProvider::trackForUrl( const KUrl &url ) +{ + if( url.isEmpty() ) + return TrackPtr(); + + SqlPodcastEpisodePtr episode = sqlEpisodeForString( url.url() ); return Meta::TrackPtr::dynamicCast( episode ); } @@ -263,6 +260,12 @@ SqlPodcastProvider::playlists() return playlistList; } +Meta::PodcastEpisodePtr +SqlPodcastProvider::episodeForGuid( const QString &guid ) +{ + return PodcastEpisodePtr::dynamicCast( sqlEpisodeForString( guid ) ); +} + void SqlPodcastProvider::addPodcast( const KUrl &url ) { diff --git a/src/podcasts/sql/SqlPodcastProvider.h b/src/podcasts/sql/SqlPodcastProvider.h index d45c968..0bfb20b 100644 --- a/src/podcasts/sql/SqlPodcastProvider.h +++ b/src/podcasts/sql/SqlPodcastProvider.h @@ -50,6 +50,8 @@ class SqlPodcastProvider : public PodcastProvider Meta::PlaylistList playlists(); //PodcastProvider methods + virtual Meta::PodcastEpisodePtr episodeForGuid( const QString &guid ); + void addPodcast( const KUrl &url ); Meta::PodcastChannelPtr addChannel( Meta::PodcastChannelPtr channel ); @@ -114,9 +116,8 @@ class SqlPodcastProvider : public PodcastProvider void createTables() const; void loadPodcasts(); - /** return the url as a string. Removes percent encoding if it actually has a non-url guid. - */ - static QString cleanUrlOrGuid( const KUrl &url ); + /** @arg string: a url, localUrl or guid in string form */ + Meta::SqlPodcastEpisodePtr sqlEpisodeForString( const QString &string ); void updateDatabase( int fromVersion, int toVersion ); void fetchImage( Meta::SqlPodcastChannelPtr channel );
commit 839538ae580be93d4ab6260b3b3825ed584b02c2 Author: Bart Cerneels <bart.cerneels@kde.org> Date: Thu Mar 25 20:13:04 2010 +0100 Work around KUrl string parsing for guids. trackForUrl can not be used to query by guid because urls are not allowed to have non-latin characters, spaces, percent encoded entries, capitals, etc. So we'll use a function that doesn't take a KUrl. BUG:231230 diff --git a/src/collection/umscollection/podcasts/UmsPodcastProvider.cpp b/src/collection/umscollection/podcasts/UmsPodcastProvider.cpp index 3a8ce5b..7700a16 100644 --- a/src/collection/umscollection/podcasts/UmsPodcastProvider.cpp +++ b/src/collection/umscollection/podcasts/UmsPodcastProvider.cpp @@ -55,6 +55,13 @@ UmsPodcastProvider::trackForUrl( const KUrl &url ) return TrackPtr(); } +PodcastEpisodePtr +UmsPodcastProvider::episodeForGuid( const QString &guid ) +{ + Q_UNUSED( guid ) + return PodcastEpisodePtr(); +} + void UmsPodcastProvider::addPodcast( const KUrl &url ) { diff --git a/src/collection/umscollection/podcasts/UmsPodcastProvider.h b/src/collection/umscollection/podcasts/UmsPodcastProvider.h index 059ed45..f052769 100644 --- a/src/collection/umscollection/podcasts/UmsPodcastProvider.h +++ b/src/collection/umscollection/podcasts/UmsPodcastProvider.h @@ -36,6 +36,8 @@ class UmsPodcastProvider : public PodcastProvider virtual bool possiblyContainsTrack( const KUrl &url ) const; virtual Meta::TrackPtr trackForUrl( const KUrl &url ); + virtual Meta::PodcastEpisodePtr episodeForGuid( const QString &guid ); + virtual void addPodcast( const KUrl &url ); virtual Meta::PodcastChannelPtr addChannel( Meta::PodcastChannelPtr channel ); diff --git a/src/podcasts/PodcastProvider.h b/src/podcasts/PodcastProvider.h index 6bda936..d670ec1 100644 --- a/src/podcasts/PodcastProvider.h +++ b/src/podcasts/PodcastProvider.h @@ -41,6 +41,14 @@ class AMAROK_EXPORT PodcastProvider : public Amarok::TrackProvider, public Playl virtual bool possiblyContainsTrack( const KUrl &url ) const = 0; virtual Meta::TrackPtr trackForUrl( const KUrl &url ) = 0; + /** Special function to get an episode for a given guid. + * + * note: this functions is required because KUrl does not preserve every possible guids. + * This means we can not use trackForUrl(). + * Problematic guids contain non-latin characters, percent encoded parts, capitals, etc. + */ + virtual Meta::PodcastEpisodePtr episodeForGuid( const QString &guid ) = 0; + virtual void addPodcast( const KUrl &url ) = 0; virtual Meta::PodcastChannelPtr addChannel( Meta::PodcastChannelPtr channel ) = 0; diff --git a/src/podcasts/PodcastReader.cpp b/src/podcasts/PodcastReader.cpp index f609222..1722bd8 100644 --- a/src/podcasts/PodcastReader.cpp +++ b/src/podcasts/PodcastReader.cpp @@ -1149,15 +1149,18 @@ PodcastReader::endItem() m_item->setDescription( description ); } + Meta::PodcastEpisodePtr episode; QString guid = m_item->guid(); - bool useGuid = !guid.isEmpty() && - !guid.contains( "[A-Z]" ) && //KUrl only uses lowercase - !guid.startsWith( '/' ); //appends file:// - - const KUrl trackId( useGuid ? m_item->guid() : m_item->uidUrl() ); - Meta::PodcastEpisodePtr episode = Meta::PodcastEpisodePtr::dynamicCast( - m_podcastProvider->trackForUrl( trackId ) + if( guid.isEmpty() ) + { + episode = Meta::PodcastEpisodePtr::dynamicCast( + m_podcastProvider->trackForUrl( m_item->uidUrl() ) ); + } + else + { + episode = m_podcastProvider->episodeForGuid( guid ); + } //make sure that the episode is not a bogus match. The channel has to be correct. // See http://bugs.kde.org/show_bug.cgi?id=227515 diff --git a/src/podcasts/sql/SqlPodcastProvider.cpp b/src/podcasts/sql/SqlPodcastProvider.cpp index fa11604..a805867 100644 --- a/src/podcasts/sql/SqlPodcastProvider.cpp +++ b/src/podcasts/sql/SqlPodcastProvider.cpp @@ -170,47 +170,25 @@ SqlPodcastProvider::loadPodcasts() emit( updated() ); } -QString -SqlPodcastProvider::cleanUrlOrGuid( const KUrl &url ) +SqlPodcastEpisodePtr +SqlPodcastProvider::sqlEpisodeForString( const QString &string ) { - QString decodedUrl = QUrl::fromPercentEncoding( url.url().toUtf8() ); - return decodedUrl; -} + if( string.isEmpty() ) + return SqlPodcastEpisodePtr(); -bool -SqlPodcastProvider::possiblyContainsTrack( const KUrl &url ) const -{ SqlStorage *sqlStorage = CollectionManager::instance()->sqlStorage(); if( !sqlStorage ) - return false; - - QString command = "SELECT title FROM podcastepisodes WHERE guid='%1' OR url='%1' " - "OR localurl='%1';"; - command = command.arg( sqlStorage->escape( cleanUrlOrGuid( url ) ) ); - - QStringList dbResult = sqlStorage->query( command ); - return !dbResult.isEmpty(); -} - -Meta::TrackPtr -SqlPodcastProvider::trackForUrl( const KUrl &url ) -{ - if( url.isEmpty() ) - return TrackPtr(); - - SqlStorage *sqlStorage = CollectionManager::instance()->sqlStorage(); - if( !sqlStorage ) - return TrackPtr(); + return SqlPodcastEpisodePtr(); QString command = "SELECT id, url, channel, localurl, guid, " "title, subtitle, sequencenumber, description, mimetype, pubdate, " "duration, filesize, isnew FROM podcastepisodes " "WHERE guid='%1' OR url='%1' OR localurl='%1' ORDER BY id DESC;"; - command = command.arg( sqlStorage->escape( cleanUrlOrGuid( url ) ) ); + command = command.arg( sqlStorage->escape( string ) ); QStringList dbResult = sqlStorage->query( command ); if( dbResult.isEmpty() ) - return TrackPtr(); + return SqlPodcastEpisodePtr(); int episodeId = dbResult[0].toInt(); int channelId = dbResult[2].toInt(); @@ -229,23 +207,42 @@ SqlPodcastProvider::trackForUrl( const KUrl &url ) { error() << QString( "There is a track in the database with url/guid=%1 (%2) " "but there is no channel with dbId=%3 in our list!" ) - .arg( url.url() ).arg( episodeId ).arg( channelId ); - return TrackPtr(); + .arg( string ).arg( episodeId ).arg( channelId ); + return SqlPodcastEpisodePtr(); } Meta::SqlPodcastEpisodePtr episode; foreach( episode, channel->sqlEpisodes() ) - { if( episode->dbId() == episodeId ) - { - debug() << "found it!"; - return Meta::TrackPtr::dynamicCast( episode ); - } - } + return episode; //The episode was found in the database but it's channel didn't have it in it's list. //That probably is because it's beyond the purgecount limit. - episode = new Meta::SqlPodcastEpisode( dbResult.mid( 0, 14 ), channel ); + return SqlPodcastEpisodePtr( new SqlPodcastEpisode( dbResult.mid( 0, 14 ), channel ) ); +} + +bool +SqlPodcastProvider::possiblyContainsTrack( const KUrl &url ) const +{ + SqlStorage *sqlStorage = CollectionManager::instance()->sqlStorage(); + if( !sqlStorage ) + return false; + + QString command = "SELECT title FROM podcastepisodes WHERE guid='%1' OR url='%1' " + "OR localurl='%1';"; + command = command.arg( sqlStorage->escape( url.url() ) ); + + QStringList dbResult = sqlStorage->query( command ); + return !dbResult.isEmpty(); +} + +Meta::TrackPtr +SqlPodcastProvider::trackForUrl( const KUrl &url ) +{ + if( url.isEmpty() ) + return TrackPtr(); + + SqlPodcastEpisodePtr episode = sqlEpisodeForString( url.url() ); return Meta::TrackPtr::dynamicCast( episode ); } @@ -263,6 +260,12 @@ SqlPodcastProvider::playlists() return playlistList; } +Meta::PodcastEpisodePtr +SqlPodcastProvider::episodeForGuid( const QString &guid ) +{ + return PodcastEpisodePtr::dynamicCast( sqlEpisodeForString( guid ) ); +} + void SqlPodcastProvider::addPodcast( const KUrl &url ) { diff --git a/src/podcasts/sql/SqlPodcastProvider.h b/src/podcasts/sql/SqlPodcastProvider.h index d45c968..0bfb20b 100644 --- a/src/podcasts/sql/SqlPodcastProvider.h +++ b/src/podcasts/sql/SqlPodcastProvider.h @@ -50,6 +50,8 @@ class SqlPodcastProvider : public PodcastProvider Meta::PlaylistList playlists(); //PodcastProvider methods + virtual Meta::PodcastEpisodePtr episodeForGuid( const QString &guid ); + void addPodcast( const KUrl &url ); Meta::PodcastChannelPtr addChannel( Meta::PodcastChannelPtr channel ); @@ -114,9 +116,8 @@ class SqlPodcastProvider : public PodcastProvider void createTables() const; void loadPodcasts(); - /** return the url as a string. Removes percent encoding if it actually has a non-url guid. - */ - static QString cleanUrlOrGuid( const KUrl &url ); + /** @arg string: a url, localUrl or guid in string form */ + Meta::SqlPodcastEpisodePtr sqlEpisodeForString( const QString &string ); void updateDatabase( int fromVersion, int toVersion ); void fetchImage( Meta::SqlPodcastChannelPtr channel );