2010-03-24 00:11:46 +01:00
|
|
|
/* This file is part of Clementine.
|
2010-11-20 14:27:10 +01:00
|
|
|
Copyright 2010, David Sansome <me@davidsansome.com>
|
2010-03-24 00:11:46 +01:00
|
|
|
|
|
|
|
Clementine 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.
|
|
|
|
|
|
|
|
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2009-12-26 16:13:38 +01:00
|
|
|
#include "lastfmservice.h"
|
|
|
|
#include "radioitem.h"
|
2009-12-30 03:15:38 +01:00
|
|
|
#include "lastfmstationdialog.h"
|
2010-05-10 13:12:44 +02:00
|
|
|
#include "radiomodel.h"
|
2010-10-16 17:22:14 +02:00
|
|
|
#include "radioplaylistitem.h"
|
2010-05-10 23:50:31 +02:00
|
|
|
#include "core/song.h"
|
2010-06-23 15:21:30 +02:00
|
|
|
#include "core/taskmanager.h"
|
2010-05-19 17:45:29 +02:00
|
|
|
#include "ui/iconloader.h"
|
2010-06-09 00:56:31 +02:00
|
|
|
#include "ui/settingsdialog.h"
|
2009-12-26 16:13:38 +01:00
|
|
|
|
2010-02-25 02:16:58 +01:00
|
|
|
#include <boost/scoped_ptr.hpp>
|
|
|
|
|
2010-02-25 01:18:32 +01:00
|
|
|
#include <lastfm/Audioscrobbler>
|
2009-12-26 18:19:14 +01:00
|
|
|
#include <lastfm/misc.h>
|
2010-02-25 01:18:32 +01:00
|
|
|
#include <lastfm/RadioStation>
|
|
|
|
#include <lastfm/ws.h>
|
2009-12-26 18:19:14 +01:00
|
|
|
#include <lastfm/XmlQuery>
|
|
|
|
|
2009-12-30 00:01:07 +01:00
|
|
|
#include <QMenu>
|
2010-02-26 15:50:02 +01:00
|
|
|
#include <QSettings>
|
2009-12-26 18:19:14 +01:00
|
|
|
|
2010-02-25 02:16:58 +01:00
|
|
|
using boost::scoped_ptr;
|
2010-02-25 01:18:32 +01:00
|
|
|
using lastfm::XmlQuery;
|
|
|
|
|
|
|
|
uint qHash(const lastfm::Track& track) {
|
|
|
|
return qHash(track.title()) ^
|
|
|
|
qHash(track.artist().name()) ^
|
|
|
|
qHash(track.album().title());
|
|
|
|
}
|
|
|
|
|
2009-12-29 20:22:02 +01:00
|
|
|
const char* LastFMService::kServiceName = "Last.fm";
|
2009-12-26 18:19:14 +01:00
|
|
|
const char* LastFMService::kSettingsGroup = "Last.fm";
|
2009-12-29 20:22:02 +01:00
|
|
|
const char* LastFMService::kAudioscrobblerClientId = "tng";
|
|
|
|
const char* LastFMService::kApiKey = "75d20fb472be99275392aefa2760ea09";
|
|
|
|
const char* LastFMService::kSecret = "d3072b60ae626be12be69448f5c46e70";
|
2009-12-26 18:19:14 +01:00
|
|
|
|
2010-05-09 17:51:04 +02:00
|
|
|
LastFMService::LastFMService(RadioModel* parent)
|
2009-12-29 20:22:02 +01:00
|
|
|
: RadioService(kServiceName, parent),
|
|
|
|
scrobbler_(NULL),
|
2009-12-30 03:15:38 +01:00
|
|
|
station_dialog_(new LastFMStationDialog),
|
2009-12-30 00:01:07 +01:00
|
|
|
context_menu_(new QMenu),
|
2009-12-29 21:48:50 +01:00
|
|
|
initial_tune_(false),
|
2010-06-23 15:21:30 +02:00
|
|
|
tune_task_id_(0),
|
2009-12-30 01:31:00 +01:00
|
|
|
scrobbling_enabled_(false),
|
2009-12-30 03:15:38 +01:00
|
|
|
artist_list_(NULL),
|
|
|
|
tag_list_(NULL),
|
2010-10-07 15:59:24 +02:00
|
|
|
custom_list_(NULL),
|
2009-12-30 01:31:00 +01:00
|
|
|
friends_list_(NULL),
|
2010-10-16 19:20:54 +02:00
|
|
|
neighbours_list_(NULL)
|
2009-12-26 16:13:38 +01:00
|
|
|
{
|
2010-02-03 19:32:48 +01:00
|
|
|
ReloadSettings();
|
2009-12-30 00:01:07 +01:00
|
|
|
|
2010-02-23 19:33:09 +01:00
|
|
|
play_action_ = context_menu_->addAction(
|
2010-05-19 17:45:29 +02:00
|
|
|
IconLoader::Load("media-playback-start"), tr("Add to playlist"), this, SLOT(AddToPlaylist()));
|
2010-12-04 16:49:43 +01:00
|
|
|
load_action_ = context_menu_->addAction(
|
|
|
|
IconLoader::Load("media-playback-start"), tr("Load"), this, SLOT(LoadToPlaylist()));
|
2010-02-23 19:33:09 +01:00
|
|
|
remove_action_ = context_menu_->addAction(
|
2010-05-19 17:45:29 +02:00
|
|
|
IconLoader::Load("list-remove"), tr("Remove"), this, SLOT(Remove()));
|
2009-12-30 02:41:37 +01:00
|
|
|
context_menu_->addSeparator();
|
2010-02-23 19:33:09 +01:00
|
|
|
add_artist_action_ = context_menu_->addAction(
|
|
|
|
QIcon(":last.fm/icon_radio.png"), tr("Play artist radio..."), this, SLOT(AddArtistRadio()));
|
|
|
|
add_tag_action_ = context_menu_->addAction(
|
|
|
|
QIcon(":last.fm/icon_tag.png"), tr("Play tag radio..."), this, SLOT(AddTagRadio()));
|
2010-10-07 15:59:24 +02:00
|
|
|
add_custom_action_ = context_menu_->addAction(
|
|
|
|
QIcon(":last.fm/icon_radio.png"), tr("Play custom radio..."), this, SLOT(AddCustomRadio()));
|
2010-02-23 19:33:09 +01:00
|
|
|
context_menu_->addAction(
|
2010-05-19 17:45:29 +02:00
|
|
|
IconLoader::Load("configure"), tr("Configure Last.fm..."), this, SLOT(ShowConfig()));
|
2009-12-30 02:41:37 +01:00
|
|
|
|
2009-12-30 03:23:09 +01:00
|
|
|
remove_action_->setEnabled(false);
|
2009-12-30 03:15:38 +01:00
|
|
|
add_artist_action_->setEnabled(false);
|
|
|
|
add_tag_action_->setEnabled(false);
|
2010-10-07 15:59:24 +02:00
|
|
|
add_custom_action_->setEnabled(false);
|
2009-12-26 18:19:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
LastFMService::~LastFMService() {
|
2009-12-26 16:13:38 +01:00
|
|
|
}
|
|
|
|
|
2010-02-03 19:32:48 +01:00
|
|
|
void LastFMService::ReloadSettings() {
|
|
|
|
QSettings settings;
|
|
|
|
settings.beginGroup(kSettingsGroup);
|
|
|
|
lastfm::ws::Username = settings.value("Username").toString();
|
|
|
|
lastfm::ws::SessionKey = settings.value("Session").toString();
|
|
|
|
scrobbling_enabled_ = settings.value("ScrobblingEnabled", true).toBool();
|
2010-04-07 21:26:49 +02:00
|
|
|
buttons_visible_ = settings.value("ShowLoveBanButtons", true).toBool();
|
2010-02-03 19:32:48 +01:00
|
|
|
|
|
|
|
emit ScrobblingEnabledChanged(scrobbling_enabled_);
|
2010-04-07 21:26:49 +02:00
|
|
|
emit ButtonVisibilityChanged(buttons_visible_);
|
2009-12-29 20:22:02 +01:00
|
|
|
}
|
|
|
|
|
2010-02-03 19:32:48 +01:00
|
|
|
void LastFMService::ShowConfig() {
|
2010-08-27 17:42:58 +02:00
|
|
|
emit OpenSettingsAtPage(SettingsDialog::Page_Lastfm);
|
2010-02-03 19:32:48 +01:00
|
|
|
}
|
2009-12-29 21:48:50 +01:00
|
|
|
|
2010-02-03 19:32:48 +01:00
|
|
|
bool LastFMService::IsAuthenticated() const {
|
|
|
|
return !lastfm::ws::SessionKey.isEmpty();
|
2009-12-29 21:48:50 +01:00
|
|
|
}
|
|
|
|
|
2009-12-26 16:13:38 +01:00
|
|
|
RadioItem* LastFMService::CreateRootItem(RadioItem* parent) {
|
2010-01-18 03:23:55 +01:00
|
|
|
RadioItem* item = new RadioItem(this, RadioItem::Type_Service, kServiceName, parent);
|
2009-12-26 16:13:38 +01:00
|
|
|
item->icon = QIcon(":last.fm/as.png");
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LastFMService::LazyPopulate(RadioItem *item) {
|
|
|
|
switch (item->type) {
|
|
|
|
case RadioItem::Type_Service:
|
2009-12-30 01:31:00 +01:00
|
|
|
// Normal radio types
|
2010-02-23 19:33:09 +01:00
|
|
|
CreateStationItem(Type_MyRecommendations, tr("My Recommendations"), ":last.fm/recommended_radio.png", item);
|
|
|
|
CreateStationItem(Type_MyRadio, tr("My Radio Station"), ":last.fm/personal_radio.png", item);
|
2010-11-18 22:55:50 +01:00
|
|
|
CreateStationItem(Type_MyMix, tr("My Mix Radio"), ":last.fm/loved_radio.png", item);
|
2010-04-15 18:12:44 +02:00
|
|
|
CreateStationItem(Type_MyNeighbourhood, tr("My Neighborhood"), ":last.fm/neighbour_radio.png", item);
|
2009-12-26 18:19:14 +01:00
|
|
|
|
2009-12-30 03:15:38 +01:00
|
|
|
// Types that have children
|
2010-02-23 19:33:09 +01:00
|
|
|
artist_list_ = new RadioItem(this, Type_ArtistRadio, tr("Artist radio"), item);
|
2009-12-30 03:15:38 +01:00
|
|
|
artist_list_->icon = QIcon(":last.fm/icon_radio.png");
|
|
|
|
artist_list_->lazy_loaded = true;
|
2009-12-30 01:31:00 +01:00
|
|
|
|
2010-02-23 19:33:09 +01:00
|
|
|
tag_list_ = new RadioItem(this, Type_TagRadio, tr("Tag radio"), item);
|
2009-12-30 03:15:38 +01:00
|
|
|
tag_list_->icon = QIcon(":last.fm/icon_tag.png");
|
|
|
|
tag_list_->lazy_loaded = true;
|
|
|
|
|
2010-10-07 15:59:24 +02:00
|
|
|
custom_list_ = new RadioItem(this, Type_CustomRadio, tr("Custom radio"), item);
|
|
|
|
custom_list_->icon = QIcon(":last.fm/icon_radio.png");
|
|
|
|
custom_list_->lazy_loaded = true;
|
|
|
|
|
2009-12-30 03:15:38 +01:00
|
|
|
RestoreList("artists", Type_Artist, QIcon(":last.fm/icon_radio.png"), artist_list_);
|
|
|
|
RestoreList("tags", Type_Tag, QIcon(":last.fm/icon_tag.png"), tag_list_);
|
2010-10-07 15:59:24 +02:00
|
|
|
RestoreList("custom", Type_Custom, QIcon(":last.fm/icon_radio.png"), custom_list_);
|
2009-12-30 01:31:00 +01:00
|
|
|
|
2010-02-23 19:33:09 +01:00
|
|
|
friends_list_ = new RadioItem(this, Type_MyFriends, tr("Friends"), item);
|
2009-12-30 01:31:00 +01:00
|
|
|
friends_list_->icon = QIcon(":last.fm/my_friends.png");
|
|
|
|
|
2010-04-15 18:12:44 +02:00
|
|
|
neighbours_list_ = new RadioItem(this, Type_MyNeighbours, tr("Neighbors"), item);
|
2009-12-30 01:31:00 +01:00
|
|
|
neighbours_list_->icon = QIcon(":last.fm/my_neighbours.png");
|
|
|
|
|
2009-12-29 20:22:02 +01:00
|
|
|
if (!IsAuthenticated())
|
2010-02-03 19:32:48 +01:00
|
|
|
ShowConfig();
|
2009-12-30 03:15:38 +01:00
|
|
|
|
|
|
|
add_artist_action_->setEnabled(true);
|
|
|
|
add_tag_action_->setEnabled(true);
|
2010-10-07 15:59:24 +02:00
|
|
|
add_custom_action_->setEnabled(true);
|
2009-12-26 18:19:14 +01:00
|
|
|
break;
|
|
|
|
|
2009-12-30 01:31:00 +01:00
|
|
|
case Type_MyFriends:
|
|
|
|
RefreshFriends();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Type_MyNeighbours:
|
|
|
|
RefreshNeighbours();
|
|
|
|
break;
|
|
|
|
|
2009-12-30 02:29:47 +01:00
|
|
|
case Type_OtherUser:
|
|
|
|
CreateStationItem(Type_OtherUserRadio, item->key, ":last.fm/recommended_radio.png", item)
|
2010-04-15 18:12:44 +02:00
|
|
|
->display_text = tr("Last.fm Radio Station - %1").arg(item->key);
|
2010-11-18 22:55:50 +01:00
|
|
|
CreateStationItem(Type_OtherUserMix, item->key, ":last.fm/loved_radio.png", item)
|
|
|
|
->display_text = tr("Last.fm Mix Radio - %1").arg(item->key);
|
2009-12-30 02:29:47 +01:00
|
|
|
CreateStationItem(Type_OtherUserNeighbourhood, item->key, ":last.fm/neighbour_radio.png", item)
|
2010-04-15 18:12:44 +02:00
|
|
|
->display_text = tr("Last.fm Neighbor Radio - %1").arg(item->key);
|
2009-12-30 02:29:47 +01:00
|
|
|
break;
|
|
|
|
|
2009-12-26 18:19:14 +01:00
|
|
|
default:
|
|
|
|
break;
|
2009-12-26 16:13:38 +01:00
|
|
|
}
|
2009-12-26 18:19:14 +01:00
|
|
|
|
|
|
|
item->lazy_loaded = true;
|
2009-12-26 16:13:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
RadioItem* LastFMService::CreateStationItem(ItemType type, const QString& name,
|
|
|
|
const QString& icon, RadioItem* parent) {
|
|
|
|
RadioItem* ret = new RadioItem(this, type, name, parent);
|
|
|
|
ret->lazy_loaded = true;
|
|
|
|
ret->icon = QIcon(icon);
|
2009-12-26 22:35:45 +01:00
|
|
|
ret->playable = true;
|
2009-12-26 16:13:38 +01:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2009-12-26 18:19:14 +01:00
|
|
|
|
|
|
|
void LastFMService::Authenticate(const QString& username, const QString& password) {
|
|
|
|
QMap<QString, QString> params;
|
|
|
|
params["method"] = "auth.getMobileSession";
|
|
|
|
params["username"] = username;
|
|
|
|
params["authToken"] = lastfm::md5((username + lastfm::md5(password.toUtf8())).toUtf8());
|
|
|
|
|
|
|
|
QNetworkReply* reply = lastfm::ws::post(params);
|
|
|
|
connect(reply, SIGNAL(finished()), SLOT(AuthenticateReplyFinished()));
|
|
|
|
}
|
|
|
|
|
2010-04-07 21:26:49 +02:00
|
|
|
void LastFMService::SignOut() {
|
|
|
|
lastfm::ws::Username.clear();
|
|
|
|
lastfm::ws::SessionKey.clear();
|
|
|
|
|
|
|
|
QSettings settings;
|
|
|
|
settings.beginGroup(kSettingsGroup);
|
|
|
|
settings.setValue("Username", QString());
|
|
|
|
settings.setValue("Session", QString());
|
|
|
|
}
|
|
|
|
|
2009-12-26 18:19:14 +01:00
|
|
|
void LastFMService::AuthenticateReplyFinished() {
|
|
|
|
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
|
|
|
|
if (!reply) {
|
|
|
|
emit AuthenticationComplete(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the reply
|
|
|
|
try {
|
|
|
|
lastfm::XmlQuery const lfm = lastfm::ws::parse(reply);
|
2010-09-14 01:44:11 +02:00
|
|
|
#ifdef Q_OS_WIN32
|
|
|
|
if (lastfm::ws::last_parse_error != lastfm::ws::NoError)
|
2010-09-14 01:52:05 +02:00
|
|
|
throw std::runtime_error("");
|
2010-09-14 01:44:11 +02:00
|
|
|
#endif
|
2009-12-26 18:19:14 +01:00
|
|
|
|
|
|
|
lastfm::ws::Username = lfm["session"]["name"].text();
|
|
|
|
lastfm::ws::SessionKey = lfm["session"]["key"].text();
|
|
|
|
} catch (std::runtime_error& e) {
|
|
|
|
qDebug() << e.what();
|
|
|
|
emit AuthenticationComplete(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save the session key
|
|
|
|
QSettings settings;
|
|
|
|
settings.beginGroup(kSettingsGroup);
|
2010-02-03 19:32:48 +01:00
|
|
|
settings.setValue("Username", lastfm::ws::Username);
|
|
|
|
settings.setValue("Session", lastfm::ws::SessionKey);
|
2009-12-26 18:19:14 +01:00
|
|
|
|
2009-12-29 20:22:02 +01:00
|
|
|
// Invalidate the scrobbler - it will get recreated later
|
|
|
|
delete scrobbler_;
|
|
|
|
scrobbler_ = NULL;
|
|
|
|
|
2009-12-26 18:19:14 +01:00
|
|
|
emit AuthenticationComplete(true);
|
|
|
|
}
|
2009-12-26 22:35:45 +01:00
|
|
|
|
2009-12-30 00:17:54 +01:00
|
|
|
QUrl LastFMService::UrlForItem(const RadioItem* item) const {
|
2009-12-26 22:35:45 +01:00
|
|
|
switch (item->type) {
|
|
|
|
case Type_MyRecommendations:
|
2009-12-30 00:17:54 +01:00
|
|
|
return "lastfm://user/" + lastfm::ws::Username + "/recommended";
|
2009-12-26 22:35:45 +01:00
|
|
|
|
2010-11-18 22:55:50 +01:00
|
|
|
case Type_MyMix:
|
|
|
|
return QString("lastfm://rql/") + QString("adv:" + lastfm::ws::Username).toUtf8().toBase64();
|
2009-12-26 22:35:45 +01:00
|
|
|
|
|
|
|
case Type_MyNeighbourhood:
|
2009-12-30 00:17:54 +01:00
|
|
|
return "lastfm://user/" + lastfm::ws::Username + "/neighbours";
|
2009-12-26 22:35:45 +01:00
|
|
|
|
|
|
|
case Type_MyRadio:
|
2009-12-30 00:17:54 +01:00
|
|
|
return "lastfm://user/" + lastfm::ws::Username + "/library";
|
2009-12-30 01:31:00 +01:00
|
|
|
|
2009-12-30 02:29:47 +01:00
|
|
|
case Type_OtherUser:
|
|
|
|
case Type_OtherUserRadio:
|
2009-12-30 01:31:00 +01:00
|
|
|
return "lastfm://user/" + item->key + "/library";
|
|
|
|
|
2010-11-18 22:55:50 +01:00
|
|
|
case Type_OtherUserMix:
|
|
|
|
return QString("lastfm://rql/") + QString("adv:" + item->key).toUtf8().toBase64();
|
2009-12-30 02:29:47 +01:00
|
|
|
|
|
|
|
case Type_OtherUserNeighbourhood:
|
|
|
|
return "lastfm://user/" + item->key + "/neighbours";
|
2009-12-30 03:15:38 +01:00
|
|
|
|
|
|
|
case Type_Artist:
|
|
|
|
return "lastfm://artist/" + item->key + "/similarartists";
|
|
|
|
|
|
|
|
case Type_Tag:
|
|
|
|
return "lastfm://globaltags/" + item->key;
|
2010-10-07 15:59:24 +02:00
|
|
|
|
|
|
|
case Type_Custom:
|
|
|
|
return QString("lastfm://rql/" + item->key.toUtf8().toBase64());
|
2009-12-26 22:35:45 +01:00
|
|
|
}
|
2009-12-30 00:17:54 +01:00
|
|
|
return QUrl();
|
|
|
|
}
|
2009-12-26 22:35:45 +01:00
|
|
|
|
2009-12-30 00:17:54 +01:00
|
|
|
QString LastFMService::TitleForItem(const RadioItem* item) const {
|
2009-12-30 01:31:00 +01:00
|
|
|
const QString me(lastfm::ws::Username);
|
2009-12-30 00:17:54 +01:00
|
|
|
|
|
|
|
switch (item->type) {
|
2010-04-15 18:12:44 +02:00
|
|
|
case Type_MyRecommendations: return tr("Last.fm Recommended Radio - %1").arg(me);
|
2010-11-18 22:55:50 +01:00
|
|
|
case Type_MyMix: return tr("Last.fm Mix Radio - %1").arg(me);
|
2010-04-15 18:12:44 +02:00
|
|
|
case Type_MyNeighbourhood: return tr("Last.fm Neighbor Radio - %1").arg(me);
|
|
|
|
case Type_MyRadio: return tr("Last.fm Library - %1").arg(me);
|
2009-12-30 02:29:47 +01:00
|
|
|
case Type_OtherUser:
|
2010-04-15 18:12:44 +02:00
|
|
|
case Type_OtherUserRadio: return tr("Last.fm Library - %1").arg(item->key);
|
2010-11-18 22:55:50 +01:00
|
|
|
case Type_OtherUserMix: return tr("Last.fm Mix Radio - %1").arg(item->key);
|
2010-04-15 18:12:44 +02:00
|
|
|
case Type_OtherUserNeighbourhood: return tr("Last.fm Neighbor Radio - %1").arg(item->key);
|
|
|
|
case Type_Artist: return tr("Last.fm Similar Artists to %1").arg(item->key);
|
|
|
|
case Type_Tag: return tr("Last.fm Tag Radio: %1").arg(item->key);
|
2010-11-19 00:22:47 +01:00
|
|
|
case Type_Custom: return tr("Last.fm Custom Radio: %1").arg(item->key);
|
2009-12-30 00:17:54 +01:00
|
|
|
}
|
|
|
|
return QString();
|
2009-12-26 22:35:45 +01:00
|
|
|
}
|
|
|
|
|
2010-05-18 22:43:10 +02:00
|
|
|
PlaylistItem::SpecialLoadResult LastFMService::StartLoading(const QUrl& url) {
|
2009-12-26 22:35:45 +01:00
|
|
|
if (url.scheme() != "lastfm")
|
2010-05-18 22:43:10 +02:00
|
|
|
return PlaylistItem::SpecialLoadResult();
|
2009-12-29 20:22:02 +01:00
|
|
|
if (!IsAuthenticated())
|
2010-05-18 22:43:10 +02:00
|
|
|
return PlaylistItem::SpecialLoadResult();
|
2009-12-26 22:35:45 +01:00
|
|
|
|
2010-06-23 15:21:30 +02:00
|
|
|
if (!tune_task_id_)
|
|
|
|
tune_task_id_ = model()->task_manager()->StartTask(tr("Loading Last.fm radio"));
|
2009-12-26 22:35:45 +01:00
|
|
|
|
|
|
|
last_url_ = url;
|
2009-12-26 23:59:11 +01:00
|
|
|
initial_tune_ = true;
|
2010-02-25 01:18:32 +01:00
|
|
|
Tune(lastfm::RadioStation(url));
|
2010-05-18 22:43:10 +02:00
|
|
|
|
|
|
|
return PlaylistItem::SpecialLoadResult(
|
|
|
|
PlaylistItem::SpecialLoadResult::WillLoadAsynchronously, url);
|
2009-12-26 22:35:45 +01:00
|
|
|
}
|
|
|
|
|
2010-05-18 22:43:10 +02:00
|
|
|
PlaylistItem::SpecialLoadResult LastFMService::LoadNext(const QUrl &) {
|
2010-02-25 01:18:32 +01:00
|
|
|
if (playlist_.empty()) {
|
2010-05-18 22:43:10 +02:00
|
|
|
return PlaylistItem::SpecialLoadResult();
|
2009-12-26 23:59:11 +01:00
|
|
|
}
|
|
|
|
|
2010-03-21 01:22:15 +01:00
|
|
|
lastfm::MutableTrack track = playlist_.dequeue();
|
|
|
|
track.stamp();
|
|
|
|
|
2010-02-26 15:50:02 +01:00
|
|
|
last_track_ = track;
|
2010-02-25 01:18:32 +01:00
|
|
|
if (playlist_.empty()) {
|
|
|
|
FetchMoreTracks();
|
|
|
|
}
|
|
|
|
|
2010-02-26 15:50:02 +01:00
|
|
|
next_metadata_ = track;
|
2010-05-17 00:46:56 +02:00
|
|
|
StreamMetadataReady();
|
2010-05-18 22:43:10 +02:00
|
|
|
|
|
|
|
return PlaylistItem::SpecialLoadResult(
|
|
|
|
PlaylistItem::SpecialLoadResult::TrackAvailable, last_url_, last_track_.url());
|
2010-02-26 15:50:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void LastFMService::StreamMetadataReady() {
|
2009-12-26 23:59:11 +01:00
|
|
|
Song metadata;
|
2010-02-26 15:50:02 +01:00
|
|
|
metadata.InitFromLastFM(next_metadata_);
|
2010-05-17 00:46:56 +02:00
|
|
|
|
|
|
|
if (art_urls_.contains(next_metadata_))
|
|
|
|
metadata.set_art_automatic(art_urls_[next_metadata_]);
|
2009-12-29 20:22:02 +01:00
|
|
|
|
2009-12-26 23:59:11 +01:00
|
|
|
emit StreamMetadataFound(last_url_, metadata);
|
|
|
|
}
|
|
|
|
|
2009-12-26 22:35:45 +01:00
|
|
|
void LastFMService::TunerError(lastfm::ws::Error error) {
|
2009-12-26 23:59:11 +01:00
|
|
|
qDebug() << "Last.fm error" << error;
|
|
|
|
if (!initial_tune_)
|
|
|
|
return;
|
|
|
|
|
2010-06-23 15:21:30 +02:00
|
|
|
model()->task_manager()->SetTaskFinished(tune_task_id_);
|
|
|
|
tune_task_id_ = 0;
|
2009-12-26 22:35:45 +01:00
|
|
|
|
|
|
|
if (error == lastfm::ws::NotEnoughContent) {
|
2010-05-18 22:43:10 +02:00
|
|
|
emit AsyncLoadFinished(PlaylistItem::SpecialLoadResult(
|
|
|
|
PlaylistItem::SpecialLoadResult::NoMoreTracks, last_url_));
|
2009-12-26 22:35:45 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
emit StreamError(ErrorString(error));
|
|
|
|
}
|
|
|
|
|
|
|
|
QString LastFMService::ErrorString(lastfm::ws::Error error) const {
|
|
|
|
switch (error) {
|
2010-02-23 19:33:09 +01:00
|
|
|
case lastfm::ws::InvalidService: return tr("Invalid service");
|
|
|
|
case lastfm::ws::InvalidMethod: return tr("Invalid method");
|
|
|
|
case lastfm::ws::AuthenticationFailed: return tr("Authentication failed");
|
|
|
|
case lastfm::ws::InvalidFormat: return tr("Invalid format");
|
|
|
|
case lastfm::ws::InvalidParameters: return tr("Invalid parameters");
|
|
|
|
case lastfm::ws::InvalidResourceSpecified: return tr("Invalid resource specified");
|
|
|
|
case lastfm::ws::OperationFailed: return tr("Operation failed");
|
|
|
|
case lastfm::ws::InvalidSessionKey: return tr("Invalid session key");
|
|
|
|
case lastfm::ws::InvalidApiKey: return tr("Invalid API key");
|
|
|
|
case lastfm::ws::ServiceOffline: return tr("Service offline");
|
|
|
|
case lastfm::ws::SubscribersOnly: return tr("This stream is for paid subscribers only");
|
|
|
|
|
|
|
|
case lastfm::ws::TryAgainLater: return tr("Last.fm is currently busy, please try again in a few minutes");
|
|
|
|
|
|
|
|
case lastfm::ws::NotEnoughContent: return tr("Not enough content");
|
|
|
|
case lastfm::ws::NotEnoughMembers: return tr("Not enough members");
|
|
|
|
case lastfm::ws::NotEnoughFans: return tr("Not enough fans");
|
2010-04-15 18:12:44 +02:00
|
|
|
case lastfm::ws::NotEnoughNeighbours: return tr("Not enough neighbors");
|
2010-02-23 19:33:09 +01:00
|
|
|
|
|
|
|
case lastfm::ws::MalformedResponse: return tr("Malformed response");
|
2009-12-26 22:35:45 +01:00
|
|
|
|
|
|
|
case lastfm::ws::UnknownError:
|
|
|
|
default:
|
2010-02-23 19:33:09 +01:00
|
|
|
return tr("Unknown error");
|
2009-12-26 22:35:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LastFMService::TunerTrackAvailable() {
|
2009-12-26 23:59:11 +01:00
|
|
|
if (initial_tune_) {
|
2010-05-18 22:43:10 +02:00
|
|
|
emit AsyncLoadFinished(LoadNext(last_url_));
|
2009-12-26 23:59:11 +01:00
|
|
|
initial_tune_ = false;
|
|
|
|
}
|
2009-12-26 22:35:45 +01:00
|
|
|
}
|
2009-12-29 20:22:02 +01:00
|
|
|
|
|
|
|
bool LastFMService::InitScrobbler() {
|
2009-12-29 21:48:50 +01:00
|
|
|
if (!IsAuthenticated() || !IsScrobblingEnabled())
|
2009-12-29 20:22:02 +01:00
|
|
|
return false;
|
|
|
|
|
2009-12-29 20:57:33 +01:00
|
|
|
if (!scrobbler_)
|
2009-12-29 20:22:02 +01:00
|
|
|
scrobbler_ = new lastfm::Audioscrobbler(kAudioscrobblerClientId);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
lastfm::Track LastFMService::TrackFromSong(const Song &song) const {
|
|
|
|
if (song.title() == last_track_.title() &&
|
|
|
|
song.artist() == last_track_.artist() &&
|
|
|
|
song.album() == last_track_.album())
|
|
|
|
return last_track_;
|
|
|
|
|
|
|
|
lastfm::Track ret;
|
|
|
|
song.ToLastFM(&ret);
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void LastFMService::NowPlaying(const Song &song) {
|
|
|
|
if (!InitScrobbler())
|
|
|
|
return;
|
|
|
|
|
2009-12-29 21:11:03 +01:00
|
|
|
last_track_ = TrackFromSong(song);
|
|
|
|
|
|
|
|
lastfm::MutableTrack mtrack(last_track_);
|
|
|
|
mtrack.stamp();
|
2010-03-21 01:22:15 +01:00
|
|
|
last_track_ = mtrack;
|
2009-12-29 21:11:03 +01:00
|
|
|
|
2010-03-21 01:22:15 +01:00
|
|
|
scrobbler_->nowPlaying(mtrack);
|
2009-12-29 20:22:02 +01:00
|
|
|
}
|
|
|
|
|
2009-12-29 21:11:03 +01:00
|
|
|
void LastFMService::Scrobble() {
|
2009-12-29 20:22:02 +01:00
|
|
|
if (!InitScrobbler())
|
|
|
|
return;
|
|
|
|
|
2009-12-29 21:11:03 +01:00
|
|
|
scrobbler_->cache(last_track_);
|
|
|
|
scrobbler_->submit();
|
2009-12-29 20:22:02 +01:00
|
|
|
}
|
|
|
|
|
2009-12-29 21:11:03 +01:00
|
|
|
void LastFMService::Love() {
|
2009-12-29 21:48:50 +01:00
|
|
|
if (!IsAuthenticated())
|
2010-02-03 19:32:48 +01:00
|
|
|
ShowConfig();
|
2009-12-29 21:48:50 +01:00
|
|
|
|
2009-12-29 21:11:03 +01:00
|
|
|
lastfm::MutableTrack mtrack(last_track_);
|
2009-12-29 20:22:02 +01:00
|
|
|
mtrack.love();
|
2010-03-21 01:22:15 +01:00
|
|
|
last_track_ = mtrack;
|
2009-12-29 20:22:02 +01:00
|
|
|
}
|
|
|
|
|
2009-12-29 21:11:03 +01:00
|
|
|
void LastFMService::Ban() {
|
|
|
|
lastfm::MutableTrack mtrack(last_track_);
|
2009-12-29 20:22:02 +01:00
|
|
|
mtrack.ban();
|
2010-03-21 01:22:15 +01:00
|
|
|
last_track_ = mtrack;
|
2009-12-29 21:48:50 +01:00
|
|
|
|
|
|
|
Scrobble();
|
2010-06-21 14:16:05 +02:00
|
|
|
emit AsyncLoadFinished(LoadNext(last_url_));
|
2009-12-29 20:22:02 +01:00
|
|
|
}
|
2009-12-30 00:01:07 +01:00
|
|
|
|
2010-05-09 19:53:27 +02:00
|
|
|
void LastFMService::ShowContextMenu(RadioItem* item, const QModelIndex&,
|
|
|
|
const QPoint &global_pos) {
|
2009-12-30 02:41:37 +01:00
|
|
|
context_item_ = item;
|
|
|
|
|
2009-12-30 03:23:09 +01:00
|
|
|
switch (item->type) {
|
|
|
|
case Type_Artist:
|
|
|
|
case Type_Tag:
|
2010-10-07 15:59:24 +02:00
|
|
|
case Type_Custom:
|
2009-12-30 03:23:09 +01:00
|
|
|
remove_action_->setEnabled(true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
remove_action_->setEnabled(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-12-30 02:41:37 +01:00
|
|
|
play_action_->setEnabled(item->playable);
|
2010-12-04 16:49:43 +01:00
|
|
|
load_action_->setEnabled(item->playable);
|
2009-12-30 00:01:07 +01:00
|
|
|
context_menu_->popup(global_pos);
|
|
|
|
}
|
2009-12-30 01:31:00 +01:00
|
|
|
|
|
|
|
void LastFMService::RefreshFriends() {
|
|
|
|
if (!friends_list_ || !IsAuthenticated())
|
|
|
|
return;
|
|
|
|
|
|
|
|
friends_list_->ClearNotify();
|
|
|
|
|
|
|
|
lastfm::AuthenticatedUser user;
|
|
|
|
QNetworkReply* reply = user.getFriends();
|
|
|
|
connect(reply, SIGNAL(finished()), SLOT(RefreshFriendsFinished()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void LastFMService::RefreshNeighbours() {
|
|
|
|
if (!friends_list_ || !IsAuthenticated())
|
|
|
|
return;
|
|
|
|
|
|
|
|
neighbours_list_->ClearNotify();
|
|
|
|
|
|
|
|
lastfm::AuthenticatedUser user;
|
|
|
|
QNetworkReply* reply = user.getNeighbours();
|
|
|
|
connect(reply, SIGNAL(finished()), SLOT(RefreshNeighboursFinished()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void LastFMService::RefreshFriendsFinished() {
|
|
|
|
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
|
|
|
|
if (!reply)
|
|
|
|
return;
|
|
|
|
|
|
|
|
QList<lastfm::User> friends;
|
|
|
|
|
|
|
|
try {
|
|
|
|
friends = lastfm::User::list(reply);
|
2010-09-14 01:44:11 +02:00
|
|
|
#ifdef Q_OS_WIN32
|
|
|
|
if (lastfm::ws::last_parse_error != lastfm::ws::NoError)
|
2010-09-14 01:52:05 +02:00
|
|
|
throw std::runtime_error("");
|
2010-09-14 01:44:11 +02:00
|
|
|
#endif
|
2009-12-30 01:31:00 +01:00
|
|
|
} catch (std::runtime_error& e) {
|
|
|
|
qDebug() << e.what();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (const lastfm::User& f, friends) {
|
2009-12-30 02:29:47 +01:00
|
|
|
RadioItem* item = new RadioItem(this, Type_OtherUser, f);
|
2009-12-30 01:31:00 +01:00
|
|
|
item->icon = QIcon(":last.fm/icon_user.png");
|
|
|
|
item->playable = true;
|
|
|
|
item->InsertNotify(friends_list_);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LastFMService::RefreshNeighboursFinished() {
|
|
|
|
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
|
|
|
|
if (!reply)
|
|
|
|
return;
|
|
|
|
|
|
|
|
QList<lastfm::User> neighbours;
|
|
|
|
|
|
|
|
try {
|
|
|
|
neighbours = lastfm::User::list(reply);
|
2010-09-14 01:44:11 +02:00
|
|
|
#ifdef Q_OS_WIN32
|
|
|
|
if (lastfm::ws::last_parse_error != lastfm::ws::NoError)
|
2010-09-14 01:52:05 +02:00
|
|
|
throw std::runtime_error("");
|
2010-09-14 01:44:11 +02:00
|
|
|
#endif
|
2009-12-30 01:31:00 +01:00
|
|
|
} catch (std::runtime_error& e) {
|
|
|
|
qDebug() << e.what();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (const lastfm::User& n, neighbours) {
|
2009-12-30 02:29:47 +01:00
|
|
|
RadioItem* item = new RadioItem(this, Type_OtherUser, n);
|
2009-12-30 01:31:00 +01:00
|
|
|
item->icon = QIcon(":last.fm/user_purple.png");
|
|
|
|
item->playable = true;
|
|
|
|
item->InsertNotify(neighbours_list_);
|
|
|
|
}
|
|
|
|
}
|
2009-12-30 02:41:37 +01:00
|
|
|
|
|
|
|
void LastFMService::AddToPlaylist() {
|
2010-12-04 16:49:43 +01:00
|
|
|
emit AddItemToPlaylist(context_item_, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LastFMService::LoadToPlaylist() {
|
|
|
|
emit AddItemToPlaylist(context_item_, true);
|
2009-12-30 02:41:37 +01:00
|
|
|
}
|
2009-12-30 03:15:38 +01:00
|
|
|
|
|
|
|
void LastFMService::AddArtistRadio() {
|
|
|
|
AddArtistOrTag("artists", LastFMStationDialog::Artist, Type_Artist, QIcon(":last.fm/icon_radio.png"), artist_list_);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LastFMService::AddTagRadio() {
|
|
|
|
AddArtistOrTag("tags", LastFMStationDialog::Tag, Type_Tag, QIcon(":last.fm/icon_tag.png"), tag_list_);
|
|
|
|
}
|
|
|
|
|
2010-10-07 15:59:24 +02:00
|
|
|
void LastFMService::AddCustomRadio() {
|
|
|
|
AddArtistOrTag("custom", LastFMStationDialog::Custom, Type_Custom, QIcon(":last.fm/icon_radio.png"), custom_list_);
|
|
|
|
}
|
|
|
|
|
2009-12-30 03:15:38 +01:00
|
|
|
void LastFMService::AddArtistOrTag(const QString& name,
|
|
|
|
LastFMStationDialog::Type dialog_type, ItemType item_type,
|
|
|
|
const QIcon& icon, RadioItem* list) {
|
|
|
|
station_dialog_->SetType(dialog_type);
|
|
|
|
if (station_dialog_->exec() == QDialog::Rejected)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (station_dialog_->content().isEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
RadioItem* item = new RadioItem(this, item_type, station_dialog_->content());
|
|
|
|
item->icon = icon;
|
|
|
|
item->playable = true;
|
|
|
|
item->lazy_loaded = true;
|
|
|
|
item->InsertNotify(list);
|
2010-12-04 16:49:43 +01:00
|
|
|
emit AddItemToPlaylist(item, false);
|
2009-12-30 03:15:38 +01:00
|
|
|
|
|
|
|
SaveList(name, list);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LastFMService::SaveList(const QString& name, RadioItem* list) const {
|
|
|
|
QSettings settings;
|
|
|
|
settings.beginGroup(kSettingsGroup);
|
|
|
|
|
|
|
|
settings.beginWriteArray(name, list->children.count());
|
|
|
|
for (int i=0 ; i<list->children.count() ; ++i) {
|
|
|
|
settings.setArrayIndex(i);
|
|
|
|
settings.setValue("key", list->children[i]->key);
|
|
|
|
}
|
|
|
|
settings.endArray();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LastFMService::RestoreList(const QString &name, ItemType item_type,
|
|
|
|
const QIcon& icon, RadioItem *list) {
|
|
|
|
QSettings settings;
|
|
|
|
settings.beginGroup(kSettingsGroup);
|
|
|
|
|
|
|
|
list->ClearNotify();
|
|
|
|
|
|
|
|
int count = settings.beginReadArray(name);
|
|
|
|
for (int i=0 ; i<count ; ++i) {
|
|
|
|
settings.setArrayIndex(i);
|
|
|
|
RadioItem* item = new RadioItem(this, item_type,
|
|
|
|
settings.value("key").toString(), list);
|
|
|
|
item->icon = icon;
|
|
|
|
item->playable = true;
|
|
|
|
item->lazy_loaded = true;
|
|
|
|
}
|
|
|
|
settings.endArray();
|
|
|
|
}
|
2009-12-30 03:23:09 +01:00
|
|
|
|
|
|
|
void LastFMService::Remove() {
|
|
|
|
int type = context_item_->type;
|
|
|
|
|
|
|
|
context_item_->parent->DeleteNotify(context_item_->row);
|
|
|
|
|
|
|
|
if (type == Type_Artist)
|
|
|
|
SaveList("artists", artist_list_);
|
|
|
|
else if (type == Type_Tag)
|
|
|
|
SaveList("tags", tag_list_);
|
2010-10-07 15:59:24 +02:00
|
|
|
else if (type == Type_Custom)
|
|
|
|
SaveList("custom", custom_list_);
|
2009-12-30 03:23:09 +01:00
|
|
|
}
|
2010-02-25 01:18:32 +01:00
|
|
|
|
|
|
|
void LastFMService::FetchMoreTracks() {
|
|
|
|
QMap<QString, QString> params;
|
|
|
|
params["method"] = "radio.getPlaylist";
|
|
|
|
params["rtp"] = "1";
|
|
|
|
QNetworkReply* reply = lastfm::ws::post(params);
|
|
|
|
connect(reply, SIGNAL(finished()), SLOT(FetchMoreTracksFinished()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void LastFMService::FetchMoreTracksFinished() {
|
|
|
|
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
|
|
|
|
if (!reply) {
|
|
|
|
qWarning() << "Invalid reply on radio.getPlaylist";
|
2010-05-18 22:43:10 +02:00
|
|
|
emit AsyncLoadFinished(PlaylistItem::SpecialLoadResult(
|
|
|
|
PlaylistItem::SpecialLoadResult::NoMoreTracks, reply->url()));
|
2010-02-25 01:18:32 +01:00
|
|
|
return;
|
|
|
|
}
|
2010-03-18 18:18:54 +01:00
|
|
|
reply->deleteLater();
|
2010-06-23 15:21:30 +02:00
|
|
|
model()->task_manager()->SetTaskFinished(tune_task_id_);
|
|
|
|
tune_task_id_ = 0;
|
2010-02-25 01:18:32 +01:00
|
|
|
|
2010-03-18 18:18:54 +01:00
|
|
|
try {
|
|
|
|
const XmlQuery& query = lastfm::ws::parse(reply);
|
2010-09-14 01:44:11 +02:00
|
|
|
#ifdef Q_OS_WIN32
|
|
|
|
if (lastfm::ws::last_parse_error != lastfm::ws::NoError)
|
2010-09-14 01:52:05 +02:00
|
|
|
throw std::runtime_error("");
|
2010-09-14 01:44:11 +02:00
|
|
|
#endif
|
|
|
|
|
2010-03-18 18:18:54 +01:00
|
|
|
const XmlQuery& playlist = query["playlist"];
|
|
|
|
foreach (const XmlQuery& q, playlist["trackList"].children("track")) {
|
|
|
|
lastfm::MutableTrack t;
|
|
|
|
t.setUrl(q["location"].text());
|
|
|
|
t.setExtra("trackauth", q["extension"]["trackauth"].text());
|
|
|
|
t.setTitle(q["title"].text());
|
|
|
|
t.setArtist(q["creator"].text());
|
|
|
|
t.setAlbum(q["album"].text());
|
|
|
|
t.setDuration(q["duration"].text().toInt() / 1000);
|
|
|
|
t.setSource(lastfm::Track::LastFmRadio);
|
2010-05-17 00:46:56 +02:00
|
|
|
|
|
|
|
art_urls_[t] = q["image"].text();
|
2010-03-18 18:18:54 +01:00
|
|
|
playlist_ << t;
|
2010-02-25 01:18:32 +01:00
|
|
|
}
|
2010-03-18 18:18:54 +01:00
|
|
|
} catch (std::runtime_error& e) {
|
2010-05-17 01:16:38 +02:00
|
|
|
// For some reason a catch block that takes a lastfm::ws::ParseError&
|
|
|
|
// doesn't get called, even when a lastfm::ws::ParseError is thrown...
|
|
|
|
// Hacks like this remind me of Java...
|
|
|
|
if (QString(typeid(e).name()).contains("ParseError")) {
|
|
|
|
// dynamic_cast throws a std::bad_cast ... *boggle*
|
2010-09-29 21:26:02 +02:00
|
|
|
emit StreamError(tr("Couldn't load the last.fm radio station")
|
|
|
|
.arg(e.what()));
|
2010-05-17 01:16:38 +02:00
|
|
|
} else {
|
|
|
|
emit StreamError(tr("An unknown last.fm error occurred: %1").arg(e.what()));
|
|
|
|
}
|
2010-03-18 18:18:54 +01:00
|
|
|
return;
|
2010-02-25 01:18:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
TunerTrackAvailable();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LastFMService::Tune(const lastfm::RadioStation& station) {
|
2010-02-25 02:20:59 +01:00
|
|
|
playlist_.clear();
|
2010-05-17 00:46:56 +02:00
|
|
|
|
|
|
|
// Remove all the old album art URLs
|
|
|
|
art_urls_.clear();
|
2010-02-25 18:47:01 +01:00
|
|
|
|
2010-02-25 01:18:32 +01:00
|
|
|
QMap<QString, QString> params;
|
|
|
|
params["method"] = "radio.tune";
|
|
|
|
params["station"] = station.url();
|
|
|
|
QNetworkReply* reply = lastfm::ws::post(params);
|
|
|
|
connect(reply, SIGNAL(finished()), SLOT(TuneFinished()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void LastFMService::TuneFinished() {
|
|
|
|
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
|
|
|
|
if (!reply) {
|
|
|
|
qWarning() << "Invalid reply on radio.tune";
|
2010-05-18 22:43:10 +02:00
|
|
|
emit AsyncLoadFinished(PlaylistItem::SpecialLoadResult(
|
|
|
|
PlaylistItem::SpecialLoadResult::NoMoreTracks, reply->url()));
|
2010-02-25 01:18:32 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
FetchMoreTracks();
|
|
|
|
reply->deleteLater();
|
|
|
|
}
|
2010-05-18 22:43:10 +02:00
|
|
|
|
|
|
|
PlaylistItem::Options LastFMService::playlistitem_options() const {
|
|
|
|
return PlaylistItem::SpecialPlayBehaviour |
|
|
|
|
PlaylistItem::LastFMControls |
|
|
|
|
PlaylistItem::PauseDisabled |
|
|
|
|
PlaylistItem::ContainsMultipleTracks;
|
|
|
|
}
|
2010-10-16 17:22:14 +02:00
|
|
|
|
|
|
|
PlaylistItemPtr LastFMService::PlaylistItemForUrl(const QUrl& url) {
|
|
|
|
// This is a bit of a hack, it's only used by the artist/song info tag
|
|
|
|
// widgets for tag radio and similar artists radio.
|
|
|
|
|
|
|
|
PlaylistItemPtr ret;
|
|
|
|
|
|
|
|
if (url.scheme() != "lastfm")
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
QStringList sections(url.path().split("/", QString::SkipEmptyParts));
|
|
|
|
|
|
|
|
if (sections.count() == 2 && url.host() == "artist" && sections[1] == "similarartists") {
|
|
|
|
ret.reset(new RadioPlaylistItem(this, url,
|
|
|
|
tr("Last.fm Similar Artists to %1").arg(sections[0]), QString()));
|
|
|
|
} else if (sections.count() == 1 && url.host() == "globaltags") {
|
|
|
|
ret.reset(new RadioPlaylistItem(this, url,
|
|
|
|
tr("Last.fm Tag Radio: %1").arg(sections[0]), QString()));
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|