File indexing completed on 2024-05-19 04:50:00
0001 /**************************************************************************************** 0002 * Copyright (c) 2008 Nikolaj Hald Nielsen <nhn@kde.org> * 0003 * Copyright (c) 2008 Bart Cerneels <bart.cerneels@kde.org> * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify it under * 0006 * the terms of the GNU General Public License as published by the Free Software * 0007 * Foundation; either version 2 of the License, or (at your option) any later * 0008 * version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0011 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0012 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0013 * * 0014 * You should have received a copy of the GNU General Public License along with * 0015 * this program. If not, see <http://www.gnu.org/licenses/>. * 0016 ****************************************************************************************/ 0017 0018 #include "SqlUserPlaylistProvider.h" 0019 0020 #include "SvgHandler.h" 0021 #include "browsers/playlistbrowser/UserPlaylistModel.h" 0022 #include <core/storage/SqlStorage.h> 0023 #include "core/playlists/PlaylistFormat.h" 0024 #include "core/support/Amarok.h" 0025 #include "core/support/Debug.h" 0026 #include "core-impl/storage/StorageManager.h" 0027 #include "core-impl/playlists/types/file/m3u/M3UPlaylist.h" 0028 #include "core-impl/playlists/types/file/pls/PLSPlaylist.h" 0029 #include "core-impl/playlists/types/file/xspf/XSPFPlaylist.h" 0030 #include "core-impl/playlists/types/file/PlaylistFileSupport.h" 0031 0032 #include <QAction> 0033 #include <QIcon> 0034 #include <QInputDialog> 0035 #include <QLabel> 0036 #include <QMap> 0037 #include <QUrl> 0038 0039 #include <KLocalizedString> 0040 #include <KMessageBox> 0041 #include <KConfigGroup> 0042 0043 static const int USERPLAYLIST_DB_VERSION = 3; 0044 // a database updater has been added in checkTables(). Use that when updating db version 0045 static const QString key(QStringLiteral("AMAROK_USERPLAYLIST")); 0046 0047 namespace Playlists { 0048 0049 SqlUserPlaylistProvider::SqlUserPlaylistProvider( bool debug ) 0050 : UserPlaylistProvider() 0051 , m_debug( debug ) 0052 { 0053 checkTables(); 0054 m_root = Playlists::SqlPlaylistGroupPtr( new Playlists::SqlPlaylistGroup( QString(), 0055 Playlists::SqlPlaylistGroupPtr(), this ) ); 0056 } 0057 0058 SqlUserPlaylistProvider::~SqlUserPlaylistProvider() 0059 { 0060 } 0061 0062 int 0063 SqlUserPlaylistProvider::playlistCount() const 0064 { 0065 return m_root->childSqlPlaylists().count(); 0066 } 0067 0068 Playlists::PlaylistList 0069 SqlUserPlaylistProvider::playlists() 0070 { 0071 Playlists::PlaylistList playlists; 0072 foreach( Playlists::SqlPlaylistPtr sqlPlaylist, m_root->allChildPlaylists() ) 0073 { 0074 playlists << Playlists::PlaylistPtr::staticCast( sqlPlaylist ); 0075 } 0076 return playlists; 0077 } 0078 0079 void 0080 SqlUserPlaylistProvider::renamePlaylist(PlaylistPtr playlist, const QString &newName ) 0081 { 0082 playlist->setName( newName.trimmed() ); 0083 } 0084 0085 bool 0086 SqlUserPlaylistProvider::isWritable() 0087 { 0088 return true; 0089 } 0090 0091 bool 0092 SqlUserPlaylistProvider::deletePlaylists( const Playlists::PlaylistList &playlistList ) 0093 { 0094 Playlists::SqlPlaylistList sqlPlaylists; 0095 foreach( Playlists::PlaylistPtr playlist, playlistList ) 0096 { 0097 Playlists::SqlPlaylistPtr sqlPlaylist = 0098 Playlists::SqlPlaylistPtr::dynamicCast( playlist ); 0099 if( !sqlPlaylist.isNull() ) 0100 sqlPlaylists << sqlPlaylist; 0101 } 0102 return deleteSqlPlaylists( sqlPlaylists ); 0103 } 0104 0105 bool 0106 SqlUserPlaylistProvider::deleteSqlPlaylists( Playlists::SqlPlaylistList playlistList ) 0107 { 0108 //this delete is not confirmed, has to be done by the slot connected to the delete action. 0109 foreach( Playlists::SqlPlaylistPtr sqlPlaylist, playlistList ) 0110 { 0111 if( sqlPlaylist ) 0112 { 0113 debug() << "deleting " << sqlPlaylist->name(); 0114 m_root->m_childPlaylists.removeAll( sqlPlaylist ); 0115 Q_EMIT playlistRemoved( Playlists::PlaylistPtr::dynamicCast( sqlPlaylist ) ); 0116 sqlPlaylist->removeFromDb(); 0117 } 0118 } 0119 0120 return true; 0121 } 0122 0123 Playlists::PlaylistPtr 0124 SqlUserPlaylistProvider::save( const Meta::TrackList &tracks ) 0125 { 0126 DEBUG_BLOCK 0127 QString name = QLocale().toString( QDateTime::currentDateTime(), QLocale::LongFormat ); 0128 return save( tracks, name ); 0129 } 0130 0131 Playlists::PlaylistPtr 0132 SqlUserPlaylistProvider::save( const Meta::TrackList &tracks, const QString& name ) 0133 { 0134 DEBUG_BLOCK 0135 debug() << "saving " << tracks.count() << " tracks to db with name" << name; 0136 Playlists::SqlPlaylistPtr sqlPlaylist = Playlists::SqlPlaylistPtr( 0137 new Playlists::SqlPlaylist( name, tracks, 0138 Playlists::SqlPlaylistGroupPtr(), 0139 this ) 0140 ); 0141 m_root->m_childPlaylists << sqlPlaylist; 0142 Playlists::PlaylistPtr playlist( sqlPlaylist.data() ); 0143 0144 Q_EMIT playlistAdded( playlist ); 0145 return playlist; // assumes insertion in db was successful! 0146 } 0147 0148 void 0149 SqlUserPlaylistProvider::reloadFromDb() 0150 { 0151 DEBUG_BLOCK; 0152 m_root->clear(); 0153 Q_EMIT updated(); 0154 } 0155 0156 Playlists::SqlPlaylistGroupPtr 0157 SqlUserPlaylistProvider::group( const QString &name ) 0158 { 0159 DEBUG_BLOCK 0160 Playlists::SqlPlaylistGroupPtr group; 0161 0162 if( name.isEmpty() ) 0163 return m_root; 0164 0165 //clear the root first to force a reload. 0166 m_root->clear(); 0167 0168 foreach( const Playlists::SqlPlaylistGroupPtr &group, m_root->allChildGroups() ) 0169 { 0170 debug() << group->name(); 0171 if( group->name() == name ) 0172 { 0173 debug() << "match"; 0174 return group; 0175 } 0176 } 0177 0178 debug() << "Creating a new group " << name; 0179 group = new Playlists::SqlPlaylistGroup( name, m_root, this ); 0180 group->save(); 0181 0182 return group; 0183 } 0184 0185 void 0186 SqlUserPlaylistProvider::createTables() 0187 { 0188 DEBUG_BLOCK 0189 0190 auto sqlStorage = StorageManager::instance()->sqlStorage(); 0191 if( !sqlStorage ) 0192 { 0193 debug() << "No SQL Storage available!"; 0194 return; 0195 } 0196 sqlStorage->query( QString( "CREATE TABLE playlist_groups (" 0197 " id " + sqlStorage->idType() + 0198 ", parent_id INTEGER" 0199 ", name " + sqlStorage->textColumnType() + 0200 ", description " + sqlStorage->textColumnType() + " ) ENGINE = MyISAM;" ) ); 0201 sqlStorage->query( QStringLiteral("CREATE INDEX parent_podchannel ON playlist_groups( parent_id );") ); 0202 0203 0204 sqlStorage->query( QString( "CREATE TABLE playlists (" 0205 " id " + sqlStorage->idType() + 0206 ", parent_id INTEGER" 0207 ", name " + sqlStorage->textColumnType() + 0208 ", urlid " + sqlStorage->exactTextColumnType() + " ) ENGINE = MyISAM;" ) ); 0209 sqlStorage->query( QStringLiteral("CREATE INDEX parent_playlist ON playlists( parent_id );") ); 0210 0211 sqlStorage->query( QString( "CREATE TABLE playlist_tracks (" 0212 " id " + sqlStorage->idType() + 0213 ", playlist_id INTEGER " 0214 ", track_num INTEGER " 0215 ", url " + sqlStorage->exactTextColumnType() + 0216 ", title " + sqlStorage->textColumnType() + 0217 ", album " + sqlStorage->textColumnType() + 0218 ", artist " + sqlStorage->textColumnType() + 0219 ", length INTEGER " 0220 ", uniqueid " + sqlStorage->textColumnType(128) + ") ENGINE = MyISAM;" ) ); 0221 0222 sqlStorage->query( QStringLiteral("CREATE INDEX parent_playlist_tracks ON playlist_tracks( playlist_id );") ); 0223 sqlStorage->query( QStringLiteral("CREATE INDEX playlist_tracks_uniqueid ON playlist_tracks( uniqueid );") ); 0224 } 0225 0226 void 0227 SqlUserPlaylistProvider::deleteTables() 0228 { 0229 DEBUG_BLOCK 0230 0231 auto sqlStorage = StorageManager::instance()->sqlStorage(); 0232 0233 if( !sqlStorage ) 0234 { 0235 debug() << "No SQL Storage available!"; 0236 return; 0237 } 0238 0239 sqlStorage->query( QStringLiteral("DROP INDEX parent_podchannel ON playlist_groups;") ); 0240 sqlStorage->query( QStringLiteral("DROP INDEX parent_playlist ON playlists;") ); 0241 sqlStorage->query( QStringLiteral("DROP INDEX parent_playlist_tracks ON playlist_tracks;") ); 0242 sqlStorage->query( QStringLiteral("DROP INDEX playlist_tracks_uniqueid ON playlist_tracks;") ); 0243 0244 sqlStorage->query( QStringLiteral("DROP TABLE IF EXISTS playlist_groups;") ); 0245 sqlStorage->query( QStringLiteral("DROP TABLE IF EXISTS playlists;") ); 0246 sqlStorage->query( QStringLiteral("DROP TABLE IF EXISTS playlist_tracks;") ); 0247 0248 } 0249 0250 void 0251 SqlUserPlaylistProvider::checkTables() 0252 { 0253 DEBUG_BLOCK 0254 0255 auto sqlStorage = StorageManager::instance()->sqlStorage(); 0256 QStringList values; 0257 0258 //Prevents amarok from crashing on bad DB 0259 if ( !sqlStorage ) 0260 return; 0261 0262 values = sqlStorage->query( QStringLiteral("SELECT version FROM admin WHERE component = '%1';").arg(sqlStorage->escape( key ) ) ); 0263 0264 if( values.isEmpty() ) 0265 { 0266 //debug() << "creating Playlist Tables"; 0267 createTables(); 0268 0269 sqlStorage->query( "INSERT INTO admin(component,version) " 0270 "VALUES('" + key + "'," + QString::number( USERPLAYLIST_DB_VERSION ) + ");" ); 0271 } 0272 else 0273 { 0274 int dbVersion = values.at( 0 ).toInt(); 0275 switch ( dbVersion ) 0276 { 0277 case 2: 0278 upgradeVersion2to3(); 0279 sqlStorage->query( "UPDATE admin SET version = '" + QString::number( USERPLAYLIST_DB_VERSION ) + "' WHERE component = '" + key + "';" ); 0280 case 3: // current version 0281 break; 0282 default: 0283 KMessageBox::error( 0284 nullptr, // QWidget *parent 0285 i18n( "Version %1 of playlist database schema encountered, however this " 0286 "Amarok version only supports version %2 (and previous versions " 0287 "starting with %2). Playlists saved in the Amarok Database probably " 0288 "will not work and any write operations with them may result in losing " 0289 "them. Perhaps you have started an older version of Amarok with a " 0290 "database written by newer version?", dbVersion, USERPLAYLIST_DB_VERSION ), 0291 i18nc( "the user's 'database version' is newer and unsupported by this software version", 0292 "Future version of Playlist Database?" ) ); 0293 } 0294 } 0295 } 0296 0297 void 0298 SqlUserPlaylistProvider::upgradeVersion2to3() 0299 { 0300 DEBUG_BLOCK 0301 auto sqlStorage = StorageManager::instance()->sqlStorage(); 0302 sqlStorage->query( QStringLiteral("ALTER TABLE playlists DROP COLUMN description") ); 0303 } 0304 0305 Playlists::SqlPlaylistList 0306 SqlUserPlaylistProvider::toSqlPlaylists( Playlists::PlaylistList playlists ) 0307 { 0308 Playlists::SqlPlaylistList sqlPlaylists; 0309 foreach( Playlists::PlaylistPtr playlist, playlists ) 0310 { 0311 Playlists::SqlPlaylistPtr sqlPlaylist = 0312 Playlists::SqlPlaylistPtr::dynamicCast( playlist ); 0313 if( !sqlPlaylist.isNull() ) 0314 sqlPlaylists << sqlPlaylist; 0315 } 0316 return sqlPlaylists; 0317 } 0318 0319 } //namespace Playlists 0320