From 38feb17697ba70a52fc1b9e46ccdda0b6cdc4da1 Mon Sep 17 00:00:00 2001 From: David Sansome Date: Tue, 29 Dec 2009 19:22:02 +0000 Subject: [PATCH] "Now listening" last.fm notifications --- data/data.qrc | 2 + data/last.fm/ban.png | Bin 0 -> 1777 bytes data/last.fm/love.png | Bin 0 -> 1894 bytes src/lastfmservice.cpp | 91 +++++++++++++++++++++++++++++++++----- src/lastfmservice.h | 22 +++++++-- src/main.cpp | 1 + src/mainwindow.cpp | 16 ++++++- src/mainwindow.ui | 69 +++++++++++++++++++++++++++++ src/player.cpp | 9 +++- src/player.h | 4 +- src/playlist.cpp | 21 ++++----- src/playlistitem.h | 6 +-- src/radiomodel.cpp | 6 +++ src/radiomodel.h | 4 ++ src/radioplaylistitem.cpp | 41 +++++++---------- src/radioplaylistitem.h | 10 ++--- src/song.cpp | 10 +++++ src/song.h | 3 ++ src/songplaylistitem.cpp | 20 --------- src/songplaylistitem.h | 6 +-- 20 files changed, 253 insertions(+), 88 deletions(-) create mode 100644 data/last.fm/ban.png create mode 100644 data/last.fm/love.png diff --git a/data/data.qrc b/data/data.qrc index 15217e8a9..b3389161d 100644 --- a/data/data.qrc +++ b/data/data.qrc @@ -39,5 +39,7 @@ last.fm/personal_radio.png last.fm/recommended_radio.png spinner.gif + last.fm/ban.png + last.fm/love.png diff --git a/data/last.fm/ban.png b/data/last.fm/ban.png new file mode 100644 index 0000000000000000000000000000000000000000..5cbf154e42af882a50da7e5a78a074cf3dac24b8 GIT binary patch literal 1777 zcmVPx#AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUy32;bRa{vGf6951U69E94oEQKA23ko(K~z}7rI&e7Rdp1{eJrAn zJrNBA6wp*$h(!_EWHk(Ykib(=k-!B7HAT{-aZD2vQ*t387&Es36%djj7e>=uXVA=4 zd@hJ+ZY@s!(I2Ptz1@3#4@4fu%xC6ue&>A8_x}`~(G+@jW`M2zsnE;Sc_OOIvnm5)NweWA`s>t%*Fv+gm};j=_EcI7SR>$kDEOu)C6u#m$0= z<$4+5#F$;ff~fWDa{8n0xWJQxhv{P0Dys0CNLl8N*OHWd>&BT_7rPquTn%uH7}k)3 z+(-Ls<@$%EHFWg7w01ku&HyL)l{k+g&DsKbTJ-}x<;D_6R4J5c*6#$TO=fUj$1v_9 zW5n3x028ZCbIk0|912&{johtr{k@_+bdXP}_Dtv)z_b_kdz&t2uc626_(}P9?Km7Y zomN{q@8EQ6M#*#+QHn7~#*2xW(4$w;&LIKRv@&0=znYUrg$^DhT^%|GHdqbJXoyXv zM>{J7?icQ+3$s3y|CgwbOoG7H4hGvmG-HolQT4RRuNgN<(30xW1HE(%;KotVcQ`fW ztfPm;r2^+uvxv9yLjCwDa!dlTSD3(`A!EsmTxjl44=t${J%;_h!!llJn+`2#O10>Po>~T6KRY!!ogREq zBJguY4t;FV{|tTs6UxK)qiLZ#mu1`%>T--%b~s zJ8t4)bEXdy3=_4%adJ-U+AY+)WHnWJgm-2_39UoC3%6!25o#`{FNJ}6*#Hm4t((i% zQ0tn_0{gupaLG*-x6x4BMD^%M(j;ZjwTMKz;u9rM_TMeH!@-2sPJ4GbzmW$MJ+%!y zZ(fl{_f~BXC>h{Q@0-5q-exOh6J@;qYk*1z#5ytot!=h$a_(inXc%~|W8iL1F14&! zCr~`Vi+Fm6zT|wqFyT6yu7*z10kM~vfY!D?ZgSo)!Lhmq)?2yWX=_dd=QDEA1V zTuYY;9SoIhqI{4KU5`}jfLL1-(Aw4CQ_g7&jv@4v4Xm|vX}CBelUi~<6*wFbkA!8f zm~7d^zQMk9LzSchV%jF4RXrk5UjHc|iqKOwu+qYL>+z^5)bi0PfwP>%Q(E20<@LhE z(6OY6OV$A~$po}c21Uzjb>5+bp0WXciY4#!3gzaXQ1kq3x~@*4oi4&q1?p>J|1f{L znV6~rVlV-%>j^XD_};gC@KjBf4FsB4_20r%dU5(3x|24KZYR&8qX82zD4RQZt*wMY~COm>Qz?HTGzSEi@Z-OL37=O-mn>2Tp(ZqjEaR6Tnygo$I}Dp>ws49wz=P#ghaYo zjG9Sd=7^+-u}Cq;S*$UZ2JW@LjyX`500000NkvXXu0mjf-PJ)n literal 0 HcmV?d00001 diff --git a/data/last.fm/love.png b/data/last.fm/love.png new file mode 100644 index 0000000000000000000000000000000000000000..5a185a9d1591efd30101d116d108cce13c847d16 GIT binary patch literal 1894 zcmV-s2buVZP)Px#AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUy32;bRa{vGf6951U69E94oEQKA2G2=EK~z}7-n%7Ca9(YA^kh=N$!gt_(Q^UrZ07-58s?~&vMWC&$-)g2EgpUgxPzMfaP$3nWaFW zrCRj3FwxHCs=f7*GNIM8aw{uYnT_y9iIdIxW3!wGk>1==V8OTNuxGAopW?ALtH}13 z>m#kygcjykJkB;~uV`wYu5r2~V8N8;dqh(QlzwG>@cIa=KkG6!qxr&7s7ni>DA~_9**|Rb|l4O zFie0H=_1!puG$N4RK*3O{Z0uq_sj6|)&;cRIuFg=QfMBOL6)@*l-wT|C)$OPPfwOe z;S8s7lvq=Bas=n2xqk)iH_zkc&2!M))B4qg)@&{tP5zes$^bD7O)|XZ~I|DV9z4>ge5n4Fp;pMfn zXw2WmzUW<-nKw}n zjZkPfZoOOxbx|HvKcu6L)=1OoY^@E?PSwS~`AiO!$M>Lgw6%;97|5@{r?ldm6i4?! zbz(o1`MU{eP#j6)s2<#yFFUpuO$C`ocHQE5I+SEj3-S%c9Llf2FzVx5#nHV`UvR0R6Lax_kn}#xXClvH?Wp>uDD1k5d75I|M^0M(z3L0sGhJ6yq2@Tyq zuaocJYGfzZ$xZnv52r$&DM86tTRFABAc0|Y@I0;G5d%eb3L19D8zN0l<2qzA;_H$& zpe8;PFQS&CDs&N^u9yeuVsBLV&BhavCm#EFaA5osKQGj54uv$t52xK7OAT5;gTcqV zoKIGT`$Ltt8?w|`4)rOq9lVV3+hb5m0iTBlP%uAK_|AfKo)?D--%eVglW}7`NM0SY z5_epkutPj8mMZWuKY@W;d_7jN(@%MLCmK>WL6#KFp+0dV>Jq|Gvpxuw3w`jE!(5K9 z)bXaqT6B(UHie)vcs|a%*wxXRbEKGk`3ZbTLWiO$4$_*0P^efEi5pPQ0!Ien*|Pcn zh$=<{{D}86(mh}0kNPd)xa&S1sp4sgtmRaJ9{gRv&h?>5;%NyFd|c6#l?qw>I#dTO zBKRBAU>=yPgZDSd%fH`R$t_d*7^C`!#F_y_Cv{0jh*xvtb?Oe|wiZO)H)A%;j-flx8#Gb3^V)(3cNnmr!@tF?S^s*n?xrDG#Un(#3P2&PahW zE(*#`kx<4)YN?)&jnGj(BA`l$Ml1PMkpF4-F^_~JEInw>&-JD6=0PIRuZ3Q0L3&Pc z5ucl6-%z!BA=(b4p=on;2UPKTK8E8v$I)os7RT9F28uz~b?uBPF23y8rMW-gUPGO6 z3=`0oMQ6~PWFta+JVP&!v3^y(ZW%O(GN9fX&!I&UXF$~w9iJ@W?4-*?6x^ZS*TZcI zn}^U_A4C5nGi(7**wG4spf8PWBE_B?uZ*^STN56L*SQDLmb?vZNn1IzCQ3N8B}vep zv5V7JF89S**U{Bf!G$!>NVcw6-}PnJCSlQ~1%l4tyehCHJ|dYzm}o|HiKF$a7wZD> zCO-$S(s!XfH5r;61fs9=4xu$O4bmk(DD-f8NWmA7pC!%Fhrj6f{WrY`c_q>r^&kvj zNv!tqjJV`%+fo(00B?`w;q8$eygsm>-ji>1&4>O#z z`xbQhKj3fAeypsdpOq?h%PAgjr>3>>F7N9J9oYRIrY@yZtZdVql_l z=DOW6gfO1$L^Spzemc=nL1N#~&;_PjFx+$kym3!mO9qo{C}EJk #include #include +#include #include +const char* LastFMService::kServiceName = "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) - : RadioService("Last.fm", parent), + : RadioService(kServiceName, parent), tuner_(NULL), + scrobbler_(NULL), initial_tune_(false) { - lastfm::ws::ApiKey = "75d20fb472be99275392aefa2760ea09"; - lastfm::ws::SharedSecret = "d3072b60ae626be12be69448f5c46e70"; + lastfm::ws::ApiKey = kApiKey; + lastfm::ws::SharedSecret = kSecret; QSettings settings; settings.beginGroup(kSettingsGroup); @@ -31,6 +37,10 @@ LastFMService::~LastFMService() { delete config_; } +bool LastFMService::IsAuthenticated() const { + return !lastfm::ws::SessionKey.isEmpty(); +} + RadioItem* LastFMService::CreateRootItem(RadioItem* parent) { RadioItem* item = new RadioItem(this, RadioItem::Type_Service, "Last.fm", parent); item->icon = QIcon(":last.fm/as.png"); @@ -50,7 +60,7 @@ void LastFMService::LazyPopulate(RadioItem *item) { CreateStationItem(Type_MyNeighbourhood, "My Neighbourhood", ":last.fm/neighbour_radio.png", item); - if (lastfm::ws::SessionKey.isEmpty()) + if (!IsAuthenticated()) config_->show(); break; @@ -106,6 +116,10 @@ void LastFMService::AuthenticateReplyFinished() { settings.setValue("username", lastfm::ws::Username); settings.setValue("session", lastfm::ws::SessionKey); + // Invalidate the scrobbler - it will get recreated later + delete scrobbler_; + scrobbler_ = NULL; + emit AuthenticationComplete(true); } @@ -142,7 +156,7 @@ QList LastFMService::DataForItem(RadioItem* item) { void LastFMService::StartLoading(const QUrl& url) { if (url.scheme() != "lastfm") return; - if (lastfm::ws::SessionKey.isEmpty()) + if (!IsAuthenticated()) return; emit LoadingStarted(); @@ -158,18 +172,18 @@ void LastFMService::StartLoading(const QUrl& url) { } void LastFMService::LoadNext(const QUrl &) { - lastfm::Track track = tuner_->takeNextTrack(); + last_track_ = tuner_->takeNextTrack(); - if (track.isNull()) { + if (last_track_.isNull()) { emit StreamFinished(); return; } - emit StreamReady(last_url_, track.url()); - Song metadata; - metadata.InitFromLastFM(track); + metadata.InitFromLastFM(last_track_); + emit StreamMetadataFound(last_url_, metadata); + emit StreamReady(last_url_, last_track_.url()); } void LastFMService::TunerError(lastfm::ws::Error error) { @@ -224,3 +238,60 @@ void LastFMService::TunerTrackAvailable() { 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(status); +} diff --git a/src/lastfmservice.h b/src/lastfmservice.h index 69f112c56..2392b0642 100644 --- a/src/lastfmservice.h +++ b/src/lastfmservice.h @@ -2,6 +2,7 @@ #define LASTFMSERVICE_H #include "radioservice.h" +#include "song.h" #include @@ -14,7 +15,11 @@ class LastFMService : public RadioService { LastFMService(QObject* parent = 0); ~LastFMService(); + static const char* kServiceName; static const char* kSettingsGroup; + static const char* kAudioscrobblerClientId; + static const char* kApiKey; + static const char* kSecret; enum ItemType { Type_MyRecommendations = 1000, @@ -27,15 +32,19 @@ class LastFMService : public RadioService { RadioItem* CreateRootItem(RadioItem* parent); void LazyPopulate(RadioItem *item); QList DataForItem(RadioItem* item); - void StartLoading(const QUrl& url); void LoadNext(const QUrl& url); - bool IsPauseAllowed() const { return false; } bool ShowLastFmControls() const { return true; } + bool IsAuthenticated() const; 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: void AuthenticationComplete(bool success); @@ -45,14 +54,21 @@ class LastFMService : public RadioService { void TunerTrackAvailable(); void TunerError(lastfm::ws::Error error); + void ScrobblerStatus(int status); + private: RadioItem* CreateStationItem(ItemType type, const QString& name, const QString& icon, RadioItem* parent); QString ErrorString(lastfm::ws::Error error) const; + bool InitScrobbler(); + lastfm::Track TrackFromSong(const Song& song) const; private: - LastFMConfig* config_; lastfm::RadioTuner* tuner_; + lastfm::Audioscrobbler* scrobbler_; + lastfm::Track last_track_; + + LastFMConfig* config_; QUrl last_url_; bool initial_tune_; }; diff --git a/src/main.cpp b/src/main.cpp index 23f480eaa..418c582c1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,6 +6,7 @@ int main(int argc, char *argv[]) { QCoreApplication::setApplicationName("Tangerine"); + QCoreApplication::setApplicationVersion("0.1"); QCoreApplication::setOrganizationName("Tangerine"); QCoreApplication::setOrganizationDomain("davidsansome.com"); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 7b49d2f05..086d94c70 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -25,7 +25,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), radio_model_(new RadioModel(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_sort_model_(new QSortFilterProxyModel(this)), tray_icon_(new SystemTrayIcon(this)) @@ -36,6 +36,7 @@ MainWindow::MainWindow(QWidget *parent) tray_icon_->show(); ui_.volume->setValue(player_->GetVolume()); + ui_.last_fm_controls->hide(); // Models library_sort_model_->setSourceModel(library_); @@ -72,6 +73,8 @@ MainWindow::MainWindow(QWidget *parent) ui_.back_button->setDefaultAction(ui_.action_previous_track); ui_.pause_play_button->setDefaultAction(ui_.action_play_pause); ui_.stop_button->setDefaultAction(ui_.action_stop); + ui_.love_button->setDefaultAction(ui_.action_love); + ui_.ban_button->setDefaultAction(ui_.action_ban); // Stop actions 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_stop); tray_menu->addAction(ui_.action_next_track); + tray_menu->addAction(ui_.action_love); + tray_menu->addAction(ui_.action_ban); tray_menu->addSeparator(); tray_menu->addAction(ui_.action_quit); tray_icon_->setContextMenu(tray_menu); @@ -209,6 +214,10 @@ void MainWindow::MediaStopped() { ui_.action_play_pause->setText("Play"); ui_.action_play_pause->setEnabled(true); + + ui_.action_ban->setVisible(false); + ui_.action_love->setVisible(false); + ui_.last_fm_controls->hide(); } void MainWindow::MediaPaused() { @@ -228,6 +237,11 @@ void MainWindow::MediaPlaying() { ui_.action_play_pause->setEnabled( ! 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*) { diff --git a/src/mainwindow.ui b/src/mainwindow.ui index ba8e2b28f..84031e9df 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -136,6 +136,51 @@ + + + + + 1 + + + 0 + + + + + Qt::Vertical + + + + + + + + 22 + 22 + + + + true + + + + + + + + 22 + 22 + + + + true + + + + + + @@ -489,6 +534,30 @@ Added this month + + + + :/last.fm/love.png:/last.fm/love.png + + + Love + + + false + + + + + + :/last.fm/ban.png:/last.fm/ban.png + + + Ban + + + false + + diff --git a/src/player.cpp b/src/player.cpp index 354c2c4c3..831ce00cc 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -1,12 +1,14 @@ #include "player.h" #include "playlist.h" #include "xine-engine.h" +#include "lastfmservice.h" #include -Player::Player(Playlist* playlist, QObject* parent) +Player::Player(Playlist* playlist, LastFMService* lastfm, QObject* parent) : QObject(parent), playlist_(playlist), + lastfm_(lastfm), engine_(new XineEngine) { if (!engine_->init()) { @@ -119,8 +121,10 @@ void Player::PlayAt(int index) { if (item->options() & PlaylistItem::SpecialPlayBehaviour) item->StartLoading(); - else + else { engine_->play(item->Url()); + lastfm_->NowPlaying(item->Metadata()); + } } 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; engine_->play(media_url); + lastfm_->NowPlaying(item->Metadata()); } diff --git a/src/player.h b/src/player.h index 1a89efbfc..9e78e60f0 100644 --- a/src/player.h +++ b/src/player.h @@ -8,12 +8,13 @@ class Playlist; class Settings; +class LastFMService; class Player : public QObject { Q_OBJECT public: - Player(Playlist* playlist, QObject* parent = 0); + Player(Playlist* playlist, LastFMService* lastfm, QObject* parent = 0); EngineBase* GetEngine() { return engine_; } Engine::State GetState() const; @@ -41,6 +42,7 @@ class Player : public QObject { private: Playlist* playlist_; + LastFMService* lastfm_; QSettings settings_; EngineBase* engine_; diff --git a/src/playlist.cpp b/src/playlist.cpp index 63d635f5c..0577fccca 100644 --- a/src/playlist.cpp +++ b/src/playlist.cpp @@ -55,13 +55,14 @@ QVariant Playlist::data(const QModelIndex& index, int role) const { case Qt::DisplayRole: { PlaylistItem* item = items_[index.row()]; + Song song = item->Metadata(); switch (index.column()) { - case Column_Title: return item->Title(); - case Column_Artist: return item->Artist(); - case Column_Album: return item->Album(); - case Column_Length: return item->Length(); - case Column_Track: return item->Track(); + case Column_Title: return song.title(); + case Column_Artist: return song.artist(); + case Column_Album: return song.album(); + case Column_Length: return song.length(); + 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; switch (column) { - case Column_Title: return a->Title() < b->Title(); - case Column_Artist: return a->Artist() < b->Artist(); - case Column_Album: return a->Album() < b->Album(); - case Column_Length: return a->Length() < b->Length(); - case Column_Track: return a->Track() < b->Track(); + case Column_Title: return a->Metadata().title() < b->Metadata().title(); + case Column_Artist: return a->Metadata().artist() < b->Metadata().artist(); + case Column_Album: return a->Metadata().album() < b->Metadata().album(); + case Column_Length: return a->Metadata().length() < b->Metadata().length(); + case Column_Track: return a->Metadata().track() < b->Metadata().track(); } return false; } diff --git a/src/playlistitem.h b/src/playlistitem.h index bd045daf5..f294794ae 100644 --- a/src/playlistitem.h +++ b/src/playlistitem.h @@ -38,11 +38,7 @@ class PlaylistItem { virtual void Save(QSettings& settings) const = 0; virtual void Restore(const QSettings& settings) = 0; - virtual QString Title() const = 0; - virtual QString Artist() const = 0; - virtual QString Album() const = 0; - virtual int Length() const = 0; - virtual int Track() const = 0; + virtual Song Metadata() const = 0; // If the item needs to do anything special before it can play (eg. start // streaming the radio stream), then it should implement StartLoading() and diff --git a/src/radiomodel.cpp b/src/radiomodel.cpp index e1f4ae09f..9be785cde 100644 --- a/src/radiomodel.cpp +++ b/src/radiomodel.cpp @@ -111,3 +111,9 @@ QMimeData* RadioModel::mimeData(const QModelIndexList& indexes) const { return data; } + +LastFMService* RadioModel::GetLastFMService() const { + if (sServices.contains(LastFMService::kServiceName)) + return static_cast(sServices[LastFMService::kServiceName]); + return NULL; +} diff --git a/src/radiomodel.h b/src/radiomodel.h index b6746db37..9e275e6f4 100644 --- a/src/radiomodel.h +++ b/src/radiomodel.h @@ -5,6 +5,7 @@ #include "simpletreemodel.h" class RadioService; +class LastFMService; class Song; class RadioModel : public SimpleTreeModel { @@ -22,6 +23,9 @@ class RadioModel : public SimpleTreeModel { // Needs to be static for RadioPlaylistItem::restore static RadioService* ServiceByName(const QString& name); + // This is special because Player needs it for scrobbling + LastFMService* GetLastFMService() const; + // QAbstractItemModel QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; Qt::ItemFlags flags(const QModelIndex& index) const; diff --git a/src/radioplaylistitem.cpp b/src/radioplaylistitem.cpp index ac99a4e15..6fae07e25 100644 --- a/src/radioplaylistitem.cpp +++ b/src/radioplaylistitem.cpp @@ -15,6 +15,7 @@ RadioPlaylistItem::RadioPlaylistItem(RadioService* service, const QUrl& url, url_(url), title_(title) { + InitMetadata(); } void RadioPlaylistItem::Save(QSettings& settings) const { @@ -27,35 +28,23 @@ void RadioPlaylistItem::Restore(const QSettings& settings) { service_ = RadioModel::ServiceByName(settings.value("service").toString()); url_ = settings.value("url").toString(); title_ = settings.value("title").toString(); + + InitMetadata(); } -QString RadioPlaylistItem::Title() const { +void RadioPlaylistItem::InitMetadata() { if (!service_) - return "Radio service couldn't be loaded :-("; - - if (metadata_.is_valid()) - return metadata_.title(); - - if (!title_.isEmpty()) - return title_; - - return url_.toString(); + metadata_.set_title("Radio service couldn't be loaded :-("); + else if (!title_.isEmpty()) + metadata_.set_title(title_); + else + metadata_.set_title(url_.toString()); } -QString RadioPlaylistItem::Artist() const { - return metadata_.is_valid() ? metadata_.artist() : QString::null; -} - -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; +Song RadioPlaylistItem::Metadata() const { + if (temp_metadata_.is_valid()) + return temp_metadata_; + return metadata_; } void RadioPlaylistItem::StartLoading() { @@ -88,9 +77,9 @@ PlaylistItem::Options RadioPlaylistItem::options() const { } void RadioPlaylistItem::SetTemporaryMetadata(const Song& metadata) { - metadata_ = metadata; + temp_metadata_ = metadata; } void RadioPlaylistItem::ClearTemporaryMetadata() { - metadata_ = Song(); + temp_metadata_ = Song(); } diff --git a/src/radioplaylistitem.h b/src/radioplaylistitem.h index ad40b3568..aea501300 100644 --- a/src/radioplaylistitem.h +++ b/src/radioplaylistitem.h @@ -19,11 +19,7 @@ class RadioPlaylistItem : public PlaylistItem { void Save(QSettings& settings) const; void Restore(const QSettings& settings); - QString Title() const; - QString Artist() const; - QString Album() const; - int Length() const; - int Track() const; + Song Metadata() const; void StartLoading(); QUrl Url(); @@ -33,12 +29,16 @@ class RadioPlaylistItem : public PlaylistItem { void SetTemporaryMetadata(const Song& metadata); void ClearTemporaryMetadata(); + private: + void InitMetadata(); + private: RadioService* service_; QUrl url_; QString title_; Song metadata_; + Song temp_metadata_; }; #endif // RADIOPLAYLISTITEM_H diff --git a/src/song.cpp b/src/song.cpp index 86adf32a7..02f636748 100644 --- a/src/song.cpp +++ b/src/song.cpp @@ -234,6 +234,16 @@ void Song::BindToQuery(QSqlQuery *query) const { #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 title(title_); diff --git a/src/song.h b/src/song.h index 743955fa8..bda3d18cc 100644 --- a/src/song.h +++ b/src/song.h @@ -9,6 +9,7 @@ namespace lastfm { class Track; } +// TODO: QSharedData class Song { public: Song(); @@ -24,6 +25,7 @@ class Song { // Save void BindToQuery(QSqlQuery* query) const; + void ToLastFM(lastfm::Track* track) const; // Simple accessors bool is_valid() const { return valid_; } @@ -59,6 +61,7 @@ class Song { // Setters void set_id(int id) { id_ = id; } + void set_title(const QString& title) { title_ = title; } // Comparison functions bool IsMetadataEqual(const Song& other) const; diff --git a/src/songplaylistitem.cpp b/src/songplaylistitem.cpp index f11ca8ceb..eec206a66 100644 --- a/src/songplaylistitem.cpp +++ b/src/songplaylistitem.cpp @@ -24,26 +24,6 @@ void SongPlaylistItem::Restore(const QSettings& settings) { 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 ret(QUrl::fromLocalFile(song_.filename())); ret.setHost("localhost"); diff --git a/src/songplaylistitem.h b/src/songplaylistitem.h index 4868d9b3e..0a32b34fc 100644 --- a/src/songplaylistitem.h +++ b/src/songplaylistitem.h @@ -14,11 +14,7 @@ class SongPlaylistItem : public PlaylistItem { void Save(QSettings& settings) const; void Restore(const QSettings& settings); - QString Title() const; - QString Artist() const; - QString Album() const; - int Length() const; - int Track() const; + Song Metadata() const { return song_; } QUrl Url();