Also add a configurable option to increment the play count if song has played for a shorter duration.
This commit is contained in:
parent
9eb92ee2b5
commit
f4d84bc05a
|
@ -35,37 +35,38 @@
|
|||
#include <QtConcurrentRun>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "core/application.h"
|
||||
#include "core/closure.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/player.h"
|
||||
#include "core/qhash_qurl.h"
|
||||
#include "core/tagreaderclient.h"
|
||||
#include "core/timeconstants.h"
|
||||
#include "internet/core/internetmimedata.h"
|
||||
#include "internet/core/internetmodel.h"
|
||||
#include "internet/core/internetplaylistitem.h"
|
||||
#include "internet/core/internetsongmimedata.h"
|
||||
#include "internet/internetradio/savedradio.h"
|
||||
#include "internet/jamendo/jamendoplaylistitem.h"
|
||||
#include "internet/jamendo/jamendoservice.h"
|
||||
#include "internet/magnatune/magnatuneplaylistitem.h"
|
||||
#include "internet/magnatune/magnatuneservice.h"
|
||||
#include "library/library.h"
|
||||
#include "library/librarybackend.h"
|
||||
#include "library/librarymodel.h"
|
||||
#include "library/libraryplaylistitem.h"
|
||||
#include "playlistbackend.h"
|
||||
#include "playlistfilter.h"
|
||||
#include "playlistitemmimedata.h"
|
||||
#include "playlistundocommands.h"
|
||||
#include "playlistview.h"
|
||||
#include "queue.h"
|
||||
#include "songloaderinserter.h"
|
||||
#include "songmimedata.h"
|
||||
#include "songplaylistitem.h"
|
||||
#include "core/application.h"
|
||||
#include "core/closure.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/qhash_qurl.h"
|
||||
#include "core/tagreaderclient.h"
|
||||
#include "core/timeconstants.h"
|
||||
#include "internet/jamendo/jamendoplaylistitem.h"
|
||||
#include "internet/jamendo/jamendoservice.h"
|
||||
#include "internet/magnatune/magnatuneplaylistitem.h"
|
||||
#include "internet/magnatune/magnatuneservice.h"
|
||||
#include "internet/core/internetmimedata.h"
|
||||
#include "internet/core/internetmodel.h"
|
||||
#include "internet/core/internetplaylistitem.h"
|
||||
#include "internet/core/internetsongmimedata.h"
|
||||
#include "internet/internetradio/savedradio.h"
|
||||
#include "library/library.h"
|
||||
#include "library/librarybackend.h"
|
||||
#include "library/librarymodel.h"
|
||||
#include "library/libraryplaylistitem.h"
|
||||
#include "smartplaylists/generator.h"
|
||||
#include "smartplaylists/generatorinserter.h"
|
||||
#include "smartplaylists/generatormimedata.h"
|
||||
#include "songloaderinserter.h"
|
||||
#include "songmimedata.h"
|
||||
#include "songplaylistitem.h"
|
||||
|
||||
using std::placeholders::_1;
|
||||
using std::placeholders::_2;
|
||||
|
@ -156,6 +157,22 @@ Playlist::Playlist(PlaylistBackend* backend, TaskManager* task_manager,
|
|||
connect(queue_, SIGNAL(layoutChanged()), SLOT(QueueLayoutChanged()));
|
||||
|
||||
column_alignments_ = PlaylistView::DefaultColumnAlignment();
|
||||
|
||||
min_play_count_point_nsecs_ = (31ll * kNsecPerSec); // 30 seconds
|
||||
|
||||
QSettings settings;
|
||||
settings.beginGroup(Player::kSettingsGroup);
|
||||
|
||||
if (settings.value("play_count_short_duration").toBool()) {
|
||||
max_play_count_point_nsecs_ = (60ll * kNsecPerSec); // 1 minute
|
||||
} else {
|
||||
max_play_count_point_nsecs_ = (240ll * kNsecPerSec); // 4 minutes
|
||||
}
|
||||
|
||||
settings.endGroup();
|
||||
|
||||
qLog(Debug) << "k_max_scrobble_point"
|
||||
<< (max_play_count_point_nsecs_ / kNsecPerSec);
|
||||
}
|
||||
|
||||
Playlist::~Playlist() {
|
||||
|
@ -1803,6 +1820,15 @@ Song Playlist::current_item_metadata() const {
|
|||
return current_item()->Metadata();
|
||||
}
|
||||
|
||||
/**
|
||||
* Last.fm defines a track to be scrobbled when
|
||||
* - the track is longer than 30 seconds
|
||||
* - the track has been played for at least half its duration, or for 4 minutes
|
||||
* (whichever occurs earlier.)
|
||||
*
|
||||
* If you seek a track, the scrobble point is recalculated from the point seeked
|
||||
* to (as 50% or 4 minutes).
|
||||
*/
|
||||
void Playlist::UpdateScrobblePoint(qint64 seek_point_nanosec) {
|
||||
const qint64 length = current_item_metadata().length_nanosec();
|
||||
|
||||
|
@ -1825,6 +1851,41 @@ void Playlist::UpdateScrobblePoint(qint64 seek_point_nanosec) {
|
|||
}
|
||||
|
||||
set_lastfm_status(LastFM_New);
|
||||
UpdatePlayCountPoint(seek_point_nanosec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initially the play count tracking and scrobbling went hand in hand.
|
||||
* However, it is is possible that someone's preferences for tracking play
|
||||
* counts are more relaxed than that of scrobbling. For those cases, we use
|
||||
* the following algorithm to track whether a song should increment it's play
|
||||
* count or not.
|
||||
*
|
||||
* Note that that this is very similar to the scrobbling algorithm with the only
|
||||
* difference that the requirement of 4 mins worth of listening is now
|
||||
* configurable via the `max_play_count_point_nsecs_` parameter.
|
||||
*/
|
||||
void Playlist::UpdatePlayCountPoint(qint64 seek_point_nanosec) {
|
||||
const qint64 length = current_item_metadata().length_nanosec();
|
||||
|
||||
if (seek_point_nanosec == 0) {
|
||||
if (length == 0) {
|
||||
play_count_point_ = max_play_count_point_nsecs_; // 4 minutes
|
||||
} else {
|
||||
play_count_point_ = qBound(min_play_count_point_nsecs_, length / 2,
|
||||
max_play_count_point_nsecs_);
|
||||
}
|
||||
} else {
|
||||
if (length == 0) {
|
||||
play_count_point_ = seek_point_nanosec + max_play_count_point_nsecs_;
|
||||
} else {
|
||||
play_count_point_ =
|
||||
qBound(seek_point_nanosec + min_play_count_point_nsecs_,
|
||||
seek_point_nanosec + (length / 2),
|
||||
seek_point_nanosec + max_play_count_point_nsecs_);
|
||||
}
|
||||
}
|
||||
|
||||
have_incremented_playcount_ = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -236,6 +236,16 @@ class Playlist : public QAbstractListModel {
|
|||
void set_have_incremented_playcount() { have_incremented_playcount_ = true; }
|
||||
void UpdateScrobblePoint(qint64 seek_point_nanosec = 0);
|
||||
|
||||
// play count tracking
|
||||
qint64 play_count_point_nanosec() const { return play_count_point_; }
|
||||
void set_max_play_count_point_nsecs(qint64 max_play_count_point_nsecs) {
|
||||
max_play_count_point_nsecs_ = max_play_count_point_nsecs;
|
||||
}
|
||||
qint64 get_max_play_count_point_nsecs() const {
|
||||
return max_play_count_point_nsecs_;
|
||||
}
|
||||
void UpdatePlayCountPoint(qint64 seek_point_nanosec = 0);
|
||||
|
||||
// Changing the playlist
|
||||
void InsertItems(const PlaylistItemList& items, int pos = -1,
|
||||
bool play_now = false, bool enqueue = false,
|
||||
|
@ -440,6 +450,8 @@ signals:
|
|||
LastFMStatus lastfm_status_;
|
||||
bool have_incremented_playcount_;
|
||||
|
||||
qint64 play_count_point_;
|
||||
|
||||
PlaylistSequence* playlist_sequence_;
|
||||
|
||||
// Hack to stop QTreeView::setModel sorting the playlist
|
||||
|
@ -454,6 +466,9 @@ signals:
|
|||
|
||||
QString special_type_;
|
||||
|
||||
qint64 min_play_count_point_nsecs_;
|
||||
qint64 max_play_count_point_nsecs_;
|
||||
|
||||
// Cancel async restore if songs are already replaced
|
||||
bool cancel_restore_;
|
||||
};
|
||||
|
|
|
@ -15,13 +15,15 @@
|
|||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "core/appearance.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/player.h"
|
||||
#include "core/timeconstants.h"
|
||||
#include "playlistcontainer.h"
|
||||
#include "playlistmanager.h"
|
||||
#include "ui_playlistcontainer.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/appearance.h"
|
||||
#include "playlistparsers/playlistparser.h"
|
||||
#include "ui/iconloader.h"
|
||||
#include "ui_playlistcontainer.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QInputDialog>
|
||||
|
@ -464,4 +466,16 @@ void PlaylistContainer::ReloadSettings() {
|
|||
settings.beginGroup(Appearance::kSettingsGroup);
|
||||
bool hide_toolbar = settings.value("b_hide_filter_toolbar", false).toBool();
|
||||
ui_->toolbar->setVisible(!hide_toolbar);
|
||||
settings.endGroup();
|
||||
|
||||
settings.beginGroup(Player::kSettingsGroup);
|
||||
if (settings.value("play_count_short_duration").toBool()) {
|
||||
playlist_->set_max_play_count_point_nsecs(60ll * kNsecPerSec);
|
||||
} else {
|
||||
playlist_->set_max_play_count_point_nsecs(240ll * kNsecPerSec);
|
||||
}
|
||||
settings.endGroup();
|
||||
|
||||
qLog(Debug) << "new max scrobble point:"
|
||||
<< (playlist_->get_max_play_count_point_nsecs() / kNsecPerSec);
|
||||
}
|
||||
|
|
|
@ -172,6 +172,14 @@ void BehaviourSettingsPage::Load() {
|
|||
s.value("menu_previousmode", Player::PreviousBehaviour_DontRestart)
|
||||
.toInt()));
|
||||
ui_->seek_step_sec->setValue(s.value("seek_step_sec", 10).toInt());
|
||||
|
||||
if (s.value("play_count_short_duration", false).toBool()) {
|
||||
ui_->b_play_count_short_duration->setChecked(true);
|
||||
ui_->b_play_count_normal_duration->setChecked(false);
|
||||
} else {
|
||||
ui_->b_play_count_short_duration->setChecked(false);
|
||||
ui_->b_play_count_normal_duration->setChecked(true);
|
||||
}
|
||||
s.endGroup();
|
||||
|
||||
s.beginGroup("General");
|
||||
|
@ -277,6 +285,13 @@ void BehaviourSettingsPage::Save() {
|
|||
ui_->stop_play_if_fail_->isChecked());
|
||||
s.setValue("menu_previousmode", menu_previousmode);
|
||||
s.setValue("seek_step_sec", ui_->seek_step_sec->value());
|
||||
|
||||
if (ui_->b_play_count_short_duration->isChecked()) {
|
||||
s.setValue("play_count_short_duration", true);
|
||||
} else {
|
||||
s.setValue("play_count_short_duration", false);
|
||||
}
|
||||
|
||||
s.endGroup();
|
||||
|
||||
s.beginGroup("General");
|
||||
|
|
|
@ -428,6 +428,32 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_play_count">
|
||||
<property name="title">
|
||||
<string>When calculating play counts, use</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="b_play_count_normal_duration">
|
||||
<property name="text">
|
||||
<string>Normal duration (at least 4 minutes or half the track length)</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="b_play_count_short_duration">
|
||||
<property name="text">
|
||||
<string>Short duration (at least 1 minute or half the track length)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
|
|
|
@ -1468,6 +1468,9 @@ void MainWindow::Seeked(qlonglong microseconds) {
|
|||
if (ui_->action_toggle_scrobbling->isVisible()) SetToggleScrobblingIcon(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update track position, tray icon, playcount
|
||||
*/
|
||||
void MainWindow::UpdateTrackPosition() {
|
||||
// Track position in seconds
|
||||
Playlist* playlist = app_->playlist_manager()->active();
|
||||
|
@ -1477,29 +1480,32 @@ void MainWindow::UpdateTrackPosition() {
|
|||
float(app_->player()->engine()->position_nanosec()) / kNsecPerSec + 0.5);
|
||||
const int length = app_->player()->engine()->length_nanosec() / kNsecPerSec;
|
||||
const int scrobble_point = playlist->scrobble_point_nanosec() / kNsecPerSec;
|
||||
const int play_count_point =
|
||||
playlist->play_count_point_nanosec() / kNsecPerSec;
|
||||
|
||||
if (length <= 0) {
|
||||
// Probably a stream that we don't know the length of
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBLASTFM
|
||||
// Time to scrobble?
|
||||
const bool last_fm_enabled = ui_->action_toggle_scrobbling->isVisible() &&
|
||||
app_->scrobbler()->IsScrobblingEnabled() &&
|
||||
app_->scrobbler()->IsAuthenticated();
|
||||
#endif
|
||||
|
||||
// Time to scrobble?
|
||||
if (position >= scrobble_point) {
|
||||
if (playlist->get_lastfm_status() == Playlist::LastFM_New) {
|
||||
#ifdef HAVE_LIBLASTFM
|
||||
if (app_->scrobbler()->IsScrobblingEnabled() &&
|
||||
app_->scrobbler()->IsAuthenticated()) {
|
||||
qLog(Info) << "Scrobbling at" << scrobble_point;
|
||||
app_->scrobbler()->Scrobble();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (position >= play_count_point) {
|
||||
// Update the play count for the song if it's from the library
|
||||
if (!playlist->have_incremented_playcount() && item->IsLocalLibraryItem() &&
|
||||
item->Metadata().id() != -1 &&
|
||||
|
@ -1519,8 +1525,14 @@ void MainWindow::UpdateTrackPosition() {
|
|||
|
||||
// Update the tray icon every 10 seconds
|
||||
if (position % 10 == 0) {
|
||||
qLog(Debug) << "position" << position << "scrobble point" << scrobble_point
|
||||
<< "status" << playlist->get_lastfm_status();
|
||||
qLog(Debug) << "position:" << position
|
||||
<< ", scrobble point:" << scrobble_point
|
||||
<< ", lastfm status:" << playlist->get_lastfm_status()
|
||||
<< ", play count point:" << play_count_point
|
||||
<< ", is local libary item:" << item->IsLocalLibraryItem()
|
||||
<< ", playlist have incremented playcount: "
|
||||
<< playlist->have_incremented_playcount();
|
||||
|
||||
if (tray_icon_) tray_icon_->SetProgress(double(position) / length * 100);
|
||||
|
||||
// if we're waiting for the scrobble point, update the icon
|
||||
|
|
Loading…
Reference in New Issue