mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-25 06:51:13 +02:00
start actually implementing tomahawk-side spotify sync
This commit is contained in:
@@ -119,8 +119,6 @@ SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg
|
|||||||
setConfiguration( config );
|
setConfiguration( config );
|
||||||
sync();
|
sync();
|
||||||
|
|
||||||
qDebug() << "SET SPOTIFY CREDS:" << credentials().value( "username" ) << credentials().value( "password" );
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,10 +126,11 @@ SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg
|
|||||||
const QString qid = msg.value( "qid" ).toString();
|
const QString qid = msg.value( "qid" ).toString();
|
||||||
if ( m_qidToSlotMap.contains( qid ) )
|
if ( m_qidToSlotMap.contains( qid ) )
|
||||||
{
|
{
|
||||||
const QString& slot = m_qidToSlotMap[ qid ];
|
QObject* receiver = m_qidToSlotMap[ qid ].first;
|
||||||
|
const QString& slot = m_qidToSlotMap[ qid ].second;
|
||||||
m_qidToSlotMap.remove( qid );
|
m_qidToSlotMap.remove( qid );
|
||||||
|
|
||||||
QMetaObject::invokeMethod( this, slot.toLatin1(), Q_ARG( QString, msgType ), Q_ARG( QVariantMap, msg ) );
|
QMetaObject::invokeMethod( receiver, slot.toLatin1(), Q_ARG( QString, msgType ), Q_ARG( QVariantMap, msg ) );
|
||||||
}
|
}
|
||||||
else if ( msgType == "allPlaylists" )
|
else if ( msgType == "allPlaylists" )
|
||||||
{
|
{
|
||||||
@@ -160,6 +159,63 @@ SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg
|
|||||||
m_configWidget.data()->setPlaylists( m_allSpotifyPlaylists );
|
m_configWidget.data()->setPlaylists( m_allSpotifyPlaylists );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if ( msgType == "tracksAdded" )
|
||||||
|
{
|
||||||
|
const QString plid = msg.value( "playlistid" ).toString();
|
||||||
|
// We should already be syncing this playlist if we get updates for it
|
||||||
|
Q_ASSERT( m_updaters.contains( plid ) );
|
||||||
|
|
||||||
|
if ( !m_updaters.contains( plid ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
SpotifyPlaylistUpdater* updater = m_updaters[ plid ];
|
||||||
|
Q_ASSERT( updater->sync() );
|
||||||
|
|
||||||
|
const int startPos = msg.value( "startPosition" ).toInt();
|
||||||
|
const QVariantList tracksList = msg.value( "tracks" ).toList();
|
||||||
|
const QString newRev = msg.value( "revid" ).toString();
|
||||||
|
const QString oldRev = msg.value( "oldRev" ).toString();
|
||||||
|
|
||||||
|
updater->spotifyTracksAdded( tracksList, startPos, newRev, oldRev );
|
||||||
|
}
|
||||||
|
else if ( msgType == "tracksRemoved" )
|
||||||
|
{
|
||||||
|
const QString plid = msg.value( "playlistid" ).toString();
|
||||||
|
// We should already be syncing this playlist if we get updates for it
|
||||||
|
Q_ASSERT( m_updaters.contains( plid ) );
|
||||||
|
|
||||||
|
if ( !m_updaters.contains( plid ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
SpotifyPlaylistUpdater* updater = m_updaters[ plid ];
|
||||||
|
Q_ASSERT( updater->sync() );
|
||||||
|
|
||||||
|
const QVariantList tracksList = msg.value( "tracks" ).toList();
|
||||||
|
const QString newRev = msg.value( "revid" ).toString();
|
||||||
|
const QString oldRev = msg.value( "oldRev" ).toString();
|
||||||
|
|
||||||
|
|
||||||
|
updater->spotifyTracksRemoved( tracksList, newRev, oldRev );
|
||||||
|
}
|
||||||
|
else if ( msgType == "tracksMoved" )
|
||||||
|
{
|
||||||
|
const QString plid = msg.value( "playlistid" ).toString();
|
||||||
|
// We should already be syncing this playlist if we get updates for it
|
||||||
|
Q_ASSERT( m_updaters.contains( plid ) );
|
||||||
|
|
||||||
|
if ( !m_updaters.contains( plid ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
SpotifyPlaylistUpdater* updater = m_updaters[ plid ];
|
||||||
|
Q_ASSERT( updater->sync() );
|
||||||
|
|
||||||
|
const QVariantList tracksList = msg.value( "tracks" ).toList();
|
||||||
|
const QString newRev = msg.value( "revid" ).toString();
|
||||||
|
const QString oldRev = msg.value( "oldRev" ).toString();
|
||||||
|
|
||||||
|
|
||||||
|
updater->spotifyTracksMoved( tracksList, newRev, oldRev );
|
||||||
|
}
|
||||||
else if ( msgType == "playlists" )
|
else if ( msgType == "playlists" )
|
||||||
{
|
{
|
||||||
// QList< Tomahawk::query_ptr > tracks;
|
// QList< Tomahawk::query_ptr > tracks;
|
||||||
@@ -245,7 +301,7 @@ SpotifyAccount::saveConfig()
|
|||||||
msg[ "playlistid" ] = pl->plid;
|
msg[ "playlistid" ] = pl->plid;
|
||||||
msg[ "sync" ] = pl->sync;
|
msg[ "sync" ] = pl->sync;
|
||||||
|
|
||||||
sendMessage( msg, "startPlaylistSyncWithPlaylist" );
|
sendMessage( msg, this, "startPlaylistSyncWithPlaylist" );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
stopPlaylistSync( pl );
|
stopPlaylistSync( pl );
|
||||||
@@ -260,30 +316,43 @@ SpotifyAccount::startPlaylistSyncWithPlaylist( const QString& msgType, const QVa
|
|||||||
qDebug() << Q_FUNC_INFO << "Got full spotify playlist body, creating a tomahawk playlist and enabling sync!!";
|
qDebug() << Q_FUNC_INFO << "Got full spotify playlist body, creating a tomahawk playlist and enabling sync!!";
|
||||||
const QString id = msg.value( "id" ).toString();
|
const QString id = msg.value( "id" ).toString();
|
||||||
const QString name = msg.value( "name" ).toString();
|
const QString name = msg.value( "name" ).toString();
|
||||||
|
const QString revid = msg.value( "revid" ).toString();
|
||||||
|
|
||||||
qDebug() << "Starting sync with pl:" << id << name;
|
qDebug() << "Starting sync with pl:" << id << name;
|
||||||
QVariantList tracks = msg.value( "tracks" ).toList();
|
QVariantList tracks = msg.value( "tracks" ).toList();
|
||||||
|
|
||||||
// create a list of query/plentries directly
|
// create a list of query/plentries directly
|
||||||
QList< query_ptr > queries;
|
QList< query_ptr > queries = SpotifyPlaylistUpdater::variantToQueries( tracks );
|
||||||
foreach ( const QVariant& trackV, tracks )
|
|
||||||
|
/**
|
||||||
|
* Begin syncing a playlist. Two options:
|
||||||
|
* 1) This is a playlist that has never been synced to tomahawk. Create a new one
|
||||||
|
* and attach a new SpotifyPlaylistUpdater to it
|
||||||
|
* 2) This was previously synced, and has since been unsynced. THe playlist is still around
|
||||||
|
* with an inactive SpotifyPlaylistUpdater, so just enable it and bring it up to date by merging current with new
|
||||||
|
* TODO: show a warning( "Do you want to overwrite with spotify's version?" )
|
||||||
|
*/
|
||||||
|
if ( m_updaters.contains( id ) )
|
||||||
{
|
{
|
||||||
const QVariantMap trackMap = trackV.toMap();
|
Q_ASSERT( m_updaters[ id ]->sync() == false ); /// Should have been unchecked/off before
|
||||||
qDebug() << "Adding spotify track to new tomahawk playlist:" << trackMap.value( "track" ).toString() << trackMap.value( "artist" ).toString() << trackMap.value( "album" ).toString();
|
m_updaters[ id ]->setSync( true );
|
||||||
query_ptr q = Query::get( trackMap.value( "artist" ).toString(), trackMap.value( "track" ).toString(), trackMap.value( "album" ).toString(), uuid(), false );
|
// m_updaters[ id ]->
|
||||||
q->setProperty( "spotifytrackid", trackMap.value( "id" ) );
|
// TODO
|
||||||
|
|
||||||
queries << q;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
playlist_ptr plPtr = Tomahawk::Playlist::create( SourceList::instance()->getLocal(),
|
||||||
|
uuid(),
|
||||||
|
name,
|
||||||
|
QString(),
|
||||||
|
QString(),
|
||||||
|
false,
|
||||||
|
queries );
|
||||||
|
|
||||||
playlist_ptr plPtr = Tomahawk::Playlist::create( SourceList::instance()->getLocal(),
|
SpotifyPlaylistUpdater* updater = new SpotifyPlaylistUpdater( this, revid, id, plPtr );
|
||||||
uuid(),
|
updater->setSync( true );
|
||||||
name,
|
m_updaters[ id ] = updater;
|
||||||
QString(),
|
}
|
||||||
QString(),
|
|
||||||
false,
|
|
||||||
queries );
|
|
||||||
SpotifyPlaylistUpdater* updater = new SpotifyPlaylistUpdater( this, plPtr );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -341,12 +410,12 @@ SpotifyAccount::addPlaylist( const QString &qid, const QString& title, QList< To
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
SpotifyAccount::sendMessage( const QVariantMap &m, const QString& slot )
|
SpotifyAccount::sendMessage( const QVariantMap &m, QObject* obj, const QString& slot )
|
||||||
{
|
{
|
||||||
QVariantMap msg = m;
|
QVariantMap msg = m;
|
||||||
const QString qid = QUuid::createUuid().toString().replace( "{", "" ).replace( "}", "" );
|
const QString qid = QUuid::createUuid().toString().replace( "{", "" ).replace( "}", "" );
|
||||||
|
|
||||||
m_qidToSlotMap[ qid ] = slot;
|
m_qidToSlotMap[ qid ] = qMakePair( obj, slot );
|
||||||
msg[ "qid" ] = qid;
|
msg[ "qid" ] = qid;
|
||||||
|
|
||||||
m_spotifyResolver.data()->sendMessage( msg );
|
m_spotifyResolver.data()->sendMessage( msg );
|
||||||
@@ -354,30 +423,16 @@ SpotifyAccount::sendMessage( const QVariantMap &m, const QString& slot )
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
SpotifyAccount::fetchFullPlaylist( SpotifyPlaylistInfo* playlist )
|
SpotifyAccount::registerUpdaterForPlaylist( const QString& plId, SpotifyPlaylistUpdater* updater )
|
||||||
{
|
{
|
||||||
|
m_updaters[ plId ] = updater;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
SpotifyAccount::startPlaylistSync( SpotifyPlaylistInfo* playlist )
|
SpotifyAccount::fetchFullPlaylist( SpotifyPlaylistInfo* playlist )
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Begin syncing a playlist. Two options:
|
|
||||||
* 1) This is a playlist that has never been synced to tomahawk. Create a new one
|
|
||||||
* and attach a new SpotifyPlaylistUpdater to it
|
|
||||||
* 2) This was previously synced, and has since been unsynced. THe playlist is still around
|
|
||||||
* with an inactive SpotifyPlaylistUpdater, so just enable it and bring it up to date.
|
|
||||||
*/
|
|
||||||
if ( m_updaters.contains( playlist->plid ) )
|
|
||||||
{
|
|
||||||
// update and re-sync
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -395,5 +450,5 @@ SpotifyAccount::loadPlaylists()
|
|||||||
// TODO cache this and only get changed?
|
// TODO cache this and only get changed?
|
||||||
QVariantMap msg;
|
QVariantMap msg;
|
||||||
msg[ "_msgtype" ] = "getAllPlaylists";
|
msg[ "_msgtype" ] = "getAllPlaylists";
|
||||||
sendMessage( msg, "allPlaylistsLoaded" );
|
sendMessage( msg, this, "allPlaylistsLoaded" );
|
||||||
}
|
}
|
||||||
|
@@ -93,6 +93,9 @@ public:
|
|||||||
Tomahawk::playlist_ptr playlist;
|
Tomahawk::playlist_ptr playlist;
|
||||||
};*/
|
};*/
|
||||||
|
|
||||||
|
void sendMessage( const QVariantMap& msg, QObject* receiver, const QString& slot );
|
||||||
|
void registerUpdaterForPlaylist( const QString& plId, SpotifyPlaylistUpdater* updater );
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void resolverMessage( const QString& msgType, const QVariantMap& msg );
|
void resolverMessage( const QString& msgType, const QVariantMap& msg );
|
||||||
|
|
||||||
@@ -103,9 +106,7 @@ private slots:
|
|||||||
private:
|
private:
|
||||||
void init();
|
void init();
|
||||||
void loadPlaylists();
|
void loadPlaylists();
|
||||||
void sendMessage( const QVariantMap& msg, const QString& slot );
|
|
||||||
|
|
||||||
void startPlaylistSync( SpotifyPlaylistInfo* playlist );
|
|
||||||
void stopPlaylistSync( SpotifyPlaylistInfo* playlist );
|
void stopPlaylistSync( SpotifyPlaylistInfo* playlist );
|
||||||
|
|
||||||
void fetchFullPlaylist( SpotifyPlaylistInfo* playlist );
|
void fetchFullPlaylist( SpotifyPlaylistInfo* playlist );
|
||||||
@@ -114,7 +115,7 @@ private:
|
|||||||
QWeakPointer<SpotifyAccountConfig> m_configWidget;
|
QWeakPointer<SpotifyAccountConfig> m_configWidget;
|
||||||
QWeakPointer<ScriptResolver> m_spotifyResolver;
|
QWeakPointer<ScriptResolver> m_spotifyResolver;
|
||||||
|
|
||||||
QMap<QString, QString> m_qidToSlotMap;
|
QMap<QString, QPair<QObject*, QString> > m_qidToSlotMap;
|
||||||
|
|
||||||
// List of synced spotify playlists in config UI
|
// List of synced spotify playlists in config UI
|
||||||
QList< SpotifyPlaylistInfo* > m_allSpotifyPlaylists;
|
QList< SpotifyPlaylistInfo* > m_allSpotifyPlaylists;
|
||||||
|
@@ -40,15 +40,44 @@ SpotifyUpdaterFactory::create( const Tomahawk::playlist_ptr& pl )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new SpotifyPlaylistUpdater( m_account, pl );
|
// Register the updater with the account
|
||||||
|
const QString spotifyId = QString( "playlistupdaters/%1" ).arg( pl->guid() );
|
||||||
|
Q_ASSERT( !spotifyId.isEmpty() );
|
||||||
|
SpotifyPlaylistUpdater* updater = new SpotifyPlaylistUpdater( m_account, pl );
|
||||||
|
m_account->registerUpdaterForPlaylist( spotifyId, updater );
|
||||||
|
|
||||||
|
return updater;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SpotifyPlaylistUpdater::SpotifyPlaylistUpdater( SpotifyAccount* acct, const playlist_ptr& pl )
|
SpotifyPlaylistUpdater::SpotifyPlaylistUpdater( SpotifyAccount* acct, const playlist_ptr& pl )
|
||||||
: PlaylistUpdaterInterface( pl )
|
: PlaylistUpdaterInterface( pl )
|
||||||
, m_spotify( acct )
|
, m_spotify( acct )
|
||||||
|
, m_sync( false )
|
||||||
|
{
|
||||||
|
// values will be loaded from settings
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SpotifyPlaylistUpdater::SpotifyPlaylistUpdater( SpotifyAccount* acct, const QString& revid, const QString& spotifyId, const playlist_ptr& pl )
|
||||||
|
: PlaylistUpdaterInterface( pl )
|
||||||
|
, m_spotify( acct )
|
||||||
|
, m_latestRev( revid )
|
||||||
|
, m_spotifyId( spotifyId )
|
||||||
|
, m_sync( false )
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SpotifyPlaylistUpdater::init()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
connect( playlist().data(), SIGNAL( tracksInserted( QList<Tomahawk::plentry_ptr>, int ) ), this, SLOT( tomahawkTracksInserted( QList<Tomahawk::plentry_ptr>, int ) ) );
|
||||||
|
connect( playlist().data(), SIGNAL( tracksRemoved( QList<Tomahawk::query_ptr> ) ), this, SLOT( tomahawkTracksRemoved( QList<Tomahawk::query_ptr> ) ) );
|
||||||
|
// TODO reorders in a playlist
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -60,30 +89,217 @@ SpotifyPlaylistUpdater::~SpotifyPlaylistUpdater()
|
|||||||
void
|
void
|
||||||
SpotifyPlaylistUpdater::loadFromSettings( const QString& group )
|
SpotifyPlaylistUpdater::loadFromSettings( const QString& group )
|
||||||
{
|
{
|
||||||
|
m_latestRev = TomahawkSettings::instance()->value( QString( "%1/latestrev" ).arg( group ) ).toString();
|
||||||
|
m_sync = TomahawkSettings::instance()->value( QString( "%1/sync" ).arg( group ) ).toBool();
|
||||||
|
m_spotifyId = TomahawkSettings::instance()->value( QString( "%1/spotifyId" ).arg( group ) ).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SpotifyPlaylistUpdater::removeFromSettings( const QString& group ) const
|
SpotifyPlaylistUpdater::removeFromSettings( const QString& group ) const
|
||||||
{
|
{
|
||||||
|
TomahawkSettings::instance()->remove( QString( "%1/latestrev" ).arg( group ) );
|
||||||
|
TomahawkSettings::instance()->remove( QString( "%1/sync" ).arg( group ) );
|
||||||
|
TomahawkSettings::instance()->remove( QString( "%1/spotifyId" ).arg( group ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
SpotifyPlaylistUpdater::saveToSettings( const QString& group ) const
|
SpotifyPlaylistUpdater::saveToSettings( const QString& group ) const
|
||||||
{
|
{
|
||||||
|
TomahawkSettings::instance()->setValue( QString( "%1/latestrev" ).arg( group ), m_latestRev );
|
||||||
|
TomahawkSettings::instance()->setValue( QString( "%1/sync" ).arg( group ), m_sync );
|
||||||
|
TomahawkSettings::instance()->setValue( QString( "%1/spotifyId" ).arg( group ), m_spotifyId );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QString
|
QString
|
||||||
SpotifyPlaylistUpdater::type() const
|
SpotifyPlaylistUpdater::type() const
|
||||||
{
|
{
|
||||||
return QString();
|
return "spotify";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
SpotifyPlaylistUpdater::updateNow()
|
SpotifyPlaylistUpdater::setSync( bool sync )
|
||||||
{
|
{
|
||||||
|
m_sync = sync;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
SpotifyPlaylistUpdater::sync() const
|
||||||
|
{
|
||||||
|
return m_sync;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SpotifyPlaylistUpdater::spotifyTracksAdded( const QVariantList& tracks, int startPos, const QString& newRev, const QString& oldRev )
|
||||||
|
{
|
||||||
|
const QList< query_ptr > queries = variantToQueries( tracks );
|
||||||
|
|
||||||
|
qDebug() << Q_FUNC_INFO << "inserting tracks in middle of tomahawk playlist, from spotify command!" << tracks << startPos << newRev << oldRev;
|
||||||
|
// Uh oh, dont' want to get out of sync!!
|
||||||
|
Q_ASSERT( m_latestRev == oldRev );
|
||||||
|
m_latestRev = newRev;
|
||||||
|
|
||||||
|
playlist()->insertEntries( queries, startPos, playlist()->currentrevision() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SpotifyPlaylistUpdater::spotifyTracksRemoved( const QVariantList& tracks, const QString& newRev, const QString& oldRev )
|
||||||
|
{
|
||||||
|
qDebug() << Q_FUNC_INFO << "remove tracks in middle of tomahawk playlist, from spotify command!" << tracks << newRev << oldRev;
|
||||||
|
// Uh oh, dont' want to get out of sync!!
|
||||||
|
Q_ASSERT( m_latestRev == oldRev );
|
||||||
|
m_latestRev = newRev;
|
||||||
|
|
||||||
|
QList< plentry_ptr > entries = playlist()->entries();
|
||||||
|
|
||||||
|
// FIXME UGH have to do a manual lookup for each track we want to remove... any ideas?
|
||||||
|
foreach( const QVariant& blob, tracks )
|
||||||
|
{
|
||||||
|
const QVariantMap trackMap = blob.toMap();
|
||||||
|
for ( QList<plentry_ptr>::iterator iter = entries.begin(); iter != entries.end(); ++iter )
|
||||||
|
{
|
||||||
|
const QString trackId = iter->data()->query()->property( "spotifytrackid" ).toString();
|
||||||
|
// easy case, we have a track id on both sides, so we're sure
|
||||||
|
if ( trackId.isEmpty() && trackId == trackMap.value( "id" ).toString() )
|
||||||
|
{
|
||||||
|
iter = entries.erase( iter );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fuzzy case, check metadata
|
||||||
|
if ( iter->data()->query()->track() == trackMap[ "track" ].toString() &&
|
||||||
|
iter->data()->query()->artist() == trackMap[ "artist" ].toString() &&
|
||||||
|
iter->data()->query()->album() == trackMap[ "album" ].toString() )
|
||||||
|
{
|
||||||
|
iter = entries.erase( iter );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "We were asked to delete:" << tracks.size() << "tracks from the playlist, and we deleted:" << ( playlist()->entries().size() - entries.size() );
|
||||||
|
playlist()->createNewRevision( uuid(), playlist()->currentrevision(), entries );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SpotifyPlaylistUpdater::spotifyTracksMoved( const QVariantList& tracks, const QString& newRev, const QString& oldRev )
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SpotifyPlaylistUpdater::tomahawkTracksInserted( const QList< plentry_ptr >& tracks, int pos )
|
||||||
|
{
|
||||||
|
// Notify the resolver that we've updated
|
||||||
|
qDebug() << Q_FUNC_INFO << "updating spotify resolver with inserted tracks at:" << pos << tracks;
|
||||||
|
QVariantMap msg;
|
||||||
|
msg[ "_msgtype" ] = "addTracksToPlaylist";
|
||||||
|
msg[ "oldrev" ] = m_latestRev;
|
||||||
|
msg[ "startPosition" ] = pos;
|
||||||
|
|
||||||
|
QVariantList tracksJson;
|
||||||
|
foreach ( const plentry_ptr& ple, tracks )
|
||||||
|
{
|
||||||
|
const query_ptr q = ple->query();
|
||||||
|
if ( q.isNull() )
|
||||||
|
{
|
||||||
|
qDebug() << "Got null query_ptr in plentry_ptr!!!" << ple;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tracksJson << queryToVariant( q );
|
||||||
|
}
|
||||||
|
msg[ "tracks" ] = tracksJson;
|
||||||
|
|
||||||
|
m_spotify->sendMessage( msg, this, "onTracksInsertedReturn" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SpotifyPlaylistUpdater::onTracksInsertedReturn( const QString& msgType, const QVariantMap& msg )
|
||||||
|
{
|
||||||
|
const bool success = msg.value( "success" ).toBool();
|
||||||
|
|
||||||
|
qDebug() << Q_FUNC_INFO << "GOT RETURN FOR tracksInserted call from spotify!" << msgType << msg << "Succeeded?" << success;
|
||||||
|
m_latestRev = msg.value( "revid" ).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SpotifyPlaylistUpdater::tomahawkTracksRemoved( const QList< query_ptr >& tracks )
|
||||||
|
{
|
||||||
|
qDebug() << Q_FUNC_INFO << "updating spotify resolver with removed tracks:" << tracks;
|
||||||
|
QVariantMap msg;
|
||||||
|
msg[ "_msgtype" ] = "removeTracksFromPlaylist";
|
||||||
|
msg[ "oldrev" ] = m_latestRev;
|
||||||
|
msg[ "tracks" ] = queriesToVariant( tracks );
|
||||||
|
|
||||||
|
m_spotify->sendMessage( msg, this, "onTracksRemovedReturn" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SpotifyPlaylistUpdater::onTracksRemovedReturn( const QString& msgType, const QVariantMap& msg )
|
||||||
|
{
|
||||||
|
const bool success = msg.value( "success" ).toBool();
|
||||||
|
|
||||||
|
qDebug() << Q_FUNC_INFO << "GOT RETURN FOR tracksRemoved call from spotify!" << msgType << msg << "Succeeded?" << success;
|
||||||
|
m_latestRev = msg.value( "revid" ).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QVariantList
|
||||||
|
SpotifyPlaylistUpdater::queriesToVariant( const QList< query_ptr >& queries )
|
||||||
|
{
|
||||||
|
QVariantList tracksJson;
|
||||||
|
foreach ( const query_ptr& q, queries )
|
||||||
|
{
|
||||||
|
QVariantMap m;
|
||||||
|
if ( q.isNull() )
|
||||||
|
continue;
|
||||||
|
tracksJson << queryToVariant( q );
|
||||||
|
}
|
||||||
|
|
||||||
|
return tracksJson;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QVariant
|
||||||
|
SpotifyPlaylistUpdater::queryToVariant( const query_ptr& query )
|
||||||
|
{
|
||||||
|
QVariantMap m;
|
||||||
|
m[ "track" ] = query->track();
|
||||||
|
m[ "artist" ] = query->artist();
|
||||||
|
m[ "album" ] = query->album();
|
||||||
|
|
||||||
|
if ( !query->property( "spotifytrackid" ).isNull() )
|
||||||
|
m[ "id" ] = query->property( "spotifytrackid" );
|
||||||
|
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QList< query_ptr >
|
||||||
|
SpotifyPlaylistUpdater::variantToQueries( const QVariantList& list )
|
||||||
|
{
|
||||||
|
QList< query_ptr > queries;
|
||||||
|
foreach ( const QVariant& blob, list )
|
||||||
|
{
|
||||||
|
QVariantMap trackMap = blob.toMap();
|
||||||
|
const query_ptr q = Query::get( trackMap.value( "artist" ).toString(), trackMap.value( "track" ).toString(), trackMap.value( "album" ).toString(), uuid(), false );
|
||||||
|
if ( trackMap.contains( "id" ) )
|
||||||
|
q->setProperty( "spotifytrackid", trackMap.value( "id" ) );
|
||||||
|
|
||||||
|
queries << q;
|
||||||
|
}
|
||||||
|
|
||||||
|
return queries;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
#define SPOTIFYPLAYLISTUPDATER_H
|
#define SPOTIFYPLAYLISTUPDATER_H
|
||||||
|
|
||||||
#include "playlist/PlaylistUpdaterInterface.h"
|
#include "playlist/PlaylistUpdaterInterface.h"
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
namespace Tomahawk {
|
namespace Tomahawk {
|
||||||
namespace Accounts {
|
namespace Accounts {
|
||||||
@@ -27,25 +28,53 @@ namespace Accounts {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class SpotifyPlaylistUpdater : public Tomahawk::PlaylistUpdaterInterface
|
class SpotifyPlaylistUpdater : public Tomahawk::PlaylistUpdaterInterface
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
friend class Tomahawk::Accounts::SpotifyAccount;
|
||||||
public:
|
public:
|
||||||
|
// used when creating anew
|
||||||
|
SpotifyPlaylistUpdater( Tomahawk::Accounts::SpotifyAccount* acct, const QString& revid, const QString& spotifyId, const Tomahawk::playlist_ptr& pl );
|
||||||
|
|
||||||
|
// used when inflating from config file
|
||||||
SpotifyPlaylistUpdater( Tomahawk::Accounts::SpotifyAccount* acct, const Tomahawk::playlist_ptr& pl );
|
SpotifyPlaylistUpdater( Tomahawk::Accounts::SpotifyAccount* acct, const Tomahawk::playlist_ptr& pl );
|
||||||
|
|
||||||
virtual ~SpotifyPlaylistUpdater();
|
virtual ~SpotifyPlaylistUpdater();
|
||||||
|
|
||||||
virtual QString type() const;
|
virtual QString type() const;
|
||||||
virtual void updateNow();
|
virtual void updateNow() {}
|
||||||
|
|
||||||
|
bool sync() const;
|
||||||
|
void setSync( bool sync );
|
||||||
|
|
||||||
|
/// Spotify callbacks when we are directly instructed from the resolver
|
||||||
|
void spotifyTracksAdded( const QVariantList& tracks, int startPos, const QString& newRev, const QString& oldRev );
|
||||||
|
void spotifyTracksRemoved( const QVariantList& tracks, const QString& newRev, const QString& oldRev );
|
||||||
|
void spotifyTracksMoved( const QVariantList& tracks, const QString& newRev, const QString& oldRev );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void removeFromSettings(const QString& group) const;
|
virtual void removeFromSettings(const QString& group) const;
|
||||||
virtual void saveToSettings(const QString& group) const;
|
virtual void saveToSettings(const QString& group) const;
|
||||||
virtual void loadFromSettings(const QString& group);
|
virtual void loadFromSettings(const QString& group);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void tomahawkTracksInserted( const QList<Tomahawk::plentry_ptr>& ,int );
|
||||||
|
void tomahawkTracksRemoved( const QList<Tomahawk::query_ptr>& );
|
||||||
|
|
||||||
|
// SpotifyResolver message handlers, all take msgtype, msg as argument
|
||||||
|
void onTracksInsertedReturn( const QString& msgType, const QVariantMap& msg );
|
||||||
|
void onTracksRemovedReturn( const QString& msgType, const QVariantMap& msg );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void init();
|
||||||
|
static QVariantList queriesToVariant( const QList< Tomahawk::query_ptr >& queries );
|
||||||
|
static QVariant queryToVariant( const Tomahawk::query_ptr& query );
|
||||||
|
static QList< Tomahawk::query_ptr > variantToQueries( const QVariantList& list );
|
||||||
|
|
||||||
Tomahawk::Accounts::SpotifyAccount* m_spotify;
|
Tomahawk::Accounts::SpotifyAccount* m_spotify;
|
||||||
|
QString m_latestRev, m_spotifyId;
|
||||||
|
bool m_sync;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
*
|
*
|
||||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||||
|
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||||
*
|
*
|
||||||
* Tomahawk is free software: you can redistribute it and/or modify
|
* Tomahawk is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -517,6 +518,27 @@ Playlist::addEntries( const QList<query_ptr>& queries, const QString& oldrev )
|
|||||||
createNewRevision( newrev, oldrev, el );
|
createNewRevision( newrev, oldrev, el );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Playlist::insertEntries( const QList< query_ptr >& queries, const int position, const QString& oldrev )
|
||||||
|
{
|
||||||
|
QList<plentry_ptr> toInsert = entriesFromQueries( queries, true );
|
||||||
|
QList<plentry_ptr> entries = m_entries;
|
||||||
|
|
||||||
|
Q_ASSERT( position < m_entries.size() );
|
||||||
|
if ( position >= m_entries.size() )
|
||||||
|
{
|
||||||
|
qWarning() << "ERROR trying to insert tracks past end of playlist! Appending!!";
|
||||||
|
addEntries( queries, oldrev );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( QList< plentry_ptr >::iterator iter = toInsert.end(); iter != toInsert.begin(); iter-- )
|
||||||
|
entries.insert( position, *iter );
|
||||||
|
|
||||||
|
qDebug() << "Done inserting playlist entries in the middle of the playlist! Committing...";
|
||||||
|
createNewRevision( uuid(), oldrev, entries );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QList<plentry_ptr>
|
QList<plentry_ptr>
|
||||||
Playlist::entriesFromQueries( const QList<Tomahawk::query_ptr>& queries, bool clearFirst )
|
Playlist::entriesFromQueries( const QList<Tomahawk::query_ptr>& queries, bool clearFirst )
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
*
|
*
|
||||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||||
|
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
|
||||||
*
|
*
|
||||||
* Tomahawk is free software: you can redistribute it and/or modify
|
* Tomahawk is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -37,6 +38,8 @@ class DatabaseCommand_LoadAllPlaylists;
|
|||||||
class DatabaseCommand_LoadAllSortedPlaylists;
|
class DatabaseCommand_LoadAllSortedPlaylists;
|
||||||
class DatabaseCommand_SetPlaylistRevision;
|
class DatabaseCommand_SetPlaylistRevision;
|
||||||
class DatabaseCommand_CreatePlaylist;
|
class DatabaseCommand_CreatePlaylist;
|
||||||
|
class PlaylistModel;
|
||||||
|
|
||||||
namespace Tomahawk
|
namespace Tomahawk
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -116,20 +119,21 @@ public:
|
|||||||
|
|
||||||
class DLLEXPORT Playlist : public QObject
|
class DLLEXPORT Playlist : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY( QString guid READ guid WRITE setGuid )
|
Q_PROPERTY( QString guid READ guid WRITE setGuid )
|
||||||
Q_PROPERTY( QString currentrevision READ currentrevision WRITE setCurrentrevision )
|
Q_PROPERTY( QString currentrevision READ currentrevision WRITE setCurrentrevision )
|
||||||
Q_PROPERTY( QString title READ title WRITE setTitle )
|
Q_PROPERTY( QString title READ title WRITE setTitle )
|
||||||
Q_PROPERTY( QString info READ info WRITE setInfo )
|
Q_PROPERTY( QString info READ info WRITE setInfo )
|
||||||
Q_PROPERTY( QString creator READ creator WRITE setCreator )
|
Q_PROPERTY( QString creator READ creator WRITE setCreator )
|
||||||
Q_PROPERTY( unsigned int createdon READ createdOn WRITE setCreatedOn )
|
Q_PROPERTY( unsigned int createdon READ createdOn WRITE setCreatedOn )
|
||||||
Q_PROPERTY( bool shared READ shared WRITE setShared )
|
Q_PROPERTY( bool shared READ shared WRITE setShared )
|
||||||
|
|
||||||
friend class ::DatabaseCommand_LoadAllPlaylists;
|
friend class ::DatabaseCommand_LoadAllPlaylists;
|
||||||
friend class ::DatabaseCommand_LoadAllSortedPlaylists;
|
friend class ::DatabaseCommand_LoadAllSortedPlaylists;
|
||||||
friend class ::DatabaseCommand_SetPlaylistRevision;
|
friend class ::DatabaseCommand_SetPlaylistRevision;
|
||||||
friend class ::DatabaseCommand_CreatePlaylist;
|
friend class ::DatabaseCommand_CreatePlaylist;
|
||||||
friend class DynamicPlaylist;
|
friend class DynamicPlaylist;
|
||||||
|
friend class ::PlaylistModel;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~Playlist();
|
virtual ~Playlist();
|
||||||
@@ -165,6 +169,7 @@ public:
|
|||||||
const QList< plentry_ptr >& entries() { return m_entries; }
|
const QList< plentry_ptr >& entries() { return m_entries; }
|
||||||
virtual void addEntry( const Tomahawk::query_ptr& query, const QString& oldrev );
|
virtual void addEntry( const Tomahawk::query_ptr& query, const QString& oldrev );
|
||||||
virtual void addEntries( const QList<Tomahawk::query_ptr>& queries, const QString& oldrev );
|
virtual void addEntries( const QList<Tomahawk::query_ptr>& queries, const QString& oldrev );
|
||||||
|
virtual void insertEntries( const QList<Tomahawk::query_ptr>& queries, const int position, const QString& oldrev );
|
||||||
|
|
||||||
// <IGNORE hack="true">
|
// <IGNORE hack="true">
|
||||||
// these need to exist and be public for the json serialization stuff
|
// these need to exist and be public for the json serialization stuff
|
||||||
@@ -182,6 +187,7 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
QList<plentry_ptr> entriesFromQueries( const QList<Tomahawk::query_ptr>& queries, bool clearFirst = false );
|
QList<plentry_ptr> entriesFromQueries( const QList<Tomahawk::query_ptr>& queries, bool clearFirst = false );
|
||||||
|
|
||||||
void setUpdater( PlaylistUpdaterInterface* interface ) { m_updater = interface; }
|
void setUpdater( PlaylistUpdaterInterface* interface ) { m_updater = interface; }
|
||||||
PlaylistUpdaterInterface* updater() const { return m_updater; }
|
PlaylistUpdaterInterface* updater() const { return m_updater; }
|
||||||
|
|
||||||
@@ -206,6 +212,13 @@ signals:
|
|||||||
/// was deleted, eh?
|
/// was deleted, eh?
|
||||||
void deleted( const Tomahawk::playlist_ptr& pl );
|
void deleted( const Tomahawk::playlist_ptr& pl );
|
||||||
|
|
||||||
|
/// Notification for tracks being inserted at a specific point
|
||||||
|
/// Contiguous range from startPosition
|
||||||
|
void tracksInserted( const QList< Tomahawk::plentry_ptr >& tracks, int startPosition );
|
||||||
|
|
||||||
|
/// Notification for tracks being removed from playlist
|
||||||
|
void tracksRemoved( const QList< Tomahawk::query_ptr >& tracks );
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
// want to update the playlist from the model?
|
// want to update the playlist from the model?
|
||||||
// generate a newrev using uuid() and call this:
|
// generate a newrev using uuid() and call this:
|
||||||
|
@@ -40,6 +40,7 @@ PlaylistModel::PlaylistModel( QObject* parent )
|
|||||||
: TrackModel( parent )
|
: TrackModel( parent )
|
||||||
, m_isTemporary( false )
|
, m_isTemporary( false )
|
||||||
, m_changesOngoing( false )
|
, m_changesOngoing( false )
|
||||||
|
, m_savedInsertPos( -1 )
|
||||||
{
|
{
|
||||||
m_dropStorage.parent = QPersistentModelIndex();
|
m_dropStorage.parent = QPersistentModelIndex();
|
||||||
m_dropStorage.row = -10;
|
m_dropStorage.row = -10;
|
||||||
@@ -202,6 +203,9 @@ PlaylistModel::insert( const QList< Tomahawk::plentry_ptr >& entries, int row )
|
|||||||
crows.first = c;
|
crows.first = c;
|
||||||
crows.second = c + entries.count() - 1;
|
crows.second = c + entries.count() - 1;
|
||||||
|
|
||||||
|
m_savedInsertPos = row;
|
||||||
|
m_savedInsertTracks = entries;
|
||||||
|
|
||||||
emit beginInsertRows( QModelIndex(), crows.first, crows.second );
|
emit beginInsertRows( QModelIndex(), crows.first, crows.second );
|
||||||
|
|
||||||
QList< Tomahawk::query_ptr > queries;
|
QList< Tomahawk::query_ptr > queries;
|
||||||
@@ -398,6 +402,18 @@ PlaylistModel::endPlaylistChanges()
|
|||||||
{
|
{
|
||||||
m_playlist->createNewRevision( newrev, m_playlist->currentrevision(), l );
|
m_playlist->createNewRevision( newrev, m_playlist->currentrevision(), l );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( m_savedInsertPos >= 0 )
|
||||||
|
{
|
||||||
|
emit m_playlist->tracksInserted( m_savedInsertTracks, m_savedInsertPos );
|
||||||
|
m_savedInsertPos = -1;
|
||||||
|
m_savedInsertTracks.clear();
|
||||||
|
}
|
||||||
|
else if ( !m_savedRemoveTracks.isEmpty() )
|
||||||
|
{
|
||||||
|
emit m_playlist->tracksRemoved( m_savedRemoveTracks );
|
||||||
|
m_savedRemoveTracks.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -442,6 +458,9 @@ PlaylistModel::remove( const QModelIndex& index, bool moreToCome )
|
|||||||
if ( !m_changesOngoing )
|
if ( !m_changesOngoing )
|
||||||
beginPlaylistChanges();
|
beginPlaylistChanges();
|
||||||
|
|
||||||
|
if ( item )
|
||||||
|
m_savedRemoveTracks << item->query();
|
||||||
|
|
||||||
TrackModel::remove( index, moreToCome );
|
TrackModel::remove( index, moreToCome );
|
||||||
|
|
||||||
if ( !moreToCome )
|
if ( !moreToCome )
|
||||||
|
@@ -100,6 +100,10 @@ private:
|
|||||||
QList< Tomahawk::Query* > m_waitingForResolved;
|
QList< Tomahawk::Query* > m_waitingForResolved;
|
||||||
QStringList m_waitForRevision;
|
QStringList m_waitForRevision;
|
||||||
|
|
||||||
|
int m_savedInsertPos;
|
||||||
|
QList< Tomahawk::plentry_ptr > m_savedInsertTracks;
|
||||||
|
QList< Tomahawk::query_ptr > m_savedRemoveTracks;
|
||||||
|
|
||||||
DropStorageData m_dropStorage;
|
DropStorageData m_dropStorage;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user