mirror of
https://github.com/clementine-player/Clementine
synced 2025-02-03 12:47:31 +01:00
"Now listening" last.fm notifications
This commit is contained in:
parent
62dda6430c
commit
38feb17697
@ -39,5 +39,7 @@
|
|||||||
<file>last.fm/personal_radio.png</file>
|
<file>last.fm/personal_radio.png</file>
|
||||||
<file>last.fm/recommended_radio.png</file>
|
<file>last.fm/recommended_radio.png</file>
|
||||||
<file>spinner.gif</file>
|
<file>spinner.gif</file>
|
||||||
|
<file>last.fm/ban.png</file>
|
||||||
|
<file>last.fm/love.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
BIN
data/last.fm/ban.png
Normal file
BIN
data/last.fm/ban.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
BIN
data/last.fm/love.png
Normal file
BIN
data/last.fm/love.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
@ -6,18 +6,24 @@
|
|||||||
#include <lastfm/ws.h>
|
#include <lastfm/ws.h>
|
||||||
#include <lastfm/misc.h>
|
#include <lastfm/misc.h>
|
||||||
#include <lastfm/XmlQuery>
|
#include <lastfm/XmlQuery>
|
||||||
|
#include <lastfm/Audioscrobbler>
|
||||||
|
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
|
||||||
|
const char* LastFMService::kServiceName = "Last.fm";
|
||||||
const char* LastFMService::kSettingsGroup = "Last.fm";
|
const char* LastFMService::kSettingsGroup = "Last.fm";
|
||||||
|
const char* LastFMService::kAudioscrobblerClientId = "tng";
|
||||||
|
const char* LastFMService::kApiKey = "75d20fb472be99275392aefa2760ea09";
|
||||||
|
const char* LastFMService::kSecret = "d3072b60ae626be12be69448f5c46e70";
|
||||||
|
|
||||||
LastFMService::LastFMService(QObject* parent)
|
LastFMService::LastFMService(QObject* parent)
|
||||||
: RadioService("Last.fm", parent),
|
: RadioService(kServiceName, parent),
|
||||||
tuner_(NULL),
|
tuner_(NULL),
|
||||||
|
scrobbler_(NULL),
|
||||||
initial_tune_(false)
|
initial_tune_(false)
|
||||||
{
|
{
|
||||||
lastfm::ws::ApiKey = "75d20fb472be99275392aefa2760ea09";
|
lastfm::ws::ApiKey = kApiKey;
|
||||||
lastfm::ws::SharedSecret = "d3072b60ae626be12be69448f5c46e70";
|
lastfm::ws::SharedSecret = kSecret;
|
||||||
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.beginGroup(kSettingsGroup);
|
settings.beginGroup(kSettingsGroup);
|
||||||
@ -31,6 +37,10 @@ LastFMService::~LastFMService() {
|
|||||||
delete config_;
|
delete config_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LastFMService::IsAuthenticated() const {
|
||||||
|
return !lastfm::ws::SessionKey.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
RadioItem* LastFMService::CreateRootItem(RadioItem* parent) {
|
RadioItem* LastFMService::CreateRootItem(RadioItem* parent) {
|
||||||
RadioItem* item = new RadioItem(this, RadioItem::Type_Service, "Last.fm", parent);
|
RadioItem* item = new RadioItem(this, RadioItem::Type_Service, "Last.fm", parent);
|
||||||
item->icon = QIcon(":last.fm/as.png");
|
item->icon = QIcon(":last.fm/as.png");
|
||||||
@ -50,7 +60,7 @@ void LastFMService::LazyPopulate(RadioItem *item) {
|
|||||||
CreateStationItem(Type_MyNeighbourhood, "My Neighbourhood",
|
CreateStationItem(Type_MyNeighbourhood, "My Neighbourhood",
|
||||||
":last.fm/neighbour_radio.png", item);
|
":last.fm/neighbour_radio.png", item);
|
||||||
|
|
||||||
if (lastfm::ws::SessionKey.isEmpty())
|
if (!IsAuthenticated())
|
||||||
config_->show();
|
config_->show();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -106,6 +116,10 @@ void LastFMService::AuthenticateReplyFinished() {
|
|||||||
settings.setValue("username", lastfm::ws::Username);
|
settings.setValue("username", lastfm::ws::Username);
|
||||||
settings.setValue("session", lastfm::ws::SessionKey);
|
settings.setValue("session", lastfm::ws::SessionKey);
|
||||||
|
|
||||||
|
// Invalidate the scrobbler - it will get recreated later
|
||||||
|
delete scrobbler_;
|
||||||
|
scrobbler_ = NULL;
|
||||||
|
|
||||||
emit AuthenticationComplete(true);
|
emit AuthenticationComplete(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +156,7 @@ QList<RadioItem::PlaylistData> LastFMService::DataForItem(RadioItem* item) {
|
|||||||
void LastFMService::StartLoading(const QUrl& url) {
|
void LastFMService::StartLoading(const QUrl& url) {
|
||||||
if (url.scheme() != "lastfm")
|
if (url.scheme() != "lastfm")
|
||||||
return;
|
return;
|
||||||
if (lastfm::ws::SessionKey.isEmpty())
|
if (!IsAuthenticated())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
emit LoadingStarted();
|
emit LoadingStarted();
|
||||||
@ -158,18 +172,18 @@ void LastFMService::StartLoading(const QUrl& url) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LastFMService::LoadNext(const QUrl &) {
|
void LastFMService::LoadNext(const QUrl &) {
|
||||||
lastfm::Track track = tuner_->takeNextTrack();
|
last_track_ = tuner_->takeNextTrack();
|
||||||
|
|
||||||
if (track.isNull()) {
|
if (last_track_.isNull()) {
|
||||||
emit StreamFinished();
|
emit StreamFinished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit StreamReady(last_url_, track.url());
|
|
||||||
|
|
||||||
Song metadata;
|
Song metadata;
|
||||||
metadata.InitFromLastFM(track);
|
metadata.InitFromLastFM(last_track_);
|
||||||
|
|
||||||
emit StreamMetadataFound(last_url_, metadata);
|
emit StreamMetadataFound(last_url_, metadata);
|
||||||
|
emit StreamReady(last_url_, last_track_.url());
|
||||||
}
|
}
|
||||||
|
|
||||||
void LastFMService::TunerError(lastfm::ws::Error error) {
|
void LastFMService::TunerError(lastfm::ws::Error error) {
|
||||||
@ -224,3 +238,60 @@ void LastFMService::TunerTrackAvailable() {
|
|||||||
initial_tune_ = false;
|
initial_tune_ = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LastFMService::InitScrobbler() {
|
||||||
|
if (!IsAuthenticated())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!scrobbler_) {
|
||||||
|
scrobbler_ = new lastfm::Audioscrobbler(kAudioscrobblerClientId);
|
||||||
|
connect(scrobbler_, SIGNAL(status(int)), SLOT(ScrobblerStatus(int)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastfm::Track LastFMService::TrackFromSong(const Song &song) const {
|
||||||
|
qDebug() << song.title() << last_track_.title();
|
||||||
|
qDebug() << song.artist() << last_track_.artist();
|
||||||
|
qDebug() << song.album() << last_track_.album();
|
||||||
|
qDebug() << last_track_.fingerprintId() << last_track_.mbid();
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
scrobbler_->nowPlaying(TrackFromSong(song));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LastFMService::Scrobble(const Song& song) {
|
||||||
|
if (!InitScrobbler())
|
||||||
|
return;
|
||||||
|
|
||||||
|
scrobbler_->cache(TrackFromSong(song));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LastFMService::Love(const Song& song) {
|
||||||
|
lastfm::MutableTrack mtrack(TrackFromSong(song));
|
||||||
|
mtrack.love();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LastFMService::Ban(const Song& song) {
|
||||||
|
lastfm::MutableTrack mtrack(TrackFromSong(song));
|
||||||
|
mtrack.ban();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LastFMService::ScrobblerStatus(int status) {
|
||||||
|
qDebug() << static_cast<lastfm::Audioscrobbler::Status>(status);
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define LASTFMSERVICE_H
|
#define LASTFMSERVICE_H
|
||||||
|
|
||||||
#include "radioservice.h"
|
#include "radioservice.h"
|
||||||
|
#include "song.h"
|
||||||
|
|
||||||
#include <lastfm/RadioTuner>
|
#include <lastfm/RadioTuner>
|
||||||
|
|
||||||
@ -14,7 +15,11 @@ class LastFMService : public RadioService {
|
|||||||
LastFMService(QObject* parent = 0);
|
LastFMService(QObject* parent = 0);
|
||||||
~LastFMService();
|
~LastFMService();
|
||||||
|
|
||||||
|
static const char* kServiceName;
|
||||||
static const char* kSettingsGroup;
|
static const char* kSettingsGroup;
|
||||||
|
static const char* kAudioscrobblerClientId;
|
||||||
|
static const char* kApiKey;
|
||||||
|
static const char* kSecret;
|
||||||
|
|
||||||
enum ItemType {
|
enum ItemType {
|
||||||
Type_MyRecommendations = 1000,
|
Type_MyRecommendations = 1000,
|
||||||
@ -27,15 +32,19 @@ class LastFMService : public RadioService {
|
|||||||
RadioItem* CreateRootItem(RadioItem* parent);
|
RadioItem* CreateRootItem(RadioItem* parent);
|
||||||
void LazyPopulate(RadioItem *item);
|
void LazyPopulate(RadioItem *item);
|
||||||
QList<RadioItem::PlaylistData> DataForItem(RadioItem* item);
|
QList<RadioItem::PlaylistData> DataForItem(RadioItem* item);
|
||||||
|
|
||||||
void StartLoading(const QUrl& url);
|
void StartLoading(const QUrl& url);
|
||||||
void LoadNext(const QUrl& url);
|
void LoadNext(const QUrl& url);
|
||||||
|
|
||||||
bool IsPauseAllowed() const { return false; }
|
bool IsPauseAllowed() const { return false; }
|
||||||
bool ShowLastFmControls() const { return true; }
|
bool ShowLastFmControls() const { return true; }
|
||||||
|
|
||||||
|
bool IsAuthenticated() const;
|
||||||
void Authenticate(const QString& username, const QString& password);
|
void Authenticate(const QString& username, const QString& password);
|
||||||
|
|
||||||
|
void NowPlaying(const Song& song);
|
||||||
|
void Scrobble(const Song& song);
|
||||||
|
void Love(const Song& song);
|
||||||
|
void Ban(const Song& song);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void AuthenticationComplete(bool success);
|
void AuthenticationComplete(bool success);
|
||||||
|
|
||||||
@ -45,14 +54,21 @@ class LastFMService : public RadioService {
|
|||||||
void TunerTrackAvailable();
|
void TunerTrackAvailable();
|
||||||
void TunerError(lastfm::ws::Error error);
|
void TunerError(lastfm::ws::Error error);
|
||||||
|
|
||||||
|
void ScrobblerStatus(int status);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RadioItem* CreateStationItem(ItemType type, const QString& name,
|
RadioItem* CreateStationItem(ItemType type, const QString& name,
|
||||||
const QString& icon, RadioItem* parent);
|
const QString& icon, RadioItem* parent);
|
||||||
QString ErrorString(lastfm::ws::Error error) const;
|
QString ErrorString(lastfm::ws::Error error) const;
|
||||||
|
bool InitScrobbler();
|
||||||
|
lastfm::Track TrackFromSong(const Song& song) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LastFMConfig* config_;
|
|
||||||
lastfm::RadioTuner* tuner_;
|
lastfm::RadioTuner* tuner_;
|
||||||
|
lastfm::Audioscrobbler* scrobbler_;
|
||||||
|
lastfm::Track last_track_;
|
||||||
|
|
||||||
|
LastFMConfig* config_;
|
||||||
QUrl last_url_;
|
QUrl last_url_;
|
||||||
bool initial_tune_;
|
bool initial_tune_;
|
||||||
};
|
};
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
QCoreApplication::setApplicationName("Tangerine");
|
QCoreApplication::setApplicationName("Tangerine");
|
||||||
|
QCoreApplication::setApplicationVersion("0.1");
|
||||||
QCoreApplication::setOrganizationName("Tangerine");
|
QCoreApplication::setOrganizationName("Tangerine");
|
||||||
QCoreApplication::setOrganizationDomain("davidsansome.com");
|
QCoreApplication::setOrganizationDomain("davidsansome.com");
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
: QMainWindow(parent),
|
: QMainWindow(parent),
|
||||||
radio_model_(new RadioModel(this)),
|
radio_model_(new RadioModel(this)),
|
||||||
playlist_(new Playlist(this)),
|
playlist_(new Playlist(this)),
|
||||||
player_(new Player(playlist_, this)),
|
player_(new Player(playlist_, radio_model_->GetLastFMService(), this)),
|
||||||
library_(new Library(player_->GetEngine(), this)),
|
library_(new Library(player_->GetEngine(), this)),
|
||||||
library_sort_model_(new QSortFilterProxyModel(this)),
|
library_sort_model_(new QSortFilterProxyModel(this)),
|
||||||
tray_icon_(new SystemTrayIcon(this))
|
tray_icon_(new SystemTrayIcon(this))
|
||||||
@ -36,6 +36,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
tray_icon_->show();
|
tray_icon_->show();
|
||||||
|
|
||||||
ui_.volume->setValue(player_->GetVolume());
|
ui_.volume->setValue(player_->GetVolume());
|
||||||
|
ui_.last_fm_controls->hide();
|
||||||
|
|
||||||
// Models
|
// Models
|
||||||
library_sort_model_->setSourceModel(library_);
|
library_sort_model_->setSourceModel(library_);
|
||||||
@ -72,6 +73,8 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
ui_.back_button->setDefaultAction(ui_.action_previous_track);
|
ui_.back_button->setDefaultAction(ui_.action_previous_track);
|
||||||
ui_.pause_play_button->setDefaultAction(ui_.action_play_pause);
|
ui_.pause_play_button->setDefaultAction(ui_.action_play_pause);
|
||||||
ui_.stop_button->setDefaultAction(ui_.action_stop);
|
ui_.stop_button->setDefaultAction(ui_.action_stop);
|
||||||
|
ui_.love_button->setDefaultAction(ui_.action_love);
|
||||||
|
ui_.ban_button->setDefaultAction(ui_.action_ban);
|
||||||
|
|
||||||
// Stop actions
|
// Stop actions
|
||||||
QMenu* stop_menu = new QMenu(this);
|
QMenu* stop_menu = new QMenu(this);
|
||||||
@ -151,6 +154,8 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
tray_menu->addAction(ui_.action_play_pause);
|
tray_menu->addAction(ui_.action_play_pause);
|
||||||
tray_menu->addAction(ui_.action_stop);
|
tray_menu->addAction(ui_.action_stop);
|
||||||
tray_menu->addAction(ui_.action_next_track);
|
tray_menu->addAction(ui_.action_next_track);
|
||||||
|
tray_menu->addAction(ui_.action_love);
|
||||||
|
tray_menu->addAction(ui_.action_ban);
|
||||||
tray_menu->addSeparator();
|
tray_menu->addSeparator();
|
||||||
tray_menu->addAction(ui_.action_quit);
|
tray_menu->addAction(ui_.action_quit);
|
||||||
tray_icon_->setContextMenu(tray_menu);
|
tray_icon_->setContextMenu(tray_menu);
|
||||||
@ -209,6 +214,10 @@ void MainWindow::MediaStopped() {
|
|||||||
ui_.action_play_pause->setText("Play");
|
ui_.action_play_pause->setText("Play");
|
||||||
|
|
||||||
ui_.action_play_pause->setEnabled(true);
|
ui_.action_play_pause->setEnabled(true);
|
||||||
|
|
||||||
|
ui_.action_ban->setVisible(false);
|
||||||
|
ui_.action_love->setVisible(false);
|
||||||
|
ui_.last_fm_controls->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::MediaPaused() {
|
void MainWindow::MediaPaused() {
|
||||||
@ -228,6 +237,11 @@ void MainWindow::MediaPlaying() {
|
|||||||
|
|
||||||
ui_.action_play_pause->setEnabled(
|
ui_.action_play_pause->setEnabled(
|
||||||
! playlist_->current_item_options() & PlaylistItem::PauseDisabled);
|
! playlist_->current_item_options() & PlaylistItem::PauseDisabled);
|
||||||
|
|
||||||
|
bool lastfm = playlist_->current_item_options() & PlaylistItem::LastFMControls;
|
||||||
|
ui_.action_ban->setVisible(lastfm);
|
||||||
|
ui_.action_love->setVisible(lastfm);
|
||||||
|
ui_.last_fm_controls->setVisible(lastfm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::resizeEvent(QResizeEvent*) {
|
void MainWindow::resizeEvent(QResizeEvent*) {
|
||||||
|
@ -136,6 +136,51 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="last_fm_controls" native="true">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="margin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="love_button">
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>22</width>
|
||||||
|
<height>22</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="autoRaise">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="ban_button">
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>22</width>
|
||||||
|
<height>22</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="autoRaise">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="Line" name="line">
|
<widget class="Line" name="line">
|
||||||
<property name="maximumSize">
|
<property name="maximumSize">
|
||||||
@ -489,6 +534,30 @@
|
|||||||
<string>Added this month</string>
|
<string>Added this month</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="action_love">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../data/data.qrc">
|
||||||
|
<normaloff>:/last.fm/love.png</normaloff>:/last.fm/love.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Love</string>
|
||||||
|
</property>
|
||||||
|
<property name="visible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="action_ban">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="../data/data.qrc">
|
||||||
|
<normaloff>:/last.fm/ban.png</normaloff>:/last.fm/ban.png</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Ban</string>
|
||||||
|
</property>
|
||||||
|
<property name="visible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "playlist.h"
|
#include "playlist.h"
|
||||||
#include "xine-engine.h"
|
#include "xine-engine.h"
|
||||||
|
#include "lastfmservice.h"
|
||||||
|
|
||||||
#include <QtDebug>
|
#include <QtDebug>
|
||||||
|
|
||||||
Player::Player(Playlist* playlist, QObject* parent)
|
Player::Player(Playlist* playlist, LastFMService* lastfm, QObject* parent)
|
||||||
: QObject(parent),
|
: QObject(parent),
|
||||||
playlist_(playlist),
|
playlist_(playlist),
|
||||||
|
lastfm_(lastfm),
|
||||||
engine_(new XineEngine)
|
engine_(new XineEngine)
|
||||||
{
|
{
|
||||||
if (!engine_->init()) {
|
if (!engine_->init()) {
|
||||||
@ -119,8 +121,10 @@ void Player::PlayAt(int index) {
|
|||||||
|
|
||||||
if (item->options() & PlaylistItem::SpecialPlayBehaviour)
|
if (item->options() & PlaylistItem::SpecialPlayBehaviour)
|
||||||
item->StartLoading();
|
item->StartLoading();
|
||||||
else
|
else {
|
||||||
engine_->play(item->Url());
|
engine_->play(item->Url());
|
||||||
|
lastfm_->NowPlaying(item->Metadata());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::StreamReady(const QUrl& original_url, const QUrl& media_url) {
|
void Player::StreamReady(const QUrl& original_url, const QUrl& media_url) {
|
||||||
@ -133,4 +137,5 @@ void Player::StreamReady(const QUrl& original_url, const QUrl& media_url) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
engine_->play(media_url);
|
engine_->play(media_url);
|
||||||
|
lastfm_->NowPlaying(item->Metadata());
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,13 @@
|
|||||||
|
|
||||||
class Playlist;
|
class Playlist;
|
||||||
class Settings;
|
class Settings;
|
||||||
|
class LastFMService;
|
||||||
|
|
||||||
class Player : public QObject {
|
class Player : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Player(Playlist* playlist, QObject* parent = 0);
|
Player(Playlist* playlist, LastFMService* lastfm, QObject* parent = 0);
|
||||||
|
|
||||||
EngineBase* GetEngine() { return engine_; }
|
EngineBase* GetEngine() { return engine_; }
|
||||||
Engine::State GetState() const;
|
Engine::State GetState() const;
|
||||||
@ -41,6 +42,7 @@ class Player : public QObject {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Playlist* playlist_;
|
Playlist* playlist_;
|
||||||
|
LastFMService* lastfm_;
|
||||||
QSettings settings_;
|
QSettings settings_;
|
||||||
|
|
||||||
EngineBase* engine_;
|
EngineBase* engine_;
|
||||||
|
@ -55,13 +55,14 @@ QVariant Playlist::data(const QModelIndex& index, int role) const {
|
|||||||
|
|
||||||
case Qt::DisplayRole: {
|
case Qt::DisplayRole: {
|
||||||
PlaylistItem* item = items_[index.row()];
|
PlaylistItem* item = items_[index.row()];
|
||||||
|
Song song = item->Metadata();
|
||||||
|
|
||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
case Column_Title: return item->Title();
|
case Column_Title: return song.title();
|
||||||
case Column_Artist: return item->Artist();
|
case Column_Artist: return song.artist();
|
||||||
case Column_Album: return item->Album();
|
case Column_Album: return song.album();
|
||||||
case Column_Length: return item->Length();
|
case Column_Length: return song.length();
|
||||||
case Column_Track: return item->Track();
|
case Column_Track: return song.track();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,11 +283,11 @@ bool Playlist::CompareItems(int column, Qt::SortOrder order,
|
|||||||
const PlaylistItem* b = order == Qt::AscendingOrder ? _b : _a;
|
const PlaylistItem* b = order == Qt::AscendingOrder ? _b : _a;
|
||||||
|
|
||||||
switch (column) {
|
switch (column) {
|
||||||
case Column_Title: return a->Title() < b->Title();
|
case Column_Title: return a->Metadata().title() < b->Metadata().title();
|
||||||
case Column_Artist: return a->Artist() < b->Artist();
|
case Column_Artist: return a->Metadata().artist() < b->Metadata().artist();
|
||||||
case Column_Album: return a->Album() < b->Album();
|
case Column_Album: return a->Metadata().album() < b->Metadata().album();
|
||||||
case Column_Length: return a->Length() < b->Length();
|
case Column_Length: return a->Metadata().length() < b->Metadata().length();
|
||||||
case Column_Track: return a->Track() < b->Track();
|
case Column_Track: return a->Metadata().track() < b->Metadata().track();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -38,11 +38,7 @@ class PlaylistItem {
|
|||||||
virtual void Save(QSettings& settings) const = 0;
|
virtual void Save(QSettings& settings) const = 0;
|
||||||
virtual void Restore(const QSettings& settings) = 0;
|
virtual void Restore(const QSettings& settings) = 0;
|
||||||
|
|
||||||
virtual QString Title() const = 0;
|
virtual Song Metadata() const = 0;
|
||||||
virtual QString Artist() const = 0;
|
|
||||||
virtual QString Album() const = 0;
|
|
||||||
virtual int Length() const = 0;
|
|
||||||
virtual int Track() const = 0;
|
|
||||||
|
|
||||||
// If the item needs to do anything special before it can play (eg. start
|
// If the item needs to do anything special before it can play (eg. start
|
||||||
// streaming the radio stream), then it should implement StartLoading() and
|
// streaming the radio stream), then it should implement StartLoading() and
|
||||||
|
@ -111,3 +111,9 @@ QMimeData* RadioModel::mimeData(const QModelIndexList& indexes) const {
|
|||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LastFMService* RadioModel::GetLastFMService() const {
|
||||||
|
if (sServices.contains(LastFMService::kServiceName))
|
||||||
|
return static_cast<LastFMService*>(sServices[LastFMService::kServiceName]);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "simpletreemodel.h"
|
#include "simpletreemodel.h"
|
||||||
|
|
||||||
class RadioService;
|
class RadioService;
|
||||||
|
class LastFMService;
|
||||||
class Song;
|
class Song;
|
||||||
|
|
||||||
class RadioModel : public SimpleTreeModel<RadioItem> {
|
class RadioModel : public SimpleTreeModel<RadioItem> {
|
||||||
@ -22,6 +23,9 @@ class RadioModel : public SimpleTreeModel<RadioItem> {
|
|||||||
// Needs to be static for RadioPlaylistItem::restore
|
// Needs to be static for RadioPlaylistItem::restore
|
||||||
static RadioService* ServiceByName(const QString& name);
|
static RadioService* ServiceByName(const QString& name);
|
||||||
|
|
||||||
|
// This is special because Player needs it for scrobbling
|
||||||
|
LastFMService* GetLastFMService() const;
|
||||||
|
|
||||||
// QAbstractItemModel
|
// QAbstractItemModel
|
||||||
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
|
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
|
||||||
Qt::ItemFlags flags(const QModelIndex& index) const;
|
Qt::ItemFlags flags(const QModelIndex& index) const;
|
||||||
|
@ -15,6 +15,7 @@ RadioPlaylistItem::RadioPlaylistItem(RadioService* service, const QUrl& url,
|
|||||||
url_(url),
|
url_(url),
|
||||||
title_(title)
|
title_(title)
|
||||||
{
|
{
|
||||||
|
InitMetadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioPlaylistItem::Save(QSettings& settings) const {
|
void RadioPlaylistItem::Save(QSettings& settings) const {
|
||||||
@ -27,35 +28,23 @@ void RadioPlaylistItem::Restore(const QSettings& settings) {
|
|||||||
service_ = RadioModel::ServiceByName(settings.value("service").toString());
|
service_ = RadioModel::ServiceByName(settings.value("service").toString());
|
||||||
url_ = settings.value("url").toString();
|
url_ = settings.value("url").toString();
|
||||||
title_ = settings.value("title").toString();
|
title_ = settings.value("title").toString();
|
||||||
|
|
||||||
|
InitMetadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString RadioPlaylistItem::Title() const {
|
void RadioPlaylistItem::InitMetadata() {
|
||||||
if (!service_)
|
if (!service_)
|
||||||
return "Radio service couldn't be loaded :-(";
|
metadata_.set_title("Radio service couldn't be loaded :-(");
|
||||||
|
else if (!title_.isEmpty())
|
||||||
if (metadata_.is_valid())
|
metadata_.set_title(title_);
|
||||||
return metadata_.title();
|
else
|
||||||
|
metadata_.set_title(url_.toString());
|
||||||
if (!title_.isEmpty())
|
|
||||||
return title_;
|
|
||||||
|
|
||||||
return url_.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString RadioPlaylistItem::Artist() const {
|
Song RadioPlaylistItem::Metadata() const {
|
||||||
return metadata_.is_valid() ? metadata_.artist() : QString::null;
|
if (temp_metadata_.is_valid())
|
||||||
}
|
return temp_metadata_;
|
||||||
|
return metadata_;
|
||||||
QString RadioPlaylistItem::Album() const {
|
|
||||||
return metadata_.is_valid() ? metadata_.album() : QString::null;
|
|
||||||
}
|
|
||||||
|
|
||||||
int RadioPlaylistItem::Length() const {
|
|
||||||
return metadata_.is_valid() ? metadata_.length() : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int RadioPlaylistItem::Track() const {
|
|
||||||
return metadata_.is_valid() ? metadata_.track() : -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioPlaylistItem::StartLoading() {
|
void RadioPlaylistItem::StartLoading() {
|
||||||
@ -88,9 +77,9 @@ PlaylistItem::Options RadioPlaylistItem::options() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RadioPlaylistItem::SetTemporaryMetadata(const Song& metadata) {
|
void RadioPlaylistItem::SetTemporaryMetadata(const Song& metadata) {
|
||||||
metadata_ = metadata;
|
temp_metadata_ = metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioPlaylistItem::ClearTemporaryMetadata() {
|
void RadioPlaylistItem::ClearTemporaryMetadata() {
|
||||||
metadata_ = Song();
|
temp_metadata_ = Song();
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,7 @@ class RadioPlaylistItem : public PlaylistItem {
|
|||||||
void Save(QSettings& settings) const;
|
void Save(QSettings& settings) const;
|
||||||
void Restore(const QSettings& settings);
|
void Restore(const QSettings& settings);
|
||||||
|
|
||||||
QString Title() const;
|
Song Metadata() const;
|
||||||
QString Artist() const;
|
|
||||||
QString Album() const;
|
|
||||||
int Length() const;
|
|
||||||
int Track() const;
|
|
||||||
|
|
||||||
void StartLoading();
|
void StartLoading();
|
||||||
QUrl Url();
|
QUrl Url();
|
||||||
@ -33,12 +29,16 @@ class RadioPlaylistItem : public PlaylistItem {
|
|||||||
void SetTemporaryMetadata(const Song& metadata);
|
void SetTemporaryMetadata(const Song& metadata);
|
||||||
void ClearTemporaryMetadata();
|
void ClearTemporaryMetadata();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void InitMetadata();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RadioService* service_;
|
RadioService* service_;
|
||||||
QUrl url_;
|
QUrl url_;
|
||||||
QString title_;
|
QString title_;
|
||||||
|
|
||||||
Song metadata_;
|
Song metadata_;
|
||||||
|
Song temp_metadata_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // RADIOPLAYLISTITEM_H
|
#endif // RADIOPLAYLISTITEM_H
|
||||||
|
10
src/song.cpp
10
src/song.cpp
@ -234,6 +234,16 @@ void Song::BindToQuery(QSqlQuery *query) const {
|
|||||||
#undef intval
|
#undef intval
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Song::ToLastFM(lastfm::Track* track) const {
|
||||||
|
lastfm::MutableTrack mtrack(*track);
|
||||||
|
|
||||||
|
mtrack.setArtist(artist_);
|
||||||
|
mtrack.setAlbum(album_);
|
||||||
|
mtrack.setTitle(title_);
|
||||||
|
mtrack.setDuration(length_);
|
||||||
|
mtrack.setTrackNumber(track_);
|
||||||
|
}
|
||||||
|
|
||||||
QString Song::PrettyTitleWithArtist() const {
|
QString Song::PrettyTitleWithArtist() const {
|
||||||
QString title(title_);
|
QString title(title_);
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ namespace lastfm {
|
|||||||
class Track;
|
class Track;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: QSharedData
|
||||||
class Song {
|
class Song {
|
||||||
public:
|
public:
|
||||||
Song();
|
Song();
|
||||||
@ -24,6 +25,7 @@ class Song {
|
|||||||
|
|
||||||
// Save
|
// Save
|
||||||
void BindToQuery(QSqlQuery* query) const;
|
void BindToQuery(QSqlQuery* query) const;
|
||||||
|
void ToLastFM(lastfm::Track* track) const;
|
||||||
|
|
||||||
// Simple accessors
|
// Simple accessors
|
||||||
bool is_valid() const { return valid_; }
|
bool is_valid() const { return valid_; }
|
||||||
@ -59,6 +61,7 @@ class Song {
|
|||||||
|
|
||||||
// Setters
|
// Setters
|
||||||
void set_id(int id) { id_ = id; }
|
void set_id(int id) { id_ = id; }
|
||||||
|
void set_title(const QString& title) { title_ = title; }
|
||||||
|
|
||||||
// Comparison functions
|
// Comparison functions
|
||||||
bool IsMetadataEqual(const Song& other) const;
|
bool IsMetadataEqual(const Song& other) const;
|
||||||
|
@ -24,26 +24,6 @@ void SongPlaylistItem::Restore(const QSettings& settings) {
|
|||||||
song_.InitFromFile(filename, directory_id);
|
song_.InitFromFile(filename, directory_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SongPlaylistItem::Title() const {
|
|
||||||
return song_.PrettyTitle();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString SongPlaylistItem::Artist() const {
|
|
||||||
return song_.artist();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString SongPlaylistItem::Album() const {
|
|
||||||
return song_.album();
|
|
||||||
}
|
|
||||||
|
|
||||||
int SongPlaylistItem::Length() const {
|
|
||||||
return song_.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
int SongPlaylistItem::Track() const {
|
|
||||||
return song_.track();
|
|
||||||
}
|
|
||||||
|
|
||||||
QUrl SongPlaylistItem::Url() {
|
QUrl SongPlaylistItem::Url() {
|
||||||
QUrl ret(QUrl::fromLocalFile(song_.filename()));
|
QUrl ret(QUrl::fromLocalFile(song_.filename()));
|
||||||
ret.setHost("localhost");
|
ret.setHost("localhost");
|
||||||
|
@ -14,11 +14,7 @@ class SongPlaylistItem : public PlaylistItem {
|
|||||||
void Save(QSettings& settings) const;
|
void Save(QSettings& settings) const;
|
||||||
void Restore(const QSettings& settings);
|
void Restore(const QSettings& settings);
|
||||||
|
|
||||||
QString Title() const;
|
Song Metadata() const { return song_; }
|
||||||
QString Artist() const;
|
|
||||||
QString Album() const;
|
|
||||||
int Length() const;
|
|
||||||
int Track() const;
|
|
||||||
|
|
||||||
QUrl Url();
|
QUrl Url();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user