strawberry-audio-player-win.../src/playlist/playlistmanager.cpp

657 lines
19 KiB
C++
Raw Normal View History

2018-02-27 18:06:05 +01:00
/*
* Strawberry Music Player
* This file was part of Clementine.
* Copyright 2010, David Sansome <me@davidsansome.com>
2021-03-20 21:14:47 +01:00
* Copyright 2018-2021, Jonas Kvinge <jonas@jkvinge.net>
2018-02-27 18:06:05 +01:00
*
* 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 <http://www.gnu.org/licenses/>.
2018-08-09 18:39:44 +02:00
*
2018-02-27 18:06:05 +01:00
*/
#include "config.h"
#include <functional>
#include <utility>
#include <QtGlobal>
#include <QObject>
#include <QDialog>
#include <QtConcurrent>
#include <QFuture>
2021-01-30 21:53:53 +01:00
#include <QFutureWatcher>
#include <QDir>
2018-02-27 18:06:05 +01:00
#include <QFileDialog>
#include <QFileInfo>
#include <QList>
#include <QSet>
#include <QString>
#include <QRegularExpression>
#include <QUrl>
#include <QAbstractItemModel>
#include <QScrollBar>
#include <QSettings>
#include <QMessageBox>
2018-02-27 18:06:05 +01:00
#include "core/application.h"
#include "core/player.h"
#include "utilities/filenameconstants.h"
#include "utilities/timeutils.h"
2018-02-27 18:06:05 +01:00
#include "collection/collectionbackend.h"
#include "covermanager/currentalbumcoverloader.h"
#include "settings/playlistsettingspage.h"
#include "playlist.h"
#include "playlistbackend.h"
#include "playlistcontainer.h"
#include "playlistmanager.h"
#include "playlistitem.h"
#include "playlistview.h"
#include "playlistsaveoptionsdialog.h"
2018-02-27 18:06:05 +01:00
#include "playlistparsers/playlistparser.h"
2022-07-20 01:09:00 +02:00
#include "dialogs/saveplaylistsdialog.h"
2018-02-27 18:06:05 +01:00
class ParserBase;
2018-02-27 18:06:05 +01:00
PlaylistManager::PlaylistManager(Application *app, QObject *parent)
: PlaylistManagerInterface(app, parent),
app_(app),
playlist_backend_(nullptr),
collection_backend_(nullptr),
sequence_(nullptr),
parser_(nullptr),
playlist_container_(nullptr),
current_(-1),
2019-05-02 11:31:31 +02:00
active_(-1),
2021-01-26 16:48:04 +01:00
playlists_loading_(0) {
QObject::connect(app_->player(), &Player::Paused, this, &PlaylistManager::SetActivePaused);
QObject::connect(app_->player(), &Player::Playing, this, &PlaylistManager::SetActivePlaying);
QObject::connect(app_->player(), &Player::Stopped, this, &PlaylistManager::SetActiveStopped);
2018-02-27 18:06:05 +01:00
}
PlaylistManager::~PlaylistManager() {
2021-03-21 04:47:11 +01:00
QList<Data> datas = playlists_.values();
for (const Data &data : datas) delete data.p;
2018-02-27 18:06:05 +01:00
}
void PlaylistManager::Init(CollectionBackend *collection_backend, PlaylistBackend *playlist_backend, PlaylistSequence *sequence, PlaylistContainer *playlist_container) {
collection_backend_ = collection_backend;
playlist_backend_ = playlist_backend;
sequence_ = sequence;
parser_ = new PlaylistParser(collection_backend, this);
playlist_container_ = playlist_container;
2021-01-26 16:48:04 +01:00
QObject::connect(collection_backend_, &CollectionBackend::SongsDiscovered, this, &PlaylistManager::SongsDiscovered);
QObject::connect(collection_backend_, &CollectionBackend::SongsStatisticsChanged, this, &PlaylistManager::SongsDiscovered);
QObject::connect(collection_backend_, &CollectionBackend::SongsRatingChanged, this, &PlaylistManager::SongsDiscovered);
2018-02-27 18:06:05 +01:00
for (const PlaylistBackend::Playlist &p : playlist_backend->GetAllOpenPlaylists()) {
2020-08-23 19:17:50 +02:00
++playlists_loading_;
2019-05-02 11:31:31 +02:00
Playlist *ret = AddPlaylist(p.id, p.name, p.special_type, p.ui_path, p.favorite);
2021-01-26 16:48:04 +01:00
QObject::connect(ret, &Playlist::PlaylistLoaded, this, &PlaylistManager::PlaylistLoaded);
2018-02-27 18:06:05 +01:00
}
// If no playlist exists then make a new one
if (playlists_.isEmpty()) New(tr("Playlist"));
emit PlaylistManagerInitialized();
}
2019-05-02 11:31:31 +02:00
void PlaylistManager::PlaylistLoaded() {
Playlist *playlist = qobject_cast<Playlist*>(sender());
if (!playlist) return;
2021-01-26 16:48:04 +01:00
QObject::disconnect(playlist, &Playlist::PlaylistLoaded, this, &PlaylistManager::PlaylistLoaded);
2020-08-23 19:17:50 +02:00
--playlists_loading_;
if (playlists_loading_ == 0) {
emit AllPlaylistsLoaded();
}
2019-05-02 11:31:31 +02:00
}
2018-02-27 18:06:05 +01:00
QList<Playlist*> PlaylistManager::GetAllPlaylists() const {
QList<Playlist*> result;
2021-03-21 04:47:11 +01:00
QList<Data> datas = playlists_.values();
2021-06-20 19:04:08 +02:00
result.reserve(datas.count());
2021-03-21 04:47:11 +01:00
for (const Data &data : datas) {
2018-02-27 18:06:05 +01:00
result.append(data.p);
}
return result;
}
2020-09-10 22:05:12 +02:00
QItemSelection PlaylistManager::selection(const int id) const {
2018-02-27 18:06:05 +01:00
QMap<int, Data>::const_iterator it = playlists_.find(id);
return it->selection;
}
2020-08-23 19:17:50 +02:00
Playlist *PlaylistManager::AddPlaylist(const int id, const QString &name, const QString &special_type, const QString &ui_path, const bool favorite) {
2018-02-27 18:06:05 +01:00
Playlist *ret = new Playlist(playlist_backend_, app_->task_manager(), collection_backend_, id, special_type, favorite);
ret->set_sequence(sequence_);
ret->set_ui_path(ui_path);
2021-01-26 16:48:04 +01:00
QObject::connect(ret, &Playlist::CurrentSongChanged, this, &PlaylistManager::CurrentSongChanged);
QObject::connect(ret, &Playlist::SongMetadataChanged, this, &PlaylistManager::SongMetadataChanged);
QObject::connect(ret, &Playlist::PlaylistChanged, this, &PlaylistManager::OneOfPlaylistsChanged);
QObject::connect(ret, &Playlist::PlaylistChanged, this, &PlaylistManager::UpdateSummaryText);
QObject::connect(ret, &Playlist::EditingFinished, this, &PlaylistManager::EditingFinished);
QObject::connect(ret, &Playlist::Error, this, &PlaylistManager::Error);
QObject::connect(ret, &Playlist::PlayRequested, this, &PlaylistManager::PlayRequested);
QObject::connect(playlist_container_->view(), &PlaylistView::ColumnAlignmentChanged, ret, &Playlist::SetColumnAlignment);
QObject::connect(app_->current_albumcover_loader(), &CurrentAlbumCoverLoader::AlbumCoverLoaded, ret, &Playlist::AlbumCoverLoaded);
2018-02-27 18:06:05 +01:00
playlists_[id] = Data(ret, name);
emit PlaylistAdded(id, name, favorite);
if (current_ == -1) {
SetCurrentPlaylist(id);
}
if (active_ == -1) {
SetActivePlaylist(id);
}
return ret;
}
void PlaylistManager::New(const QString &name, const SongList &songs, const QString &special_type) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
if (name.isNull()) return;
int id = playlist_backend_->CreatePlaylist(name, special_type);
if (id == -1) qFatal("Couldn't create playlist");
Playlist *playlist = AddPlaylist(id, name, special_type, QString(), false);
playlist->InsertSongsOrCollectionItems(songs);
SetCurrentPlaylist(id);
// If the name is just "Playlist", append the id
if (name == tr("Playlist")) {
Rename(id, QString("%1 %2").arg(name).arg(id));
}
}
void PlaylistManager::Load(const QString &filename) {
2018-10-02 00:38:52 +02:00
QFileInfo fileinfo(filename);
2018-02-27 18:06:05 +01:00
int id = playlist_backend_->CreatePlaylist(fileinfo.completeBaseName(), QString());
2018-02-27 18:06:05 +01:00
if (id == -1) {
emit Error(tr("Couldn't create playlist"));
return;
}
Playlist *playlist = AddPlaylist(id, fileinfo.completeBaseName(), QString(), QString(), false);
2018-02-27 18:06:05 +01:00
2021-02-06 00:32:01 +01:00
playlist->InsertUrls(QList<QUrl>() << QUrl::fromLocalFile(filename));
2018-02-27 18:06:05 +01:00
}
void PlaylistManager::Save(const int id, const QString &filename, const PlaylistSettingsPage::PathType path_type) {
2018-02-27 18:06:05 +01:00
if (playlists_.contains(id)) {
parser_->Save(playlist(id)->GetAllSongs(), filename, path_type);
}
else {
2022-08-28 02:44:37 +02:00
// Playlist is not in the playlist manager: probably save action was triggered from the left sidebar and the playlist isn't loaded.
2020-11-14 02:13:22 +01:00
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
2021-01-30 21:53:53 +01:00
QFuture<SongList> future = QtConcurrent::run(&PlaylistBackend::GetPlaylistSongs, playlist_backend_, id);
2020-11-14 02:13:22 +01:00
#else
2021-01-30 21:53:53 +01:00
QFuture<SongList> future = QtConcurrent::run(playlist_backend_, &PlaylistBackend::GetPlaylistSongs, id);
2020-11-14 02:13:22 +01:00
#endif
2021-01-30 21:53:53 +01:00
QFutureWatcher<SongList> *watcher = new QFutureWatcher<SongList>();
QObject::connect(watcher, &QFutureWatcher<SongList>::finished, this, [this, watcher, filename, path_type]() {
ItemsLoadedForSavePlaylist(watcher->result(), filename, path_type);
watcher->deleteLater();
});
watcher->setFuture(future);
2018-02-27 18:06:05 +01:00
}
}
void PlaylistManager::ItemsLoadedForSavePlaylist(const SongList &songs, const QString &filename, const PlaylistSettingsPage::PathType path_type) {
2020-07-19 19:07:12 +02:00
2021-01-30 21:53:53 +01:00
parser_->Save(songs, filename, path_type);
2020-07-19 19:07:12 +02:00
}
2020-08-23 19:17:50 +02:00
void PlaylistManager::SaveWithUI(const int id, const QString &playlist_name) {
2018-02-27 18:06:05 +01:00
QSettings s;
s.beginGroup(Playlist::kSettingsGroup);
QString last_save_filter = s.value("last_save_filter", parser()->default_filter()).toString();
QString last_save_path = s.value("last_save_path", QDir::homePath()).toString();
QString last_save_extension = s.value("last_save_extension", parser()->default_extension()).toString();
s.endGroup();
2018-02-27 18:06:05 +01:00
QString suggested_filename = playlist_name;
QString filename = last_save_path + "/" + suggested_filename.remove(QRegularExpression(QString(kProblematicCharactersRegex), QRegularExpression::CaseInsensitiveOption)) + "." + last_save_extension;
2018-02-27 18:06:05 +01:00
QFileInfo fileinfo;
2018-02-27 18:06:05 +01:00
forever {
2023-02-18 14:09:27 +01:00
filename = QFileDialog::getSaveFileName(nullptr, tr("Save playlist", "Title of the playlist save dialog."), filename, parser()->filters(PlaylistParser::Type::Save), &last_save_filter);
if (filename.isEmpty()) return;
fileinfo.setFile(filename);
2023-02-18 14:09:27 +01:00
ParserBase *parser = parser_->ParserForExtension(PlaylistParser::Type::Save, fileinfo.suffix());
if (parser) break;
QMessageBox::warning(nullptr, tr("Unknown playlist extension"), tr("Unknown file extension for playlist."));
2018-02-27 18:06:05 +01:00
}
s.beginGroup(PlaylistSettingsPage::kSettingsGroup);
2023-02-18 14:09:27 +01:00
PlaylistSettingsPage::PathType path_type = static_cast<PlaylistSettingsPage::PathType>(s.value("path_type", static_cast<int>(PlaylistSettingsPage::PathType::Automatic)).toInt());
s.endGroup();
2023-02-18 14:09:27 +01:00
if (path_type == PlaylistSettingsPage::PathType::Ask_User) {
2022-07-20 01:09:00 +02:00
PlaylistSaveOptionsDialog optionsdialog;
optionsdialog.setModal(true);
if (optionsdialog.exec() != QDialog::Accepted) return;
path_type = optionsdialog.path_type();
2018-02-27 18:06:05 +01:00
}
s.beginGroup(Playlist::kSettingsGroup);
s.setValue("last_save_filter", last_save_filter);
s.setValue("last_save_path", fileinfo.path());
s.setValue("last_save_extension", fileinfo.suffix());
s.endGroup();
2018-02-27 18:06:05 +01:00
Save(id == -1 ? current_id() : id, filename, path_type);
2018-02-27 18:06:05 +01:00
}
2020-08-23 19:17:50 +02:00
void PlaylistManager::Rename(const int id, const QString &new_name) {
2018-02-27 18:06:05 +01:00
Q_ASSERT(playlists_.contains(id));
playlist_backend_->RenamePlaylist(id, new_name);
playlists_[id].name = new_name;
emit PlaylistRenamed(id, new_name);
}
2020-08-23 19:17:50 +02:00
void PlaylistManager::Favorite(const int id, const bool favorite) {
2018-02-27 18:06:05 +01:00
if (playlists_.contains(id)) {
// If playlists_ contains this playlist, its means it's opened: star or unstar it.
2018-02-27 18:06:05 +01:00
playlist_backend_->FavoritePlaylist(id, favorite);
playlists_[id].p->set_favorite(favorite);
}
else {
Q_ASSERT(!favorite);
// Otherwise it means user wants to remove this playlist from the left panel,
// while it's not visible in the playlist tabbar either, because it has been closed: delete it.
2018-02-27 18:06:05 +01:00
playlist_backend_->RemovePlaylist(id);
}
emit PlaylistFavorited(id, favorite);
}
2020-08-23 19:17:50 +02:00
bool PlaylistManager::Close(const int id) {
2018-02-27 18:06:05 +01:00
// Won't allow removing the last playlist
if (playlists_.count() <= 1 || !playlists_.contains(id)) return false;
int next_id = -1;
2021-03-21 04:47:11 +01:00
QList<int> playlist_ids = playlists_.keys();
for (const int possible_next_id : playlist_ids) {
2018-02-27 18:06:05 +01:00
if (possible_next_id != id) {
next_id = possible_next_id;
break;
}
}
if (next_id == -1) return false;
if (id == active_) SetActivePlaylist(next_id);
if (id == current_) SetCurrentPlaylist(next_id);
Data data = playlists_.take(id);
emit PlaylistClosed(id);
if (!data.p->is_favorite()) {
playlist_backend_->RemovePlaylist(id);
emit PlaylistDeleted(id);
}
delete data.p;
return true;
}
2020-08-23 19:17:50 +02:00
void PlaylistManager::Delete(const int id) {
2018-02-27 18:06:05 +01:00
if (!Close(id)) {
return;
}
playlist_backend_->RemovePlaylist(id);
emit PlaylistDeleted(id);
}
void PlaylistManager::OneOfPlaylistsChanged() {
emit PlaylistChanged(qobject_cast<Playlist*>(sender()));
}
2020-08-23 19:17:50 +02:00
void PlaylistManager::SetCurrentPlaylist(const int id) {
2018-02-27 18:06:05 +01:00
Q_ASSERT(playlists_.contains(id));
// Save the scroll position for the current playlist.
if (playlists_.contains(current_)) {
playlists_[current_].scroll_position = playlist_container_->view()->verticalScrollBar()->value();
}
2018-02-27 18:06:05 +01:00
current_ = id;
emit CurrentChanged(current(), playlists_[id].scroll_position);
2018-02-27 18:06:05 +01:00
UpdateSummaryText();
}
2020-08-23 19:17:50 +02:00
void PlaylistManager::SetActivePlaylist(const int id) {
2018-02-27 18:06:05 +01:00
Q_ASSERT(playlists_.contains(id));
2019-05-02 11:31:31 +02:00
// Kinda a hack: unset the current item from the old active playlist before setting the new one
2018-02-27 18:06:05 +01:00
if (active_ != -1 && active_ != id) active()->set_current_row(-1);
active_ = id;
2018-02-27 18:06:05 +01:00
emit ActiveChanged(active());
sequence_->set_dynamic(active()->is_dynamic());
2018-02-27 18:06:05 +01:00
}
void PlaylistManager::SetActiveToCurrent() {
// Check if we need to update the active playlist.
// By calling SetActiveToCurrent, the playlist manager emits the signal "ActiveChanged".
2019-08-22 18:45:32 +02:00
// This signal causes the network remote module to send all playlists to the clients, even if no change happen.
2018-02-27 18:06:05 +01:00
if (current_id() != active_id()) {
SetActivePlaylist(current_id());
}
}
void PlaylistManager::ClearCurrent() {
current()->Clear();
}
void PlaylistManager::ShuffleCurrent() {
current()->Shuffle();
}
void PlaylistManager::RemoveDuplicatesCurrent() {
current()->RemoveDuplicateSongs();
}
void PlaylistManager::RemoveUnavailableCurrent() {
current()->RemoveUnavailableSongs();
}
void PlaylistManager::SetActivePlaying() { active()->Playing(); }
void PlaylistManager::SetActivePaused() { active()->Paused(); }
void PlaylistManager::SetActiveStopped() { active()->Stopped(); }
void PlaylistManager::ChangePlaylistOrder(const QList<int> &ids) {
playlist_backend_->SetPlaylistOrder(ids);
}
void PlaylistManager::UpdateSummaryText() {
int tracks = current()->rowCount();
quint64 nanoseconds = 0;
int selected = 0;
// Get the length of the selected tracks
for (const QItemSelectionRange &range : playlists_[current_id()].selection) {
if (!range.isValid()) continue;
selected += range.bottom() - range.top() + 1;
2021-08-23 21:21:08 +02:00
for (int i = range.top(); i <= range.bottom(); ++i) {
2018-02-27 18:06:05 +01:00
qint64 length = range.model()->index(i, Playlist::Column_Length).data().toLongLong();
2021-08-23 21:21:08 +02:00
if (length > 0) {
2018-02-27 18:06:05 +01:00
nanoseconds += length;
2021-08-23 21:21:08 +02:00
}
2018-02-27 18:06:05 +01:00
}
}
QString summary;
if (selected > 1) {
summary += tr("%1 selected of").arg(selected) + " ";
}
else {
2018-02-27 18:06:05 +01:00
nanoseconds = current()->GetTotalLength();
}
// TODO: Make the plurals translatable
summary += tracks == 1 ? tr("1 track") : tr("%1 tracks").arg(tracks);
2021-06-22 13:54:58 +02:00
if (nanoseconds > 0) {
2018-02-27 18:06:05 +01:00
summary += " - [ " + Utilities::WordyTimeNanosec(nanoseconds) + " ]";
2021-06-22 13:54:58 +02:00
}
2018-02-27 18:06:05 +01:00
emit SummaryTextChanged(summary);
}
void PlaylistManager::SelectionChanged(const QItemSelection &selection) {
playlists_[current_id()].selection = selection;
UpdateSummaryText();
}
void PlaylistManager::SongsDiscovered(const SongList &songs) {
2018-03-10 13:02:56 +01:00
// Some songs might've changed in the collection, let's update any playlist items we have that match those songs
2018-02-27 18:06:05 +01:00
for (const Song &song : songs) {
for (const Data &data : std::as_const(playlists_)) {
2023-02-18 14:09:27 +01:00
PlaylistItemPtrList items = data.p->collection_items_by_id(song.id());
for (PlaylistItemPtr item : items) {
2018-02-27 18:06:05 +01:00
if (item->Metadata().directory_id() != song.directory_id()) continue;
item->SetMetadata(song);
if (item->HasTemporaryMetadata()) item->UpdateTemporaryMetadata(song);
2018-02-27 18:06:05 +01:00
data.p->ItemChanged(item);
}
}
}
}
// When Player has processed the new song chosen by the user...
2020-08-23 19:17:50 +02:00
void PlaylistManager::SongChangeRequestProcessed(const QUrl &url, const bool valid) {
2018-02-27 18:06:05 +01:00
for (Playlist *playlist : GetAllPlaylists()) {
if (playlist->ApplyValidityOnCurrentSong(url, valid)) {
return;
}
}
}
2020-08-23 19:17:50 +02:00
void PlaylistManager::InsertUrls(const int id, const QList<QUrl> &urls, const int pos, const bool play_now, const bool enqueue) {
2018-02-27 18:06:05 +01:00
Q_ASSERT(playlists_.contains(id));
playlists_[id].p->InsertUrls(urls, pos, play_now, enqueue);
}
2020-08-23 19:17:50 +02:00
void PlaylistManager::InsertSongs(const int id, const SongList &songs, const int pos, const bool play_now, const bool enqueue) {
2018-02-27 18:06:05 +01:00
Q_ASSERT(playlists_.contains(id));
playlists_[id].p->InsertSongs(songs, pos, play_now, enqueue);
}
2020-08-23 19:17:50 +02:00
void PlaylistManager::RemoveItemsWithoutUndo(const int id, const QList<int> &indices) {
2018-02-27 18:06:05 +01:00
Q_ASSERT(playlists_.contains(id));
playlists_[id].p->RemoveItemsWithoutUndo(indices);
}
2021-06-22 13:45:29 +02:00
void PlaylistManager::RemoveCurrentSong() const {
2018-02-27 18:06:05 +01:00
active()->removeRows(active()->current_index().row(), 1);
}
void PlaylistManager::InvalidateDeletedSongs() {
for (Playlist *playlist : GetAllPlaylists()) {
playlist->InvalidateDeletedSongs();
}
}
void PlaylistManager::RemoveDeletedSongs() {
for (Playlist *playlist : GetAllPlaylists()) {
playlist->RemoveDeletedSongs();
}
}
QString PlaylistManager::GetNameForNewPlaylist(const SongList &songs) {
if (songs.isEmpty()) {
return tr("Playlist");
}
QSet<QString> artists;
QSet<QString> albums;
2021-06-20 19:04:08 +02:00
artists.reserve(songs.count());
albums.reserve(songs.count());
2018-02-27 18:06:05 +01:00
for (const Song &song : songs) {
artists << (song.artist().isEmpty() ? tr("Unknown") : song.artist());
albums << (song.album().isEmpty() ? tr("Unknown") : song.album());
if (artists.size() > 1) {
break;
}
}
bool various_artists = artists.size() > 1;
QString result;
if (various_artists) {
result = tr("Various artists");
}
else {
2021-03-21 04:47:11 +01:00
QStringList artist_names = artists.values();
result = artist_names.first();
2018-02-27 18:06:05 +01:00
}
if (!various_artists && albums.size() == 1) {
2021-03-21 04:47:11 +01:00
QStringList album_names = albums.values();
result += " - " + album_names.first();
2018-02-27 18:06:05 +01:00
}
return result;
}
2020-08-23 19:17:50 +02:00
void PlaylistManager::Open(const int id) {
2018-02-27 18:06:05 +01:00
if (playlists_.contains(id)) {
return;
}
const PlaylistBackend::Playlist &p = playlist_backend_->GetPlaylist(id);
if (p.id != id) {
return;
}
AddPlaylist(p.id, p.name, p.special_type, p.ui_path, p.favorite);
}
2020-08-23 19:17:50 +02:00
void PlaylistManager::SetCurrentOrOpen(const int id) {
2018-02-27 18:06:05 +01:00
Open(id);
SetCurrentPlaylist(id);
}
2020-08-23 19:17:50 +02:00
bool PlaylistManager::IsPlaylistOpen(const int id) {
2018-02-27 18:06:05 +01:00
return playlists_.contains(id);
}
void PlaylistManager::PlaySmartPlaylist(PlaylistGeneratorPtr generator, bool as_new, bool clear) {
if (as_new) {
New(generator->name());
}
if (clear) {
current()->Clear();
}
current()->InsertSmartPlaylist(generator);
}
2021-10-30 18:53:14 +02:00
void PlaylistManager::RateCurrentSong(const float rating) {
active()->RateSong(active()->current_index(), rating);
}
2021-10-30 18:53:14 +02:00
void PlaylistManager::RateCurrentSong2(const int rating) {
RateCurrentSong(static_cast<float>(rating) / 5.0F);
}
2022-07-20 01:09:00 +02:00
void PlaylistManager::SaveAllPlaylists() {
2023-02-18 14:09:27 +01:00
SavePlaylistsDialog dialog(parser()->file_extensions(PlaylistParser::Type::Save), parser()->default_extension());
2022-07-20 01:09:00 +02:00
if (dialog.exec() != QDialog::Accepted) {
return;
}
const QString path = dialog.path();
if (path.isEmpty() || !QDir().exists(path)) return;
QString extension = dialog.extension();
if (extension.isEmpty()) extension = parser()->default_extension();
QSettings s;
s.beginGroup(PlaylistSettingsPage::kSettingsGroup);
2023-02-18 14:09:27 +01:00
PlaylistSettingsPage::PathType path_type = static_cast<PlaylistSettingsPage::PathType>(s.value("path_type", static_cast<int>(PlaylistSettingsPage::PathType::Automatic)).toInt());
2022-07-20 01:09:00 +02:00
s.endGroup();
2023-02-18 14:09:27 +01:00
if (path_type == PlaylistSettingsPage::PathType::Ask_User) {
2022-07-20 01:09:00 +02:00
PlaylistSaveOptionsDialog optionsdialog;
optionsdialog.setModal(true);
if (optionsdialog.exec() != QDialog::Accepted) return;
path_type = optionsdialog.path_type();
}
for (QMap<int, Data>::const_iterator it = playlists_.constBegin(); it != playlists_.constEnd(); ++it) {
const Data &data = *it;
const QString filepath = path + "/" + data.name + "." + extension;
Save(it.key(), filepath, path_type);
}
}