1
0
mirror of https://github.com/clementine-player/Clementine synced 2025-01-31 19:45:31 +01:00

Add GS 'My Music' support.

Fixes issue 2609
Retrieving and removing songs works well :)
Adding songs doesn't work :(
This commit is contained in:
Arnaud Bienner 2012-07-21 18:09:16 +02:00
parent 0a4b6aec5c
commit 77c6199dd9
2 changed files with 189 additions and 11 deletions

View File

@ -92,6 +92,7 @@ GroovesharkService::GroovesharkService(Application* app, InternetModel *parent)
stations_(NULL),
grooveshark_radio_(NULL),
favorites_(NULL),
library_(NULL),
playlists_parent_(NULL),
subscribed_playlists_parent_(NULL),
network_(new NetworkAccessManager(this)),
@ -101,6 +102,7 @@ GroovesharkService::GroovesharkService(Application* app, InternetModel *parent)
rename_playlist_(NULL),
remove_from_playlist_(NULL),
remove_from_favorites_(NULL),
remove_from_library_(NULL),
get_url_to_share_song_(NULL),
get_url_to_share_playlist_(NULL),
search_box_(new SearchBoxWidget(this)),
@ -438,6 +440,7 @@ void GroovesharkService::RemoveItems() {
search_ = NULL;
popular_month_ = NULL;
popular_today_ = NULL;
library_ = NULL;
favorites_ = NULL;
subscribed_playlists_parent_ = NULL;
stations_ = NULL;
@ -463,6 +466,7 @@ void GroovesharkService::ShowContextMenu(const QPoint& global_pos) {
bool display_delete_playlist_action = false,
display_remove_from_playlist_action = false,
display_remove_from_favorites_action = false,
display_remove_from_library_action = false,
display_share_song_url = false,
display_share_playlist_url = false;
@ -479,6 +483,8 @@ void GroovesharkService::ShowContextMenu(const QPoint& global_pos) {
int parent_playlist_type = index.parent().data(Role_PlaylistType).toInt();
if (parent_playlist_type == UserFavorites)
display_remove_from_favorites_action = true;
else if (parent_playlist_type == UserLibrary)
display_remove_from_library_action = true;
else if (parent_playlist_type == UserPlaylist)
display_remove_from_playlist_action = true;
}
@ -487,6 +493,7 @@ void GroovesharkService::ShowContextMenu(const QPoint& global_pos) {
rename_playlist_->setVisible(display_delete_playlist_action);
remove_from_playlist_->setVisible(display_remove_from_playlist_action);
remove_from_favorites_->setVisible(display_remove_from_favorites_action);
remove_from_library_->setVisible(display_remove_from_library_action);
// Check if we can display actions to get URL for sharing songs/playlists:
// - share song
@ -534,6 +541,9 @@ void GroovesharkService::EnsureMenuCreated() {
remove_from_favorites_ = context_menu_->addAction(
IconLoader::Load("list-remove"), tr("Remove from favorites"),
this, SLOT(RemoveCurrentFromFavorites()));
remove_from_library_ = context_menu_->addAction(
IconLoader::Load("list-remove"), tr("Remove from My Music"),
this, SLOT(RemoveCurrentFromLibrary()));
get_url_to_share_song_ = context_menu_->addAction(
tr("Get a URL to share this Grooveshark song"),
this, SLOT(GetCurrentSongUrlToShare()));
@ -604,6 +614,15 @@ void GroovesharkService::EnsureItemsCreated() {
grooveshark_radio_->setData(InternetModel::Type_SmartPlaylist, InternetModel::Role_Type);
radios_divider->appendRow(grooveshark_radio_);
library_ = new QStandardItem(IconLoader::Load("folder-sound"), tr("My Music"));
library_->setData(InternetModel::Type_UserPlaylist, InternetModel::Role_Type);
library_->setData(UserLibrary, Role_PlaylistType);
library_->setData(true, InternetModel::Role_CanLazyLoad);
library_->setData(true, InternetModel::Role_CanBeModified);
library_->setData(InternetModel::PlayBehaviour_SingleItem,
InternetModel::Role_PlayBehaviour);
root_->appendRow(library_);
favorites_ = new QStandardItem(QIcon(":/last.fm/love.png"), tr("Favorites"));
favorites_->setData(InternetModel::Type_UserPlaylist, InternetModel::Role_Type);
favorites_->setData(UserFavorites, Role_PlaylistType);
@ -620,6 +639,7 @@ void GroovesharkService::EnsureItemsCreated() {
root_->appendRow(subscribed_playlists_parent_);
RetrieveUserFavorites();
RetrieveUserLibrarySongs();
RetrieveUserPlaylists();
RetrieveSubscribedPlaylists();
RetrieveAutoplayTags();
@ -750,6 +770,40 @@ void GroovesharkService::UserFavoritesRetrieved(QNetworkReply* reply, int task_i
app_->task_manager()->SetTaskFinished(task_id);
}
void GroovesharkService::RetrieveUserLibrarySongs() {
int task_id =
app_->task_manager()->StartTask(tr("Retrieving Grooveshark My Music songs"));
QNetworkReply* reply = CreateRequest("getUserLibrarySongs", QList<Param>());
NewClosure(reply, SIGNAL(finished()),
this, SLOT(UserLibrarySongsRetrieved(QNetworkReply*, int)), reply, task_id);
}
void GroovesharkService::UserLibrarySongsRetrieved(QNetworkReply* reply, int task_id) {
reply->deleteLater();
if (!library_) {
// The use probably logged out before the response arrived.
return;
}
library_->removeRows(0, library_->rowCount());
QVariantMap result = ExtractResult(reply);
SongList songs = ExtractSongs(result);
foreach (const Song& song, songs) {
QStandardItem* child = new QStandardItem(song.PrettyTitleWithArtist());
child->setData(InternetModel::Type_Track, InternetModel::Role_Type);
child->setData(QVariant::fromValue(song), InternetModel::Role_SongMetadata);
child->setData(InternetModel::PlayBehaviour_SingleItem, InternetModel::Role_PlayBehaviour);
child->setData(song.url(), InternetModel::Role_Url);
child->setData(true, InternetModel::Role_CanBeModified);
library_->appendRow(child);
}
app_->task_manager()->SetTaskFinished(task_id);
}
void GroovesharkService::RetrievePopularSongs() {
task_popular_id_ =
app_->task_manager()->StartTask(tr("Getting Grooveshark popular songs"));
@ -1021,6 +1075,12 @@ void GroovesharkService::DropMimeData(const QMimeData* data, const QModelIndex&
foreach (int song_id, data_songs_ids) {
AddUserFavoriteSong(song_id);
}
} else if (playlist_type == UserLibrary || parent_playlist_type == UserLibrary) {
// FIXME: Adding songs to user libray doesn't work atm, but the problem
// seems to be on Grooveshark server side, as it returns success=true
// when calling addUserLibrarySongs with a valid song id.
// So this code is deactivated for now to not mislead user
//AddUserLibrarySongs(data_songs_ids);
} else { // Dropped on a normal playlist
// Get the playlist
int playlist_id = index.data(Role_UserPlaylistId).toInt();
@ -1053,6 +1113,12 @@ QList<QAction*> GroovesharkService::playlistitem_actions(const Song& song) {
connect(add_to_favorites, SIGNAL(triggered()), SLOT(AddCurrentSongToUserFavorites()));
playlistitem_actions_.append(add_to_favorites);
// FIXME: as explained above, adding songs to library doesn't work currently
//QAction* add_to_library = new QAction(IconLoader::Load("folder-sound"),
// tr("Add to Grooveshark My Music"), this);
//connect(add_to_library, SIGNAL(triggered()), SLOT(AddCurrentSongToUserLibrary()));
//playlistitem_actions_.append(add_to_library);
// Create a menu with 'add to playlist' actions for each Grooveshark playlist
QAction* add_to_playlists = new QAction(IconLoader::Load("list-add"),
tr("Add to Grooveshark playlists"), this);
@ -1350,6 +1416,42 @@ void GroovesharkService::UserFavoriteSongAdded(QNetworkReply* reply, int task_id
RetrieveUserFavorites();
}
void GroovesharkService::AddUserLibrarySongs(QList<int>& songs_ids) {
int task_id = app_->task_manager()->StartTask(tr("Adding song to My Music"));
QList<Param> parameters;
// Convert songs ids to QVariant
QVariantList songs_ids_qvariant;
foreach (int song_id, songs_ids) {
songs_ids_qvariant << QVariant(song_id);
}
QVariantList albums_ids_qvariant;
QVariantList artists_ids_qvariant;
parameters << Param("songIDs", songs_ids_qvariant);
// We do not support albums and artist parameters for now, but they are
// required
parameters << Param("albumIDs", albums_ids_qvariant);
parameters << Param("artistIDs", artists_ids_qvariant);
QNetworkReply* reply = CreateRequest("addUserLibrarySongs", parameters);
NewClosure(reply, SIGNAL(finished()),
this, SLOT(UserLibrarySongAdded(QNetworkReply*, int)),
reply, task_id);
}
void GroovesharkService::UserLibrarySongAdded(QNetworkReply* reply, int task_id) {
reply->deleteLater();
app_->task_manager()->SetTaskFinished(task_id);
QVariantMap result = ExtractResult(reply);
if (!result["success"].toBool()) {
qLog(Warning) << "Grooveshark addUserLibrarySongs failed";
return;
}
// Refresh user's library list
RetrieveUserLibrarySongs();
}
void GroovesharkService::RemoveCurrentFromPlaylist() {
const QModelIndexList& indexes(model()->selected_indexes());
QMap<int, QList<int> > playlists_songs_ids;
@ -1410,7 +1512,7 @@ void GroovesharkService::RemoveFromFavorites(const QList<int>& songs_ids_to_remo
if (songs_ids_to_remove.isEmpty())
return;
int task_id = app_->task_manager()->StartTask(tr("Removing song from favorites"));
int task_id = app_->task_manager()->StartTask(tr("Removing songs from favorites"));
QList<Param> parameters;
// Convert song ids to QVariant
@ -1422,10 +1524,10 @@ void GroovesharkService::RemoveFromFavorites(const QList<int>& songs_ids_to_remo
parameters << Param("songIDs", songs_ids_qvariant);
QNetworkReply* reply = CreateRequest("removeUserFavoriteSongs", parameters);
NewClosure(reply, SIGNAL(finished()), this,
SLOT(SongRemovedFromFavorites(QNetworkReply*, int)), reply, task_id);
SLOT(SongsRemovedFromFavorites(QNetworkReply*, int)), reply, task_id);
}
void GroovesharkService::SongRemovedFromFavorites(QNetworkReply* reply, int task_id) {
void GroovesharkService::SongsRemovedFromFavorites(QNetworkReply* reply, int task_id) {
app_->task_manager()->SetTaskFinished(task_id);
reply->deleteLater();
@ -1437,8 +1539,68 @@ void GroovesharkService::SongRemovedFromFavorites(QNetworkReply* reply, int task
RetrieveUserFavorites();
}
QNetworkReply* GroovesharkService::CreateRequest(const QString& method_name, QList<Param> params,
void GroovesharkService::RemoveCurrentFromLibrary() {
const QModelIndexList& indexes(model()->selected_indexes());
QList<int> songs_ids;
foreach (const QModelIndex& index, indexes) {
if (index.parent().data(Role_PlaylistType).toInt() != UserLibrary) {
continue;
}
int song_id = ExtractSongId(index.data(InternetModel::Role_Url).toUrl());
if (song_id) {
songs_ids << song_id;
}
}
RemoveFromLibrary(songs_ids);
}
void GroovesharkService::RemoveFromLibrary(const QList<int>& songs_ids_to_remove) {
if (songs_ids_to_remove.isEmpty())
return;
int task_id = app_->task_manager()->StartTask(tr("Removing songs from My Music"));
QList<Param> parameters;
// Convert song ids to QVariant
QVariantList songs_ids_qvariant;
foreach (const int song_id, songs_ids_to_remove) {
songs_ids_qvariant << QVariant(song_id);
}
QVariantList albums_ids_qvariant;
QVariantList artists_ids_qvariant;
parameters << Param("songIDs", songs_ids_qvariant);
// We do not support albums and artist parameters for now, but they are
// required
parameters << Param("albumIDs", albums_ids_qvariant);
parameters << Param("artistIDs", artists_ids_qvariant);
QNetworkReply* reply = CreateRequest("removeUserLibrarySongs", parameters);
NewClosure(reply, SIGNAL(finished()), this,
SLOT(SongsRemovedFromLibrary(QNetworkReply*, int)), reply, task_id);
}
void GroovesharkService::SongsRemovedFromLibrary(QNetworkReply* reply, int task_id) {
app_->task_manager()->SetTaskFinished(task_id);
reply->deleteLater();
QVariantMap result = ExtractResult(reply);
if (!result["success"].toBool()) {
qLog(Warning) << "Grooveshark removeUserLibrarySongs failed";
return;
}
RetrieveUserLibrarySongs();
}
QNetworkReply* GroovesharkService::CreateRequest(
const QString& method_name,
const QList<Param>& params,
bool use_https) {
QVariantMap request_params;
request_params.insert("method", method_name);

View File

@ -46,9 +46,10 @@ class GroovesharkService : public InternetService {
enum PlaylistType {
UserPlaylist = Qt::UserRole,
// Favorites list is like a playlist, but we want to do special treatments
// in some cases
// Favorites and Library list are like playlists, but we want to do special
// treatments in some cases
UserFavorites,
UserLibrary,
SubscribedPlaylist
};
@ -80,6 +81,7 @@ class GroovesharkService : public InternetService {
bool IsLoggedIn() const { return !session_id_.isEmpty(); }
void RetrieveUserPlaylists();
void RetrieveUserFavorites();
void RetrieveUserLibrarySongs();
void RetrievePopularSongs();
void RetrievePopularSongsMonth();
void RetrievePopularSongsToday();
@ -93,6 +95,8 @@ class GroovesharkService : public InternetService {
void RenamePlaylist(int playlist_id);
void AddUserFavoriteSong(int song_id);
void RemoveFromFavorites(const QList<int>& songs_ids_to_remove);
void AddUserLibrarySongs(QList<int>& songs_ids);
void RemoveFromLibrary(const QList<int>& songs_ids_to_remove);
void GetSongUrlToShare(int song_id);
void GetPlaylistUrlToShare(int playlist_id);
// Start autoplay for the given tag_id, fill the autoplay_state, returns a
@ -156,6 +160,7 @@ class GroovesharkService : public InternetService {
void Authenticated();
void UserPlaylistsRetrieved();
void UserFavoritesRetrieved(QNetworkReply* reply, int task_id);
void UserLibrarySongsRetrieved(QNetworkReply* reply, int task_id);
void PopularSongsMonthRetrieved(QNetworkReply* reply);
void PopularSongsTodayRetrieved(QNetworkReply* reply);
void SubscribedPlaylistsRetrieved(QNetworkReply* reply);
@ -169,15 +174,19 @@ class GroovesharkService : public InternetService {
void PlaylistDeleted(QNetworkReply* reply, int playlist_id);
void PlaylistRenamed(QNetworkReply* reply, int playlist_id, const QString& new_name);
void AddCurrentSongToUserFavorites() { AddUserFavoriteSong(current_song_id_); }
void AddCurrentSongToUserLibrary() { AddUserLibrarySongs(QList<int>() << current_song_id_); }
void AddCurrentSongToPlaylist(QAction* action);
void UserFavoriteSongAdded(QNetworkReply* reply, int task_id);
void UserLibrarySongAdded(QNetworkReply* reply, int task_id);
void GetCurrentSongUrlToShare();
void SongUrlToShareReceived(QNetworkReply* reply);
void GetCurrentPlaylistUrlToShare();
void PlaylistUrlToShareReceived(QNetworkReply* reply);
void RemoveCurrentFromPlaylist();
void RemoveCurrentFromFavorites();
void SongRemovedFromFavorites(QNetworkReply* reply, int task_id);
void RemoveCurrentFromLibrary();
void SongsRemovedFromFavorites(QNetworkReply* reply, int task_id);
void SongsRemovedFromLibrary(QNetworkReply* reply, int task_id);
void StreamMarked();
void SongMarkedAsComplete();
@ -204,7 +213,9 @@ class GroovesharkService : public InternetService {
// Create a request for the given method, with the given params.
// If need_authentication is true, add session_id to params.
// Returns the reply object created
QNetworkReply* CreateRequest(const QString& method_name, const QList<QPair<QString, QVariant> > params,
QNetworkReply* CreateRequest(
const QString& method_name,
const QList<QPair<QString, QVariant> >& params,
bool use_https = false);
// Convenient function which block until 'reply' replies, or timeout after 10
// seconds. Returns false if reply has timeouted
@ -249,6 +260,10 @@ class GroovesharkService : public InternetService {
QStandardItem* stations_;
QStandardItem* grooveshark_radio_;
QStandardItem* favorites_;
// Grooveshark Library (corresponds to Grooveshark 'MyMusic' actually, but
// called 'Library' in the API).
// Nothing to do with Clementine's local library
QStandardItem* library_;
QStandardItem* playlists_parent_;
QStandardItem* subscribed_playlists_parent_;
@ -265,6 +280,7 @@ class GroovesharkService : public InternetService {
QAction* rename_playlist_;
QAction* remove_from_playlist_;
QAction* remove_from_favorites_;
QAction* remove_from_library_;
QAction* get_url_to_share_song_;
QAction* get_url_to_share_playlist_;
QList<QAction*> playlistitem_actions_;