Get GrooveShark songs' length (give the ability to seek through stream). markStream and markSongComplete, as resquested by GrooveShark
This commit is contained in:
parent
f142279a0a
commit
4143823870
|
@ -104,6 +104,14 @@ void Player::HandleLoadResult(const UrlHandler::LoadResult& result) {
|
||||||
qLog(Debug) << "URL handler for" << result.original_url_
|
qLog(Debug) << "URL handler for" << result.original_url_
|
||||||
<< "returned" << result.media_url_;
|
<< "returned" << result.media_url_;
|
||||||
|
|
||||||
|
// If there was no length info in song's metadata, use the one provided by
|
||||||
|
// URL handler, if there is one
|
||||||
|
if (item->Metadata().length_nanosec() <= 0 && result.length_nanosec_ != -1) {
|
||||||
|
Song song = item->Metadata();
|
||||||
|
song.set_length_nanosec(result.length_nanosec_);
|
||||||
|
item->SetTemporaryMetadata(song);
|
||||||
|
playlists_->active()->UpdateItems(SongList() << song);
|
||||||
|
}
|
||||||
engine_->Play(result.media_url_, stream_change_type_,
|
engine_->Play(result.media_url_, stream_change_type_,
|
||||||
item->Metadata().has_cue(),
|
item->Metadata().has_cue(),
|
||||||
item->Metadata().beginning_nanosec(),
|
item->Metadata().beginning_nanosec(),
|
||||||
|
@ -276,6 +284,10 @@ int Player::GetVolume() const {
|
||||||
void Player::PlayAt(int index, Engine::TrackChangeFlags change, bool reshuffle) {
|
void Player::PlayAt(int index, Engine::TrackChangeFlags change, bool reshuffle) {
|
||||||
if (change == Engine::Manual && engine_->position_nanosec() != engine_->length_nanosec()) {
|
if (change == Engine::Manual && engine_->position_nanosec() != engine_->length_nanosec()) {
|
||||||
emit TrackSkipped(current_item_);
|
emit TrackSkipped(current_item_);
|
||||||
|
const QUrl& url = current_item_->Url();
|
||||||
|
if (url_handlers_.contains(url.scheme())) {
|
||||||
|
url_handlers_[url.scheme()]->TrackSkipped();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current_item_ && current_item_->Metadata().IsOnSameAlbum(
|
if (current_item_ && current_item_->Metadata().IsOnSameAlbum(
|
||||||
|
@ -427,8 +439,10 @@ void Player::TrackAboutToEnd() {
|
||||||
// again immediately after.
|
// again immediately after.
|
||||||
if (playlists_->active()->current_item()) {
|
if (playlists_->active()->current_item()) {
|
||||||
const QUrl url = playlists_->active()->current_item()->Url();
|
const QUrl url = playlists_->active()->current_item()->Url();
|
||||||
if (url_handlers_.contains(url.scheme()))
|
if (url_handlers_.contains(url.scheme())) {
|
||||||
|
url_handlers_[url.scheme()]->TrackAboutToEnd();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool has_next_row = playlists_->active()->next_row() != -1;
|
const bool has_next_row = playlists_->active()->next_row() != -1;
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
#include "urlhandler.h"
|
#include "urlhandler.h"
|
||||||
|
|
||||||
UrlHandler::LoadResult::LoadResult(
|
UrlHandler::LoadResult::LoadResult(
|
||||||
const QUrl& original_url, Type type, const QUrl& media_url)
|
const QUrl& original_url, Type type, const QUrl& media_url, qint64 length_nanosec)
|
||||||
: original_url_(original_url), type_(type), media_url_(media_url)
|
: original_url_(original_url), type_(type), media_url_(media_url), length_nanosec_(length_nanosec)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,8 @@ public:
|
||||||
|
|
||||||
LoadResult(const QUrl& original_url = QUrl(),
|
LoadResult(const QUrl& original_url = QUrl(),
|
||||||
Type type = NoMoreTracks,
|
Type type = NoMoreTracks,
|
||||||
const QUrl& media_url = QUrl());
|
const QUrl& media_url = QUrl(),
|
||||||
|
qint64 length_nanosec_ = -1);
|
||||||
|
|
||||||
// The url that the playlist item has in Url().
|
// The url that the playlist item has in Url().
|
||||||
// Might be something unplayable like lastfm://...
|
// Might be something unplayable like lastfm://...
|
||||||
|
@ -59,6 +60,9 @@ public:
|
||||||
|
|
||||||
// The actual url to something that gstreamer can play.
|
// The actual url to something that gstreamer can play.
|
||||||
QUrl media_url_;
|
QUrl media_url_;
|
||||||
|
|
||||||
|
// Track length, if we are able to get it only now
|
||||||
|
qint64 length_nanosec_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Called by the Player when a song starts loading - gives the handler
|
// Called by the Player when a song starts loading - gives the handler
|
||||||
|
@ -69,6 +73,10 @@ public:
|
||||||
// get another track to play.
|
// get another track to play.
|
||||||
virtual LoadResult LoadNext(const QUrl& url) { return LoadResult(url); }
|
virtual LoadResult LoadNext(const QUrl& url) { return LoadResult(url); }
|
||||||
|
|
||||||
|
// Functions to be warned when something happen to a track handled by UrlHandler.
|
||||||
|
virtual void TrackAboutToEnd() { };
|
||||||
|
virtual void TrackSkipped() { };
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void AsyncLoadComplete(const UrlHandler::LoadResult& result);
|
void AsyncLoadComplete(const UrlHandler::LoadResult& result);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* This file is part of Clementine.
|
/* This file is part of Clementine.
|
||||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
Copyright 2011, David Sansome <me@davidsansome.com>
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
Clementine is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -156,9 +156,8 @@ void GrooveSharkService::InitCountry() {
|
||||||
if (!country_.isEmpty())
|
if (!country_.isEmpty())
|
||||||
return;
|
return;
|
||||||
// Get country info
|
// Get country info
|
||||||
QNetworkReply *reply_country;
|
QNetworkReply *reply_country = CreateRequest("getCountry", QList<Param>(), true);
|
||||||
|
|
||||||
reply_country = CreateRequest("getCountry", QList<Param>(), true);
|
|
||||||
// Wait for the reply
|
// Wait for the reply
|
||||||
{
|
{
|
||||||
QEventLoop event_loop;
|
QEventLoop event_loop;
|
||||||
|
@ -176,14 +175,14 @@ void GrooveSharkService::InitCountry() {
|
||||||
country_ = ExtractResult(reply_country);
|
country_ = ExtractResult(reply_country);
|
||||||
}
|
}
|
||||||
|
|
||||||
QUrl GrooveSharkService::GetStreamingUrlFromSongId(const QString& song_id) {
|
QUrl GrooveSharkService::GetStreamingUrlFromSongId(const QString& song_id,
|
||||||
|
QString* server_id, QString* stream_key, qint64* length_nanosec) {
|
||||||
QList<Param> parameters;
|
QList<Param> parameters;
|
||||||
QNetworkReply *reply;
|
|
||||||
|
|
||||||
InitCountry();
|
InitCountry();
|
||||||
parameters << Param("songID", song_id)
|
parameters << Param("songID", song_id)
|
||||||
<< Param("country", country_);
|
<< Param("country", country_);
|
||||||
reply = CreateRequest("getSubscriberStreamKey", parameters, true);
|
QNetworkReply* reply = CreateRequest("getSubscriberStreamKey", parameters, true);
|
||||||
// Wait for the reply
|
// Wait for the reply
|
||||||
{
|
{
|
||||||
QEventLoop event_loop;
|
QEventLoop event_loop;
|
||||||
|
@ -199,6 +198,11 @@ QUrl GrooveSharkService::GetStreamingUrlFromSongId(const QString& song_id) {
|
||||||
timeout_timer.stop();
|
timeout_timer.stop();
|
||||||
}
|
}
|
||||||
QVariantMap result = ExtractResult(reply);
|
QVariantMap result = ExtractResult(reply);
|
||||||
|
server_id->clear();
|
||||||
|
server_id->append(result["StreamServerID"].toString());
|
||||||
|
stream_key->clear();
|
||||||
|
stream_key->append(result["StreamKey"].toString());
|
||||||
|
*length_nanosec = result["uSecs"].toLongLong() * 1000;
|
||||||
|
|
||||||
return QUrl(result["url"].toString());
|
return QUrl(result["url"].toString());
|
||||||
}
|
}
|
||||||
|
@ -211,9 +215,7 @@ void GrooveSharkService::Login(const QString& username, const QString& password)
|
||||||
password_ = QCryptographicHash::hash(password.toLocal8Bit(), QCryptographicHash::Md5).toHex();
|
password_ = QCryptographicHash::hash(password.toLocal8Bit(), QCryptographicHash::Md5).toHex();
|
||||||
|
|
||||||
QList<Param> parameters;
|
QList<Param> parameters;
|
||||||
QNetworkReply *reply;
|
QNetworkReply *reply = CreateRequest("startSession", parameters, false, true);
|
||||||
|
|
||||||
reply = CreateRequest("startSession", parameters, false, true);
|
|
||||||
|
|
||||||
connect(reply, SIGNAL(finished()), SLOT(SessionCreated()));
|
connect(reply, SIGNAL(finished()), SLOT(SessionCreated()));
|
||||||
}
|
}
|
||||||
|
@ -237,13 +239,10 @@ void GrooveSharkService::SessionCreated() {
|
||||||
|
|
||||||
void GrooveSharkService::AuthenticateSession() {
|
void GrooveSharkService::AuthenticateSession() {
|
||||||
QList<Param> parameters;
|
QList<Param> parameters;
|
||||||
QNetworkReply *reply;
|
|
||||||
|
|
||||||
parameters << Param("login", username_)
|
parameters << Param("login", username_)
|
||||||
<< Param("password", password_);
|
<< Param("password", password_);
|
||||||
|
|
||||||
reply = CreateRequest("authenticate", parameters, true, true);
|
QNetworkReply *reply = CreateRequest("authenticate", parameters, true, true);
|
||||||
|
|
||||||
connect(reply, SIGNAL(finished()), SLOT(Authenticated()));
|
connect(reply, SIGNAL(finished()), SLOT(Authenticated()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,9 +332,7 @@ void GrooveSharkService::EnsureConnected() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrooveSharkService::RetrieveUserPlaylists() {
|
void GrooveSharkService::RetrieveUserPlaylists() {
|
||||||
QNetworkReply *reply;
|
QNetworkReply* reply = CreateRequest("getUserPlaylists", QList<Param>(), true);
|
||||||
|
|
||||||
reply = CreateRequest("getUserPlaylists", QList<Param>(), true);
|
|
||||||
|
|
||||||
connect(reply, SIGNAL(finished()), SLOT(UserPlaylistsRetrieved()));
|
connect(reply, SIGNAL(finished()), SLOT(UserPlaylistsRetrieved()));
|
||||||
}
|
}
|
||||||
|
@ -396,6 +393,53 @@ void GrooveSharkService::PlaylistSongsRetrieved() {
|
||||||
root_->appendRow(item);
|
root_->appendRow(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GrooveSharkService::MarkStreamKeyOver30Secs(const QString& stream_key,
|
||||||
|
const QString& server_id) {
|
||||||
|
QList<Param> parameters;
|
||||||
|
parameters << Param("streamKey", stream_key)
|
||||||
|
<< Param("streamServerID", server_id);
|
||||||
|
|
||||||
|
QNetworkReply* reply = CreateRequest("markStreamKeyOver30Secs", parameters, true, false);
|
||||||
|
connect(reply, SIGNAL(finished()), SLOT(StreamMarked()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GrooveSharkService::StreamMarked() {
|
||||||
|
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
|
||||||
|
if (!reply)
|
||||||
|
return;
|
||||||
|
|
||||||
|
reply->deleteLater();
|
||||||
|
QVariantMap result = ExtractResult(reply);
|
||||||
|
if (!result["success"].toBool()) {
|
||||||
|
qLog(Warning) << "GrooveShark markStreamKeyOver30Secs failed";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GrooveSharkService::MarkSongComplete(const QString& song_id,
|
||||||
|
const QString& stream_key,
|
||||||
|
const QString& server_id) {
|
||||||
|
QList<Param> parameters;
|
||||||
|
parameters << Param("songID", song_id)
|
||||||
|
<< Param("streamKey", stream_key)
|
||||||
|
<< Param("streamServerID", server_id);
|
||||||
|
|
||||||
|
QNetworkReply* reply = CreateRequest("markSongComplete", parameters, true, false);
|
||||||
|
connect(reply, SIGNAL(finished()), SLOT(SongMarkedAsComplete()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GrooveSharkService::SongMarkedAsComplete() {
|
||||||
|
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
|
||||||
|
if (!reply)
|
||||||
|
return;
|
||||||
|
|
||||||
|
reply->deleteLater();
|
||||||
|
QVariantMap result = ExtractResult(reply);
|
||||||
|
if (!result["success"].toBool()) {
|
||||||
|
qLog(Warning) << "GrooveShark markSongComplete failed";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GrooveSharkService::OpenSearchTab() {
|
void GrooveSharkService::OpenSearchTab() {
|
||||||
model()->player()->playlists()->New(tr("Search GrooveShark"), SongList(),
|
model()->player()->playlists()->New(tr("Search GrooveShark"), SongList(),
|
||||||
GrooveSharkSearchPlaylistType::kName);
|
GrooveSharkSearchPlaylistType::kName);
|
||||||
|
@ -411,7 +455,6 @@ QNetworkReply* GrooveSharkService::CreateRequest(const QString& method_name, QLi
|
||||||
bool need_authentication,
|
bool need_authentication,
|
||||||
bool use_https) {
|
bool use_https) {
|
||||||
QVariantMap request_params;
|
QVariantMap request_params;
|
||||||
|
|
||||||
request_params.insert("method", method_name);
|
request_params.insert("method", method_name);
|
||||||
|
|
||||||
QVariantMap header;
|
QVariantMap header;
|
||||||
|
@ -470,7 +513,6 @@ SongList GrooveSharkService::ExtractSongs(const QVariantMap& result) {
|
||||||
QString album_name = result_song["AlbumName"].toString();
|
QString album_name = result_song["AlbumName"].toString();
|
||||||
QString cover = result_song["CoverArtFilename"].toString();
|
QString cover = result_song["CoverArtFilename"].toString();
|
||||||
song.Init(song_name, artist_name, album_name, 0);
|
song.Init(song_name, artist_name, album_name, 0);
|
||||||
song.set_id(song_id);
|
|
||||||
song.set_art_automatic(QString(kUrlCover) + cover);
|
song.set_art_automatic(QString(kUrlCover) + cover);
|
||||||
// Special kind of URL: because we need to request a stream key for each
|
// Special kind of URL: because we need to request a stream key for each
|
||||||
// play, we generate a fake URL for now, and we will create a real streaming
|
// play, we generate a fake URL for now, and we will create a real streaming
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* This file is part of Clementine.
|
/* This file is part of Clementine.
|
||||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
Copyright 2011, David Sansome <me@davidsansome.com>
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
Clementine is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -57,11 +57,15 @@ class GrooveSharkService : public InternetService {
|
||||||
|
|
||||||
void Search(const QString& text, Playlist* playlist, bool now = false);
|
void Search(const QString& text, Playlist* playlist, bool now = false);
|
||||||
// User should be logged in to be able to generate streaming urls
|
// User should be logged in to be able to generate streaming urls
|
||||||
QUrl GetStreamingUrlFromSongId(const QString& song_id);
|
QUrl GetStreamingUrlFromSongId(const QString& song_id,
|
||||||
|
QString* server_id, QString* stream_key,
|
||||||
|
qint64* length_nanosec);
|
||||||
void Login(const QString& username, const QString& password);
|
void Login(const QString& username, const QString& password);
|
||||||
void Logout();
|
void Logout();
|
||||||
bool IsLoggedIn() { return !session_id_.isEmpty(); }
|
bool IsLoggedIn() { return !session_id_.isEmpty(); }
|
||||||
void RetrieveUserPlaylists();
|
void RetrieveUserPlaylists();
|
||||||
|
void MarkStreamKeyOver30Secs(const QString& stream_key, const QString& server_id);
|
||||||
|
void MarkSongComplete(const QString& song_id, const QString& stream_key, const QString& server_id);
|
||||||
|
|
||||||
// Persisted in the settings and updated on each Login().
|
// Persisted in the settings and updated on each Login().
|
||||||
LoginState login_state() const { return login_state_; }
|
LoginState login_state() const { return login_state_; }
|
||||||
|
@ -105,6 +109,8 @@ class GrooveSharkService : public InternetService {
|
||||||
void Authenticated();
|
void Authenticated();
|
||||||
void UserPlaylistsRetrieved();
|
void UserPlaylistsRetrieved();
|
||||||
void PlaylistSongsRetrieved();
|
void PlaylistSongsRetrieved();
|
||||||
|
void StreamMarked();
|
||||||
|
void SongMarkedAsComplete();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void EnsureMenuCreated();
|
void EnsureMenuCreated();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* This file is part of Clementine.
|
/* This file is part of Clementine.
|
||||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
Copyright 2011, David Sansome <me@davidsansome.com>
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
Clementine is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -15,21 +15,55 @@
|
||||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "groovesharkservice.h"
|
|
||||||
#include "groovesharkurlhandler.h"
|
#include "groovesharkurlhandler.h"
|
||||||
|
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include "groovesharkservice.h"
|
||||||
#include "core/logging.h"
|
#include "core/logging.h"
|
||||||
|
|
||||||
|
|
||||||
GrooveSharkUrlHandler::GrooveSharkUrlHandler(GrooveSharkService* service, QObject* parent)
|
GrooveSharkUrlHandler::GrooveSharkUrlHandler(GrooveSharkService* service, QObject* parent)
|
||||||
: UrlHandler(parent),
|
: UrlHandler(parent),
|
||||||
service_(service) {
|
service_(service),
|
||||||
|
timer_mark_stream_key_(new QTimer(this)) {
|
||||||
|
// We have to warn GrooveShark when user has listened for more than 30
|
||||||
|
// seconds of a song, and when it ends. I guess this is used by GrooveShark
|
||||||
|
// for statistics and user history.
|
||||||
|
// To do this, we have TrackAboutToEnd method, and timer_mark_stream_key_ timer.
|
||||||
|
// It is not perfect, as we may call GrooveShark MarkStreamKeyOver30Secs even
|
||||||
|
// if user hasn't actually listen to 30 seconds (e.g. stream set to pause
|
||||||
|
// state) but this is not a big deal and it should be accurate enough anyway.
|
||||||
|
timer_mark_stream_key_->setInterval(30000);
|
||||||
|
timer_mark_stream_key_->setSingleShot(true);
|
||||||
|
connect(timer_mark_stream_key_, SIGNAL(timeout()), SLOT(MarkStreamKeyOver30Secs()));
|
||||||
}
|
}
|
||||||
|
|
||||||
UrlHandler::LoadResult GrooveSharkUrlHandler::StartLoading(const QUrl& url) {
|
UrlHandler::LoadResult GrooveSharkUrlHandler::StartLoading(const QUrl& url) {
|
||||||
QString song_id = url.toString().remove("grooveshark://");
|
qint64 length_nanosec;
|
||||||
QUrl streaming_url = service_->GetStreamingUrlFromSongId(song_id);
|
last_song_id_ = url.toString().remove("grooveshark://");
|
||||||
|
|
||||||
|
QUrl streaming_url = service_->GetStreamingUrlFromSongId(last_song_id_,
|
||||||
|
&last_server_id_, &last_stream_key_, &length_nanosec);
|
||||||
qLog(Debug) << "GrooveShark Streaming URL: " << streaming_url;
|
qLog(Debug) << "GrooveShark Streaming URL: " << streaming_url;
|
||||||
return LoadResult(url, LoadResult::TrackAvailable, streaming_url);
|
|
||||||
|
timer_mark_stream_key_->start();
|
||||||
|
|
||||||
|
return LoadResult(url, LoadResult::TrackAvailable, streaming_url, length_nanosec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GrooveSharkUrlHandler::TrackAboutToEnd() {
|
||||||
|
if (timer_mark_stream_key_->isActive()) {
|
||||||
|
timer_mark_stream_key_->stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
service_->MarkSongComplete(last_song_id_, last_stream_key_, last_server_id_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GrooveSharkUrlHandler::TrackSkipped() {
|
||||||
|
timer_mark_stream_key_->stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GrooveSharkUrlHandler::MarkStreamKeyOver30Secs() {
|
||||||
|
service_->MarkStreamKeyOver30Secs(last_stream_key_, last_server_id_);
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* This file is part of Clementine.
|
/* This file is part of Clementine.
|
||||||
Copyright 2010, David Sansome <me@davidsansome.com>
|
Copyright 2011, David Sansome <me@davidsansome.com>
|
||||||
|
|
||||||
Clementine is free software: you can redistribute it and/or modify
|
Clementine is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -21,19 +21,27 @@
|
||||||
#include "core/urlhandler.h"
|
#include "core/urlhandler.h"
|
||||||
|
|
||||||
class GrooveSharkService;
|
class GrooveSharkService;
|
||||||
|
class QTimer;
|
||||||
|
|
||||||
class GrooveSharkUrlHandler : public UrlHandler {
|
class GrooveSharkUrlHandler : public UrlHandler {
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
GrooveSharkUrlHandler(GrooveSharkService* service, QObject* parent);
|
GrooveSharkUrlHandler(GrooveSharkService* service, QObject* parent);
|
||||||
|
|
||||||
QString scheme() const { return "grooveshark"; }
|
QString scheme() const { return "grooveshark"; }
|
||||||
LoadResult StartLoading(const QUrl& url);
|
LoadResult StartLoading(const QUrl& url);
|
||||||
|
void TrackAboutToEnd();
|
||||||
|
void TrackSkipped();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void MarkStreamKeyOver30Secs();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GrooveSharkService* service_;
|
GrooveSharkService* service_;
|
||||||
|
QTimer* timer_mark_stream_key_;
|
||||||
QString last_song_id_;
|
QString last_song_id_;
|
||||||
QString last_server_id_;
|
QString last_server_id_;
|
||||||
QString last_stream_key;
|
QString last_stream_key_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // GROOVESHARKURLHANDLER_H
|
#endif // GROOVESHARKURLHANDLER_H
|
||||||
|
|
|
@ -969,9 +969,10 @@ void Playlist::UpdateItems(const SongList& songs) {
|
||||||
// Update current items list
|
// Update current items list
|
||||||
for (int i=0; i<items_.size(); i++) {
|
for (int i=0; i<items_.size(); i++) {
|
||||||
PlaylistItemPtr item = items_[i];
|
PlaylistItemPtr item = items_[i];
|
||||||
|
|
||||||
if (item->Metadata().url() == song.url() &&
|
if (item->Metadata().url() == song.url() &&
|
||||||
item->Metadata().filetype() == Song::Type_Unknown) {
|
(item->Metadata().filetype() == Song::Type_Unknown ||
|
||||||
|
// Stream may change and may need to be updated too
|
||||||
|
item->Metadata().filetype() == Song::Type_Stream)) {
|
||||||
PlaylistItemPtr new_item;
|
PlaylistItemPtr new_item;
|
||||||
if (song.id() == -1) {
|
if (song.id() == -1) {
|
||||||
new_item = PlaylistItemPtr(new SongPlaylistItem(song));
|
new_item = PlaylistItemPtr(new SongPlaylistItem(song));
|
||||||
|
|
Loading…
Reference in New Issue