From cc7ecc679522987ac69f9d4854f07e0f1f5c1e3c Mon Sep 17 00:00:00 2001 From: Leo Franchi <lfranchi@kde.org> Date: Mon, 2 Apr 2012 09:41:35 -0400 Subject: [PATCH] allow updating playlist metadata --- .../spotify/SpotifyPlaylistUpdater.cpp | 8 +-- .../databasecommand_setplaylistrevision.cpp | 64 ++++++++++++++---- .../databasecommand_setplaylistrevision.h | 18 ++++- src/libtomahawk/playlist.cpp | 65 +++++++++++++++---- src/libtomahawk/playlist.h | 7 ++ 5 files changed, 129 insertions(+), 33 deletions(-) diff --git a/src/accounts/spotify/SpotifyPlaylistUpdater.cpp b/src/accounts/spotify/SpotifyPlaylistUpdater.cpp index b4c84f31a..5a3a6e7d2 100644 --- a/src/accounts/spotify/SpotifyPlaylistUpdater.cpp +++ b/src/accounts/spotify/SpotifyPlaylistUpdater.cpp @@ -295,8 +295,8 @@ SpotifyPlaylistUpdater::onTracksInsertedReturn( const QString& msgType, const QV Q_ASSERT( trackPositionsInserted.size() == trackIdsInserted.size() ); const QList< plentry_ptr > curEntries = playlist()->entries(); + QList< plentry_ptr > changed; - int changed = 0; for ( int i = 0; i < trackPositionsInserted.size(); i++ ) { const QVariant posV = trackPositionsInserted[ i ]; @@ -326,13 +326,13 @@ SpotifyPlaylistUpdater::onTracksInsertedReturn( const QString& msgType, const QV qDebug() << "Setting annotation for track:" << m_waitingForIds[ pos ]->query()->track() << m_waitingForIds[ pos ]->query()->artist() << trackIdsInserted.at( i ).toString(); m_waitingForIds[ pos ]->setAnnotation( trackIdsInserted.at( i ).toString() ); - changed++; + changed << m_waitingForIds[ pos ]; } m_waitingForIds.clear(); // Save our changes if we added some IDs - if ( changed > 0 ) - playlist()->createNewRevision( uuid(), playlist()->currentrevision(), playlist()->entries() ); + if ( changed.size() > 0 ) + playlist()->updateEntries( uuid(), playlist()->currentrevision(), changed ); } diff --git a/src/libtomahawk/database/databasecommand_setplaylistrevision.cpp b/src/libtomahawk/database/databasecommand_setplaylistrevision.cpp index 689bbb316..b6d431881 100644 --- a/src/libtomahawk/database/databasecommand_setplaylistrevision.cpp +++ b/src/libtomahawk/database/databasecommand_setplaylistrevision.cpp @@ -43,6 +43,7 @@ DatabaseCommand_SetPlaylistRevision::DatabaseCommand_SetPlaylistRevision( , m_oldrev( oldrev ) , m_addedentries( addedentries ) , m_entries( entries ) + , m_metadataUpdate( false ) { Q_ASSERT( !newrev.isEmpty() ); m_localOnly = ( newrev == oldrev ); @@ -57,6 +58,33 @@ DatabaseCommand_SetPlaylistRevision::DatabaseCommand_SetPlaylistRevision( } +DatabaseCommand_SetPlaylistRevision::DatabaseCommand_SetPlaylistRevision( + const source_ptr& s, + const QString& playlistguid, + const QString& newrev, + const QString& oldrev, + const QStringList& orderedguids, + const QList<plentry_ptr>& entriesToUpdate ) + : DatabaseCommandLoggable( s ) + , m_applied( false ) + , m_newrev( newrev ) + , m_oldrev( oldrev ) + , m_entries( entriesToUpdate ) + , m_metadataUpdate( true ) +{ + Q_ASSERT( !newrev.isEmpty() ); + m_localOnly = false; + + QVariantList tmp; + foreach( const QString& s, orderedguids ) + tmp << s; + + setOrderedguids( tmp ); + + setPlaylistguid( playlistguid ); +} + + void DatabaseCommand_SetPlaylistRevision::postCommitHook() { @@ -105,7 +133,7 @@ DatabaseCommand_SetPlaylistRevision::exec( DatabaseImpl* lib ) else { tDebug() << "Playlist:" << m_playlistguid << m_currentRevision << source()->friendlyName() << source()->id(); - throw "No such playlist, WTF?"; + Q_ASSERT_X( false, "DatabaseCommand_SetPlaylistRevision::exec", "No such playlist, WTF?" ); return; } @@ -132,20 +160,28 @@ DatabaseCommand_SetPlaylistRevision::exec( DatabaseImpl* lib ) return; } + else if ( m_metadataUpdate ) + { + QString sql = "UPDATE playlist_item SET trackname = ?, artistname = ?, albumname = ?, annotation = ?, duration = ?, addedon = ?, addedby = ? WHERE guid = ?"; + adde.prepare( sql ); + + foreach( const plentry_ptr& e, m_entries ) + { + + adde.bindValue( 0, e->query()->track() ); + adde.bindValue( 1, e->query()->artist() ); + adde.bindValue( 2, e->query()->album() ); + adde.bindValue( 3, e->annotation() ); + adde.bindValue( 4, (int) e->duration() ); + adde.bindValue( 5, e->lastmodified() ); + adde.bindValue( 6, source()->isLocal() ? QVariant(QVariant::Int) : source()->id() ); + adde.bindValue( 7, e->guid() ); + + adde.exec(); + } + } else { - // DEBUG only - qDebug() << "Current entries in the playlist_item table for this playlist:" << m_playlistguid; - TomahawkSqlQuery q = lib->newquery(); - q.prepare( "SELECT guid, playlist, trackname, artistname, annotation FROM playlist_item WHERE playlist = ?" ); - q.addBindValue( m_playlistguid ); - if ( q.exec() ) - { - while ( q.next() ) - { - qDebug() << "====" << q.value( 0 ).toString() << q.value( 1 ).toString() << q.value( 2 ).toString() << q.value( 3 ).toString() << q.value( 4 ).toString() << "===="; - } - } QString sql = "INSERT INTO playlist_item( guid, playlist, trackname, artistname, albumname, " "annotation, duration, addedon, addedby, result_hint ) " "VALUES( ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )"; @@ -154,7 +190,7 @@ DatabaseCommand_SetPlaylistRevision::exec( DatabaseImpl* lib ) qDebug() << "Num new playlist_items to add:" << m_addedentries.length(); foreach( const plentry_ptr& e, m_addedentries ) { - qDebug() << "Adding:" << e->guid() << e->query()->track() << e->query()->artist(); +// qDebug() << "Adding:" << e->guid() << e->query()->track() << e->query()->artist(); m_addedmap.insert( e->guid(), e ); // needed in postcommithook diff --git a/src/libtomahawk/database/databasecommand_setplaylistrevision.h b/src/libtomahawk/database/databasecommand_setplaylistrevision.h index 1033f7bfb..6ef20c945 100644 --- a/src/libtomahawk/database/databasecommand_setplaylistrevision.h +++ b/src/libtomahawk/database/databasecommand_setplaylistrevision.h @@ -35,15 +35,18 @@ Q_PROPERTY( QString newrev READ newrev WRITE setNewrev ) Q_PROPERTY( QString oldrev READ oldrev WRITE setOldrev ) Q_PROPERTY( QVariantList orderedguids READ orderedguids WRITE setOrderedguids ) Q_PROPERTY( QVariantList addedentries READ addedentriesV WRITE setAddedentriesV ) +Q_PROPERTY( bool metadataUpdate READ metadataUpdate WRITE setMetadataUpdate ) public: explicit DatabaseCommand_SetPlaylistRevision( QObject* parent = 0 ) : DatabaseCommandLoggable( parent ) , m_applied( false ) , m_localOnly( false ) + , m_metadataUpdate( false ) {} - explicit DatabaseCommand_SetPlaylistRevision( const source_ptr& s, + // Constructor for inserting or removing entries + DatabaseCommand_SetPlaylistRevision( const source_ptr& s, const QString& playlistguid, const QString& newrev, const QString& oldrev, @@ -51,6 +54,15 @@ public: const QList<Tomahawk::plentry_ptr>& addedentries, const QList<Tomahawk::plentry_ptr>& entries ); + // constructor for updating metadata only + DatabaseCommand_SetPlaylistRevision( const source_ptr& s, + const QString& playlistguid, + const QString& newrev, + const QString& oldrev, + const QStringList& orderedguids, + const QList<Tomahawk::plentry_ptr>& entriesToUpdate ); + + QString commandname() const { return "setplaylistrevision"; } virtual void exec( DatabaseImpl* lib ); @@ -89,6 +101,8 @@ public: QString newrev() const { return m_newrev; } QString oldrev() const { return m_oldrev; } QString playlistguid() const { return m_playlistguid; } + bool metadataUpdate() const { return m_metadataUpdate; } + void setMetadataUpdate( bool metadataUpdate ) { m_metadataUpdate = metadataUpdate; } void setOrderedguids( const QVariantList& l ) { m_orderedguids = l; } QVariantList orderedguids() const { return m_orderedguids; } @@ -106,7 +120,7 @@ private: QVariantList m_orderedguids; QList<Tomahawk::plentry_ptr> m_addedentries, m_entries; - bool m_localOnly; + bool m_localOnly, m_metadataUpdate; }; #endif // DATABASECOMMAND_SETPLAYLISTREVISION_H diff --git a/src/libtomahawk/playlist.cpp b/src/libtomahawk/playlist.cpp index c75b8cd77..cfa869300 100644 --- a/src/libtomahawk/playlist.cpp +++ b/src/libtomahawk/playlist.cpp @@ -319,9 +319,9 @@ Playlist::createNewRevision( const QString& newrev, const QString& oldrev, const foreach( const plentry_ptr& p, entries ) orderedguids << p->guid(); - qDebug() << "INSERTING ORDERED GUIDS:" << orderedguids << "and with new entries:"; - foreach( const plentry_ptr& p, added ) - qDebug() << p->guid(); +// qDebug() << "INSERTING ORDERED GUIDS:" << orderedguids << "and with new entries:"; +// foreach( const plentry_ptr& p, added ) +// qDebug() << p->guid(); // source making the change (local user in this case) source_ptr author = SourceList::instance()->getLocal(); @@ -339,6 +339,38 @@ Playlist::createNewRevision( const QString& newrev, const QString& oldrev, const } +void +Playlist::updateEntries( const QString& newrev, const QString& oldrev, const QList< plentry_ptr >& entries ) +{ + tDebug() << Q_FUNC_INFO << newrev << oldrev << entries.count(); + Q_ASSERT( m_source->isLocal() || newrev == oldrev ); + + if ( busy() ) + { + m_updateQueue.enqueue( RevisionQueueItem( newrev, oldrev, entries, oldrev == currentrevision() ) ); + return; + } + + if ( newrev != oldrev ) + setBusy( true ); + + QStringList orderedguids; + foreach( const plentry_ptr& p, m_entries ) + orderedguids << p->guid(); + + qDebug() << "Updating playlist metadata:" << entries; + DatabaseCommand_SetPlaylistRevision* cmd = + new DatabaseCommand_SetPlaylistRevision( SourceList::instance()->getLocal(), + guid(), + newrev, + oldrev, + orderedguids, + entries ); + + Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) ); +} + + // private, called when we loadRevision, or by our friend class DatabaseCommand_SetPlaylistRevision // used to save new revision data (either originating locally, or via network msg for syncing) void @@ -569,19 +601,9 @@ Playlist::insertEntries( const QList< query_ptr >& queries, const int position, return; } - qDebug() << "inserting entries. GUIDs before:"; - foreach( const plentry_ptr& p, entries ) - qDebug() << p->guid(); - for ( int i = toInsert.size()-1; i >= 0; --i ) entries.insert( position, toInsert.at(i) ); - qDebug() << "inserting entries. GUIDs AFTER:"; - foreach( const plentry_ptr& p, entries ) - qDebug() << p->guid(); - - const int prevSize = m_entries.size(); - qDebug() << "Done inserting playlist entries in the middle of the playlist! Committing..."; createNewRevision( uuid(), oldrev, entries ); // We are appending at end, so notify listeners. @@ -668,6 +690,23 @@ Playlist::checkRevisionQueue() } createNewRevision( item.newRev, item.oldRev, item.entries ); } + if ( !m_updateQueue.isEmpty() ) + { + RevisionQueueItem item = m_updateQueue.dequeue(); + + if ( item.oldRev != currentrevision() && item.applyToTip ) + { + // this was applied to the then-latest, but the already-running operation changed it so it's out of date now. fix it + if ( item.oldRev == item.newRev ) + { + checkRevisionQueue(); + return; + } + + item.oldRev = currentrevision(); + } + updateEntries( item.newRev, item.oldRev, item.entries ); + } } diff --git a/src/libtomahawk/playlist.h b/src/libtomahawk/playlist.h index 78f3e3745..fb9cddd8f 100644 --- a/src/libtomahawk/playlist.h +++ b/src/libtomahawk/playlist.h @@ -223,6 +223,12 @@ public slots: // want to update the playlist from the model? // generate a newrev using uuid() and call this: void createNewRevision( const QString& newrev, const QString& oldrev, const QList< plentry_ptr >& entries ); + + // Want to update some metadata of a plentry_ptr? this gets you a new revision too. + // entries should be <= entries(), with changed metadata. + void updateEntries( const QString& newrev, const QString& oldrev, const QList< plentry_ptr >& entries ); + + void reportCreated( const Tomahawk::playlist_ptr& self ); void reportDeleted( const Tomahawk::playlist_ptr& self ); @@ -286,6 +292,7 @@ private: QList< plentry_ptr > m_entries; QQueue<RevisionQueueItem> m_revisionQueue; + QQueue<RevisionQueueItem> m_updateQueue; PlaylistUpdaterInterface* m_updater;