mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-24 14:42:53 +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 );
|
||||
sync();
|
||||
|
||||
qDebug() << "SET SPOTIFY CREDS:" << credentials().value( "username" ) << credentials().value( "password" );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -128,10 +126,11 @@ SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg
|
||||
const QString qid = msg.value( "qid" ).toString();
|
||||
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 );
|
||||
|
||||
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" )
|
||||
{
|
||||
@@ -160,6 +159,63 @@ SpotifyAccount::resolverMessage( const QString &msgType, const QVariantMap &msg
|
||||
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" )
|
||||
{
|
||||
// QList< Tomahawk::query_ptr > tracks;
|
||||
@@ -245,7 +301,7 @@ SpotifyAccount::saveConfig()
|
||||
msg[ "playlistid" ] = pl->plid;
|
||||
msg[ "sync" ] = pl->sync;
|
||||
|
||||
sendMessage( msg, "startPlaylistSyncWithPlaylist" );
|
||||
sendMessage( msg, this, "startPlaylistSyncWithPlaylist" );
|
||||
}
|
||||
else
|
||||
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!!";
|
||||
const QString id = msg.value( "id" ).toString();
|
||||
const QString name = msg.value( "name" ).toString();
|
||||
const QString revid = msg.value( "revid" ).toString();
|
||||
|
||||
qDebug() << "Starting sync with pl:" << id << name;
|
||||
QVariantList tracks = msg.value( "tracks" ).toList();
|
||||
|
||||
// create a list of query/plentries directly
|
||||
QList< query_ptr > queries;
|
||||
foreach ( const QVariant& trackV, tracks )
|
||||
QList< query_ptr > queries = SpotifyPlaylistUpdater::variantToQueries( 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();
|
||||
qDebug() << "Adding spotify track to new tomahawk playlist:" << trackMap.value( "track" ).toString() << trackMap.value( "artist" ).toString() << trackMap.value( "album" ).toString();
|
||||
query_ptr q = Query::get( trackMap.value( "artist" ).toString(), trackMap.value( "track" ).toString(), trackMap.value( "album" ).toString(), uuid(), false );
|
||||
q->setProperty( "spotifytrackid", trackMap.value( "id" ) );
|
||||
|
||||
queries << q;
|
||||
Q_ASSERT( m_updaters[ id ]->sync() == false ); /// Should have been unchecked/off before
|
||||
m_updaters[ id ]->setSync( true );
|
||||
// m_updaters[ id ]->
|
||||
// TODO
|
||||
}
|
||||
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(),
|
||||
uuid(),
|
||||
name,
|
||||
QString(),
|
||||
QString(),
|
||||
false,
|
||||
queries );
|
||||
SpotifyPlaylistUpdater* updater = new SpotifyPlaylistUpdater( this, plPtr );
|
||||
SpotifyPlaylistUpdater* updater = new SpotifyPlaylistUpdater( this, revid, id, plPtr );
|
||||
updater->setSync( true );
|
||||
m_updaters[ id ] = updater;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -341,12 +410,12 @@ SpotifyAccount::addPlaylist( const QString &qid, const QString& title, QList< To
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::sendMessage( const QVariantMap &m, const QString& slot )
|
||||
SpotifyAccount::sendMessage( const QVariantMap &m, QObject* obj, const QString& slot )
|
||||
{
|
||||
QVariantMap msg = m;
|
||||
const QString qid = QUuid::createUuid().toString().replace( "{", "" ).replace( "}", "" );
|
||||
|
||||
m_qidToSlotMap[ qid ] = slot;
|
||||
m_qidToSlotMap[ qid ] = qMakePair( obj, slot );
|
||||
msg[ "qid" ] = qid;
|
||||
|
||||
m_spotifyResolver.data()->sendMessage( msg );
|
||||
@@ -354,30 +423,16 @@ SpotifyAccount::sendMessage( const QVariantMap &m, const QString& slot )
|
||||
|
||||
|
||||
void
|
||||
SpotifyAccount::fetchFullPlaylist( SpotifyPlaylistInfo* playlist )
|
||||
SpotifyAccount::registerUpdaterForPlaylist( const QString& plId, SpotifyPlaylistUpdater* updater )
|
||||
{
|
||||
|
||||
m_updaters[ plId ] = updater;
|
||||
}
|
||||
|
||||
|
||||
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?
|
||||
QVariantMap msg;
|
||||
msg[ "_msgtype" ] = "getAllPlaylists";
|
||||
sendMessage( msg, "allPlaylistsLoaded" );
|
||||
sendMessage( msg, this, "allPlaylistsLoaded" );
|
||||
}
|
||||
|
@@ -93,6 +93,9 @@ public:
|
||||
Tomahawk::playlist_ptr playlist;
|
||||
};*/
|
||||
|
||||
void sendMessage( const QVariantMap& msg, QObject* receiver, const QString& slot );
|
||||
void registerUpdaterForPlaylist( const QString& plId, SpotifyPlaylistUpdater* updater );
|
||||
|
||||
private slots:
|
||||
void resolverMessage( const QString& msgType, const QVariantMap& msg );
|
||||
|
||||
@@ -103,9 +106,7 @@ private slots:
|
||||
private:
|
||||
void init();
|
||||
void loadPlaylists();
|
||||
void sendMessage( const QVariantMap& msg, const QString& slot );
|
||||
|
||||
void startPlaylistSync( SpotifyPlaylistInfo* playlist );
|
||||
void stopPlaylistSync( SpotifyPlaylistInfo* playlist );
|
||||
|
||||
void fetchFullPlaylist( SpotifyPlaylistInfo* playlist );
|
||||
@@ -114,7 +115,7 @@ private:
|
||||
QWeakPointer<SpotifyAccountConfig> m_configWidget;
|
||||
QWeakPointer<ScriptResolver> m_spotifyResolver;
|
||||
|
||||
QMap<QString, QString> m_qidToSlotMap;
|
||||
QMap<QString, QPair<QObject*, QString> > m_qidToSlotMap;
|
||||
|
||||
// List of synced spotify playlists in config UI
|
||||
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 )
|
||||
: PlaylistUpdaterInterface( pl )
|
||||
, 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
|
||||
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
|
||||
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
|
||||
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
|
||||
SpotifyPlaylistUpdater::type() const
|
||||
{
|
||||
return QString();
|
||||
return "spotify";
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
|
||||
#include "playlist/PlaylistUpdaterInterface.h"
|
||||
#include <QVariant>
|
||||
|
||||
namespace Tomahawk {
|
||||
namespace Accounts {
|
||||
@@ -27,25 +28,53 @@ namespace Accounts {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SpotifyPlaylistUpdater : public Tomahawk::PlaylistUpdaterInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class Tomahawk::Accounts::SpotifyAccount;
|
||||
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 );
|
||||
|
||||
virtual ~SpotifyPlaylistUpdater();
|
||||
|
||||
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:
|
||||
virtual void removeFromSettings(const QString& group) const;
|
||||
virtual void saveToSettings(const QString& group) const;
|
||||
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:
|
||||
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;
|
||||
QString m_latestRev, m_spotifyId;
|
||||
bool m_sync;
|
||||
};
|
||||
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
/* === This file is part of Tomahawk Player - <http://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
|
||||
* 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 );
|
||||
}
|
||||
|
||||
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>
|
||||
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> ===
|
||||
*
|
||||
* 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
|
||||
* 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_SetPlaylistRevision;
|
||||
class DatabaseCommand_CreatePlaylist;
|
||||
class PlaylistModel;
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
|
||||
@@ -116,20 +119,21 @@ public:
|
||||
|
||||
class DLLEXPORT Playlist : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY( QString guid READ guid WRITE setGuid )
|
||||
Q_PROPERTY( QString currentrevision READ currentrevision WRITE setCurrentrevision )
|
||||
Q_PROPERTY( QString title READ title WRITE setTitle )
|
||||
Q_PROPERTY( QString info READ info WRITE setInfo )
|
||||
Q_PROPERTY( QString creator READ creator WRITE setCreator )
|
||||
Q_PROPERTY( unsigned int createdon READ createdOn WRITE setCreatedOn )
|
||||
Q_PROPERTY( bool shared READ shared WRITE setShared )
|
||||
Q_OBJECT
|
||||
Q_PROPERTY( QString guid READ guid WRITE setGuid )
|
||||
Q_PROPERTY( QString currentrevision READ currentrevision WRITE setCurrentrevision )
|
||||
Q_PROPERTY( QString title READ title WRITE setTitle )
|
||||
Q_PROPERTY( QString info READ info WRITE setInfo )
|
||||
Q_PROPERTY( QString creator READ creator WRITE setCreator )
|
||||
Q_PROPERTY( unsigned int createdon READ createdOn WRITE setCreatedOn )
|
||||
Q_PROPERTY( bool shared READ shared WRITE setShared )
|
||||
|
||||
friend class ::DatabaseCommand_LoadAllPlaylists;
|
||||
friend class ::DatabaseCommand_LoadAllSortedPlaylists;
|
||||
friend class ::DatabaseCommand_SetPlaylistRevision;
|
||||
friend class ::DatabaseCommand_CreatePlaylist;
|
||||
friend class DynamicPlaylist;
|
||||
friend class ::PlaylistModel;
|
||||
|
||||
public:
|
||||
virtual ~Playlist();
|
||||
@@ -165,6 +169,7 @@ public:
|
||||
const QList< plentry_ptr >& entries() { return m_entries; }
|
||||
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 insertEntries( const QList<Tomahawk::query_ptr>& queries, const int position, const QString& oldrev );
|
||||
|
||||
// <IGNORE hack="true">
|
||||
// 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 );
|
||||
|
||||
void setUpdater( PlaylistUpdaterInterface* interface ) { m_updater = interface; }
|
||||
PlaylistUpdaterInterface* updater() const { return m_updater; }
|
||||
|
||||
@@ -206,6 +212,13 @@ signals:
|
||||
/// was deleted, eh?
|
||||
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:
|
||||
// want to update the playlist from the model?
|
||||
// generate a newrev using uuid() and call this:
|
||||
|
@@ -40,6 +40,7 @@ PlaylistModel::PlaylistModel( QObject* parent )
|
||||
: TrackModel( parent )
|
||||
, m_isTemporary( false )
|
||||
, m_changesOngoing( false )
|
||||
, m_savedInsertPos( -1 )
|
||||
{
|
||||
m_dropStorage.parent = QPersistentModelIndex();
|
||||
m_dropStorage.row = -10;
|
||||
@@ -202,6 +203,9 @@ PlaylistModel::insert( const QList< Tomahawk::plentry_ptr >& entries, int row )
|
||||
crows.first = c;
|
||||
crows.second = c + entries.count() - 1;
|
||||
|
||||
m_savedInsertPos = row;
|
||||
m_savedInsertTracks = entries;
|
||||
|
||||
emit beginInsertRows( QModelIndex(), crows.first, crows.second );
|
||||
|
||||
QList< Tomahawk::query_ptr > queries;
|
||||
@@ -398,6 +402,18 @@ PlaylistModel::endPlaylistChanges()
|
||||
{
|
||||
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 )
|
||||
beginPlaylistChanges();
|
||||
|
||||
if ( item )
|
||||
m_savedRemoveTracks << item->query();
|
||||
|
||||
TrackModel::remove( index, moreToCome );
|
||||
|
||||
if ( !moreToCome )
|
||||
|
@@ -100,6 +100,10 @@ private:
|
||||
QList< Tomahawk::Query* > m_waitingForResolved;
|
||||
QStringList m_waitForRevision;
|
||||
|
||||
int m_savedInsertPos;
|
||||
QList< Tomahawk::plentry_ptr > m_savedInsertTracks;
|
||||
QList< Tomahawk::query_ptr > m_savedRemoveTracks;
|
||||
|
||||
DropStorageData m_dropStorage;
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user