From bf98633f16555f54d2f46e6889f91f0eee717568 Mon Sep 17 00:00:00 2001 From: Jonas Kvinge Date: Sat, 4 Jan 2025 04:52:17 +0100 Subject: [PATCH] Load XSPF title as playlist name --- src/collection/collectionwatcher.cpp | 4 ++-- src/core/songloader.cpp | 10 +++++++--- src/core/songloader.h | 2 ++ src/playlist/playlist.cpp | 7 ++++++- src/playlist/playlist.h | 4 +++- src/playlist/playlistbackend.cpp | 10 +++++----- src/playlist/playlistmanager.cpp | 3 ++- src/playlist/songloaderinserter.cpp | 22 ++++++++++++---------- src/playlist/songloaderinserter.h | 5 +++-- src/playlistparsers/asxiniparser.cpp | 2 +- src/playlistparsers/asxiniparser.h | 2 +- src/playlistparsers/asxparser.cpp | 2 +- src/playlistparsers/asxparser.h | 2 +- src/playlistparsers/cueparser.cpp | 2 +- src/playlistparsers/cueparser.h | 2 +- src/playlistparsers/m3uparser.cpp | 2 +- src/playlistparsers/m3uparser.h | 2 +- src/playlistparsers/parserbase.h | 9 ++++++++- src/playlistparsers/playlistparser.cpp | 4 ++-- src/playlistparsers/plsparser.cpp | 2 +- src/playlistparsers/plsparser.h | 2 +- src/playlistparsers/wplparser.cpp | 12 ++++++------ src/playlistparsers/wplparser.h | 2 +- src/playlistparsers/xspfparser.cpp | 24 +++++++++++++++++------- src/playlistparsers/xspfparser.h | 2 +- 25 files changed, 87 insertions(+), 53 deletions(-) diff --git a/src/collection/collectionwatcher.cpp b/src/collection/collectionwatcher.cpp index 719191571..037c36ef0 100644 --- a/src/collection/collectionwatcher.cpp +++ b/src/collection/collectionwatcher.cpp @@ -868,7 +868,7 @@ void CollectionWatcher::UpdateCueAssociatedSongs(const QString &file, qLog(Error) << "Could not open CUE file" << matching_cue << "for reading:" << cue_file.errorString(); return; } - const SongList songs = cue_parser_->Load(&cue_file, matching_cue, path, false); + const SongList songs = cue_parser_->Load(&cue_file, matching_cue, path, false).songs; cue_file.close(); // Update every song that's in the CUE and collection @@ -955,7 +955,7 @@ SongList CollectionWatcher::ScanNewFile(const QString &file, const QString &path // Also, watch out for incorrect media files. // Playlist parser for CUEs considers every entry in sheet valid, and we don't want invalid media getting into collection! QString file_nfd = file.normalized(QString::NormalizationForm_D); - SongList cue_songs = cue_parser_->Load(&cue_file, matching_cue, path, false); + SongList cue_songs = cue_parser_->Load(&cue_file, matching_cue, path, false).songs; cue_file.close(); songs.reserve(cue_songs.count()); for (Song &cue_song : cue_songs) { diff --git a/src/core/songloader.cpp b/src/core/songloader.cpp index 7f3c1566e..30b040b3b 100644 --- a/src/core/songloader.cpp +++ b/src/core/songloader.cpp @@ -281,7 +281,7 @@ SongLoader::Result SongLoader::LoadLocalAsync(const QString &filename) { // It's a CUE - create virtual tracks QFile cue(matching_cue); if (cue.open(QIODevice::ReadOnly)) { - const SongList songs = cue_parser_->Load(&cue, matching_cue, QDir(filename.section(u'/', 0, -2))); + const SongList songs = cue_parser_->Load(&cue, matching_cue, QDir(filename.section(u'/', 0, -2))).songs; cue.close(); for (const Song &song : songs) { if (song.is_valid()) songs_ << song; @@ -348,7 +348,9 @@ void SongLoader::LoadPlaylist(ParserBase *parser, const QString &filename) { QFile file(filename); if (file.open(QIODevice::ReadOnly)) { - songs_ = parser->Load(&file, filename, QFileInfo(filename).path()); + const ParserBase::LoadResult result = parser->Load(&file, filename, QFileInfo(filename).path()); + songs_ = result.songs; + playlist_name_ = result.playlist_name; file.close(); } else { @@ -424,7 +426,9 @@ void SongLoader::StopTypefind() { // Parse the playlist QBuffer buf(&buffer_); if (buf.open(QIODevice::ReadOnly)) { - songs_ = parser_->Load(&buf); + const ParserBase::LoadResult result = parser_->Load(&buf); + songs_ = result.songs; + playlist_name_ = result.playlist_name; buf.close(); } diff --git a/src/core/songloader.h b/src/core/songloader.h index 0666e6827..c4cf123d7 100644 --- a/src/core/songloader.h +++ b/src/core/songloader.h @@ -72,6 +72,7 @@ class SongLoader : public QObject { const QUrl &url() const { return url_; } const SongList &songs() const { return songs_; } + const QString &playlist_name() const { return playlist_name_; } int timeout() const { return timeout_; } void set_timeout(int msec) { timeout_ = msec; } @@ -141,6 +142,7 @@ class SongLoader : public QObject { QUrl url_; SongList songs_; + QString playlist_name_; const SharedPtr url_handlers_; const SharedPtr collection_backend_; diff --git a/src/playlist/playlist.cpp b/src/playlist/playlist.cpp index 9485c9690..9d049a645 100644 --- a/src/playlist/playlist.cpp +++ b/src/playlist/playlist.cpp @@ -1180,7 +1180,11 @@ void Playlist::InsertSongs(const SongList &songs, const int pos, const bool play InsertSongItems(songs, pos, play_now, enqueue, enqueue_next); } -void Playlist::InsertSongsOrCollectionItems(const SongList &songs, const int pos, const bool play_now, const bool enqueue, const bool enqueue_next) { +void Playlist::InsertSongsOrCollectionItems(const SongList &songs, const QString &playlist_name, const int pos, const bool play_now, const bool enqueue, const bool enqueue_next) { + + if (!playlist_name.isEmpty()) { + Q_EMIT Rename(id_, playlist_name); + } PlaylistItemPtrList items; for (const Song &song : songs) { @@ -1201,6 +1205,7 @@ void Playlist::InsertSongsOrCollectionItems(const SongList &songs, const int pos } } } + InsertItems(items, pos, play_now, enqueue, enqueue_next); } diff --git a/src/playlist/playlist.h b/src/playlist/playlist.h index 11d8fe5ea..017066926 100644 --- a/src/playlist/playlist.h +++ b/src/playlist/playlist.h @@ -226,7 +226,7 @@ class Playlist : public QAbstractListModel { void InsertItems(const PlaylistItemPtrList &itemsIn, const int pos = -1, const bool play_now = false, const bool enqueue = false, const bool enqueue_next = false); void InsertCollectionItems(const SongList &songs, const int pos = -1, const bool play_now = false, const bool enqueue = false, const bool enqueue_next = false); void InsertSongs(const SongList &songs, const int pos = -1, const bool play_now = false, const bool enqueue = false, const bool enqueue_next = false); - void InsertSongsOrCollectionItems(const SongList &songs, const int pos = -1, const bool play_now = false, const bool enqueue = false, const bool enqueue_next = false); + void InsertSongsOrCollectionItems(const SongList &songs, const QString &playlist_name = QString(), const int pos = -1, const bool play_now = false, const bool enqueue = false, const bool enqueue_next = false); void InsertSmartPlaylist(PlaylistGeneratorPtr gen, const int pos = -1, const bool play_now = false, const bool enqueue = false, const bool enqueue_next = false); void InsertStreamingItems(StreamingServicePtr service, const SongList &songs, const int pos = -1, const bool play_now = false, const bool enqueue = false, const bool enqueue_next = false); void InsertRadioItems(const SongList &songs, const int pos = -1, const bool play_now = false, const bool enqueue = false, const bool enqueue_next = false); @@ -327,6 +327,8 @@ class Playlist : public QAbstractListModel { // Signals that the queue has changed, meaning that the remaining queued items should update their position. void QueueChanged(); + void Rename(const int id, const QString &name); + private: void SetCurrentIsPaused(const bool paused); int NextVirtualIndex(int i, const bool ignore_repeat_track) const; diff --git a/src/playlist/playlistbackend.cpp b/src/playlist/playlistbackend.cpp index 5e3c715cc..a6e3d267a 100644 --- a/src/playlist/playlistbackend.cpp +++ b/src/playlist/playlistbackend.cpp @@ -298,7 +298,7 @@ PlaylistItemPtr PlaylistBackend::RestoreCueData(PlaylistItemPtr item, SharedPtr< return item; } - SongList song_list; + SongList songs; { QMutexLocker locker(&state->mutex_); @@ -306,16 +306,16 @@ PlaylistItemPtr PlaylistBackend::RestoreCueData(PlaylistItemPtr item, SharedPtr< QFile cue_file(cue_path); if (!cue_file.open(QIODevice::ReadOnly)) return item; - song_list = cue_parser.Load(&cue_file, cue_path, QDir(cue_path.section(u'/', 0, -2))); + songs = cue_parser.Load(&cue_file, cue_path, QDir(cue_path.section(u'/', 0, -2))).songs; cue_file.close(); - state->cached_cues_[cue_path] = song_list; + state->cached_cues_[cue_path] = songs; } else { - song_list = state->cached_cues_[cue_path]; + songs = state->cached_cues_[cue_path]; } } - for (const Song &from_list : std::as_const(song_list)) { + for (const Song &from_list : std::as_const(songs)) { if (from_list.url().toEncoded() == song.url().toEncoded() && from_list.beginning_nanosec() == song.beginning_nanosec()) { // We found a matching section; replace the input item with a new one containing CUE metadata return make_shared(from_list); diff --git a/src/playlist/playlistmanager.cpp b/src/playlist/playlistmanager.cpp index c210bfaff..45eed9091 100644 --- a/src/playlist/playlistmanager.cpp +++ b/src/playlist/playlistmanager.cpp @@ -166,6 +166,7 @@ Playlist *PlaylistManager::AddPlaylist(const int id, const QString &name, const 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(ret, &Playlist::Rename, this, &PlaylistManager::Rename); QObject::connect(playlist_container_->view(), &PlaylistView::ColumnAlignmentChanged, ret, &Playlist::SetColumnAlignment); QObject::connect(&*current_albumcover_loader_, &CurrentAlbumCoverLoader::AlbumCoverLoaded, ret, &Playlist::AlbumCoverLoaded); @@ -208,7 +209,7 @@ void PlaylistManager::Load(const QString &filename) { QFileInfo fileinfo(filename); - int id = playlist_backend_->CreatePlaylist(fileinfo.completeBaseName(), QString()); + const int id = playlist_backend_->CreatePlaylist(fileinfo.completeBaseName(), QString()); if (id == -1) { Q_EMIT Error(tr("Couldn't create playlist")); diff --git a/src/playlist/songloaderinserter.cpp b/src/playlist/songloaderinserter.cpp index 005944f6f..d3b163efd 100644 --- a/src/playlist/songloaderinserter.cpp +++ b/src/playlist/songloaderinserter.cpp @@ -54,7 +54,7 @@ SongLoaderInserter::SongLoaderInserter(const SharedPtr task_manager SongLoaderInserter::~SongLoaderInserter() { qDeleteAll(pending_); } -void SongLoaderInserter::Load(Playlist *destination, int row, bool play_now, bool enqueue, bool enqueue_next, const QList &urls) { +void SongLoaderInserter::Load(Playlist *destination, const int row, const bool play_now, const bool enqueue, const bool enqueue_next, const QList &urls) { destination_ = destination; row_ = row; @@ -69,15 +69,16 @@ void SongLoaderInserter::Load(Playlist *destination, int row, bool play_now, boo for (const QUrl &url : urls) { SongLoader *loader = new SongLoader(url_handlers_, collection_backend_, tagreader_client_, this); - SongLoader::Result ret = loader->Load(url); + const SongLoader::Result result = loader->Load(url); - if (ret == SongLoader::Result::BlockingLoadRequired) { + if (result == SongLoader::Result::BlockingLoadRequired) { pending_.append(loader); continue; } - if (ret == SongLoader::Result::Success) { + if (result == SongLoader::Result::Success) { songs_ << loader->songs(); + playlist_name_ = loader->playlist_name(); } else { const QStringList errors = loader->errors(); @@ -101,7 +102,7 @@ void SongLoaderInserter::Load(Playlist *destination, int row, bool play_now, boo // First, we add tracks (without metadata) into the playlist // In the meantime, MusicBrainz will be queried to get songs' metadata. // AudioCDTagsLoaded will be called next, and playlist's items will be updated. -void SongLoaderInserter::LoadAudioCD(Playlist *destination, int row, bool play_now, bool enqueue, bool enqueue_next) { +void SongLoaderInserter::LoadAudioCD(Playlist *destination, const int row, const bool play_now, const bool enqueue, const bool enqueue_next) { destination_ = destination; row_ = row; @@ -113,8 +114,8 @@ void SongLoaderInserter::LoadAudioCD(Playlist *destination, int row, bool play_n QObject::connect(loader, &SongLoader::AudioCDTracksLoadFinished, this, [this, loader]() { AudioCDTracksLoadFinished(loader); }); QObject::connect(loader, &SongLoader::LoadAudioCDFinished, this, &SongLoaderInserter::AudioCDTagsLoaded); qLog(Info) << "Loading audio CD..."; - SongLoader::Result ret = loader->LoadAudioCD(); - if (ret == SongLoader::Result::Error) { + const SongLoader::Result result = loader->LoadAudioCD(); + if (result == SongLoader::Result::Error) { if (loader->errors().isEmpty()) Q_EMIT Error(tr("Error while loading audio CD.")); else { @@ -166,7 +167,7 @@ void SongLoaderInserter::InsertSongs() { // Insert songs (that haven't been completely loaded) to allow user to see and play them while not loaded completely if (destination_) { - destination_->InsertSongsOrCollectionItems(songs_, row_, play_now_, enqueue_, enqueue_next_); + destination_->InsertSongsOrCollectionItems(songs_, playlist_name_, row_, play_now_, enqueue_, enqueue_next_); } } @@ -180,10 +181,10 @@ void SongLoaderInserter::AsyncLoad() { bool first_loaded = false; for (int i = 0; i < pending_.count(); ++i) { SongLoader *loader = pending_.value(i); - SongLoader::Result res = loader->LoadFilenamesBlocking(); + const SongLoader::Result result = loader->LoadFilenamesBlocking(); task_manager_->SetTaskProgress(async_load_id, ++async_progress); - if (res == SongLoader::Result::Error) { + if (result == SongLoader::Result::Error) { const QStringList errors = loader->errors(); for (const QString &error : errors) { Q_EMIT Error(error); @@ -199,6 +200,7 @@ void SongLoaderInserter::AsyncLoad() { } songs_ << loader->songs(); + playlist_name_ = loader->playlist_name(); } task_manager_->SetTaskFinished(async_load_id); diff --git a/src/playlist/songloaderinserter.h b/src/playlist/songloaderinserter.h index e94dc488e..3f04b3c1b 100644 --- a/src/playlist/songloaderinserter.h +++ b/src/playlist/songloaderinserter.h @@ -52,8 +52,8 @@ class SongLoaderInserter : public QObject { ~SongLoaderInserter() override; - void Load(Playlist *destination, int row, bool play_now, bool enqueue, bool enqueue_next, const QList &urls); - void LoadAudioCD(Playlist *destination, int row, bool play_now, bool enqueue, bool enqueue_next); + void Load(Playlist *destination, const int row, const bool play_now, const bool enqueue, const bool enqueue_next, const QList &urls); + void LoadAudioCD(Playlist *destination, const int row, const bool play_now, const bool enqueue, const bool enqueue_next); Q_SIGNALS: void Error(const QString &message); @@ -82,6 +82,7 @@ class SongLoaderInserter : public QObject { bool enqueue_next_; SongList songs_; + QString playlist_name_; QList pending_; }; diff --git a/src/playlistparsers/asxiniparser.cpp b/src/playlistparsers/asxiniparser.cpp index 83a5770fe..ddfe01663 100644 --- a/src/playlistparsers/asxiniparser.cpp +++ b/src/playlistparsers/asxiniparser.cpp @@ -42,7 +42,7 @@ bool AsxIniParser::TryMagic(const QByteArray &data) const { return data.toLower().contains("[reference]"); } -SongList AsxIniParser::Load(QIODevice *device, const QString &playlist_path, const QDir &dir, const bool collection_lookup) const { +ParserBase::LoadResult AsxIniParser::Load(QIODevice *device, const QString &playlist_path, const QDir &dir, const bool collection_lookup) const { Q_UNUSED(playlist_path); diff --git a/src/playlistparsers/asxiniparser.h b/src/playlistparsers/asxiniparser.h index 4d7d18d09..943cfe638 100644 --- a/src/playlistparsers/asxiniparser.h +++ b/src/playlistparsers/asxiniparser.h @@ -51,7 +51,7 @@ class AsxIniParser : public ParserBase { bool TryMagic(const QByteArray &data) const override; - SongList Load(QIODevice *device, const QString &playlist_path = QLatin1String(""), const QDir &dir = QDir(), const bool collection_lookup = true) const override; + LoadResult Load(QIODevice *device, const QString &playlist_path = QLatin1String(""), const QDir &dir = QDir(), const bool collection_lookup = true) const override; void Save(const QString &playlist_name, const SongList &songs, QIODevice *device, const QDir &dir = QDir(), const PlaylistSettings::PathType path_type = PlaylistSettings::PathType::Automatic) const override; }; diff --git a/src/playlistparsers/asxparser.cpp b/src/playlistparsers/asxparser.cpp index 65e38df07..8a83e17b7 100644 --- a/src/playlistparsers/asxparser.cpp +++ b/src/playlistparsers/asxparser.cpp @@ -42,7 +42,7 @@ class CollectionBackendInterface; ASXParser::ASXParser(const SharedPtr tagreader_client, const SharedPtr collection_backend, QObject *parent) : XMLParser(tagreader_client, collection_backend, parent) {} -SongList ASXParser::Load(QIODevice *device, const QString &playlist_path, const QDir &dir, const bool collection_lookup) const { +ParserBase::LoadResult ASXParser::Load(QIODevice *device, const QString &playlist_path, const QDir &dir, const bool collection_lookup) const { Q_UNUSED(playlist_path); diff --git a/src/playlistparsers/asxparser.h b/src/playlistparsers/asxparser.h index b5532efe1..d5195fe7e 100644 --- a/src/playlistparsers/asxparser.h +++ b/src/playlistparsers/asxparser.h @@ -53,7 +53,7 @@ class ASXParser : public XMLParser { bool TryMagic(const QByteArray &data) const override; - SongList Load(QIODevice *device, const QString &playlist_path = QLatin1String(""), const QDir &dir = QDir(), const bool collection_lookup = true) const override; + LoadResult Load(QIODevice *device, const QString &playlist_path = QLatin1String(""), const QDir &dir = QDir(), const bool collection_lookup = true) const override; void Save(const QString &playlist_name, const SongList &songs, QIODevice *device, const QDir &dir = QDir(), const PlaylistSettings::PathType path_type = PlaylistSettings::PathType::Automatic) const override; private: diff --git a/src/playlistparsers/cueparser.cpp b/src/playlistparsers/cueparser.cpp index d86770b63..6168523e4 100644 --- a/src/playlistparsers/cueparser.cpp +++ b/src/playlistparsers/cueparser.cpp @@ -66,7 +66,7 @@ constexpr char kDisc[] = "discnumber"; CueParser::CueParser(const SharedPtr tagreader_client, const SharedPtr collection_backend, QObject *parent) : ParserBase(tagreader_client, collection_backend, parent) {} -SongList CueParser::Load(QIODevice *device, const QString &playlist_path, const QDir &dir, const bool collection_lookup) const { +ParserBase::LoadResult CueParser::Load(QIODevice *device, const QString &playlist_path, const QDir &dir, const bool collection_lookup) const { SongList ret; diff --git a/src/playlistparsers/cueparser.h b/src/playlistparsers/cueparser.h index a86dd10a5..69444d083 100644 --- a/src/playlistparsers/cueparser.h +++ b/src/playlistparsers/cueparser.h @@ -56,7 +56,7 @@ class CueParser : public ParserBase { bool TryMagic(const QByteArray &data) const override; - SongList Load(QIODevice *device, const QString &playlist_path = QLatin1String(""), const QDir &dir = QDir(), const bool collection_lookup = true) const override; + LoadResult Load(QIODevice *device, const QString &playlist_path = QLatin1String(""), const QDir &dir = QDir(), const bool collection_lookup = true) const override; void Save(const QString &playlist_name, const SongList &songs, QIODevice *device, const QDir &dir = QDir(), const PlaylistSettings::PathType path_type = PlaylistSettings::PathType::Automatic) const override; static QString FindCueFilename(const QString &filename); diff --git a/src/playlistparsers/m3uparser.cpp b/src/playlistparsers/m3uparser.cpp index ca0b19e6c..c7a6bb9fc 100644 --- a/src/playlistparsers/m3uparser.cpp +++ b/src/playlistparsers/m3uparser.cpp @@ -42,7 +42,7 @@ class CollectionBackendInterface; M3UParser::M3UParser(const SharedPtr tagreader_client, const SharedPtr collection_backend, QObject *parent) : ParserBase(tagreader_client, collection_backend, parent) {} -SongList M3UParser::Load(QIODevice *device, const QString &playlist_path, const QDir &dir, const bool collection_lookup) const { +ParserBase::LoadResult M3UParser::Load(QIODevice *device, const QString &playlist_path, const QDir &dir, const bool collection_lookup) const { Q_UNUSED(playlist_path); diff --git a/src/playlistparsers/m3uparser.h b/src/playlistparsers/m3uparser.h index 198a8f3e8..f3e9282f4 100644 --- a/src/playlistparsers/m3uparser.h +++ b/src/playlistparsers/m3uparser.h @@ -53,7 +53,7 @@ class M3UParser : public ParserBase { bool TryMagic(const QByteArray &data) const override; - SongList Load(QIODevice *device, const QString &playlist_path = QLatin1String(""), const QDir &dir = QDir(), const bool collection_lookup = true) const override; + LoadResult Load(QIODevice *device, const QString &playlist_path = QLatin1String(""), const QDir &dir = QDir(), const bool collection_lookup = true) const override; void Save(const QString &playlist_name, const SongList &songs, QIODevice *device, const QDir &dir = QDir(), const PlaylistSettings::PathType path_type = PlaylistSettings::PathType::Automatic) const override; private: diff --git a/src/playlistparsers/parserbase.h b/src/playlistparsers/parserbase.h index 510a27a45..910ba4641 100644 --- a/src/playlistparsers/parserbase.h +++ b/src/playlistparsers/parserbase.h @@ -46,6 +46,13 @@ class ParserBase : public QObject { public: explicit ParserBase(const SharedPtr tagreader_client, const SharedPtr collection_backend, QObject *parent = nullptr); + class LoadResult { + public: + LoadResult(const SongList &_songs = SongList(), const QString &_playlist_name = QString()) : songs(_songs), playlist_name(_playlist_name) {} + SongList songs; + QString playlist_name; + }; + virtual QString name() const = 0; virtual QStringList file_extensions() const = 0; virtual bool load_supported() const = 0; @@ -59,7 +66,7 @@ class ParserBase : public QObject { // This method might not return all the songs found in the playlist. // Any playlist parser may decide to leave out some entries if it finds them incomplete or invalid. // This means that the final resulting SongList should be considered valid (at least from the parser's point of view). - virtual SongList Load(QIODevice *device, const QString &playlist_path = QLatin1String(""), const QDir &dir = QDir(), const bool collection_lookup = true) const = 0; + virtual LoadResult Load(QIODevice *device, const QString &playlist_path = QLatin1String(""), const QDir &dir = QDir(), const bool collection_lookup = true) const = 0; virtual void Save(const QString &playlist_name, const SongList &songs, QIODevice *device, const QDir &dir = QDir(), const PlaylistSettings::PathType path_type = PlaylistSettings::PathType::Automatic) const = 0; Q_SIGNALS: diff --git a/src/playlistparsers/playlistparser.cpp b/src/playlistparsers/playlistparser.cpp index cdf83bc89..724daf0b3 100644 --- a/src/playlistparsers/playlistparser.cpp +++ b/src/playlistparsers/playlistparser.cpp @@ -195,7 +195,7 @@ SongList PlaylistParser::LoadFromFile(const QString &filename) const { return SongList(); } - const SongList songs = parser->Load(&file, filename, fileinfo.absolutePath(), true); + const SongList songs = parser->Load(&file, filename, fileinfo.absolutePath(), true).songs; file.close(); return songs; @@ -210,7 +210,7 @@ SongList PlaylistParser::LoadFromDevice(QIODevice *device, const QString &path_h return SongList(); } - return parser->Load(device, path_hint, dir_hint); + return parser->Load(device, path_hint, dir_hint).songs; } diff --git a/src/playlistparsers/plsparser.cpp b/src/playlistparsers/plsparser.cpp index 8f916eee5..7e15f7861 100644 --- a/src/playlistparsers/plsparser.cpp +++ b/src/playlistparsers/plsparser.cpp @@ -41,7 +41,7 @@ class CollectionBackendInterface; PLSParser::PLSParser(const SharedPtr tagreader_client, const SharedPtr collection_backend, QObject *parent) : ParserBase(tagreader_client, collection_backend, parent) {} -SongList PLSParser::Load(QIODevice *device, const QString &playlist_path, const QDir &dir, const bool collection_lookup) const { +ParserBase::LoadResult PLSParser::Load(QIODevice *device, const QString &playlist_path, const QDir &dir, const bool collection_lookup) const { Q_UNUSED(playlist_path); diff --git a/src/playlistparsers/plsparser.h b/src/playlistparsers/plsparser.h index 83ab84c17..5ce2575c7 100644 --- a/src/playlistparsers/plsparser.h +++ b/src/playlistparsers/plsparser.h @@ -52,7 +52,7 @@ class PLSParser : public ParserBase { bool TryMagic(const QByteArray &data) const override; - SongList Load(QIODevice *device, const QString &playlist_path = QLatin1String(""), const QDir &dir = QDir(), const bool collection_lookup = true) const override; + LoadResult Load(QIODevice *device, const QString &playlist_path = QLatin1String(""), const QDir &dir = QDir(), const bool collection_lookup = true) const override; void Save(const QString &playlist_name, const SongList &songs, QIODevice *device, const QDir &dir = QDir(), const PlaylistSettings::PathType path_type = PlaylistSettings::PathType::Automatic) const override; }; diff --git a/src/playlistparsers/wplparser.cpp b/src/playlistparsers/wplparser.cpp index e262320ba..e178a0935 100644 --- a/src/playlistparsers/wplparser.cpp +++ b/src/playlistparsers/wplparser.cpp @@ -46,21 +46,21 @@ bool WplParser::TryMagic(const QByteArray &data) const { return data.contains(""); } -SongList WplParser::Load(QIODevice *device, const QString &playlist_path, const QDir &dir, const bool collection_lookup) const { +ParserBase::LoadResult WplParser::Load(QIODevice *device, const QString &playlist_path, const QDir &dir, const bool collection_lookup) const { Q_UNUSED(playlist_path); - SongList ret; - QXmlStreamReader reader(device); if (!Utilities::ParseUntilElement(&reader, u"smil"_s) || !Utilities::ParseUntilElement(&reader, u"body"_s)) { - return ret; + return LoadResult(); } + SongList songs; while (!reader.atEnd() && Utilities::ParseUntilElement(&reader, u"seq"_s)) { - ParseSeq(dir, &reader, &ret, collection_lookup); + ParseSeq(dir, &reader, &songs, collection_lookup); } - return ret; + + return songs; } diff --git a/src/playlistparsers/wplparser.h b/src/playlistparsers/wplparser.h index b9020b1ab..ef9f55453 100644 --- a/src/playlistparsers/wplparser.h +++ b/src/playlistparsers/wplparser.h @@ -55,7 +55,7 @@ class WplParser : public XMLParser { bool TryMagic(const QByteArray &data) const override; - SongList Load(QIODevice *device, const QString &playlist_path, const QDir &dir, const bool collection_lookup = true) const override; + LoadResult Load(QIODevice *device, const QString &playlist_path, const QDir &dir, const bool collection_lookup = true) const override; void Save(const QString &playlist_name, const SongList &songs, QIODevice *device, const QDir &dir, const PlaylistSettings::PathType path_type = PlaylistSettings::PathType::Automatic) const override; private: diff --git a/src/playlistparsers/xspfparser.cpp b/src/playlistparsers/xspfparser.cpp index 192e17df4..0ddf79d73 100644 --- a/src/playlistparsers/xspfparser.cpp +++ b/src/playlistparsers/xspfparser.cpp @@ -44,17 +44,27 @@ class CollectionBackendInterface; XSPFParser::XSPFParser(const SharedPtr tagreader_client, const SharedPtr collection_backend, QObject *parent) : XMLParser(tagreader_client, collection_backend, parent) {} -SongList XSPFParser::Load(QIODevice *device, const QString &playlist_path, const QDir &dir, const bool collection_lookup) const { +ParserBase::LoadResult XSPFParser::Load(QIODevice *device, const QString &playlist_path, const QDir &dir, const bool collection_lookup) const { Q_UNUSED(playlist_path); - SongList songs; - - QXmlStreamReader reader(device); - if (!Utilities::ParseUntilElement(&reader, u"playlist"_s) || !Utilities::ParseUntilElement(&reader, u"trackList"_s)) { - return songs; + QString playlist_name; + { + QXmlStreamReader reader(device); + if (Utilities::ParseUntilElement(&reader, u"playlist"_s) && Utilities::ParseUntilElement(&reader, u"title"_s)) { + playlist_name = reader.readElementText(); + } } + device->seek(0); + QXmlStreamReader reader(device); + if (!Utilities::ParseUntilElement(&reader, u"playlist"_s)) { + return LoadResult(); + } + if (!Utilities::ParseUntilElement(&reader, u"trackList"_s)) { + return LoadResult(); + } + SongList songs; while (!reader.atEnd() && Utilities::ParseUntilElement(&reader, u"track"_s)) { const Song song = ParseTrack(&reader, dir, collection_lookup); if (song.is_valid()) { @@ -62,7 +72,7 @@ SongList XSPFParser::Load(QIODevice *device, const QString &playlist_path, const } } - return songs; + return LoadResult(songs, playlist_name); } diff --git a/src/playlistparsers/xspfparser.h b/src/playlistparsers/xspfparser.h index 1cfcfecd9..c8848c0be 100644 --- a/src/playlistparsers/xspfparser.h +++ b/src/playlistparsers/xspfparser.h @@ -52,7 +52,7 @@ class XSPFParser : public XMLParser { bool TryMagic(const QByteArray &data) const override; - SongList Load(QIODevice *device, const QString &playlist_path = QLatin1String(""), const QDir &dir = QDir(), const bool collection_lookup = true) const override; + LoadResult Load(QIODevice *device, const QString &playlist_path = QLatin1String(""), const QDir &dir = QDir(), const bool collection_lookup = true) const override; void Save(const QString &playlist_name, const SongList &songs, QIODevice *device, const QDir &dir = QDir(), const PlaylistSettings::PathType path_type = PlaylistSettings::PathType::Automatic) const override; private: