diff --git a/src/libtomahawk/contextmenu.cpp b/src/libtomahawk/contextmenu.cpp index d3d2e6421..73752e0bb 100644 --- a/src/libtomahawk/contextmenu.cpp +++ b/src/libtomahawk/contextmenu.cpp @@ -36,7 +36,7 @@ ContextMenu::ContextMenu( QWidget* parent ) m_sigmap = new QSignalMapper( this ); connect( m_sigmap, SIGNAL( mapped( int ) ), SLOT( onTriggered( int ) ) ); - m_supportedActions = ActionPlay | ActionQueue | ActionCopyLink | ActionAddToPlaylist; + m_supportedActions = ActionPlay | ActionQueue | ActionCopyLink; } ContextMenu::~ContextMenu() @@ -77,25 +77,6 @@ ContextMenu::setQueries( const QList& queries ) if ( m_supportedActions & ActionQueue ) m_sigmap->setMapping( addAction( tr( "Add to &Queue" ) ), ActionQueue ); - - - if ( m_supportedActions & ActionAddToPlaylist ){ - - QList p = SourceList::instance()->getLocal()->collection()->playlists(); - QMenu *addTo = new QMenu("Add to"); - for(int i = 0; i< p.count(); i++){ - m_sigmap->setMapping( addTo->addAction( p[i]->title() ), p[i]->guid() ); - m_sigmap->setMapping( addMenu( addTo ), ActionAddToPlaylist ); - } - - foreach ( QAction* action, addTo->actions() ) - connect( action, SIGNAL( triggered() ), m_sigmap, SLOT( map() ) ); - - connect(m_sigmap, SIGNAL(mapped(QString)), - this, SLOT(onAction(QString))); - - } - addSeparator(); if ( m_supportedActions & ActionCopyLink && itemCount() == 1 ) @@ -204,22 +185,6 @@ ContextMenu::setArtist( const Tomahawk::artist_ptr& artist ) setArtists( artists ); } - -void -ContextMenu::onClicked( int action ) -{ - qDebug() << Q_FUNC_INFO << "Action:" << action; -} - -void -ContextMenu::onAction( const QString& what ) -{ - playlist_ptr p = SourceList::instance()->getLocal()->collection()->playlist( what ); - p->addEntries( m_queries, p->currentrevision()); - qDebug() << Q_FUNC_INFO << "Adding track to guid" << what << "With title" << p->title(); -} - - void ContextMenu::onTriggered( int action ) { @@ -262,7 +227,6 @@ void ContextMenu::addToQueue() void ContextMenu::copyLink() { - qDebug() << Q_FUNC_INFO; if ( m_queries.count() ) { GlobalActionManager::instance()->copyToClipboard( m_queries.first() ); diff --git a/src/libtomahawk/contextmenu.h b/src/libtomahawk/contextmenu.h index 167723ebf..a610de4d5 100644 --- a/src/libtomahawk/contextmenu.h +++ b/src/libtomahawk/contextmenu.h @@ -38,8 +38,7 @@ public: ActionPlay = 1, ActionQueue = 2, ActionDelete = 4, - ActionCopyLink = 8, - ActionAddToPlaylist = 9 + ActionCopyLink = 8 }; @@ -64,21 +63,18 @@ public: signals: void triggered( int action ); - void clicked( int action ); private slots: void onTriggered( int action ); - void onClicked( int action ); void copyLink(); void addToQueue(); - void onAction(const QString& what); + private: QSignalMapper* m_sigmap; int m_supportedActions; QList m_queries; QList m_artists; - playlist_ptr m_playlist; QList m_albums; }; diff --git a/src/libtomahawk/dropjob.cpp b/src/libtomahawk/dropjob.cpp index f981133ec..de6666b7a 100644 --- a/src/libtomahawk/dropjob.cpp +++ b/src/libtomahawk/dropjob.cpp @@ -33,6 +33,8 @@ #include "utils/xspfloader.h" using namespace Tomahawk; +bool DropJob::s_canParseSpotifyPlaylists = false; + DropJob::DropJob( QObject *parent ) : QObject( parent ) , m_queryCount( 0 ) @@ -62,39 +64,8 @@ DropJob::mimeTypes() } bool -DropJob::DropAction() +DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType, DropJob::DropAction acceptedAction ) { - - if ( dropAction() == DropJob::Create ) - return true; - return false; - -} - - -bool -DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType, DropJob::DropActions acceptedAction) -{ - - - if (acceptedType.testFlag(DropJob::None)) - qDebug() << Q_FUNC_INFO << "AcceptedType is None"; - - if (acceptedType.testFlag(DropJob::All)) - qDebug() << Q_FUNC_INFO << "AcceptedType is All"; - - if (acceptedType.testFlag(DropJob::Playlist)) - qDebug() << Q_FUNC_INFO << "AcceptedType is Playlist"; - - if (acceptedType.testFlag(DropJob::Track)) - qDebug() << Q_FUNC_INFO << "AcceptedType is Track"; - - if (acceptedAction.testFlag(DropJob::Append)) - qDebug() << Q_FUNC_INFO << "AcceptedAction is Append"; - - if (acceptedAction.testFlag(DropJob::Create)) - qDebug() << Q_FUNC_INFO << "AcceptedAction is Create"; - if ( data->hasFormat( "application/tomahawk.query.list" ) || data->hasFormat( "application/tomahawk.plentry.list" ) || data->hasFormat( "application/tomahawk.result.list" ) @@ -106,59 +77,49 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType return true; } - if( data->hasFormat( "text/plain" ) - && data->data( "text/plain" ).contains( "xspf" ) - && ( acceptedType.testFlag(DropJob::Playlist) || acceptedType.testFlag(DropJob::All) ) - && acceptedAction.testFlag(DropJob::Create) - ) - return true; + // check plain text url types + if ( !data->hasFormat( "text/plain" ) ) + return false; - // crude check for spotify playlists - if ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "spotify" ) - && data->data( "text/plain" ).contains( "playlist" ) - && ( acceptedType.testFlag(DropJob::Playlist) || acceptedType.testFlag(DropJob::All) ) - ) - return true; + const QString url = data->data( "text/plain" ); - // crude check for itunes tracks - if ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "itunes" ) - && data->data( "text/plain" ).contains( "album" ) - && ( acceptedType.testFlag(DropJob::Track) - || acceptedType.testFlag(DropJob::Album) - || acceptedType.testFlag(DropJob::All) - ) - ) - return true; + if ( acceptedType.testFlag( Playlist ) ) + { + if( url.contains( "xspf" ) ) + return true; - // crude check for itunes artist - if ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "itunes" ) - && data->data( "text/plain" ).contains( "artist" ) - && ( acceptedType.testFlag(DropJob::Track) || acceptedType.testFlag(DropJob::All) ) - ) - return true; + // Not the most elegant + if ( url.contains( "spotify" ) && url.contains( "playlist" ) && s_canParseSpotifyPlaylists ) + return true; + } - // crude check for spotify tracks - if ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "spotify" ) - && data->data( "text/plain" ).contains( "track" ) - && ( acceptedType.testFlag(DropJob::Track) || acceptedType.testFlag(DropJob::All) ) - ) - return true; + if ( acceptedType.testFlag( Track ) ) + { + if ( url.contains( "itunes" ) && url.contains( "album" ) ) // YES itunes is fucked up and song links have album/ in the url. + return true; - // crude check for rdio tracks - if ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "rdio.com" ) - && data->data( "text/plain" ).contains( "track" ) - && ( acceptedType.testFlag(DropJob::Track) || acceptedType.testFlag(DropJob::All) ) - ) - return true; + if ( url.contains( "spotify" ) && url.contains( "track" ) ) + return true; + if ( url.contains( "rdio.com" ) && url.contains( "track" ) ) + return true; + } + + if ( acceptedType.testFlag( Album ) ) + { + if ( url.contains( "itunes" ) && url.contains( "album" ) ) // YES itunes is fucked up and song links have album/ in the url. + return true; + } + + if ( acceptedType.testFlag( Artist ) ) + { + if ( url.contains( "itunes" ) && url.contains( "artist" ) ) // YES itunes is fucked up and song links have album/ in the url. + return true; + } // We whitelist t.co and bit.ly (and j.mp) since they do some link checking. Often playable (e.g. spotify..) links hide behind them, // so we do an extra level of lookup - if ( ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "bit.ly" ) ) || - ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "j.mp" ) ) || - ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "t.co" ) ) || - ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "rd.io" ) ) - && ( acceptedType.testFlag(DropJob::Track) || acceptedType.testFlag(DropJob::All) ) ) + if ( url.contains( "bit.ly" ) || url.contains( "j.mp" ) || url.contains( "t.co" ) || url.contains( "rd.io" ) ) return true; return false; @@ -202,26 +163,6 @@ DropJob::tracksFromMimeData( const QMimeData* data, bool allowDuplicates, bool o void DropJob::parseMimeData( const QMimeData *data ) { - qDebug() << Q_FUNC_INFO << data->hasText(); - - if(dropTypes() & DropJob::Playlist) - qDebug() << Q_FUNC_INFO << "DropType is Playlist"; - if(dropTypes() & DropJob::All) - qDebug() << Q_FUNC_INFO << "DropType is All"; - if(dropTypes() & DropJob::Track) - qDebug() << Q_FUNC_INFO << "DropType is Track"; - if(dropTypes() & DropJob::Artist) - qDebug() << Q_FUNC_INFO << "DropType is Artist"; - if(DropTypes() & DropJob::None) - qDebug() << Q_FUNC_INFO << "DropType is None"; - else qDebug() << "DropType is I DONT KNOW!"; - - if(dropAction() == DropJob::Append) - qDebug() << Q_FUNC_INFO << "DropAction is Append"; - if(dropAction() == DropJob::Create) - qDebug() << Q_FUNC_INFO << "DropAction is Create"; - - QList< query_ptr > results; if ( data->hasFormat( "application/tomahawk.query.list" ) ) results = tracksFromQueryList( data ); @@ -235,13 +176,12 @@ DropJob::parseMimeData( const QMimeData *data ) tracksFromMixedData( data ); else if ( data->hasFormat( "text/plain" ) ) { - QString plainData = QString::fromUtf8( data->data( "text/plain" ).constData() ); - qDebug() << Q_FUNC_INFO << "Got text/plain mime data:" << data->data( "text/plain" ) << "decoded to:" << plainData.trimmed(); + const QString plainData = QString::fromUtf8( data->data( "text/plain" ) ); - if ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "xspf" ) ) - handleXspf( data->data( "text/plain" ).trimmed(), DropAction() ); - else if ( plainData.contains( "spotify" ) && plainData.contains( "playlist" ) ) - handleSpPlaylist( plainData, DropAction() ); + if ( plainData.contains( "xspf" ) ) + handleXspf( data->data( "text/plain" ).trimmed() ); + else if ( plainData.contains( "spotify" ) && plainData.contains( "playlist" ) && s_canParseSpotifyPlaylists ) + handleSpPlaylist( plainData ); else handleTrackUrls ( plainData ); } @@ -426,87 +366,77 @@ DropJob::tracksFromMixedData( const QMimeData *data ) } void -DropJob::handleXspf( const QString& fileUrl, bool createNewPlaylist ) +DropJob::handleXspf( const QString& fileUrl ) { - qDebug() << Q_FUNC_INFO << "Got xspf playlist!!" << fileUrl; + tDebug() << Q_FUNC_INFO << "Got xspf playlist!!" << fileUrl; - // Doing like so on *nix, dont know really how files are - // passed on others. - qDebug() << "Got xspf playlist!!"; - QString newFile = fileUrl; - newFile.replace("file://", ""); - QFile xspfFile(newFile); - XSPFLoader* l = new XSPFLoader( createNewPlaylist, this ); - tDebug( LOGINFO ) << "Loading local xspf:" << newFile; - l->load( xspfFile ); + // Doing like so on *nix, dont know really how files are + // passed on others. + // TODO look in to! +// QString newFile = fileUrl; +// newFile.replace("file://", ""); +// QFile xspfFile(newFile); +// XSPFLoader* l = new XSPFLoader( createNewPlaylist, this ); +// tDebug( LOGINFO ) << "Loading local xspf:" << newFile; +// l->load( xspfFile ); } void -DropJob::handleSpPlaylist( const QString& url, bool createNewPlaylist) +DropJob::handleSpPlaylist( const QString& url ) { - qDebug() << "Got spotify playlist!!" << url; - if ( url.contains( "open.spotify.com/user") || - url.contains( "spotify:user" ) ) - { - // Lets create a valid playlist uri - QString playlistUri = url; - QString validUri; + QString playlistUri = url; + if ( url.contains( "open.spotify.com/user" ) ) // convert to a URI + { + playlistUri.replace("http://open.spotify.com/", ""); + playlistUri.replace( "/", ":" ); + playlistUri = "spotify:" + playlistUri; + } - if(url.contains( "open.spotify.com/user")){ - playlistUri.replace("http://open.spotify.com/", ""); - QStringList playlist = playlistUri.split( "/" ); - validUri = "spotify:" + playlist.join(":"); - }else validUri = playlistUri; + tDebug() << "Got a spotify playlist uri in dropjob!" << playlistUri; + SpotifyParser* spot = new SpotifyParser( playlistUri, dropAction() == Create, this ); - tDebug() << "Got a spotify playlist in dropjob!" << validUri; - SpotifyParser* spot = new SpotifyParser( validUri, this, createNewPlaylist); - - //This currently supports draging and dropping a spotify playlist - if(createNewPlaylist){ - qDebug() << Q_FUNC_INFO << "Got spotify playlist!! Create new" << url; - }else{ - qDebug() << Q_FUNC_INFO << "Got spotify playlist!!" << url; - connect( spot, SIGNAL( tracks( QList ) ), this, SLOT( onTracksAdded( QList< Tomahawk::query_ptr > ) ) ); - } - - m_queryCount++; - } + //This currently supports draging and dropping a spotify playlist + if ( dropAction() == Append ) + { + tDebug() << Q_FUNC_INFO << "Asking for spotify playlist contents from" << playlistUri; + connect( spot, SIGNAL( tracks( QList ) ), this, SLOT( onTracksAdded( QList< Tomahawk::query_ptr > ) ) ); + } + m_queryCount++; } void DropJob::handleTrackUrls( const QString& urls ) { - qDebug() << Q_FUNC_INFO << urls; - - - + // TODO REMOVE HACK if ( urls.contains( "open.spotify.com/user") || urls.contains( "spotify:user" ) ) - handleSpPlaylist( urls, dropAction() ); - + { + Q_ASSERT( false ); +// handleSpPlaylist( urls, dropAction() ); + } else if ( urls.contains( "itunes.apple.com") ) { - QStringList tracks = urls.split(QRegExp("\\s+"), QString::SkipEmptyParts); + QStringList tracks = urls.split( QRegExp( "\\s+" ), QString::SkipEmptyParts ); tDebug() << "Got a list of itunes urls!" << tracks; ItunesParser* itunes = new ItunesParser( tracks, this ); connect( itunes, SIGNAL( tracks( QList ) ), this, SLOT( onTracksAdded( QList< Tomahawk::query_ptr > ) ) ); m_queryCount++; } - else if ( urls.contains( "open.spotify.com/track") || - urls.contains( "spotify:track" ) ) + else if ( urls.contains( "open.spotify.com/track") || urls.contains( "spotify:track" ) ) { - QStringList tracks = urls.split(QRegExp("\\s+"), QString::SkipEmptyParts); + QStringList tracks = urls.split( QRegExp( "\\s+" ), QString::SkipEmptyParts ); tDebug() << "Got a list of spotify urls!" << tracks; SpotifyParser* spot = new SpotifyParser( tracks, this ); connect( spot, SIGNAL( tracks( QList ) ), this, SLOT( onTracksAdded( QList< Tomahawk::query_ptr > ) ) ); m_queryCount++; - } else if ( urls.contains( "rdio.com" ) ) + } + else if ( urls.contains( "rdio.com" ) ) { QStringList tracks = urls.split( "\n" ); diff --git a/src/libtomahawk/dropjob.h b/src/libtomahawk/dropjob.h index cc4267633..47b7e18a2 100644 --- a/src/libtomahawk/dropjob.h +++ b/src/libtomahawk/dropjob.h @@ -45,40 +45,53 @@ public: */ enum DropType { + None = 0x00, + Playlist = 0x01, + Track = 0x02, + Album = 0x04, + Artist = 0x08, - None = 0x00, - Playlist = 0x01, - Track = 0x02, - Album = 0x04, - Artist = 0x08, - All = 0x10 - }; + All = 0xFF + }; + Q_DECLARE_FLAGS(DropTypes, DropType) - Q_DECLARE_FLAGS(DropTypes, DropType) + enum DropAction { + Append = 0, + Create + }; - enum DropAction { + /** + * Returns if the caller should accept this mimetype. + * + * \param data The mimetype object to check + * \param type The type of drop content to accept + * \param action What action is requested from the content, if not all data types support all actions + */ + static bool acceptsMimeData( const QMimeData* data, DropJob::DropTypes type = All, DropAction action = Append ); - Append = 0x00, - Create = 0x01 - - }; - Q_DECLARE_FLAGS(DropActions, DropAction) - - - static bool acceptsMimeData( const QMimeData* data, DropJob::DropTypes type = All, DropJob::DropActions action = Append ); static QStringList mimeTypes(); - virtual void setDropTypes( DropTypes types ) { m_dropTypes = types; } - virtual void setDropAction( DropAction action ) { m_dropAction = action; } - virtual DropTypes dropTypes() const { return m_dropTypes; } - virtual DropAction dropAction() const { return m_dropAction; } + /// Set the drop types that should be extracted from this drop + void setDropTypes( DropTypes types ) { m_dropTypes = types; } + + /// Set the action that the drop should do. For example, if dropping a playlist, Create will create a new playlist but Append will generate the raw tracks + void setDropAction( DropAction action ) { m_dropAction = action; } + + DropTypes dropTypes() const { return m_dropTypes; } + DropAction dropAction() const { return m_dropAction; } + + /** + * Begin the parsing of the mime data. The resulting tracks are exposed in the various signals + */ void parseMimeData( const QMimeData* data ); + void setGetWholeArtists( bool getWholeArtists ); void setGetWholeAlbums( bool getWholeAlbums ); void tracksFromMimeData( const QMimeData* data, bool allowDuplicates = false, bool onlyLocal = false, bool top10 = false ); - void handleXspf( const QString& file, bool createNewPlaylist = false ); - void handleSpPlaylist( const QString& url, bool createNewPlaylist = false ); + void handleXspf( const QString& file ); + void handleSpPlaylist( const QString& url ); + static void setCanParseSpotifyPlaylists( bool parseable ) { s_canParseSpotifyPlaylists = parseable; } signals: /// QMimeData parsing results void tracks( const QList< Tomahawk::query_ptr >& tracks ); @@ -115,9 +128,11 @@ private: bool m_top10; DropTypes m_dropTypes; DropAction m_dropAction; - bool DropAction(); QList< Tomahawk::query_ptr > m_resultList; + + static bool s_canParseSpotifyPlaylists; }; + Q_DECLARE_OPERATORS_FOR_FLAGS(DropJob::DropTypes) #endif // DROPJOB_H diff --git a/src/libtomahawk/playlist/playlistview.h b/src/libtomahawk/playlist/playlistview.h index 237cfe249..57065e1a3 100644 --- a/src/libtomahawk/playlist/playlistview.h +++ b/src/libtomahawk/playlist/playlistview.h @@ -23,7 +23,6 @@ #include "playlist/playlistmodel.h" #include "trackview.h" #include "viewpage.h" -#include "dropjob.h" #include "dllmacro.h" class DLLEXPORT PlaylistView : public TrackView, public Tomahawk::ViewPage @@ -68,9 +67,6 @@ private slots: private: PlaylistModel* m_model; - bool m_resizing; - bool m_dragging; - QRect m_dropRect; QString m_customTitle; QString m_customDescripton; diff --git a/src/libtomahawk/playlist/trackview.cpp b/src/libtomahawk/playlist/trackview.cpp index ae83c6416..5903c9b4e 100644 --- a/src/libtomahawk/playlist/trackview.cpp +++ b/src/libtomahawk/playlist/trackview.cpp @@ -89,7 +89,7 @@ TrackView::TrackView( QWidget* parent ) TrackView::~TrackView() { - qDebug() << Q_FUNC_INFO; + tDebug() << Q_FUNC_INFO; delete m_header; } @@ -119,7 +119,7 @@ void TrackView::setModel( QAbstractItemModel* model ) { Q_UNUSED( model ); - qDebug() << "Explicitly use setTrackModel instead"; + tDebug() << "Explicitly use setTrackModel instead"; Q_ASSERT( false ); } @@ -180,7 +180,7 @@ TrackView::onItemActivated( const QModelIndex& index ) TrackModelItem* item = m_model->itemFromIndex( m_proxyModel->mapToSource( index ) ); if ( item && !item->query().isNull() && item->query()->numResults() ) { - qDebug() << "Result activated:" << item->query()->toString() << item->query()->results().first()->url(); + tDebug() << "Result activated:" << item->query()->toString() << item->query()->results().first()->url(); m_proxyModel->setCurrentIndex( index ); AudioEngine::instance()->playItem( m_proxyModel, item->query()->results().first() ); } @@ -207,7 +207,7 @@ TrackView::keyPressEvent( QKeyEvent* event ) void TrackView::onItemResized( const QModelIndex& index ) { - qDebug() << Q_FUNC_INFO; + tDebug() << Q_FUNC_INFO; m_delegate->updateRowSize( index ); } @@ -243,7 +243,7 @@ TrackView::resizeEvent( QResizeEvent* event ) void TrackView::dragEnterEvent( QDragEnterEvent* event ) { - qDebug() << Q_FUNC_INFO; + tDebug() << Q_FUNC_INFO; QTreeView::dragEnterEvent( event ); if ( DropJob::acceptsMimeData( event->mimeData() ) ) @@ -251,7 +251,6 @@ TrackView::dragEnterEvent( QDragEnterEvent* event ) m_dragging = true; m_dropRect = QRect(); - qDebug() << Q_FUNC_INFO << "Accepting Drag Event"; event->acceptProposedAction(); } } @@ -306,7 +305,7 @@ TrackView::dropEvent( QDropEvent* event ) if ( event->isAccepted() ) { - qDebug() << "Ignoring accepted event!"; + tDebug() << "Ignoring accepted event!"; } else { @@ -315,7 +314,7 @@ TrackView::dropEvent( QDropEvent* event ) const QPoint pos = event->pos(); const QModelIndex index = indexAt( pos ); - qDebug() << Q_FUNC_INFO << "Drop Event accepted at row:" << index.row(); + tDebug() << Q_FUNC_INFO << "Drop Event accepted at row:" << index.row(); event->acceptProposedAction(); if ( !model()->isReadOnly() ) @@ -395,7 +394,7 @@ TrackView::startDrag( Qt::DropActions supportedActions ) if ( indexes.count() == 0 ) return; - qDebug() << "Dragging" << indexes.count() << "indexes"; + tDebug() << "Dragging" << indexes.count() << "indexes"; QMimeData* data = m_proxyModel->mimeData( indexes ); if ( !data ) return; diff --git a/src/libtomahawk/utils/itunesparser.cpp b/src/libtomahawk/utils/itunesparser.cpp index 3a406cbf2..4ce127df6 100644 --- a/src/libtomahawk/utils/itunesparser.cpp +++ b/src/libtomahawk/utils/itunesparser.cpp @@ -31,23 +31,22 @@ using namespace Tomahawk; -ItunesParser::ItunesParser( const QStringList& Urls, QObject* parent, bool createNewPlaylist) +ItunesParser::ItunesParser( const QStringList& urls, QObject* parent ) : QObject ( parent ) , m_single( false ) { - m_createNewPlaylist = createNewPlaylist; - foreach ( const QString& url, Urls ){ + foreach ( const QString& url, urls ) + { lookupItunesUri( url ); } } -ItunesParser::ItunesParser( const QString& Url, QObject* parent, bool createNewPlaylist ) +ItunesParser::ItunesParser( const QString& Url, QObject* parent ) : QObject ( parent ) , m_single( true ) { - m_createNewPlaylist = createNewPlaylist; lookupItunesUri( Url ); } @@ -69,17 +68,21 @@ ItunesParser::lookupItunesUri( const QString& link ) // Doing a parse on regex in 2 stages, // first, look if we have both album and track id - int pos = rxAlbumTrack.indexIn(link); - if (pos > -1) { - id = rxAlbumTrack.cap(1); - trackId = rxAlbumTrack.cap(2); - }else{ - + int pos = rxAlbumTrack.indexIn( link ); + if ( pos > -1 ) { + id = rxAlbumTrack.cap( 1 ); + trackId = rxAlbumTrack.cap( 2 ); + } + else + { // Second, if we dont have trackId, check for just Id - int pos = rxId.indexIn(link); - if (pos > -1) { - id = rxId.cap(1); - }else return; + int pos = rxId.indexIn( link ); + if ( pos > -1 ) + { + id = rxId.cap( 1 ); + } + else + return; } @@ -89,7 +92,8 @@ ItunesParser::lookupItunesUri( const QString& link ) QUrl url; if( link.contains( "artist" ) ) url = QUrl( QString( "http://ax.phobos.apple.com.edgesuite.net/WebObjects/MZStoreServices.woa/wa/wsLookup?id=%1&entity=song&limit=30" ).arg( id ) ); - else url = QUrl( QString( "http://ax.phobos.apple.com.edgesuite.net/WebObjects/MZStoreServices.woa/wa/wsLookup?id=%1&entity=song" ).arg( ( trackId.isEmpty() ? id : trackId ) ) ); + else + url = QUrl( QString( "http://ax.phobos.apple.com.edgesuite.net/WebObjects/MZStoreServices.woa/wa/wsLookup?id=%1&entity=song" ).arg( ( trackId.isEmpty() ? id : trackId ) ) ); qDebug() << "Looking up..." << url.toString(); @@ -125,11 +129,13 @@ ItunesParser::itunesResponseLookupFinished() } QVariantList itunesResponse = res.value( "results" ).toList(); - foreach(QVariant itune, itunesResponse){ + foreach ( QVariant itune, itunesResponse ) + { QString title, artist, album; QVariantMap ituneMap = itune.toMap(); - if( ituneMap.value( "wrapperType" ).toString().contains( "track" ) ){ + if ( ituneMap.value( "wrapperType" ).toString().contains( "track" ) ) + { title = ituneMap.value( "trackName" ).toString(); artist = ituneMap.value( "artistName" ).toString(); @@ -146,7 +152,6 @@ ItunesParser::itunesResponseLookupFinished() } } - } else { tLog() << "Error in network request to Itunes for track decoding:" << r->errorString(); @@ -156,7 +161,6 @@ ItunesParser::itunesResponseLookupFinished() } - void ItunesParser::checkTrackFinished() { diff --git a/src/libtomahawk/utils/itunesparser.h b/src/libtomahawk/utils/itunesparser.h index df847416b..6c100458f 100644 --- a/src/libtomahawk/utils/itunesparser.h +++ b/src/libtomahawk/utils/itunesparser.h @@ -29,11 +29,12 @@ class QNetworkReply; class TrackModel; + namespace Tomahawk { /** - * Small class to parse spotify links into query_ptrs + * Small class to parse itunes links into query_ptrs * * Connect to the signals to get the results */ @@ -41,16 +42,13 @@ class DLLEXPORT ItunesParser : public QObject { Q_OBJECT public: - explicit ItunesParser( const QString& trackUrl, QObject* parent = 0, bool createNewPl = false ); - explicit ItunesParser( const QStringList& trackUrls, QObject* parent = 0, bool createNewPl = false); + explicit ItunesParser( const QString& trackUrl, QObject* parent = 0 ); + explicit ItunesParser( const QStringList& trackUrls, QObject* parent = 0 ); virtual ~ItunesParser(); - signals: void track( const Tomahawk::query_ptr& track ); void tracks( const QList< Tomahawk::query_ptr > tracks ); - void playlist( const Tomahawk::query_ptr& playlist ); - private slots: void itunesResponseLookupFinished(); @@ -60,7 +58,6 @@ private: void checkTrackFinished(); bool m_single; - bool m_createNewPlaylist; QList< query_ptr > m_tracks; QSet< QNetworkReply* > m_queries; QString m_title, m_info, m_creator; diff --git a/src/libtomahawk/utils/spotifyparser.cpp b/src/libtomahawk/utils/spotifyparser.cpp index 0051a0035..14a07f6c9 100644 --- a/src/libtomahawk/utils/spotifyparser.cpp +++ b/src/libtomahawk/utils/spotifyparser.cpp @@ -29,21 +29,23 @@ using namespace Tomahawk; -SpotifyParser::SpotifyParser( const QStringList& Urls, QObject* parent, bool createNewPlaylist) +SpotifyParser::SpotifyParser( const QStringList& Urls, bool createNewPlaylist, QObject* parent ) : QObject ( parent ) , m_single( false ) + , m_trackMode( true ) + , m_createNewPlaylist( createNewPlaylist ) { - m_createNewPlaylist = createNewPlaylist; foreach ( const QString& url, Urls ) lookupUrl( url ); } -SpotifyParser::SpotifyParser( const QString& Url, QObject* parent, bool createNewPlaylist ) +SpotifyParser::SpotifyParser( const QString& Url, bool createNewPlaylist, QObject* parent ) : QObject ( parent ) , m_single( true ) + , m_trackMode( true ) + , m_createNewPlaylist( createNewPlaylist ) { - m_createNewPlaylist = createNewPlaylist; lookupUrl( Url ); } @@ -56,12 +58,18 @@ SpotifyParser::~SpotifyParser() void SpotifyParser::lookupUrl( const QString& link ) { - if( link.contains( "track" ) ) - lookupTrack(link); + { + m_trackMode = true; + lookupTrack( link ); + } else if( link.contains( "playlist" ) ) + { + m_trackMode = false; lookupPlaylist( link ); - else return; // We only support tracks and playlists + } + else + return; // We only support tracks and playlists } @@ -72,9 +80,8 @@ SpotifyParser::lookupPlaylist( const QString& link ) if ( !link.contains( "spotify:user:" ) ) // we only support playlist here return; - QString uri = link; - tLog() << "Parsing Spotify Playlist URI:" << uri; - QUrl url = QUrl( QString( "http://www.trushuffle.com:5512/playlist/%1" ).arg( uri ) ); + tLog() << "Parsing Spotify Playlist URI:" << link; + QUrl url = QUrl( QString( SPOTIFY_PLAYLIST_API_URL "/playlist/%1" ).arg( link ) ); tDebug() << "Looking up URL..." << url.toString(); QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) ); @@ -100,10 +107,8 @@ SpotifyParser::lookupTrack( const QString& link ) uri = QString( "spotify:track:%1" ).arg( hash ); } - tLog() << "Parsing Spotify Track URI:" << uri; - QUrl url = QUrl( QString( "http://ws.spotify.com/lookup/1/.json?uri=%1" ).arg( uri ) ); - tDebug() << "Looking up..." << url.toString(); + tLog() << "Looking up spotify track information..." << url.toString(); QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) ); connect( reply, SIGNAL( finished() ), this, SLOT( spotifyTrackLookupFinished() ) ); @@ -118,6 +123,7 @@ SpotifyParser::spotifyPlaylistLookupFinished() { QNetworkReply* r = qobject_cast< QNetworkReply* >( sender() ); Q_ASSERT( r ); + m_queries.remove( r ); r->deleteLater(); @@ -132,28 +138,25 @@ SpotifyParser::spotifyPlaylistLookupFinished() tLog() << "Failed to parse json from Spotify playlist lookup:" << p.errorString() << "On line" << p.errorLine(); checkTrackFinished(); return; - } else if ( !res.contains( "tracks" ) ) + } + else if ( !res.contains( "tracks" ) ) { - tLog() << "No 'tracks' item in the spotify playlist lookup result... not doing anything"; + tLog() << "No tracks' item in the spotify playlist lookup result... not doing anything"; checkTrackFinished(); return; } QVariantList trackResponse = res.value( "tracks" ).toList(); - if(!trackResponse.isEmpty()){ + if ( !trackResponse.isEmpty() ) + { m_title = res.value( "title" ).toString(); m_creator = res.value( "creator" ).toString(); qDebug() << "playlist owner: " << m_creator; } - foreach(QVariant track, trackResponse){ - - QString title, artist, album; - title = track.toMap().value( "title" ).toString(); - artist = track.toMap().value( "artists" ).toList().first().toString(); - album = track.toMap().value( "album" ).toString(); - Tomahawk::query_ptr q = Tomahawk::Query::get( artist, title, album, uuid(), true ); - m_tracks << q; + foreach( QVariant track, trackResponse ) + { + lookupTrack( track.toString() ); } } else @@ -218,7 +221,10 @@ SpotifyParser::spotifyTrackLookupFinished() tLog() << "Error in network request to Spotify for track decoding:" << r->errorString(); } - checkTrackFinished(); + if ( m_trackMode ) + checkTrackFinished(); + else + checkPlaylistFinished(); } void @@ -226,7 +232,7 @@ SpotifyParser::checkPlaylistFinished() { if ( m_queries.isEmpty() ) // we're done { - if(m_createNewPlaylist) + if( m_createNewPlaylist ) m_playlist = Playlist::create( SourceList::instance()->getLocal(), uuid(), m_title, diff --git a/src/libtomahawk/utils/spotifyparser.h b/src/libtomahawk/utils/spotifyparser.h index b7381fe4f..1270c29de 100644 --- a/src/libtomahawk/utils/spotifyparser.h +++ b/src/libtomahawk/utils/spotifyparser.h @@ -27,6 +27,8 @@ #include #include +#define SPOTIFY_PLAYLIST_API_URL "http://spotikea.tomahawk-player.org:10380" + class QNetworkReply; namespace Tomahawk { @@ -40,8 +42,8 @@ class DLLEXPORT SpotifyParser : public QObject { Q_OBJECT public: - explicit SpotifyParser( const QString& trackUrl, QObject* parent = 0, bool createNewPl = false ); - explicit SpotifyParser( const QStringList& trackUrls, QObject* parent = 0, bool createNewPl = false); + explicit SpotifyParser( const QString& trackUrl, bool createNewPlaylist = false, QObject* parent = 0 ); + explicit SpotifyParser( const QStringList& trackUrls, bool createNewPlaylist = false, QObject* parent = 0 ); virtual ~SpotifyParser(); signals: @@ -59,7 +61,9 @@ private: void lookupPlaylist( const QString& playlist ); void checkTrackFinished(); void checkPlaylistFinished(); + bool m_single; + bool m_trackMode; bool m_createNewPlaylist; QList< query_ptr > m_tracks; QSet< QNetworkReply* > m_queries; diff --git a/src/sourcetree/sourcetreeview.cpp b/src/sourcetree/sourcetreeview.cpp index 00c04cfe6..9ad9ff59f 100644 --- a/src/sourcetree/sourcetreeview.cpp +++ b/src/sourcetree/sourcetreeview.cpp @@ -27,7 +27,7 @@ #include #include #include -#include "libtomahawk/pipeline.h" + #include "playlist.h" #include "viewmanager.h" #include "sourcesproxymodel.h" @@ -40,7 +40,6 @@ #include "tomahawksettings.h" #include "globalactionmanager.h" #include "dropjob.h" -#include "resolversmodel.h" #include "utils/logger.h" #include "items/genericpageitems.h" #include "items/temporarypageitem.h" @@ -160,16 +159,6 @@ SourceTreeView::setupMenus() m_copyPlaylistAction = m_playlistMenu.addAction( tr( "&Copy Link" ) ); m_deletePlaylistAction = m_playlistMenu.addAction( tr( "&Delete %1" ).arg( SourcesModel::rowTypeToString( type ) ) ); - // Add a menu for spotify export - TomahawkSettings* settings = TomahawkSettings::instance(); - foreach(QString resolver, settings->enabledScriptResolvers() ){ - if( resolver.contains( "spotify" ) ){ - QAction *m_addToSpotify = m_playlistMenu.addAction( tr( "Add to &Spotify" ) ); - connect( m_addToSpotify, SIGNAL( triggered() ), SLOT( addToSpotify() ) ); - break; - } - } - QString addToText = QString( "Add to my %1" ); if ( type == SourcesModel::StaticPlaylist ) addToText = addToText.arg( "Playlists" ); @@ -252,36 +241,6 @@ SourceTreeView::loadPlaylist() onItemActivated( m_contextMenuIndex ); } -void -SourceTreeView::addToSpotify( ) -{ - qDebug() << Q_FUNC_INFO; - - QModelIndex idx = m_contextMenuIndex; - if ( !idx.isValid() ) - return; - - SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( idx, SourcesModel::SourceTreeItemTypeRole ).toInt(); - if ( type == SourcesModel::StaticPlaylist ) - { - PlaylistItem* item = itemFromIndex< PlaylistItem >( idx ); - playlist_ptr playlist = item->playlist(); - qDebug() << Q_FUNC_INFO << "Static playlist" << playlist->title(); - // Do something with playlist -> spotify() - - } else if( type == SourcesModel::AutomaticPlaylist || type == SourcesModel::Station ) - { - DynamicPlaylistItem* item = itemFromIndex< DynamicPlaylistItem >( idx ); - dynplaylist_ptr playlist = item->dynPlaylist(); - qDebug() << Q_FUNC_INFO << "Dynamic playlist" << playlist->title(); - } - - - -} - - - void SourceTreeView::deletePlaylist( const QModelIndex& idxIn ) { @@ -533,20 +492,18 @@ SourceTreeView::dragMoveEvent( QDragMoveEvent* event ) event->setDropAction( Qt::CopyAction ); event->accept(); } - else{ - - qDebug() << Q_FUNC_INFO << "Ignoring"; - event->ignore(); - } - }else if ( DropJob::acceptsMimeData( event->mimeData(), DropJob::Playlist, DropJob::Create ) ) - + else { - // Should maybe ignore, but we are just dropping - // a playlist in the container, not on a specific playlist - event->setDropAction( Qt::CopyAction ); - event->accept(); + qDebug() << Q_FUNC_INFO << "Ignoring"; + event->ignore(); } - setDirtyRegion( m_dropRect ); + } + else if ( DropJob::acceptsMimeData( event->mimeData(), DropJob::Playlist, DropJob::Create ) ) + { + event->setDropAction( Qt::CopyAction ); + event->accept(); + } + setDirtyRegion( m_dropRect ); } @@ -569,7 +526,6 @@ SourceTreeView::dropEvent( QDropEvent* event ) // Need to fake the dropevent because the treeview would reject it if it is outside the item (on the tree) if ( pos.x() < 100 ) { - qDebug() << Q_FUNC_INFO << "New Event"; QDropEvent* newEvent = new QDropEvent( pos + QPoint( 100, 0 ), event->possibleActions(), event->mimeData(), event->mouseButtons(), event->keyboardModifiers(), event->type() ); QTreeView::dropEvent( newEvent ); delete newEvent; @@ -582,6 +538,7 @@ SourceTreeView::dropEvent( QDropEvent* event ) dropThis->setDropTypes( DropJob::Playlist ); dropThis->setDropAction( DropJob::Create ); dropThis->parseMimeData( event->mimeData() ); + QTreeView::dropEvent( event ); } diff --git a/src/sourcetree/sourcetreeview.h b/src/sourcetree/sourcetreeview.h index 0c8f00795..567259634 100644 --- a/src/sourcetree/sourcetreeview.h +++ b/src/sourcetree/sourcetreeview.h @@ -27,7 +27,6 @@ class PlaylistModel; class SourcesModel; class SourcesProxyModel; class SourceDelegate; -class ResolversModel; class SourceTreeView : public QTreeView { @@ -35,7 +34,7 @@ Q_OBJECT public: explicit SourceTreeView( QWidget* parent = 0 ); - //static bool acceptsMimeData( const QMimeData* data, bool playlistOnly = true ); + public slots: void showOfflineSources( bool offlineSourcesShown ); @@ -54,7 +53,6 @@ private slots: void expandRequest( const QPersistentModelIndex& idx ); void loadPlaylist(); - void addToSpotify(); void deletePlaylist( const QModelIndex& = QModelIndex() ); void copyPlaylistLink(); void addToLocal(); @@ -65,7 +63,6 @@ private slots: void onCustomContextMenu( const QPoint& pos ); protected: -// void drawBranches( QPainter* painter, const QRect& rect, const QModelIndex& index ) const {} void drawRow( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const; virtual void paintEvent( QPaintEvent* event ); @@ -81,7 +78,7 @@ private: template< typename T > T* itemFromIndex( const QModelIndex& index ) const; - //void parseMimeData( const QMimeData* data ); + SourcesModel* m_model; SourcesProxyModel* m_proxyModel; QModelIndex m_contextMenuIndex; @@ -100,7 +97,6 @@ private: bool m_dragging; QRect m_dropRect; - ResolversModel* m_resolversModel; QPersistentModelIndex m_dropIndex; }; diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp index c2b684dab..f5423c314 100644 --- a/src/tomahawkapp.cpp +++ b/src/tomahawkapp.cpp @@ -54,6 +54,8 @@ #include "musicscanner.h" #include "AtticaManager.h" #include "pipeline.h" +#include "utils/spotifyparser.h" +#include "dropjob.h" #include "audio/audioengine.h" #include "utils/xspfloader.h" @@ -80,6 +82,7 @@ #include #include +#include #endif @@ -261,6 +264,10 @@ TomahawkApp::init() // Make sure to init GAM in the gui thread GlobalActionManager::instance(); + + // check if our spotify playlist api server is up and running, and enable spotify playlist drops if so + QNetworkReply* r = TomahawkUtils::nam()->get( QNetworkRequest( QUrl( SPOTIFY_PLAYLIST_API_URL "/playlist/test" ) ) ); + connect( r, SIGNAL( finished() ), this, SLOT( spotifyApiCheckFinished() ) ); } @@ -501,6 +508,18 @@ TomahawkApp::initSIP() } } +void +TomahawkApp::spotifyApiCheckFinished() +{ + QNetworkReply* reply = qobject_cast< QNetworkReply* >( sender() ); + Q_ASSERT( reply ); + + if ( reply->error() == QNetworkReply::ContentNotFoundError ) + DropJob::setCanParseSpotifyPlaylists( true ); + else + DropJob::setCanParseSpotifyPlaylists( false ); +} + void TomahawkApp::activate() diff --git a/src/tomahawkapp.h b/src/tomahawkapp.h index bd90c73eb..0b3a0b1a8 100644 --- a/src/tomahawkapp.h +++ b/src/tomahawkapp.h @@ -97,6 +97,7 @@ private slots: void initServent(); void initSIP(); + void spotifyApiCheckFinished(); private: void registerMetaTypes(); @@ -109,8 +110,6 @@ private: void initHTTP(); - void loadPlugins(); - QList m_collections; QWeakPointer m_database;