Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/constants/playlistsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ constexpr char kShowToolbar[] = "show_toolbar";
constexpr char kPlaylistClear[] = "playlist_clear";
constexpr char kAutoSort[] = "auto_sort";

constexpr char kGroupingBeforeQueue[] = "grouping_queue";
constexpr char kPathType[] = "path_type";

constexpr char kEditMetadataInline[] = "editmetadatainline";
Expand Down
5 changes: 4 additions & 1 deletion src/core/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ void Player::ReloadSettings() {
s.beginGroup(PlaylistSettings::kSettingsGroup);
continue_on_error_ = s.value("continue_on_error", false).toBool();
greyout_ = s.value("greyout_songs_play", true).toBool();
playlist_manager_->update_grouped_before_queue(s.value(PlaylistSettings::kGroupingBeforeQueue).toInt());
s.endGroup();

s.beginGroup(BehaviourSettings::kSettingsGroup);
Expand Down Expand Up @@ -435,7 +436,7 @@ void Player::NextItem(const EngineBase::TrackChangeFlags change, const Playlist:
// Manual track changes override "Repeat track"
const bool ignore_repeat_track = change & EngineBase::TrackChangeType::Manual;

int i = active_playlist->next_row(ignore_repeat_track);
int i = active_playlist->next_row(ignore_repeat_track, false);
if (i == -1) {
playlist_manager_->active()->set_current_row(i);
playlist_manager_->active()->reset_last_played();
Expand Down Expand Up @@ -635,10 +636,12 @@ void Player::PreviousItem(const EngineBase::TrackChangeFlags change) {
if (i == -1) {
Stop();
PlayAt(i, false, 0, change, Playlist::AutoScroll::Always, true);
playlist_manager_->active()->CleanNextSongQueued();
return;
}

PlayAt(i, false, 0, change, Playlist::AutoScroll::Always, false);
playlist_manager_->active()->CleanNextSongQueued();

}

Expand Down
10 changes: 10 additions & 0 deletions src/core/song.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1122,6 +1122,16 @@ bool Song::IsOnSameAlbum(const Song &other) const {

}

bool Song::IsOnSameGrouping(const Song &other) const {

return ( !grouping().isEmpty()
&& !other.grouping().isEmpty()
&& AlbumKey() == other.AlbumKey()
&& grouping() == other.grouping()
&& filetype() == other.filetype() );

}

bool Song::IsSimilar(const Song &other) const {
return title().compare(other.title(), Qt::CaseInsensitive) == 0 &&
artist().compare(other.artist(), Qt::CaseInsensitive) == 0 &&
Expand Down
1 change: 1 addition & 0 deletions src/core/song.h
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ class Song {
bool IsEqual(const Song &other) const;

bool IsOnSameAlbum(const Song &other) const;
bool IsOnSameGrouping(const Song &other) const;
bool IsSimilar(const Song &other) const;

static Source SourceFromURL(const QUrl &url);
Expand Down
76 changes: 71 additions & 5 deletions src/playlist/playlist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ Playlist::Playlist(const SharedPtr<TaskManager> task_manager,
const int id,
const QString &special_type,
const bool favorite,
const int grouped_before_queue,
QObject *parent)
: QAbstractListModel(parent),
is_loading_(false),
Expand All @@ -156,7 +157,10 @@ Playlist::Playlist(const SharedPtr<TaskManager> task_manager,
scrobble_point_(-1),
auto_sort_(false),
sort_column_(Column::Title),
sort_order_(Qt::AscendingOrder) {
sort_order_(Qt::AscendingOrder),
left_grouped_song_before_queue_(grouped_before_queue),
init_grouped_song_before_queue_(grouped_before_queue),
next_song_after_queued_(-1) {

undo_stack_->setUndoLimit(kUndoStackSize);

Expand Down Expand Up @@ -641,14 +645,72 @@ int Playlist::PreviousVirtualIndex(int i, const bool ignore_repeat_track) const

}

int Playlist::next_row(const bool ignore_repeat_track) {
int Playlist::next_row(const bool ignore_repeat_track, const bool no_grouping_track_count) {

// Any queued items take priority
if (!queue_->is_empty()) {
int next_virtual_index = next_song_after_queued_;

if (next_virtual_index < 0) {
next_virtual_index = NextVirtualIndex(current_virtual_index_, ignore_repeat_track);
switch (RepeatMode()) {
default:

// Compare with unsigned int to avoid to check if it is less than the count but positive
if ( static_cast<unsigned int>(current_virtual_index_) < static_cast<unsigned int>(virtual_items_.count())
&& static_cast<unsigned int>(next_virtual_index) < static_cast<unsigned int>(virtual_items_.count()) ) {
// The two indexes are in the virtual items array
Song this_song = item_at(virtual_items_[current_virtual_index_])->EffectiveMetadata();
Song next_song = item_at(virtual_items_[next_virtual_index])->EffectiveMetadata();

if ( this_song.IsOnSameGrouping(next_song)
&& ( left_grouped_song_before_queue_ == 0
|| no_grouping_track_count
|| --left_grouped_song_before_queue_ > 0 ) ) {
// We have two choices here :
// either resetting left_grouped_song_before_queue_ as soon as there is no queued song,
// that is too say, when a song will be queued, you will have to wait the setted number of grouped song before playing it
// either resetting left_grouped_song_before_queue_ when it reaches 0,
// that is too say, when a song will be queued, you will have to wait every n th grouped song before playing it
if (queue_->is_empty())
// if (left_grouped_song_before_queue_ == 0)
{
left_grouped_song_before_queue_ = init_grouped_song_before_queue_;
}
// The next song is on the same grouping than the current one,
// it cannot be interrupt by the queued items
break;
}
}

[[fallthrough]];

case PlaylistSequence::RepeatMode::Intro:
case PlaylistSequence::RepeatMode::Track:

// Reset the grouping values
left_grouped_song_before_queue_ = init_grouped_song_before_queue_;

// Any queued items take priority
if (!queue_->is_empty()) {
// Remember the location in the current playlist to go back right there after the queued play
next_song_after_queued_ = next_virtual_index;

// Play the queued song
return queue_->PeekNext();
}

break;
}
}
else if (!queue_->is_empty()) {
// We already remember the location where we want to go back after the queued play
// we just have to return the next queued song
return queue_->PeekNext();
}
else if (next_song_after_queued_ >= 0 && !no_grouping_track_count) {
// No more queued song, go back to the list to play
next_song_after_queued_ = -1;
}

int next_virtual_index = NextVirtualIndex(current_virtual_index_, ignore_repeat_track);
if (next_virtual_index >= virtual_items_.count()) {
// We've gone off the end of the playlist.

Expand Down Expand Up @@ -2058,6 +2120,10 @@ bool AlbumShuffleComparator(const QHash<QString, int> &album_key_positions, cons
void Playlist::ReshuffleIndices() {

const PlaylistSequence::ShuffleMode shuffle_mode = ShuffleMode();

// First, cancel the replay position
next_song_after_queued_ = -1;

switch (shuffle_mode) {
case PlaylistSequence::ShuffleMode::Off:{
// No shuffling - sort the virtual item list normally.
Expand Down
16 changes: 15 additions & 1 deletion src/playlist/playlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ using ColumnAlignmentMap = QMap<int, Qt::Alignment>;
Q_DECLARE_METATYPE(Qt::Alignment)
Q_DECLARE_METATYPE(ColumnAlignmentMap)

// This default value keep the current behavior : the queued item is played at the end of the current track, even a grouped one
static constexpr int GROUPED_BEFORE_QUEUE_DEFAULT = 1;

class Playlist : public QAbstractListModel {
Q_OBJECT

Expand All @@ -92,6 +95,7 @@ class Playlist : public QAbstractListModel {
const int id,
const QString &special_type = QString(),
const bool favorite = false,
const int grouped_before_queue = GROUPED_BEFORE_QUEUE_DEFAULT,
QObject *parent = nullptr);

~Playlist() override;
Expand Down Expand Up @@ -192,10 +196,12 @@ class Playlist : public QAbstractListModel {
int last_played_row() const;
void reset_last_played() { last_played_item_index_ = QPersistentModelIndex(); }
void reset_played_indexes() { played_indexes_.clear(); }
int next_row(const bool ignore_repeat_track = false);
int next_row(const bool ignore_repeat_track = false, const bool no_grouping_track_count = true);
int previous_row(const bool ignore_repeat_track = false) const;
int take_previous_row(const bool ignore_repeat_track = false);

void update_grouped_before_queue(const int grouped_before_queue) { init_grouped_song_before_queue_ = grouped_before_queue; }

QModelIndex current_index() const;

bool stop_after_current() const;
Expand Down Expand Up @@ -286,6 +292,9 @@ class Playlist : public QAbstractListModel {
void RateSong(const QModelIndex &idx, const float rating);
void RateSongs(const QModelIndexList &index_list, const float rating);

// Clean the queued song
void CleanNextSongQueued() { next_song_after_queued_ = -1; }

void set_auto_sort(const bool auto_sort) { auto_sort_ = auto_sort; }

void ItemReload(const QPersistentModelIndex &idx, const bool metadata_edit);
Expand Down Expand Up @@ -436,6 +445,11 @@ class Playlist : public QAbstractListModel {
bool auto_sort_;
Column sort_column_;
Qt::SortOrder sort_order_;

// Variables to count the number of times the queue list had been ignored due to grouping values
int left_grouped_song_before_queue_;
int init_grouped_song_before_queue_;
int next_song_after_queued_;
};

#endif // PLAYLIST_H
16 changes: 14 additions & 2 deletions src/playlist/playlistmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ PlaylistManager::PlaylistManager(const SharedPtr<TaskManager> task_manager,
playlist_container_(nullptr),
current_(-1),
active_(-1),
playlists_loading_(0) {
playlists_loading_(0),
grouped_before_queue_(GROUPED_BEFORE_QUEUE_DEFAULT) {

setObjectName(QLatin1String(QObject::metaObject()->className()));

Expand All @@ -95,6 +96,17 @@ PlaylistManager::~PlaylistManager() {

}

void PlaylistManager::update_grouped_before_queue(const int grouped_before_queue) {

grouped_before_queue_ = grouped_before_queue;

QList<Data> datas = playlists_.values();
for (Data &data : datas) {
data.p->update_grouped_before_queue(grouped_before_queue);
}

}

void PlaylistManager::Init(PlaylistSequence *sequence, PlaylistContainer *playlist_container) {

sequence_ = sequence;
Expand Down Expand Up @@ -155,7 +167,7 @@ QItemSelection PlaylistManager::selection(const int id) const {

Playlist *PlaylistManager::AddPlaylist(const int id, const QString &name, const QString &special_type, const QString &ui_path, const bool favorite) {

Playlist *ret = new Playlist(task_manager_, url_handlers_, playlist_backend_, collection_backend_, tagreader_client_, id, special_type, favorite);
Playlist *ret = new Playlist(task_manager_, url_handlers_, playlist_backend_, collection_backend_, tagreader_client_, id, special_type, favorite, grouped_before_queue_);
ret->set_sequence(sequence_);
ret->set_ui_path(ui_path);

Expand Down
5 changes: 5 additions & 0 deletions src/playlist/playlistmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ class PlaylistManager : public PlaylistManagerInterface {
Playlist *playlist(const int id) const override { return playlists_[id].p; }
Playlist *current() const override { return playlist(current_id()); }
Playlist *active() const override { return playlist(active_id()); }
int grouped_before_queue() const { return grouped_before_queue_; }

// Update the grouped before queue value : we have to do more than just update the attribute
void update_grouped_before_queue(const int grouped_before_queue);

// Returns the collection of playlists managed by this PlaylistManager.
QList<Playlist*> GetAllPlaylists() const override;
Expand Down Expand Up @@ -179,6 +183,7 @@ class PlaylistManager : public PlaylistManagerInterface {
int current_;
int active_;
int playlists_loading_;
int grouped_before_queue_;
};

#endif // PLAYLISTMANAGER_H
27 changes: 27 additions & 0 deletions src/settings/playlistsettingspage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,36 @@ PlaylistSettingsPage::PlaylistSettingsPage(SettingsDialog *dialog, QWidget *pare
ui_->setupUi(this);
setWindowIcon(IconLoader::Load(u"document-new"_s, true, 0, 32));

ui_->spinbox_grouping_before_queue->setToolTip(GroupingBeforeQueueToolTip());


}

PlaylistSettingsPage::~PlaylistSettingsPage() {
delete ui_;
}

QString PlaylistSettingsPage::GroupingBeforeQueueToolTip() {

return "<html><head/><body><p>"_L1 +
QObject::tr("This field is used to tell how many tracks of the same group will be played before the queued track will be played.") +
u' ' +
"</p><p>"_L1 +

"<span style=\"font-weight:600;\">0:</span> "_L1 +
QObject::tr(" is used to say that the queued track will wait for the end of the current track group before being played.") +
"</p><p>"_L1 +

"<span style=\"font-weight:600;\">1:</span> "_L1 +
QObject::tr(" is used to say that the queued track will be played after the end of the current track, whatever it belongs to a group or not.") +
"</p><p>"_L1 +

QObject::tr("Any other value to give the number of grouped tracks played before playing the queued one(s). ") +
QObject::tr("Obviously, if there are less grouped tracks to play than the given number, the queued tracks will be played as soon as the last grouped track is played.") +
"</p></body></html>"_L1;

}

void PlaylistSettingsPage::Load() {

Settings s;
Expand Down Expand Up @@ -93,6 +117,8 @@ void PlaylistSettingsPage::Load() {
ui_->radiobutton_askpath->setChecked(true);
}

ui_->spinbox_grouping_before_queue->setValue(s.value(kGroupingBeforeQueue, 1).toInt());

ui_->checkbox_editmetadatainline->setChecked(s.value(kEditMetadataInline, false).toBool());
ui_->checkbox_writemetadata->setChecked(s.value(kWriteMetadata, false).toBool());

Expand Down Expand Up @@ -135,6 +161,7 @@ void PlaylistSettingsPage::Save() {
s.setValue(kShowToolbar, ui_->checkbox_show_toolbar->isChecked());
s.setValue(kPlaylistClear, ui_->checkbox_playlist_clear->isChecked());
s.setValue(kPathType, static_cast<int>(path_type));
s.setValue(kGroupingBeforeQueue, ui_->spinbox_grouping_before_queue->value());
s.setValue(kEditMetadataInline, ui_->checkbox_editmetadatainline->isChecked());
s.setValue(kWriteMetadata, ui_->checkbox_writemetadata->isChecked());
s.setValue(kDeleteFiles, ui_->checkbox_delete_files->isChecked());
Expand Down
2 changes: 2 additions & 0 deletions src/settings/playlistsettingspage.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class PlaylistSettingsPage : public SettingsPage {
void Load() override;
void Save() override;

static QString GroupingBeforeQueueToolTip();

private:
Ui_PlaylistSettingsPage *ui_;
};
Expand Down
33 changes: 33 additions & 0 deletions src/settings/playlistsettingspage.ui
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,39 @@
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupbox_grouping_play">
<property name="title">
<string>Grouping Play</string>
</property>
<layout class="QVBoxLayout" name="layout_grouping_play">
<item>
<layout class="QHBoxLayout" name="layout_grouping_play_before_queue">
<item>
<widget class="QLabel" name="label_grouping_play_before_queue_1">
<property name="text">
<string>Number of grouped track played before play queued track</string>
</property>
<property name="indent">
<number>22</number>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinbox_grouping_before_queue">
<property name="minimum">
<number>0</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupbox_paths">
<property name="title">
Expand Down
2 changes: 1 addition & 1 deletion src/smartplaylists/smartplaylistsearchpreview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ void SmartPlaylistSearchPreview::Init(const SharedPtr<Player> player,

collection_backend_ = collection_backend;

model_ = new Playlist(nullptr, nullptr, nullptr, collection_backend_, nullptr, -1, QString(), false, this);
model_ = new Playlist(nullptr, nullptr, nullptr, collection_backend_, nullptr, -1, QString(), false, GROUPED_BEFORE_QUEUE_DEFAULT, this);
ui_->tree->setModel(model_);
ui_->tree->SetPlaylist(model_);

Expand Down
Loading