diff --git a/src/lastfmservice.cpp b/src/lastfmservice.cpp index 60f930a6f..04d5dbcfe 100644 --- a/src/lastfmservice.cpp +++ b/src/lastfmservice.cpp @@ -243,20 +243,13 @@ bool LastFMService::InitScrobbler() { if (!IsAuthenticated()) return false; - if (!scrobbler_) { + 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()) @@ -291,7 +284,3 @@ 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 2392b0642..71a4fdffb 100644 --- a/src/lastfmservice.h +++ b/src/lastfmservice.h @@ -54,8 +54,6 @@ 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); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 086d94c70..0ad497858 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -6,6 +6,8 @@ #include "songplaylistitem.h" #include "systemtrayicon.h" #include "radiomodel.h" +#include "enginebase.h" +#include "lastfmservice.h" #include #include @@ -18,17 +20,20 @@ #include #include +#include + const int MainWindow::kStateVersion = 1; const char* MainWindow::kSettingsGroup = "MainWindow"; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), + tray_icon_(new SystemTrayIcon(this)), radio_model_(new RadioModel(this)), playlist_(new 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)) + track_position_timer_(new QTimer(this)) { ui_.setupUi(this); tray_icon_->setIcon(windowIcon()); @@ -38,6 +43,9 @@ MainWindow::MainWindow(QWidget *parent) ui_.volume->setValue(player_->GetVolume()); ui_.last_fm_controls->hide(); + track_position_timer_->setInterval(1000); + connect(track_position_timer_, SIGNAL(timeout()), SLOT(UpdateTrackPosition())); + // Models library_sort_model_->setSourceModel(library_); library_sort_model_->setSortRole(Library::Role_SortText); @@ -218,6 +226,8 @@ void MainWindow::MediaStopped() { ui_.action_ban->setVisible(false); ui_.action_love->setVisible(false); ui_.last_fm_controls->hide(); + + track_position_timer_->stop(); } void MainWindow::MediaPaused() { @@ -227,6 +237,8 @@ void MainWindow::MediaPaused() { ui_.action_play_pause->setText("Play"); ui_.action_play_pause->setEnabled(true); + + track_position_timer_->stop(); } void MainWindow::MediaPlaying() { @@ -242,6 +254,9 @@ void MainWindow::MediaPlaying() { ui_.action_ban->setVisible(lastfm); ui_.action_love->setVisible(lastfm); ui_.last_fm_controls->setVisible(lastfm); + + track_position_timer_->start(); + UpdateTrackPosition(); } void MainWindow::resizeEvent(QResizeEvent*) { @@ -292,7 +307,7 @@ void MainWindow::TrayClicked(QSystemTrayIcon::ActivationReason reason) { } void MainWindow::StopAfterCurrent() { - playlist_->StopAfter(playlist_->current_item()); + playlist_->StopAfter(playlist_->current_index()); } void MainWindow::closeEvent(QCloseEvent* event) { @@ -321,3 +336,13 @@ void MainWindow::FilePathChanged(const QString& path) { settings.beginGroup(kSettingsGroup); settings.setValue("file_path", path); } + +void MainWindow::UpdateTrackPosition() { + int position = std::floor(float(player_->GetEngine()->position()) / 1000.0 + 0.5); + + if (!playlist_->has_scrobbled() && + position >= playlist_->scrobble_point()) { + radio_model_->GetLastFMService()->Scrobble(playlist_->current_item_metadata()); + playlist_->set_scrobbled(true); + } +} diff --git a/src/mainwindow.h b/src/mainwindow.h index abf8ea1f3..c46ce812b 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -46,6 +46,8 @@ class MainWindow : public QMainWindow { void VolumeWheelEvent(int delta); void TrayClicked(QSystemTrayIcon::ActivationReason reason); + void UpdateTrackPosition(); + private: void SaveGeometry(); @@ -54,6 +56,7 @@ class MainWindow : public QMainWindow { static const char* kSettingsGroup; Ui::MainWindow ui_; + SystemTrayIcon* tray_icon_; RadioModel* radio_model_; Playlist* playlist_; @@ -62,7 +65,7 @@ class MainWindow : public QMainWindow { QSortFilterProxyModel* library_sort_model_; - SystemTrayIcon* tray_icon_; + QTimer* track_position_timer_; }; #endif // MAINWINDOW_H diff --git a/src/player.cpp b/src/player.cpp index 831ce00cc..69bd9c01f 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -23,8 +23,8 @@ Player::Player(Playlist* playlist, LastFMService* lastfm, QObject* parent) } void Player::Next() { - int i = playlist_->next_item(); - playlist_->set_current_item(i); + int i = playlist_->next_index(); + playlist_->set_current_index(i); if (i == -1) { Stop(); return; @@ -35,7 +35,7 @@ void Player::Next() { } void Player::TrackEnded() { - int i = playlist_->current_item(); + int i = playlist_->current_index(); if (i == -1 || playlist_->stop_after_current()) { Stop(); return; @@ -63,7 +63,7 @@ void Player::PlayPause() { case Engine::Empty: case Engine::Idle: { - int i = playlist_->current_item(); + int i = playlist_->current_index(); if (i == -1) { if (playlist_->rowCount() == 0) break; @@ -78,12 +78,12 @@ void Player::PlayPause() { void Player::Stop() { qDebug() << "Stopping"; engine_->stop(); - playlist_->set_current_item(-1); + playlist_->set_current_index(-1); } void Player::Previous() { - int i = playlist_->previous_item(); - playlist_->set_current_item(i); + int i = playlist_->previous_index(); + playlist_->set_current_index(i); if (i == -1) { Stop(); return; @@ -115,7 +115,7 @@ Engine::State Player::GetState() const { } void Player::PlayAt(int index) { - playlist_->set_current_item(index); + playlist_->set_current_index(index); PlaylistItem* item = playlist_->item_at(index); @@ -128,7 +128,7 @@ void Player::PlayAt(int index) { } void Player::StreamReady(const QUrl& original_url, const QUrl& media_url) { - int current_index = playlist_->current_item(); + int current_index = playlist_->current_index(); if (current_index == -1) return; diff --git a/src/playlist.cpp b/src/playlist.cpp index 0577fccca..774e14b6a 100644 --- a/src/playlist.cpp +++ b/src/playlist.cpp @@ -13,13 +13,17 @@ #include +#include + const char* Playlist::kRowsMimetype = "application/x-tangerine-playlist-rows"; const char* Playlist::kSettingsGroup = "Playlist"; Playlist::Playlist(QObject *parent) : QAbstractListModel(parent), current_is_paused_(false), - ignore_sorting_(false) + ignore_sorting_(false), + scrobble_point_(-1), + has_scrobbled_(false) { } @@ -71,28 +75,28 @@ QVariant Playlist::data(const QModelIndex& index, int role) const { } } -int Playlist::current_item() const { +int Playlist::current_index() const { return current_item_.isValid() ? current_item_.row() : -1; } -int Playlist::next_item() const { - int i = current_item() + 1; +int Playlist::next_index() const { + int i = current_index() + 1; if (i >= items_.count()) return -1; - if (stop_after_.isValid() && current_item() == stop_after_.row()) + if (stop_after_.isValid() && current_index() == stop_after_.row()) return -1; return i; } -int Playlist::previous_item() const { - int i = current_item() - 1; +int Playlist::previous_index() const { + int i = current_index() - 1; if (i < 0) return -1; return i; } -void Playlist::set_current_item(int i) { +void Playlist::set_current_index(int i) { QModelIndex old_current = current_item_; ClearStreamMetadata(); @@ -102,6 +106,8 @@ void Playlist::set_current_item(int i) { emit dataChanged(old_current, old_current.sibling(old_current.row(), ColumnCount)); if (current_item_.isValid()) emit dataChanged(current_item_, current_item_.sibling(current_item_.row(), ColumnCount)); + + UpdateScrobblePoint(); } Qt::ItemFlags Playlist::flags(const QModelIndex &index) const { @@ -387,7 +393,7 @@ bool Playlist::removeRows(int row, int count, const QModelIndex& parent) { // Remove items for (int i=0 ; iSetTemporaryMetadata(song); + UpdateScrobblePoint(); emit dataChanged(index(current_item_.row(), 0), index(current_item_.row(), ColumnCount)); } @@ -428,6 +435,7 @@ void Playlist::ClearStreamMetadata() { PlaylistItem* item = items_[current_item_.row()]; item->ClearTemporaryMetadata(); + UpdateScrobblePoint(); emit dataChanged(index(current_item_.row(), 0), index(current_item_.row(), ColumnCount)); } @@ -437,14 +445,34 @@ bool Playlist::stop_after_current() const { stop_after_.row() == current_item_.row(); } -PlaylistItem::Options Playlist::current_item_options() const { - int i = current_item(); +PlaylistItem* Playlist::current_item() const { + int i = current_index(); if (i == -1) - return PlaylistItem::Default; + return NULL; - PlaylistItem* item = item_at(i); + return item_at(i); +} + +PlaylistItem::Options Playlist::current_item_options() const { + PlaylistItem* item = current_item(); if (!item) return PlaylistItem::Default; return item->options(); } + +Song Playlist::current_item_metadata() const { + PlaylistItem* item = current_item(); + if (!item) + return Song(); + + return item->Metadata(); +} + +void Playlist::UpdateScrobblePoint() { + int length = current_item_metadata().length(); + + ScrobblePoint point(length / 2); + scrobble_point_ = point; + has_scrobbled_ = false; +} diff --git a/src/playlist.h b/src/playlist.h index 93ad911a7..ccac4bd90 100644 --- a/src/playlist.h +++ b/src/playlist.h @@ -43,12 +43,21 @@ class Playlist : public QAbstractListModel { void Restore(); // Accessors - int current_item() const; - int next_item() const; - int previous_item() const; + int current_index() const; + int next_index() const; + int previous_index() const; bool stop_after_current() const; + PlaylistItem* item_at(int index) const { return items_[index]; } + PlaylistItem* current_item() const; + PlaylistItem::Options current_item_options() const; + Song current_item_metadata() const; + + // Scrobbling + int scrobble_point() const { return scrobble_point_; } + bool has_scrobbled() const { return has_scrobbled_; } + void set_scrobbled(bool v) { has_scrobbled_ = v; } // Changing the playlist QModelIndex InsertItems(const QList& items, int after = -1); @@ -73,7 +82,7 @@ class Playlist : public QAbstractListModel { bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()); public slots: - void set_current_item(int index); + void set_current_index(int index); void Paused(); void Playing(); void Stopped(); @@ -84,6 +93,7 @@ class Playlist : public QAbstractListModel { private: void SetCurrentIsPaused(bool paused); + void UpdateScrobblePoint(); private: QList items_; @@ -92,6 +102,9 @@ class Playlist : public QAbstractListModel { QPersistentModelIndex stop_after_; bool current_is_paused_; + int scrobble_point_; + bool has_scrobbled_; + // Hack to stop QTreeView::setModel sorting the playlist bool ignore_sorting_; };