diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ff86e092..565577126 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -592,6 +592,8 @@ set(SOURCES src/playlist/playlistfilter.cpp src/playlist/playlistheader.cpp src/playlist/playlistitem.cpp + src/playlist/songplaylistitem.cpp + src/playlist/streamplaylistitem.cpp src/playlist/playlistitemmimedata.cpp src/playlist/playlistlistcontainer.cpp src/playlist/playlistlistmodel.cpp @@ -605,7 +607,6 @@ set(SOURCES src/playlist/playlistview.cpp src/playlist/playlistproxystyle.cpp src/playlist/songloaderinserter.cpp - src/playlist/songplaylistitem.cpp src/playlist/dynamicplaylistcontrols.cpp src/playlist/playlistundocommandbase.cpp src/playlist/playlistundocommandinsertitems.cpp @@ -757,7 +758,7 @@ set(SOURCES src/streaming/streamingservices.cpp src/streaming/streamingservice.cpp - src/streaming/streamplaylistitem.cpp + src/streaming/streamserviceplaylistitem.cpp src/streaming/streamingsearchview.cpp src/streaming/streamingsearchmodel.cpp src/streaming/streamingsearchsortmodel.cpp @@ -775,7 +776,7 @@ set(SOURCES src/radios/radioview.cpp src/radios/radioviewcontainer.cpp src/radios/radioservice.cpp - src/radios/radioplaylistitem.cpp + src/radios/radiostreamplaylistitem.cpp src/radios/radiochannel.cpp src/radios/somafmservice.cpp src/radios/radioparadiseservice.cpp diff --git a/src/collection/collectionbackend.cpp b/src/collection/collectionbackend.cpp index e509f743b..9eab3c78d 100644 --- a/src/collection/collectionbackend.cpp +++ b/src/collection/collectionbackend.cpp @@ -522,7 +522,7 @@ void CollectionBackend::SongPathChanged(const Song &song, const QFileInfo &new_f updated_song.set_url(QUrl::fromLocalFile(QDir::cleanPath(new_file.filePath()))); updated_song.set_basefilename(new_file.fileName()); updated_song.InitArtManual(); - if (updated_song.is_collection_song() && new_collection_directory_id) { + if (updated_song.is_linked_collection_song() && new_collection_directory_id) { updated_song.set_directory_id(new_collection_directory_id.value()); } diff --git a/src/collection/collectionplaylistitem.cpp b/src/collection/collectionplaylistitem.cpp index 9c28035a4..58dbc0f11 100644 --- a/src/collection/collectionplaylistitem.cpp +++ b/src/collection/collectionplaylistitem.cpp @@ -1,8 +1,6 @@ /* * Strawberry Music Player - * This file was part of Clementine. - * Copyright 2010, David Sansome - * Copyright 2018-2021, Jonas Kvinge + * Copyright 2018-2025, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,41 +28,52 @@ class SqlRow; -CollectionPlaylistItem::CollectionPlaylistItem() : PlaylistItem(Song::Source::Collection) { - song_.set_source(Song::Source::Collection); +CollectionPlaylistItem::CollectionPlaylistItem(const Song::Source source) : PlaylistItem(source) { + song_.set_source(source); } -CollectionPlaylistItem::CollectionPlaylistItem(const Song &song) : PlaylistItem(Song::Source::Collection), song_(song) { - song_.set_source(Song::Source::Collection); -} +CollectionPlaylistItem::CollectionPlaylistItem(const Song &song) : PlaylistItem(song.source()), song_(song) {} QUrl CollectionPlaylistItem::Url() const { return song_.url(); } -void CollectionPlaylistItem::Reload() { - - const TagReaderResult result = TagReaderClient::Instance()->ReadFileBlocking(song_.url().toLocalFile(), &song_); - if (!result.success()) { - qLog(Error) << "Could not reload file" << song_.url() << result.error_string(); - return; - } - UpdateTemporaryMetadata(song_); - -} - bool CollectionPlaylistItem::InitFromQuery(const SqlRow &query) { - // Rows from the songs tables come first - song_.InitFromQuery(query, true); - song_.set_source(Song::Source::Collection); + int col = 0; + switch (source_) { + case Song::Source::Collection: + col = 0; + break; + default: + col = static_cast(Song::kRowIdColumns.count()); + break; + } + + song_.InitFromQuery(query, true, col); + return song_.is_valid(); } -QVariant CollectionPlaylistItem::DatabaseValue(DatabaseColumn column) const { +void CollectionPlaylistItem::Reload() { - switch (column) { - case Column_CollectionId: return song_.id(); - default: return PlaylistItem::DatabaseValue(column); + if (song_.url().isLocalFile()) { + const TagReaderResult result = TagReaderClient::Instance()->ReadFileBlocking(song_.url().toLocalFile(), &song_); + if (!result.success()) { + qLog(Error) << "Could not reload file" << song_.url() << result.error_string(); + return; + } + UpdateTemporaryMetadata(song_); + } + +} + +QVariant CollectionPlaylistItem::DatabaseValue(const DatabaseColumn database_column) const { + + switch (database_column) { + case DatabaseColumn::CollectionId: + return song_.id(); + default: + return PlaylistItem::DatabaseValue(database_column); } } diff --git a/src/collection/collectionplaylistitem.h b/src/collection/collectionplaylistitem.h index 908a29cfd..9491b1247 100644 --- a/src/collection/collectionplaylistitem.h +++ b/src/collection/collectionplaylistitem.h @@ -1,8 +1,6 @@ /* * Strawberry Music Player - * This file was part of Clementine. - * Copyright 2010, David Sansome - * Copyright 2018-2021, Jonas Kvinge + * Copyright 2018-2025, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,9 +32,11 @@ class SqlRow; class CollectionPlaylistItem : public PlaylistItem { public: - explicit CollectionPlaylistItem(); + explicit CollectionPlaylistItem(const Song::Source source); explicit CollectionPlaylistItem(const Song &song); + QUrl Url() const override; + bool InitFromQuery(const SqlRow &query) override; void Reload() override; @@ -44,15 +44,13 @@ class CollectionPlaylistItem : public PlaylistItem { Song OriginalMetadata() const override { return song_; } void SetMetadata(const Song &song) override { song_ = song; } - QUrl Url() const override; - - bool IsLocalCollectionItem() const override { return true; } - void SetArtManual(const QUrl &cover_url) override; + bool IsLocalCollectionItem() const override { return song_.source() == Song::Source::Collection; } + protected: - QVariant DatabaseValue(DatabaseColumn column) const override; - Song DatabaseSongMetadata() const override { return Song(Song::Source::Collection); } + QVariant DatabaseValue(const DatabaseColumn database_column) const override; + Song DatabaseSongMetadata() const override { return Song(source_); } protected: Song song_; diff --git a/src/core/mainwindow.cpp b/src/core/mainwindow.cpp index 7552a0598..c677e8f03 100644 --- a/src/core/mainwindow.cpp +++ b/src/core/mainwindow.cpp @@ -1516,7 +1516,7 @@ void MainWindow::SongChanged(const Song &song) { SendNowPlaying(); - const bool enable_change_art = song.is_collection_song() && !song.effective_albumartist().isEmpty() && !song.album().isEmpty(); + const bool enable_change_art = song.is_local_collection_song() && !song.effective_albumartist().isEmpty() && !song.album().isEmpty(); album_cover_choice_controller_->show_cover_action()->setEnabled(song.has_valid_art() && !song.art_unset()); album_cover_choice_controller_->cover_to_file_action()->setEnabled(song.has_valid_art() && !song.art_unset()); album_cover_choice_controller_->cover_from_file_action()->setEnabled(enable_change_art); @@ -3197,7 +3197,7 @@ void MainWindow::AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult Q_EMIT AlbumCoverReady(song, result.album_cover.image); - const bool enable_change_art = song.is_collection_song() && !song.effective_albumartist().isEmpty() && !song.album().isEmpty(); + const bool enable_change_art = song.is_local_collection_song() && !song.effective_albumartist().isEmpty() && !song.album().isEmpty(); album_cover_choice_controller_->show_cover_action()->setEnabled(result.success && result.type != AlbumCoverLoaderResult::Type::Unset); album_cover_choice_controller_->cover_to_file_action()->setEnabled(result.success && result.type != AlbumCoverLoaderResult::Type::Unset); album_cover_choice_controller_->cover_from_file_action()->setEnabled(enable_change_art); diff --git a/src/core/song.cpp b/src/core/song.cpp index f7bb52782..27d5ab239 100644 --- a/src/core/song.cpp +++ b/src/core/song.cpp @@ -439,6 +439,7 @@ int Song::samplerate() const { return d->samplerate_; } int Song::bitdepth() const { return d->bitdepth_; } Song::Source Song::source() const { return d->source_; } +int Song::source_id() const { return static_cast(d->source_); } int Song::directory_id() const { return d->directory_id_; } const QUrl &Song::url() const { return d->url_; } const QString &Song::basefilename() const { return d->basefilename_; } @@ -661,7 +662,8 @@ const QString &Song::playlist_albumartist() const { return is_compilation() ? d- const QString &Song::playlist_albumartist_sortable() const { return is_compilation() ? d->albumartist_sortable_ : effective_albumartist_sortable(); } bool Song::is_metadata_good() const { return !d->url_.isEmpty() && !d->artist_.isEmpty() && !d->title_.isEmpty(); } -bool Song::is_collection_song() const { return d->source_ == Source::Collection; } +bool Song::is_local_collection_song() const { return d->source_ == Source::Collection; } +bool Song::is_linked_collection_song() const { return IsLinkedCollectionSource(d->source_); } bool Song::is_stream() const { return is_radio() || d->source_ == Source::Tidal || d->source_ == Source::Subsonic || d->source_ == Source::Qobuz || d->source_ == Source::Spotify; } bool Song::is_radio() const { return d->source_ == Source::Stream || d->source_ == Source::SomaFM || d->source_ == Source::RadioParadise; } bool Song::is_cdda() const { return d->source_ == Source::CDDA; } @@ -1331,6 +1333,12 @@ Song::FileType Song::FiletypeByExtension(const QString &ext) { } +bool Song::IsLinkedCollectionSource(const Source source) { + + return source == Source::Collection; + +} + QString Song::ImageCacheDir(const Source source) { switch (source) { @@ -1831,8 +1839,8 @@ bool Song::MergeFromEngineMetadata(const EngineMetadata &engine_metadata) { bool minor = true; - if (d->init_from_file_ || is_collection_song() || d->url_.isLocalFile()) { - // This Song was already loaded using taglib. Our tags are probably better than the engine's. + if (d->init_from_file_ || is_local_collection_song() || d->url_.isLocalFile()) { + // This Song was already loaded using TagLib. Our tags are probably better than the engine's. if (title() != engine_metadata.title && title().isEmpty() && !engine_metadata.title.isEmpty()) { set_title(engine_metadata.title); minor = false; diff --git a/src/core/song.h b/src/core/song.h index a0f6bc205..9c4e51c57 100644 --- a/src/core/song.h +++ b/src/core/song.h @@ -78,6 +78,7 @@ class Song { RadioParadise = 10, Spotify = 11 }; + static const int kSourceCount = 16; enum class FileType { Unknown = 0, @@ -176,6 +177,7 @@ class Song { int bitdepth() const; Source source() const; + int source_id() const; int directory_id() const; const QUrl &url() const; const QString &basefilename() const; @@ -372,7 +374,8 @@ class Song { const QString &playlist_albumartist_sortable() const; bool is_metadata_good() const; - bool is_collection_song() const; + bool is_local_collection_song() const; + bool is_linked_collection_song() const; bool is_stream() const; bool is_radio() const; bool is_cdda() const; @@ -459,6 +462,7 @@ class Song { static FileType FiletypeByMimetype(const QString &mimetype); static FileType FiletypeByDescription(const QString &text); static FileType FiletypeByExtension(const QString &ext); + static bool IsLinkedCollectionSource(const Source source); static QString ImageCacheDir(const Source source); // Sort songs alphabetically using their pretty title diff --git a/src/dialogs/edittagdialog.cpp b/src/dialogs/edittagdialog.cpp index e7100f30e..b8a2eca03 100644 --- a/src/dialogs/edittagdialog.cpp +++ b/src/dialogs/edittagdialog.cpp @@ -716,7 +716,7 @@ void EditTagDialog::SelectionChanged() { } ui_->tags_summary->setText(summary); - const bool enable_change_art = first_song.is_collection_song(); + const bool enable_change_art = first_song.is_local_collection_song(); ui_->tags_art_button->setEnabled(enable_change_art); if ((art_different && first_cover_action != UpdateCoverAction::New) || action_different) { tags_cover_art_id_ = -1; // Cancels any pending art load. @@ -878,7 +878,7 @@ QString EditTagDialog::GetArtSummary(const Song &song, const AlbumCoverLoaderRes summary = tr("Cover art not set").toHtmlEscaped(); } - if (!song.is_collection_song()) { + if (!song.is_local_collection_song()) { if (!summary.isEmpty()) summary += "
"_L1; summary = tr("Album cover editing is only available for collection songs."); } @@ -962,7 +962,7 @@ void EditTagDialog::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderRes summary += GetArtSummary(cover_action); } ui_->tags_summary->setText(summary); - enable_change_art = first_song.is_collection_song() && !first_song.effective_albumartist().isEmpty() && !first_song.album().isEmpty(); + enable_change_art = first_song.is_local_collection_song() && !first_song.effective_albumartist().isEmpty() && !first_song.album().isEmpty(); } tags_cover_art_id_ = -1; album_cover_choice_controller_->show_cover_action()->setEnabled(result.success && result.type != AlbumCoverLoaderResult::Type::Unset); @@ -1321,7 +1321,7 @@ void EditTagDialog::SaveData() { } // If the cover was changed, but no tags written, make sure to update the collection. else if (ref.cover_action_ != UpdateCoverAction::None && !ref.current_.effective_albumartist().isEmpty() && !ref.current_.album().isEmpty()) { - if (ref.current_.is_collection_song()) { + if (ref.current_.is_local_collection_song()) { collection_songs_.insert(ref.current_.id(), ref.current_); } if (ref.current_ == current_albumcover_loader_->last_song()) { @@ -1476,7 +1476,7 @@ void EditTagDialog::SongSaveTagsComplete(TagReaderReplyPtr reply, const QString const QString error = reply->error(); if (success) { - if (song.is_collection_song()) { + if (song.is_local_collection_song()) { if (collection_songs_.contains(song.id())) { Song old_song = collection_songs_.take(song.id()); song.set_art_automatic(old_song.art_automatic()); diff --git a/src/organize/organize.cpp b/src/organize/organize.cpp index fccd8bae2..62c570a4d 100644 --- a/src/organize/organize.cpp +++ b/src/organize/organize.cpp @@ -262,7 +262,7 @@ void Organize::ProcessSomeFiles() { QString error_text; if (destination_->CopyToStorage(job, error_text)) { - if (job.remove_original_ && song.is_collection_song() && destination_->source() == Song::Source::Collection) { + if (job.remove_original_ && song.is_local_collection_song() && destination_->source() == Song::Source::Collection) { // Notify other aspects of system that song has been invalidated QString root = destination_->LocalPath(); QFileInfo new_file = QFileInfo(root + QLatin1Char('/') + task.song_info_.new_filename_); diff --git a/src/playlist/playlist.cpp b/src/playlist/playlist.cpp index 7a787dbba..4efa94869 100644 --- a/src/playlist/playlist.cpp +++ b/src/playlist/playlist.cpp @@ -92,12 +92,12 @@ #include "smartplaylists/playlistgeneratorinserter.h" #include "smartplaylists/playlistgeneratormimedata.h" -#include "streaming/streamplaylistitem.h" +#include "streaming/streamserviceplaylistitem.h" #include "streaming/streamsongmimedata.h" #include "streaming/streamingservice.h" #include "radios/radiomimedata.h" -#include "radios/radioplaylistitem.h" +#include "radios/radiostreamplaylistitem.h" using std::make_shared; using namespace std::chrono_literals; @@ -186,7 +186,7 @@ Playlist::Playlist(const SharedPtr task_manager, Playlist::~Playlist() { items_.clear(); - collection_items_by_id_.clear(); + ClearCollectionItems(); } template @@ -828,25 +828,24 @@ bool Playlist::dropMimeData(const QMimeData *data, Qt::DropAction action, const if (const SongMimeData *song_data = qobject_cast(data)) { // Dragged from a collection - // We want to check if these songs are from the actual local file backend, if they are we treat them differently. - if (song_data->backend && song_data->backend->songs_table() == QLatin1String(CollectionLibrary::kSongsTable)) { + if (song_data->backend && Song::IsLinkedCollectionSource(song_data->backend->source())) { InsertSongItems(song_data->songs, row, play_now, enqueue_now, enqueue_next_now); } else { InsertSongItems(song_data->songs, row, play_now, enqueue_now, enqueue_next_now); } } - else if (const PlaylistItemMimeData *item_data = qobject_cast(data)) { - InsertItems(item_data->items_, row, play_now, enqueue_now, enqueue_next_now); + else if (const PlaylistItemMimeData *item_mimedata = qobject_cast(data)) { + InsertItems(item_mimedata->items_, row, play_now, enqueue_now, enqueue_next_now); } - else if (const PlaylistGeneratorMimeData *generator_data = qobject_cast(data)) { - InsertSmartPlaylist(generator_data->generator_, row, play_now, enqueue_now, enqueue_next_now); + else if (const PlaylistGeneratorMimeData *generator_mimedata = qobject_cast(data)) { + InsertSmartPlaylist(generator_mimedata->generator_, row, play_now, enqueue_now, enqueue_next_now); } - else if (const StreamSongMimeData *stream_song_data = qobject_cast(data)) { - InsertStreamingItems(stream_song_data->service, stream_song_data->songs, row, play_now, enqueue_now, enqueue_next_now); + else if (const StreamSongMimeData *stream_song_mimedata = qobject_cast(data)) { + InsertStreamingItems(stream_song_mimedata->service, stream_song_mimedata->songs, row, play_now, enqueue_now, enqueue_next_now); } - else if (const RadioMimeData *radio_data = qobject_cast(data)) { - InsertRadioItems(radio_data->songs, row, play_now, enqueue_now, enqueue_next_now); + else if (const RadioMimeData *radio_mimedata = qobject_cast(data)) { + InsertRadioItems(radio_mimedata->songs, row, play_now, enqueue_now, enqueue_next_now); } else if (data->hasFormat(QLatin1String(kRowsMimetype))) { // Dragged from the playlist @@ -1131,10 +1130,10 @@ void Playlist::InsertItemsWithoutUndo(const PlaylistItemPtrList &items, const in items_.insert(i, item); virtual_items_ << static_cast(virtual_items_.count()); - if (item->source() == Song::Source::Collection) { - int id = item->Metadata().id(); + if (Song::IsLinkedCollectionSource(item->source())) { + const int id = item->Metadata().id(); if (id != -1) { - collection_items_by_id_.insert(id, item); + collection_items_[item->Metadata().source_id()].insert(id, item); } } @@ -1187,23 +1186,9 @@ void Playlist::InsertSongsOrCollectionItems(const SongList &songs, const QString } PlaylistItemPtrList items; + items.reserve(songs.count()); for (const Song &song : songs) { - if (song.url().isLocalFile()) { - if (song.is_collection_song()) { - items << make_shared(song); - } - else { - items << make_shared(song); - } - } - else { - if (song.is_radio()) { - items << make_shared(song); - } - else { - items << make_shared(song); - } - } + items << PlaylistItem::NewFromSong(song); } InsertItems(items, pos, play_now, enqueue, enqueue_next); @@ -1215,7 +1200,7 @@ void Playlist::InsertStreamingItems(StreamingServicePtr service, const SongList PlaylistItemPtrList playlist_items; playlist_items.reserve(songs.count()); for (const Song &song : songs) { - playlist_items << make_shared(service, song); + playlist_items << make_shared(service, song); } InsertItems(playlist_items, pos, play_now, enqueue, enqueue_next); @@ -1227,7 +1212,7 @@ void Playlist::InsertRadioItems(const SongList &songs, const int pos, const bool PlaylistItemPtrList playlist_items; playlist_items.reserve(songs.count()); for (const Song &song : songs) { - playlist_items << make_shared(song); + playlist_items << make_shared(song); } InsertItems(playlist_items, pos, play_now, enqueue, enqueue_next); @@ -1252,22 +1237,22 @@ void Playlist::UpdateItems(SongList songs) { const PlaylistItemPtr item = items_.value(i); if (item->Metadata().url() == song.url() && (item->Metadata().filetype() == Song::FileType::Unknown || item->Metadata().filetype() == Song::FileType::Stream || item->Metadata().filetype() == Song::FileType::CDDA || !item->Metadata().init_from_file())) { PlaylistItemPtr new_item; - if (song.url().isLocalFile()) { - if (song.is_collection_song()) { - new_item = make_shared(song); - if (collection_items_by_id_.contains(song.id(), item)) collection_items_by_id_.remove(song.id(), item); - collection_items_by_id_.insert(song.id(), new_item); - } - else { - new_item = make_shared(song); - } + if (song.is_linked_collection_song()) { + new_item = make_shared(song); + if (collection_items_[song.source_id()].contains(song.id(), item)) collection_items_[song.source_id()].remove(song.id(), item); + collection_items_[song.source_id()].insert(song.id(), new_item); } else { - if (song.is_radio()) { - new_item = make_shared(song); + if (song.url().isLocalFile()) { + new_item = make_shared(song); } else { - new_item = make_shared(song); + if (song.is_radio()) { + new_item = make_shared(song); + } + else { + new_item = make_shared(song); + } } } items_[i] = new_item; @@ -1580,7 +1565,7 @@ void Playlist::Restore() { items_.clear(); virtual_items_.clear(); - collection_items_by_id_.clear(); + ClearCollectionItems(); cancel_restore_ = false; QFuture future = QtConcurrent::run(&PlaylistBackend::GetPlaylistItems, playlist_backend_, id_); @@ -1590,6 +1575,15 @@ void Playlist::Restore() { } +void Playlist::ClearCollectionItems() { + + constexpr int collection_items_size = static_cast(sizeof(collection_items_)) / sizeof(collection_items_[0]); + for (int i = 0; i < collection_items_size; ++i) { + collection_items_[i].clear(); + } + +} + void Playlist::ItemsLoaded() { QFutureWatcher *watcher = static_cast*>(sender()); @@ -1735,12 +1729,10 @@ PlaylistItemPtrList Playlist::RemoveItemsWithoutUndo(const int row, const int co for (int i = 0; i < count; ++i) { PlaylistItemPtr item(items_.takeAt(row)); items << item; - - if (item->source() == Song::Source::Collection) { - int id = item->Metadata().id(); - if (id != -1 && collection_items_by_id_.contains(id, item)) { - collection_items_by_id_.remove(id, item); - } + const int id = item->Metadata().id(); + const int source_id = item->Metadata().source_id(); + if (id != -1 && collection_items_[source_id].contains(id, item)) { + collection_items_[source_id].remove(id, item); } } @@ -2069,8 +2061,8 @@ quint64 Playlist::GetTotalLength() const { } -PlaylistItemPtrList Playlist::collection_items_by_id(const int id) const { - return collection_items_by_id_.values(id); +PlaylistItemPtrList Playlist::collection_items(const Song::Source source, const int song_id) const { + return collection_items_[static_cast(source)].values(song_id); } void Playlist::TracksAboutToBeDequeued(const QModelIndex &idx, const int begin, const int end) { diff --git a/src/playlist/playlist.h b/src/playlist/playlist.h index 017066926..c02b4be6e 100644 --- a/src/playlist/playlist.h +++ b/src/playlist/playlist.h @@ -2,7 +2,7 @@ * Strawberry Music Player * This file was part of Clementine. * Copyright 2010, David Sansome - * Copyright 2018-2024, Jonas Kvinge + * Copyright 2018-2025, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -203,7 +203,7 @@ class Playlist : public QAbstractListModel { PlaylistItem::Options current_item_options() const; Song current_item_metadata() const; - PlaylistItemPtrList collection_items_by_id(const int id) const; + PlaylistItemPtrList collection_items(const Song::Source source, const int song_id) const; SongList GetAllSongs() const; PlaylistItemPtrList GetAllItems() const; @@ -357,6 +357,8 @@ class Playlist : public QAbstractListModel { // Grays out and reloads all deleted songs in all playlists. Also, "ungreys" those songs which were once deleted but now got restored somehow. void InvalidateDeletedSongs(); + void ClearCollectionItems(); + private Q_SLOTS: void TracksAboutToBeDequeued(const QModelIndex&, const int begin, const int end); void TracksDequeued(); @@ -393,8 +395,7 @@ class Playlist : public QAbstractListModel { QList played_indexes_; - // A map of collection ID to playlist item - for fast lookups when collection items change. - QMultiMap collection_items_by_id_; + QMultiMap collection_items_[Song::kSourceCount]; QPersistentModelIndex current_item_index_; QPersistentModelIndex last_played_item_index_; diff --git a/src/playlist/playlistitem.cpp b/src/playlist/playlistitem.cpp index a5009766d..c1a638ca4 100644 --- a/src/playlist/playlistitem.cpp +++ b/src/playlist/playlistitem.cpp @@ -2,7 +2,7 @@ * Strawberry Music Player * This file was part of Clementine. * Copyright 2010, David Sansome - * Copyright 2018-2021, Jonas Kvinge + * Copyright 2018-2025, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,30 +30,31 @@ #include "core/sqlquery.h" #include "core/song.h" -#include "collection/collectionplaylistitem.h" #include "playlistitem.h" #include "songplaylistitem.h" - -#include "streaming/streamplaylistitem.h" -#include "radios/radioplaylistitem.h" +#include "collection/collectionplaylistitem.h" +#include "streaming/streamserviceplaylistitem.h" +#include "radios/radiostreamplaylistitem.h" using std::make_shared; using namespace Qt::Literals::StringLiterals; +PlaylistItem::PlaylistItem(const Song::Source source) : should_skip_(false), source_(source) {} + PlaylistItemPtr PlaylistItem::NewFromSource(const Song::Source source) { switch (source) { case Song::Source::Collection: - return make_shared(); + return make_shared(source); case Song::Source::Subsonic: case Song::Source::Tidal: case Song::Source::Spotify: case Song::Source::Qobuz: - return make_shared(source); + return make_shared(source); case Song::Source::Stream: case Song::Source::RadioParadise: case Song::Source::SomaFM: - return make_shared(source); + return make_shared(source); case Song::Source::LocalFile: case Song::Source::CDDA: case Song::Source::Device: @@ -74,11 +75,11 @@ PlaylistItemPtr PlaylistItem::NewFromSong(const Song &song) { case Song::Source::Tidal: case Song::Source::Spotify: case Song::Source::Qobuz: - return make_shared(song); + return make_shared(song); case Song::Source::Stream: case Song::Source::RadioParadise: case Song::Source::SomaFM: - return make_shared(song); + return make_shared(song); case Song::Source::LocalFile: case Song::Source::CDDA: case Song::Source::Device: @@ -90,12 +91,10 @@ PlaylistItemPtr PlaylistItem::NewFromSong(const Song &song) { } -PlaylistItem::~PlaylistItem() = default; - void PlaylistItem::BindToQuery(SqlQuery *query) const { query->BindValue(u":type"_s, static_cast(source_)); - query->BindValue(u":collection_id"_s, DatabaseValue(Column_CollectionId)); + query->BindValue(u":collection_id"_s, DatabaseValue(DatabaseColumn::CollectionId)); DatabaseSongMetadata().BindToQuery(query); @@ -174,5 +173,5 @@ QColor PlaylistItem::GetCurrentForegroundColor() const { bool PlaylistItem::HasCurrentForegroundColor() const { return !foreground_colors_.isEmpty(); } -void PlaylistItem::SetShouldSkip(const bool val) { should_skip_ = val; } +void PlaylistItem::SetShouldSkip(const bool should_skip) { should_skip_ = should_skip; } bool PlaylistItem::GetShouldSkip() const { return should_skip_; } diff --git a/src/playlist/playlistitem.h b/src/playlist/playlistitem.h index 677cd577f..ee04f49c3 100644 --- a/src/playlist/playlistitem.h +++ b/src/playlist/playlistitem.h @@ -2,7 +2,7 @@ * Strawberry Music Player * This file was part of Clementine. * Copyright 2010, David Sansome - * Copyright 2018-2021, Jonas Kvinge + * Copyright 2018-2025, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -48,8 +48,7 @@ using std::enable_shared_from_this; class PlaylistItem : public enable_shared_from_this { public: - explicit PlaylistItem(const Song::Source source) : should_skip_(false), source_(source) {} - virtual ~PlaylistItem(); + explicit PlaylistItem(const Song::Source source); static SharedPtr NewFromSource(const Song::Source source); static SharedPtr NewFromSong(const Song &song); @@ -80,7 +79,7 @@ class PlaylistItem : public enable_shared_from_this { virtual Song OriginalMetadata() const = 0; virtual QUrl Url() const = 0; - virtual void SetMetadata(const Song&) {} + virtual void SetMetadata(const Song &song) { Q_UNUSED(song); } void SetTemporaryMetadata(const Song &metadata); void UpdateTemporaryMetadata(const Song &metadata); @@ -114,21 +113,20 @@ class PlaylistItem : public enable_shared_from_this { // Convenience function to find out whether this item is from the local collection, as opposed to a device, a file on disk, or a stream. // Remember that even if this returns true, the collection item might be invalid, so you might want to check that its id is not equal to -1 before actually using it. virtual bool IsLocalCollectionItem() const { return false; } - void SetShouldSkip(const bool val); + void SetShouldSkip(const bool should_skip); bool GetShouldSkip() const; protected: bool should_skip_; - enum DatabaseColumn { Column_CollectionId }; + enum class DatabaseColumn { + CollectionId + }; - virtual QVariant DatabaseValue(DatabaseColumn) const { - return QVariant(QString()); - } + virtual QVariant DatabaseValue(const DatabaseColumn database_column) const { Q_UNUSED(database_column); return QVariant(QString()); } virtual Song DatabaseSongMetadata() const { return Song(); } Song::Source source_; - Song temp_metadata_; QMap background_colors_; diff --git a/src/playlist/playlistmanager.cpp b/src/playlist/playlistmanager.cpp index 7e54cd6a2..202fce24f 100644 --- a/src/playlist/playlistmanager.cpp +++ b/src/playlist/playlistmanager.cpp @@ -2,7 +2,7 @@ * Strawberry Music Player * This file was part of Clementine. * Copyright 2010, David Sansome - * Copyright 2018-2021, Jonas Kvinge + * Copyright 2018-2025, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -476,7 +476,7 @@ void PlaylistManager::UpdateCollectionSongs(const SongList &songs) { for (const Song &song : songs) { for (const Data &data : std::as_const(playlists_)) { - const PlaylistItemPtrList items = data.p->collection_items_by_id(song.id()); + const PlaylistItemPtrList items = data.p->collection_items(song.source(), song.id()); for (PlaylistItemPtr item : items) { if (item->Metadata().directory_id() != song.directory_id()) continue; data.p->UpdateItemMetadata(item, song, false); diff --git a/src/playlist/playlistmanager.h b/src/playlist/playlistmanager.h index 6762763b2..be568aed2 100644 --- a/src/playlist/playlistmanager.h +++ b/src/playlist/playlistmanager.h @@ -2,7 +2,7 @@ * Strawberry Music Player * This file was part of Clementine. * Copyright 2010, David Sansome - * Copyright 2018-2021, Jonas Kvinge + * Copyright 2018-2025, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/playlist/songplaylistitem.cpp b/src/playlist/songplaylistitem.cpp index f8adc0ffc..9287870ac 100644 --- a/src/playlist/songplaylistitem.cpp +++ b/src/playlist/songplaylistitem.cpp @@ -2,7 +2,7 @@ * Strawberry Music Player * This file was part of Clementine. * Copyright 2010, David Sansome - * Copyright 2018-2021, Jonas Kvinge + * Copyright 2018-2025, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/playlist/songplaylistitem.h b/src/playlist/songplaylistitem.h index 7eddaa0f5..02d20771c 100644 --- a/src/playlist/songplaylistitem.h +++ b/src/playlist/songplaylistitem.h @@ -2,7 +2,7 @@ * Strawberry Music Player * This file was part of Clementine. * Copyright 2010, David Sansome - * Copyright 2018-2021, Jonas Kvinge + * Copyright 2018-2025, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/src/streaming/streamplaylistitem.cpp b/src/playlist/streamplaylistitem.cpp similarity index 54% rename from src/streaming/streamplaylistitem.cpp rename to src/playlist/streamplaylistitem.cpp index 32979d6f1..dc619741e 100644 --- a/src/streaming/streamplaylistitem.cpp +++ b/src/playlist/streamplaylistitem.cpp @@ -1,8 +1,6 @@ /* * Strawberry Music Player - * This file was part of Clementine. - * Copyright 2010, David Sansome - * Copyright 2018-2021, Jonas Kvinge + * Copyright 2018-2025, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,60 +23,52 @@ #include #include "streamplaylistitem.h" -#include "streamingservice.h" #include "core/sqlrow.h" StreamPlaylistItem::StreamPlaylistItem(const Song::Source source) : PlaylistItem(source), source_(source) {} -StreamPlaylistItem::StreamPlaylistItem(const Song &metadata) - : PlaylistItem(metadata.source()), - source_(metadata.source()), - metadata_(metadata) { - InitMetadata(); -} - -StreamPlaylistItem::StreamPlaylistItem(StreamingServicePtr service, const Song &metadata) - : PlaylistItem(metadata.source()), - source_(service->source()), - metadata_(metadata) { +StreamPlaylistItem::StreamPlaylistItem(const Song &song) + : PlaylistItem(song.source()), + source_(song.source()), + song_(song) { InitMetadata(); } bool StreamPlaylistItem::InitFromQuery(const SqlRow &query) { - metadata_.InitFromQuery(query, false, static_cast(Song::kRowIdColumns.count())); + song_.InitFromQuery(query, false, static_cast(Song::kRowIdColumns.count())); InitMetadata(); return true; } -QVariant StreamPlaylistItem::DatabaseValue(DatabaseColumn column) const { +QVariant StreamPlaylistItem::DatabaseValue(const DatabaseColumn column) const { return PlaylistItem::DatabaseValue(column); } void StreamPlaylistItem::InitMetadata() { - if (metadata_.title().isEmpty()) metadata_.set_title(metadata_.url().toString()); - if (metadata_.source() == Song::Source::Unknown) metadata_.set_source(Song::Source::Stream); - if (metadata_.filetype() == Song::FileType::Unknown) metadata_.set_filetype(Song::FileType::Stream); - metadata_.set_valid(true); + if (song_.title().isEmpty()) song_.set_title(song_.url().toString()); + if (song_.source() == Song::Source::Unknown) song_.set_source(Song::Source::Stream); + if (song_.filetype() == Song::FileType::Unknown) song_.set_filetype(Song::FileType::Stream); + song_.set_valid(true); } Song StreamPlaylistItem::Metadata() const { if (HasTemporaryMetadata()) return temp_metadata_; - return metadata_; + return song_; } -QUrl StreamPlaylistItem::Url() const { return metadata_.url(); } +QUrl StreamPlaylistItem::Url() const { return song_.url(); } void StreamPlaylistItem::SetArtManual(const QUrl &cover_url) { - metadata_.set_art_manual(cover_url); + song_.set_art_manual(cover_url); temp_metadata_.set_art_manual(cover_url); } diff --git a/src/streaming/streamplaylistitem.h b/src/playlist/streamplaylistitem.h similarity index 66% rename from src/streaming/streamplaylistitem.h rename to src/playlist/streamplaylistitem.h index 39ed563a3..0e7c6ce23 100644 --- a/src/streaming/streamplaylistitem.h +++ b/src/playlist/streamplaylistitem.h @@ -1,8 +1,6 @@ /* * Strawberry Music Player - * This file was part of Clementine. - * Copyright 2010, David Sansome - * Copyright 2018-2021, Jonas Kvinge + * Copyright 2018-2025, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,43 +20,37 @@ #ifndef STREAMPLAYLISTITEM_H #define STREAMPLAYLISTITEM_H -#include "config.h" - #include #include -#include "includes/shared_ptr.h" #include "core/song.h" #include "core/sqlrow.h" #include "playlist/playlistitem.h" -class StreamingService; - class StreamPlaylistItem : public PlaylistItem { public: explicit StreamPlaylistItem(const Song::Source source); - explicit StreamPlaylistItem(const Song &metadata); - explicit StreamPlaylistItem(SharedPtr service, const Song &metadata); + explicit StreamPlaylistItem(const Song &song); bool InitFromQuery(const SqlRow &query) override; Song Metadata() const override; - Song OriginalMetadata() const override { return metadata_; } + Song OriginalMetadata() const override { return song_; } QUrl Url() const override; - void SetMetadata(const Song &metadata) override { metadata_ = metadata; } + void SetMetadata(const Song &song) override { song_ = song; } void SetArtManual(const QUrl &cover_url) override; protected: - QVariant DatabaseValue(DatabaseColumn) const override; - Song DatabaseSongMetadata() const override { return metadata_; } + QVariant DatabaseValue(const DatabaseColumn column) const override; + Song DatabaseSongMetadata() const override { return song_; } private: void InitMetadata(); private: Song::Source source_; - Song metadata_; + Song song_; Q_DISABLE_COPY(StreamPlaylistItem) }; diff --git a/src/radios/radioplaylistitem.cpp b/src/radios/radioplaylistitem.cpp deleted file mode 100644 index d359cea1f..000000000 --- a/src/radios/radioplaylistitem.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Strawberry Music Player - * Copyright 2021, Jonas Kvinge - * - * Strawberry is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Strawberry is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Strawberry. If not, see . - * - */ - -#include "config.h" - -#include -#include -#include - -#include "radioplaylistitem.h" -#include "core/sqlrow.h" - -RadioPlaylistItem::RadioPlaylistItem(const Song::Source source) - : PlaylistItem(source), source_(source) {} - -RadioPlaylistItem::RadioPlaylistItem(const Song &metadata) - : PlaylistItem(metadata.source()), - source_(metadata.source()), - metadata_(metadata) { - InitMetadata(); -} - -bool RadioPlaylistItem::InitFromQuery(const SqlRow &query) { - - metadata_.InitFromQuery(query, false, static_cast(Song::kRowIdColumns.count())); - InitMetadata(); - return true; - -} - -QVariant RadioPlaylistItem::DatabaseValue(DatabaseColumn column) const { - return PlaylistItem::DatabaseValue(column); -} - -void RadioPlaylistItem::InitMetadata() { - - if (metadata_.title().isEmpty()) metadata_.set_title(metadata_.url().toString()); - if (metadata_.source() == Song::Source::Unknown) metadata_.set_source(Song::Source::Stream); - if (metadata_.filetype() == Song::FileType::Unknown) metadata_.set_filetype(Song::FileType::Stream); - metadata_.set_valid(true); - -} - -Song RadioPlaylistItem::Metadata() const { - - if (HasTemporaryMetadata()) return temp_metadata_; - return metadata_; - -} - -QUrl RadioPlaylistItem::Url() const { return metadata_.url(); } - -void RadioPlaylistItem::SetArtManual(const QUrl &cover_url) { - - metadata_.set_art_manual(cover_url); - temp_metadata_.set_art_manual(cover_url); - -} diff --git a/src/radios/radioplaylistitem.h b/src/radios/radioplaylistitem.h deleted file mode 100644 index 24c62abe7..000000000 --- a/src/radios/radioplaylistitem.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Strawberry Music Player - * Copyright 2021, Jonas Kvinge - * - * Strawberry is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Strawberry is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Strawberry. If not, see . - * - */ - -#ifndef RADIOPLAYLISTITEM_H -#define RADIOPLAYLISTITEM_H - -#include "config.h" - -#include -#include - -#include "core/song.h" -#include "core/sqlrow.h" -#include "playlist/playlistitem.h" - -class RadioService; - -class RadioPlaylistItem : public PlaylistItem { - - public: - explicit RadioPlaylistItem(const Song::Source source); - explicit RadioPlaylistItem(const Song &metadata); - - bool InitFromQuery(const SqlRow &query) override; - Song Metadata() const override; - Song OriginalMetadata() const override { return metadata_; } - QUrl Url() const override; - - void SetMetadata(const Song &metadata) override { metadata_ = metadata; } - void SetArtManual(const QUrl &cover_url) override; - - protected: - QVariant DatabaseValue(DatabaseColumn) const override; - Song DatabaseSongMetadata() const override { return metadata_; } - - private: - void InitMetadata(); - - private: - Song::Source source_; - Song metadata_; - - Q_DISABLE_COPY(RadioPlaylistItem) -}; - -#endif // RADIOPLAYLISTITEM_H diff --git a/src/radios/radiostreamplaylistitem.cpp b/src/radios/radiostreamplaylistitem.cpp new file mode 100644 index 000000000..5e65427b0 --- /dev/null +++ b/src/radios/radiostreamplaylistitem.cpp @@ -0,0 +1,26 @@ +/* + * Strawberry Music Player + * Copyright 2021-2025, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include "radiostreamplaylistitem.h" + +RadioStreamPlaylistItem::RadioStreamPlaylistItem(const Song &song) + : StreamPlaylistItem(song) {} + +RadioStreamPlaylistItem::RadioStreamPlaylistItem(const SharedPtr service, const Song &song) + : StreamPlaylistItem(song), service_(service) {} diff --git a/src/radios/radiostreamplaylistitem.h b/src/radios/radiostreamplaylistitem.h new file mode 100644 index 000000000..060f34f5a --- /dev/null +++ b/src/radios/radiostreamplaylistitem.h @@ -0,0 +1,39 @@ +/* + * Strawberry Music Player + * Copyright 2021-2025, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef RADIOSTREAMPLAYLISTITEM_H +#define RADIOSTREAMPLAYLISTITEM_H + +#include "includes/shared_ptr.h" +#include "core/song.h" +#include "playlist/streamplaylistitem.h" + +class RadioService; + +class RadioStreamPlaylistItem : public StreamPlaylistItem { + public: + explicit RadioStreamPlaylistItem(const Song &song); + explicit RadioStreamPlaylistItem(const SharedPtr service, const Song &song); + Q_DISABLE_COPY(RadioStreamPlaylistItem) + + private: + const SharedPtr service_; +}; + +#endif // RADIOSTREAMPLAYLISTITEM_H diff --git a/src/streaming/streamserviceplaylistitem.cpp b/src/streaming/streamserviceplaylistitem.cpp new file mode 100644 index 000000000..c82435b58 --- /dev/null +++ b/src/streaming/streamserviceplaylistitem.cpp @@ -0,0 +1,27 @@ +/* + * Strawberry Music Player + * Copyright 2018-2025, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#include "streamserviceplaylistitem.h" +#include "streamingservice.h" + +StreamServicePlaylistItem::StreamServicePlaylistItem(const Song &song) + : StreamPlaylistItem(song) {} + +StreamServicePlaylistItem::StreamServicePlaylistItem(const StreamingServicePtr service, const Song &song) + : StreamPlaylistItem(song), service_(service) {} diff --git a/src/streaming/streamserviceplaylistitem.h b/src/streaming/streamserviceplaylistitem.h new file mode 100644 index 000000000..64fd28241 --- /dev/null +++ b/src/streaming/streamserviceplaylistitem.h @@ -0,0 +1,38 @@ +/* + * Strawberry Music Player + * Copyright 2018-2025, Jonas Kvinge + * + * Strawberry is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Strawberry is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Strawberry. If not, see . + * + */ + +#ifndef STREAMSERVICEPLAYLISTITEM_H +#define STREAMSERVICEPLAYLISTITEM_H + +#include "includes/shared_ptr.h" +#include "core/song.h" +#include "playlist/streamplaylistitem.h" + +class StreamingService; + +class StreamServicePlaylistItem : public StreamPlaylistItem { + public: + explicit StreamServicePlaylistItem(const Song &song); + explicit StreamServicePlaylistItem(const SharedPtr service, const Song &song); + Q_DISABLE_COPY(StreamServicePlaylistItem) + private: + SharedPtr service_; +}; + +#endif // STREAMPLAYLISTITEM_H diff --git a/src/streaming/streamsongmimedata.cpp b/src/streaming/streamsongmimedata.cpp index 546d76b1f..da19bd931 100644 --- a/src/streaming/streamsongmimedata.cpp +++ b/src/streaming/streamsongmimedata.cpp @@ -2,7 +2,7 @@ * Strawberry Music Player * This file was part of Clementine. * Copyright 2011, David Sansome - * Copyright 2018-2024, Jonas Kvinge + * Copyright 2018-2025, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,6 +22,6 @@ #include "includes/shared_ptr.h" #include "streamsongmimedata.h" -StreamSongMimeData::StreamSongMimeData(SharedPtr _service, QObject *parent) : service(_service) { +StreamSongMimeData::StreamSongMimeData(const SharedPtr _service, QObject *parent) : service(_service) { Q_UNUSED(parent); } diff --git a/src/streaming/streamsongmimedata.h b/src/streaming/streamsongmimedata.h index 6b1d5d2a3..2eb07aeed 100644 --- a/src/streaming/streamsongmimedata.h +++ b/src/streaming/streamsongmimedata.h @@ -2,7 +2,7 @@ * Strawberry Music Player * This file was part of Clementine. * Copyright 2011, David Sansome - * Copyright 2018-2024, Jonas Kvinge + * Copyright 2018-2025, Jonas Kvinge * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,9 +32,9 @@ class StreamSongMimeData : public MimeData { Q_OBJECT public: - explicit StreamSongMimeData(SharedPtr _service, QObject *parent = nullptr); + explicit StreamSongMimeData(const SharedPtr _service, QObject *parent = nullptr); - SharedPtr service; + const SharedPtr service; SongList songs; }; diff --git a/tests/src/playlist_test.cpp b/tests/src/playlist_test.cpp index 1f8f0d3dc..258456742 100644 --- a/tests/src/playlist_test.cpp +++ b/tests/src/playlist_test.cpp @@ -476,22 +476,22 @@ TEST_F(PlaylistTest, ShuffleThenNext) { TEST_F(PlaylistTest, CollectionIdMapSingle) { - Song song; + Song song(Song::Source::Collection); song.Init(u"title"_s, u"artist"_s, u"album"_s, 123); song.set_id(1); PlaylistItemPtr item(std::make_shared(song)); playlist_.InsertItems(PlaylistItemPtrList() << item); - EXPECT_EQ(0, playlist_.collection_items_by_id(-1).count()); - EXPECT_EQ(0, playlist_.collection_items_by_id(0).count()); - EXPECT_EQ(0, playlist_.collection_items_by_id(2).count()); - ASSERT_EQ(1, playlist_.collection_items_by_id(1).count()); - EXPECT_EQ(song.title(), playlist_.collection_items_by_id(1)[0]->Metadata().title()); // clazy:exclude=detaching-temporary + EXPECT_EQ(0, playlist_.collection_items(Song::Source::Collection, -1).count()); + EXPECT_EQ(0, playlist_.collection_items(Song::Source::Collection, 0).count()); + EXPECT_EQ(0, playlist_.collection_items(Song::Source::Collection, 2).count()); + ASSERT_EQ(1, playlist_.collection_items(Song::Source::Collection, 1).count()); + EXPECT_EQ(song.title(), playlist_.collection_items(Song::Source::Collection, 1)[0]->Metadata().title()); // clazy:exclude=detaching-temporary playlist_.Clear(); - EXPECT_EQ(0, playlist_.collection_items_by_id(1).count()); + EXPECT_EQ(0, playlist_.collection_items(Song::Source::Collection, 1).count()); } @@ -504,20 +504,20 @@ TEST_F(PlaylistTest, CollectionIdMapInvalid) { PlaylistItemPtr item(std::make_shared(invalid)); playlist_.InsertItems(PlaylistItemPtrList() << item); - EXPECT_EQ(0, playlist_.collection_items_by_id(-1).count()); - EXPECT_EQ(0, playlist_.collection_items_by_id(0).count()); - EXPECT_EQ(0, playlist_.collection_items_by_id(1).count()); - EXPECT_EQ(0, playlist_.collection_items_by_id(2).count()); + EXPECT_EQ(0, playlist_.collection_items(Song::Source::Collection, -1).count()); + EXPECT_EQ(0, playlist_.collection_items(Song::Source::Collection, 0).count()); + EXPECT_EQ(0, playlist_.collection_items(Song::Source::Collection, 1).count()); + EXPECT_EQ(0, playlist_.collection_items(Song::Source::Collection, 2).count()); } TEST_F(PlaylistTest, CollectionIdMapMulti) { - Song one; + Song one(Song::Source::Collection); one.Init(u"title"_s, u"artist"_s, u"album"_s, 123); one.set_id(1); - Song two; + Song two(Song::Source::Collection); two.Init(u"title 2"_s, u"artist 2"_s, u"album 2"_s, 123); two.set_id(2); @@ -526,20 +526,20 @@ TEST_F(PlaylistTest, CollectionIdMapMulti) { PlaylistItemPtr item_three(std::make_shared(one)); playlist_.InsertItems(PlaylistItemPtrList() << item_one << item_two << item_three); - EXPECT_EQ(2, playlist_.collection_items_by_id(1).count()); - EXPECT_EQ(1, playlist_.collection_items_by_id(2).count()); + EXPECT_EQ(2, playlist_.collection_items(Song::Source::Collection, 1).count()); + EXPECT_EQ(1, playlist_.collection_items(Song::Source::Collection, 2).count()); playlist_.removeRow(1); // item_two - EXPECT_EQ(2, playlist_.collection_items_by_id(1).count()); - EXPECT_EQ(0, playlist_.collection_items_by_id(2).count()); + EXPECT_EQ(2, playlist_.collection_items(Song::Source::Collection, 1).count()); + EXPECT_EQ(0, playlist_.collection_items(Song::Source::Collection, 2).count()); playlist_.removeRow(1); // item_three - EXPECT_EQ(1, playlist_.collection_items_by_id(1).count()); - EXPECT_EQ(0, playlist_.collection_items_by_id(2).count()); + EXPECT_EQ(1, playlist_.collection_items(Song::Source::Collection, 1).count()); + EXPECT_EQ(0, playlist_.collection_items(Song::Source::Collection, 2).count()); playlist_.removeRow(0); // item_one - EXPECT_EQ(0, playlist_.collection_items_by_id(1).count()); - EXPECT_EQ(0, playlist_.collection_items_by_id(2).count()); + EXPECT_EQ(0, playlist_.collection_items(Song::Source::Collection, 1).count()); + EXPECT_EQ(0, playlist_.collection_items(Song::Source::Collection, 2).count()); }