From e989bc16529ccb653f6ddea62bcf8ba055b0923f Mon Sep 17 00:00:00 2001 From: Stefan Derkits Date: Wed, 21 Dec 2011 14:30:24 +0100 Subject: [PATCH 1/2] Parse Grooveshark playlists on drag & drop not much error handling yet, but it works ;) --- src/libtomahawk/CMakeLists.txt | 2 + src/libtomahawk/dropjob.cpp | 30 +++ src/libtomahawk/dropjob.h | 1 + src/libtomahawk/utils/groovesharkparser.cpp | 258 ++++++++++++++++++++ src/libtomahawk/utils/groovesharkparser.h | 81 ++++++ 5 files changed, 372 insertions(+) create mode 100644 src/libtomahawk/utils/groovesharkparser.cpp create mode 100644 src/libtomahawk/utils/groovesharkparser.h diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 3c275a63b..121cfdfc9 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -101,6 +101,7 @@ set( libGuiSources utils/m3uloader.cpp utils/itunesparser.cpp utils/rdioparser.cpp + utils/groovesharkparser.cpp utils/shortenedlinkparser.cpp utils/stylehelper.cpp utils/dropjobnotifier.cpp @@ -218,6 +219,7 @@ set( libGuiHeaders utils/m3uloader.h utils/itunesparser.h utils/rdioparser.h + utils/groovesharkparser.h utils/shortenedlinkparser.h utils/dropjobnotifier.h utils/tomahawkutilsgui.h diff --git a/src/libtomahawk/dropjob.cpp b/src/libtomahawk/dropjob.cpp index 88e2b52fb..9a83f9c1a 100644 --- a/src/libtomahawk/dropjob.cpp +++ b/src/libtomahawk/dropjob.cpp @@ -26,6 +26,7 @@ #include "utils/spotifyparser.h" #include "utils/itunesparser.h" #include "utils/rdioparser.h" +#include "utils/groovesharkparser.h" #include "utils/m3uloader.h" #include "utils/shortenedlinkparser.h" #include "utils/logger.h" @@ -120,6 +121,9 @@ DropJob::acceptsMimeData( const QMimeData* data, DropJob::DropTypes acceptedType // Not the most elegant if ( url.contains( "spotify" ) && url.contains( "playlist" ) && s_canParseSpotifyPlaylists ) return true; + + if ( url.contains( "grooveshark.com" ) && url.contains( "playlist" ) ) + return true; } if ( acceptedType.testFlag( Track ) ) @@ -188,6 +192,9 @@ DropJob::isDropType( DropJob::DropType desired, const QMimeData* data ) if ( url.contains( "rdio.com" ) && url.contains( "people" ) && url.contains( "playlist" ) ) return true; + + if ( url.contains( "grooveshark.com" ) && url.contains( "playlist" ) ) + return true; if ( ShortenedLinkParser::handlesUrl( url ) ) return true; @@ -555,6 +562,27 @@ DropJob::handleRdioUrls( const QString& urlsRaw ) rdio->parse( urls ); } +void +DropJob::handleGroovesharkUrls ( const QString& urlsRaw ) +{ + QStringList urls = urlsRaw.split( QRegExp( "\\s+" ), QString::SkipEmptyParts ); + tDebug() << "Got Grooveshark urls!" << urls; + + if ( dropAction() == Default ) + setDropAction( Create ); + + GroovesharkParser* groove = new GroovesharkParser( urls, dropAction() == Create, this ); + connect( groove, SIGNAL( tracks( QList ) ), this, SLOT( onTracksAdded( QList< Tomahawk::query_ptr > ) ) ); + + if ( dropAction() == Append ) + { + tDebug() << Q_FUNC_INFO << "Asking for grooveshark contents from" << urls; + connect( groove, SIGNAL( tracks( QList ) ), this, SLOT( onTracksAdded( QList< Tomahawk::query_ptr > ) ) ); + m_queryCount++; + } +} + + void DropJob::handleAllUrls( const QString& urls ) @@ -569,6 +597,8 @@ DropJob::handleAllUrls( const QString& urls ) handleSpotifyUrls( urls ); else if ( urls.contains( "rdio.com" ) ) handleRdioUrls( urls ); + else if ( urls.contains( "grooveshark.com" ) ) + handleGroovesharkUrls( urls ); else handleTrackUrls ( urls ); } diff --git a/src/libtomahawk/dropjob.h b/src/libtomahawk/dropjob.h index eda72504e..71ca32787 100644 --- a/src/libtomahawk/dropjob.h +++ b/src/libtomahawk/dropjob.h @@ -106,6 +106,7 @@ public: void handleM3u( const QString& urls ); void handleSpotifyUrls( const QString& urls ); void handleRdioUrls( const QString& urls ); + void handleGroovesharkUrls( const QString& urls ); static bool canParseSpotifyPlaylists() { return s_canParseSpotifyPlaylists; } static void setCanParseSpotifyPlaylists( bool parseable ) { s_canParseSpotifyPlaylists = parseable; } diff --git a/src/libtomahawk/utils/groovesharkparser.cpp b/src/libtomahawk/utils/groovesharkparser.cpp new file mode 100644 index 000000000..8fc95ebca --- /dev/null +++ b/src/libtomahawk/utils/groovesharkparser.cpp @@ -0,0 +1,258 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Stefan Derkits + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#include "groovesharkparser.h" + +#include "utils/logger.h" +#include "utils/tomahawkutils.h" +#include "query.h" +#include "sourcelist.h" +#include "dropjob.h" +#include "jobview/JobStatusView.h" +#include "jobview/JobStatusModel.h" +#include "dropjobnotifier.h" +#include "viewmanager.h" + +#include + +#include + +#include +#include +#include + +using namespace Tomahawk; + +QPixmap* GroovesharkParser::s_pixmap = 0; + +const char* enApiSecret = "erCj5s0Vebyqtc9Aduyotc1CLListJ9HfO2os5hBeew="; + +GroovesharkParser::GroovesharkParser( const QStringList& trackUrls, bool createNewPlaylist, QObject* parent ) + : QObject ( parent ) + , m_limit ( 40 ) + , m_trackMode( true ) + , m_createNewPlaylist( createNewPlaylist ) + , m_browseJob( 0 ) +{ + foreach ( const QString& url, trackUrls ) + lookupUrl( url ); +} + +GroovesharkParser::~GroovesharkParser() +{ + +} + +void +GroovesharkParser::lookupUrl( const QString& link ) +{ + if( link.contains( "playlist" ) ) + { + if( !m_createNewPlaylist ) + m_trackMode = true; + else + m_trackMode = false; + + lookupGroovesharkPlaylist( link ); + } + else + return; + +} + + +void +GroovesharkParser::lookupGroovesharkPlaylist( const QString& linkRaw ) +{ + tLog() << "Parsing Grooveshark Playlist URI:" << linkRaw; + QString browseUri = linkRaw; + + QStringList urlParts = linkRaw.split("/"); + bool ok; + int playlistID = urlParts.last().toInt(&ok, 10); + if (!ok) + { + tDebug() << "incorrect grooveshark url"; + return; + } + + m_title = urlParts.at(urlParts.size()-2); + + tDebug() << "should get playlist " << playlistID; + + DropJob::DropType type; + + if ( browseUri.contains( "playlist" ) ) + type = DropJob::Playlist; + + QString base_url("http://api.grooveshark.com/ws3.php?sig="); + + QByteArray data = QString("{\"method\":\"getPlaylistSongs\",\"parameters\":{\"playlistID\":\"%1\"},\"header\":{\"wsKey\":\"tomahawkplayer\"}}").arg(playlistID).toLocal8Bit(); + + QByteArray magic = QByteArray::fromBase64( enApiSecret ); + + QByteArray wand = QByteArray::fromBase64( QCoreApplication::applicationName().toLatin1() ); + int length = magic.length(), n2 = wand.length(); + for ( int i=0; ipost( QNetworkRequest( url ), data ); + connect( reply, SIGNAL( finished() ), this, SLOT( groovesharkLookupFinished() ) ); + + //m_browseJob = new DropJobNotifier( pixmap(), "Grooveshark", type, reply ); + //JobStatusView::instance()->model()->addJob( m_browseJob ); + + m_queries.insert( reply ); +} + +void +GroovesharkParser::groovesharkLookupFinished() +{ + QNetworkReply* r = qobject_cast< QNetworkReply* >( sender() ); + Q_ASSERT( r ); + + m_queries.remove( r ); + r->deleteLater(); + + if ( r->error() == QNetworkReply::NoError ) + { + QJson::Parser p; + bool ok; + QVariantMap res = p.parse( r, &ok ).toMap(); + + if ( !ok ) + { + tLog() << "Failed to parse json from Grooveshark browse item :" << p.errorString() << "On line" << p.errorLine(); + checkTrackFinished(); + return; + } + + //tDebug() << "parsed grooveshark result into a map " << res; + //tDebug() << "results " << res.value("result") << " which is of type " << res.value("result").type(); + QVariantList list = res.value("result").toMap().value("songs").toList(); + foreach (const QVariant& var, list) + { + QVariantMap trackResult = var.toMap(); + //tDebug() << map; + + QString title, artist, album; + + title = trackResult.value( "SongName", QString() ).toString(); + artist = trackResult.value( "ArtistName", QString() ).toString(); + album = trackResult.value( "AlbumName", QString() ).toString(); + + if ( title.isEmpty() && artist.isEmpty() ) // don't have enough... + { + tLog() << "Didn't get an artist and track name from spotify, not enough to build a query on. Aborting" << title << artist << album; + return; + } + + Tomahawk::query_ptr q = Tomahawk::Query::get( artist, title, album, uuid(), m_trackMode ); + m_tracks << q; + } + + + } else + { + tLog() << "Error in network request to grooveshark for track decoding:" << r->errorString(); + } + + if ( m_trackMode ) + checkTrackFinished(); + else + checkBrowseFinished(); +} + +void +GroovesharkParser::checkBrowseFinished() +{ + tDebug() << "Checking for grooveshark batch playlist job finished" << m_queries.isEmpty() << m_createNewPlaylist; + if ( m_queries.isEmpty() ) // we're done + { + if ( m_browseJob ) + m_browseJob->setFinished(); + + if( m_createNewPlaylist && !m_tracks.isEmpty() ) + { + m_playlist = Playlist::create( SourceList::instance()->getLocal(), + uuid(), + m_title, + m_info, + m_creator, + false, + m_tracks ); + connect( m_playlist.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), this, SLOT( playlistCreated() ) ); + return; + } + + + emit tracks( m_tracks ); + + deleteLater(); + } +} + +void +GroovesharkParser::checkTrackFinished() +{ + tDebug() << "Checking for grooveshark batch track job finished" << m_queries.isEmpty(); + if ( m_queries.isEmpty() ) // we're done + { + if ( m_browseJob ) + m_browseJob->setFinished(); + + emit tracks( m_tracks ); + + deleteLater(); + } + +} + +void +GroovesharkParser::playlistCreated() +{ + + ViewManager::instance()->show( m_playlist ); + + deleteLater(); +} + + +QPixmap +GroovesharkParser::pixmap() const +{ + if ( !s_pixmap ) + s_pixmap = new QPixmap( RESPATH "images/spotify-logo.png" ); + + return *s_pixmap; +} \ No newline at end of file diff --git a/src/libtomahawk/utils/groovesharkparser.h b/src/libtomahawk/utils/groovesharkparser.h new file mode 100644 index 000000000..7a62e87de --- /dev/null +++ b/src/libtomahawk/utils/groovesharkparser.h @@ -0,0 +1,81 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2010-2011, Stefan Derkits + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#ifndef GROOVESHARKPARSER_H +#define GROOVESHARKPARSER_H + +#include "dllmacro.h" +#include "typedefs.h" +#include "query.h" +#include "jobview/JobStatusItem.h" + +#include +#include +#include + +/** + * Small class to parse grooveshark links into query_ptrs + * + * Connect to the signals to get the results + */ + +class QNetworkReply; + +namespace Tomahawk +{ + +class DropJobNotifier; + +class DLLEXPORT GroovesharkParser : public QObject +{ + Q_OBJECT +public: + explicit GroovesharkParser( const QStringList& trackUrls, bool createNewPlaylist = false, QObject* parent = 0 ); + virtual ~GroovesharkParser(); +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 groovesharkLookupFinished(); + + void playlistCreated(); +private: + QPixmap pixmap() const; + + void lookupUrl( const QString& url ); + void lookupGroovesharkPlaylist( const QString& playlist ); + void checkTrackFinished(); + void checkBrowseFinished(); + int m_limit; + bool m_trackMode; + bool m_createNewPlaylist; + QList< query_ptr > m_tracks; + QSet< QNetworkReply* > m_queries; + QString m_title, m_info, m_creator; + Tomahawk::playlist_ptr m_playlist; + DropJobNotifier* m_browseJob; + + static QPixmap* s_pixmap; + +}; + +} + +#endif // GROOVESHARKPARSER_H From 2e25337cc11bc8fec4ceef895d9d9421e8583f0c Mon Sep 17 00:00:00 2001 From: Stefan Derkits Date: Thu, 22 Dec 2011 23:59:16 +0100 Subject: [PATCH 2/2] Small changes in groovesharkparser --- src/libtomahawk/utils/groovesharkparser.cpp | 58 ++++++++++----------- src/libtomahawk/utils/groovesharkparser.h | 10 +++- 2 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/libtomahawk/utils/groovesharkparser.cpp b/src/libtomahawk/utils/groovesharkparser.cpp index 8fc95ebca..6ee245c56 100644 --- a/src/libtomahawk/utils/groovesharkparser.cpp +++ b/src/libtomahawk/utils/groovesharkparser.cpp @@ -1,5 +1,7 @@ /* === This file is part of Tomahawk Player - === * + * Copyright 2010-2011, Leo Franchi + * Copyright 2010-2011, Hugo Lindström * Copyright 2010-2011, Stefan Derkits * * Tomahawk is free software: you can redistribute it and/or modify @@ -49,6 +51,14 @@ GroovesharkParser::GroovesharkParser( const QStringList& trackUrls, bool createN , m_createNewPlaylist( createNewPlaylist ) , m_browseJob( 0 ) { + QByteArray magic = QByteArray::fromBase64( enApiSecret ); + + QByteArray wand = QByteArray::fromBase64( QCoreApplication::applicationName().toLatin1() ); + int length = magic.length(), n2 = wand.length(); + for ( int i=0; ipost( QNetworkRequest( url ), data ); connect( reply, SIGNAL( finished() ), this, SLOT( groovesharkLookupFinished() ) ); - //m_browseJob = new DropJobNotifier( pixmap(), "Grooveshark", type, reply ); - //JobStatusView::instance()->model()->addJob( m_browseJob ); + m_browseJob = new DropJobNotifier( pixmap(), "Grooveshark", type, reply ); + JobStatusView::instance()->model()->addJob( m_browseJob ); m_queries.insert( reply ); } @@ -157,13 +158,10 @@ GroovesharkParser::groovesharkLookupFinished() return; } - //tDebug() << "parsed grooveshark result into a map " << res; - //tDebug() << "results " << res.value("result") << " which is of type " << res.value("result").type(); - QVariantList list = res.value("result").toMap().value("songs").toList(); + QVariantList list = res.value( "result" ).toMap().value( "songs" ).toList(); foreach (const QVariant& var, list) { QVariantMap trackResult = var.toMap(); - //tDebug() << map; QString title, artist, album; @@ -173,7 +171,7 @@ GroovesharkParser::groovesharkLookupFinished() if ( title.isEmpty() && artist.isEmpty() ) // don't have enough... { - tLog() << "Didn't get an artist and track name from spotify, not enough to build a query on. Aborting" << title << artist << album; + tLog() << "Didn't get an artist and track name from grooveshark, not enough to build a query on. Aborting" << title << artist << album; return; } @@ -190,11 +188,11 @@ GroovesharkParser::groovesharkLookupFinished() if ( m_trackMode ) checkTrackFinished(); else - checkBrowseFinished(); + checkPlaylistFinished(); } void -GroovesharkParser::checkBrowseFinished() +GroovesharkParser::checkPlaylistFinished() { tDebug() << "Checking for grooveshark batch playlist job finished" << m_queries.isEmpty() << m_createNewPlaylist; if ( m_queries.isEmpty() ) // we're done @@ -252,7 +250,7 @@ QPixmap GroovesharkParser::pixmap() const { if ( !s_pixmap ) - s_pixmap = new QPixmap( RESPATH "images/spotify-logo.png" ); + s_pixmap = new QPixmap( RESPATH "images/grooveshark.png" ); return *s_pixmap; -} \ No newline at end of file +} diff --git a/src/libtomahawk/utils/groovesharkparser.h b/src/libtomahawk/utils/groovesharkparser.h index 7a62e87de..a387ed928 100644 --- a/src/libtomahawk/utils/groovesharkparser.h +++ b/src/libtomahawk/utils/groovesharkparser.h @@ -1,6 +1,8 @@ /* === This file is part of Tomahawk Player - === * - * Copyright 2010-2011, Stefan Derkits + * Copyright 2010-2011, Leo Franchi + * Copyright 2010-2011, Hugo Lindström + * Copyright 2011, Stefan Derkits * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,6 +26,8 @@ #include "query.h" #include "jobview/JobStatusItem.h" +#include + #include #include #include @@ -62,7 +66,7 @@ private: void lookupUrl( const QString& url ); void lookupGroovesharkPlaylist( const QString& playlist ); void checkTrackFinished(); - void checkBrowseFinished(); + void checkPlaylistFinished(); int m_limit; bool m_trackMode; bool m_createNewPlaylist; @@ -72,6 +76,8 @@ private: Tomahawk::playlist_ptr m_playlist; DropJobNotifier* m_browseJob; + QCA::SymmetricKey m_apiKey; + static QPixmap* s_pixmap; };