Load XSPF title as playlist name
This commit is contained in:
@@ -868,7 +868,7 @@ void CollectionWatcher::UpdateCueAssociatedSongs(const QString &file,
|
|||||||
qLog(Error) << "Could not open CUE file" << matching_cue << "for reading:" << cue_file.errorString();
|
qLog(Error) << "Could not open CUE file" << matching_cue << "for reading:" << cue_file.errorString();
|
||||||
return;
|
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();
|
cue_file.close();
|
||||||
|
|
||||||
// Update every song that's in the CUE and collection
|
// 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.
|
// 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!
|
// 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);
|
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();
|
cue_file.close();
|
||||||
songs.reserve(cue_songs.count());
|
songs.reserve(cue_songs.count());
|
||||||
for (Song &cue_song : cue_songs) {
|
for (Song &cue_song : cue_songs) {
|
||||||
|
|||||||
@@ -281,7 +281,7 @@ SongLoader::Result SongLoader::LoadLocalAsync(const QString &filename) {
|
|||||||
// It's a CUE - create virtual tracks
|
// It's a CUE - create virtual tracks
|
||||||
QFile cue(matching_cue);
|
QFile cue(matching_cue);
|
||||||
if (cue.open(QIODevice::ReadOnly)) {
|
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();
|
cue.close();
|
||||||
for (const Song &song : songs) {
|
for (const Song &song : songs) {
|
||||||
if (song.is_valid()) songs_ << song;
|
if (song.is_valid()) songs_ << song;
|
||||||
@@ -348,7 +348,9 @@ void SongLoader::LoadPlaylist(ParserBase *parser, const QString &filename) {
|
|||||||
|
|
||||||
QFile file(filename);
|
QFile file(filename);
|
||||||
if (file.open(QIODevice::ReadOnly)) {
|
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();
|
file.close();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -424,7 +426,9 @@ void SongLoader::StopTypefind() {
|
|||||||
// Parse the playlist
|
// Parse the playlist
|
||||||
QBuffer buf(&buffer_);
|
QBuffer buf(&buffer_);
|
||||||
if (buf.open(QIODevice::ReadOnly)) {
|
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();
|
buf.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ class SongLoader : public QObject {
|
|||||||
|
|
||||||
const QUrl &url() const { return url_; }
|
const QUrl &url() const { return url_; }
|
||||||
const SongList &songs() const { return songs_; }
|
const SongList &songs() const { return songs_; }
|
||||||
|
const QString &playlist_name() const { return playlist_name_; }
|
||||||
|
|
||||||
int timeout() const { return timeout_; }
|
int timeout() const { return timeout_; }
|
||||||
void set_timeout(int msec) { timeout_ = msec; }
|
void set_timeout(int msec) { timeout_ = msec; }
|
||||||
@@ -141,6 +142,7 @@ class SongLoader : public QObject {
|
|||||||
|
|
||||||
QUrl url_;
|
QUrl url_;
|
||||||
SongList songs_;
|
SongList songs_;
|
||||||
|
QString playlist_name_;
|
||||||
|
|
||||||
const SharedPtr<UrlHandlers> url_handlers_;
|
const SharedPtr<UrlHandlers> url_handlers_;
|
||||||
const SharedPtr<CollectionBackendInterface> collection_backend_;
|
const SharedPtr<CollectionBackendInterface> collection_backend_;
|
||||||
|
|||||||
@@ -1180,7 +1180,11 @@ void Playlist::InsertSongs(const SongList &songs, const int pos, const bool play
|
|||||||
InsertSongItems<SongPlaylistItem>(songs, pos, play_now, enqueue, enqueue_next);
|
InsertSongItems<SongPlaylistItem>(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;
|
PlaylistItemPtrList items;
|
||||||
for (const Song &song : songs) {
|
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);
|
InsertItems(items, pos, play_now, enqueue, enqueue_next);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 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 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 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 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 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);
|
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.
|
// Signals that the queue has changed, meaning that the remaining queued items should update their position.
|
||||||
void QueueChanged();
|
void QueueChanged();
|
||||||
|
|
||||||
|
void Rename(const int id, const QString &name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetCurrentIsPaused(const bool paused);
|
void SetCurrentIsPaused(const bool paused);
|
||||||
int NextVirtualIndex(int i, const bool ignore_repeat_track) const;
|
int NextVirtualIndex(int i, const bool ignore_repeat_track) const;
|
||||||
|
|||||||
@@ -298,7 +298,7 @@ PlaylistItemPtr PlaylistBackend::RestoreCueData(PlaylistItemPtr item, SharedPtr<
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
SongList song_list;
|
SongList songs;
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&state->mutex_);
|
QMutexLocker locker(&state->mutex_);
|
||||||
|
|
||||||
@@ -306,16 +306,16 @@ PlaylistItemPtr PlaylistBackend::RestoreCueData(PlaylistItemPtr item, SharedPtr<
|
|||||||
QFile cue_file(cue_path);
|
QFile cue_file(cue_path);
|
||||||
if (!cue_file.open(QIODevice::ReadOnly)) return item;
|
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();
|
cue_file.close();
|
||||||
state->cached_cues_[cue_path] = song_list;
|
state->cached_cues_[cue_path] = songs;
|
||||||
}
|
}
|
||||||
else {
|
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()) {
|
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
|
// We found a matching section; replace the input item with a new one containing CUE metadata
|
||||||
return make_shared<SongPlaylistItem>(from_list);
|
return make_shared<SongPlaylistItem>(from_list);
|
||||||
|
|||||||
@@ -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::EditingFinished, this, &PlaylistManager::EditingFinished);
|
||||||
QObject::connect(ret, &Playlist::Error, this, &PlaylistManager::Error);
|
QObject::connect(ret, &Playlist::Error, this, &PlaylistManager::Error);
|
||||||
QObject::connect(ret, &Playlist::PlayRequested, this, &PlaylistManager::PlayRequested);
|
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(playlist_container_->view(), &PlaylistView::ColumnAlignmentChanged, ret, &Playlist::SetColumnAlignment);
|
||||||
QObject::connect(&*current_albumcover_loader_, &CurrentAlbumCoverLoader::AlbumCoverLoaded, ret, &Playlist::AlbumCoverLoaded);
|
QObject::connect(&*current_albumcover_loader_, &CurrentAlbumCoverLoader::AlbumCoverLoaded, ret, &Playlist::AlbumCoverLoaded);
|
||||||
|
|
||||||
@@ -208,7 +209,7 @@ void PlaylistManager::Load(const QString &filename) {
|
|||||||
|
|
||||||
QFileInfo fileinfo(filename);
|
QFileInfo fileinfo(filename);
|
||||||
|
|
||||||
int id = playlist_backend_->CreatePlaylist(fileinfo.completeBaseName(), QString());
|
const int id = playlist_backend_->CreatePlaylist(fileinfo.completeBaseName(), QString());
|
||||||
|
|
||||||
if (id == -1) {
|
if (id == -1) {
|
||||||
Q_EMIT Error(tr("Couldn't create playlist"));
|
Q_EMIT Error(tr("Couldn't create playlist"));
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ SongLoaderInserter::SongLoaderInserter(const SharedPtr<TaskManager> task_manager
|
|||||||
|
|
||||||
SongLoaderInserter::~SongLoaderInserter() { qDeleteAll(pending_); }
|
SongLoaderInserter::~SongLoaderInserter() { qDeleteAll(pending_); }
|
||||||
|
|
||||||
void SongLoaderInserter::Load(Playlist *destination, int row, bool play_now, bool enqueue, bool enqueue_next, const QList<QUrl> &urls) {
|
void SongLoaderInserter::Load(Playlist *destination, const int row, const bool play_now, const bool enqueue, const bool enqueue_next, const QList<QUrl> &urls) {
|
||||||
|
|
||||||
destination_ = destination;
|
destination_ = destination;
|
||||||
row_ = row;
|
row_ = row;
|
||||||
@@ -69,15 +69,16 @@ void SongLoaderInserter::Load(Playlist *destination, int row, bool play_now, boo
|
|||||||
for (const QUrl &url : urls) {
|
for (const QUrl &url : urls) {
|
||||||
SongLoader *loader = new SongLoader(url_handlers_, collection_backend_, tagreader_client_, this);
|
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);
|
pending_.append(loader);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == SongLoader::Result::Success) {
|
if (result == SongLoader::Result::Success) {
|
||||||
songs_ << loader->songs();
|
songs_ << loader->songs();
|
||||||
|
playlist_name_ = loader->playlist_name();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const QStringList errors = loader->errors();
|
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
|
// First, we add tracks (without metadata) into the playlist
|
||||||
// In the meantime, MusicBrainz will be queried to get songs' metadata.
|
// In the meantime, MusicBrainz will be queried to get songs' metadata.
|
||||||
// AudioCDTagsLoaded will be called next, and playlist's items will be updated.
|
// 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;
|
destination_ = destination;
|
||||||
row_ = row;
|
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::AudioCDTracksLoadFinished, this, [this, loader]() { AudioCDTracksLoadFinished(loader); });
|
||||||
QObject::connect(loader, &SongLoader::LoadAudioCDFinished, this, &SongLoaderInserter::AudioCDTagsLoaded);
|
QObject::connect(loader, &SongLoader::LoadAudioCDFinished, this, &SongLoaderInserter::AudioCDTagsLoaded);
|
||||||
qLog(Info) << "Loading audio CD...";
|
qLog(Info) << "Loading audio CD...";
|
||||||
SongLoader::Result ret = loader->LoadAudioCD();
|
const SongLoader::Result result = loader->LoadAudioCD();
|
||||||
if (ret == SongLoader::Result::Error) {
|
if (result == SongLoader::Result::Error) {
|
||||||
if (loader->errors().isEmpty())
|
if (loader->errors().isEmpty())
|
||||||
Q_EMIT Error(tr("Error while loading audio CD."));
|
Q_EMIT Error(tr("Error while loading audio CD."));
|
||||||
else {
|
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
|
// Insert songs (that haven't been completely loaded) to allow user to see and play them while not loaded completely
|
||||||
if (destination_) {
|
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;
|
bool first_loaded = false;
|
||||||
for (int i = 0; i < pending_.count(); ++i) {
|
for (int i = 0; i < pending_.count(); ++i) {
|
||||||
SongLoader *loader = pending_.value(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);
|
task_manager_->SetTaskProgress(async_load_id, ++async_progress);
|
||||||
|
|
||||||
if (res == SongLoader::Result::Error) {
|
if (result == SongLoader::Result::Error) {
|
||||||
const QStringList errors = loader->errors();
|
const QStringList errors = loader->errors();
|
||||||
for (const QString &error : errors) {
|
for (const QString &error : errors) {
|
||||||
Q_EMIT Error(error);
|
Q_EMIT Error(error);
|
||||||
@@ -199,6 +200,7 @@ void SongLoaderInserter::AsyncLoad() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
songs_ << loader->songs();
|
songs_ << loader->songs();
|
||||||
|
playlist_name_ = loader->playlist_name();
|
||||||
|
|
||||||
}
|
}
|
||||||
task_manager_->SetTaskFinished(async_load_id);
|
task_manager_->SetTaskFinished(async_load_id);
|
||||||
|
|||||||
@@ -52,8 +52,8 @@ class SongLoaderInserter : public QObject {
|
|||||||
|
|
||||||
~SongLoaderInserter() override;
|
~SongLoaderInserter() override;
|
||||||
|
|
||||||
void Load(Playlist *destination, int row, bool play_now, bool enqueue, bool enqueue_next, const QList<QUrl> &urls);
|
void Load(Playlist *destination, const int row, const bool play_now, const bool enqueue, const bool enqueue_next, const QList<QUrl> &urls);
|
||||||
void LoadAudioCD(Playlist *destination, int row, bool play_now, bool enqueue, bool enqueue_next);
|
void LoadAudioCD(Playlist *destination, const int row, const bool play_now, const bool enqueue, const bool enqueue_next);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void Error(const QString &message);
|
void Error(const QString &message);
|
||||||
@@ -82,6 +82,7 @@ class SongLoaderInserter : public QObject {
|
|||||||
bool enqueue_next_;
|
bool enqueue_next_;
|
||||||
|
|
||||||
SongList songs_;
|
SongList songs_;
|
||||||
|
QString playlist_name_;
|
||||||
|
|
||||||
QList<SongLoader*> pending_;
|
QList<SongLoader*> pending_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ bool AsxIniParser::TryMagic(const QByteArray &data) const {
|
|||||||
return data.toLower().contains("[reference]");
|
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);
|
Q_UNUSED(playlist_path);
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class AsxIniParser : public ParserBase {
|
|||||||
|
|
||||||
bool TryMagic(const QByteArray &data) const override;
|
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;
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class CollectionBackendInterface;
|
|||||||
ASXParser::ASXParser(const SharedPtr<TagReaderClient> tagreader_client, const SharedPtr<CollectionBackendInterface> collection_backend, QObject *parent)
|
ASXParser::ASXParser(const SharedPtr<TagReaderClient> tagreader_client, const SharedPtr<CollectionBackendInterface> collection_backend, QObject *parent)
|
||||||
: XMLParser(tagreader_client, collection_backend, 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);
|
Q_UNUSED(playlist_path);
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class ASXParser : public XMLParser {
|
|||||||
|
|
||||||
bool TryMagic(const QByteArray &data) const override;
|
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;
|
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:
|
private:
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ constexpr char kDisc[] = "discnumber";
|
|||||||
CueParser::CueParser(const SharedPtr<TagReaderClient> tagreader_client, const SharedPtr<CollectionBackendInterface> collection_backend, QObject *parent)
|
CueParser::CueParser(const SharedPtr<TagReaderClient> tagreader_client, const SharedPtr<CollectionBackendInterface> collection_backend, QObject *parent)
|
||||||
: ParserBase(tagreader_client, collection_backend, 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;
|
SongList ret;
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class CueParser : public ParserBase {
|
|||||||
|
|
||||||
bool TryMagic(const QByteArray &data) const override;
|
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;
|
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);
|
static QString FindCueFilename(const QString &filename);
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class CollectionBackendInterface;
|
|||||||
M3UParser::M3UParser(const SharedPtr<TagReaderClient> tagreader_client, const SharedPtr<CollectionBackendInterface> collection_backend, QObject *parent)
|
M3UParser::M3UParser(const SharedPtr<TagReaderClient> tagreader_client, const SharedPtr<CollectionBackendInterface> collection_backend, QObject *parent)
|
||||||
: ParserBase(tagreader_client, collection_backend, 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);
|
Q_UNUSED(playlist_path);
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ class M3UParser : public ParserBase {
|
|||||||
|
|
||||||
bool TryMagic(const QByteArray &data) const override;
|
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;
|
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:
|
private:
|
||||||
|
|||||||
@@ -46,6 +46,13 @@ class ParserBase : public QObject {
|
|||||||
public:
|
public:
|
||||||
explicit ParserBase(const SharedPtr<TagReaderClient> tagreader_client, const SharedPtr<CollectionBackendInterface> collection_backend, QObject *parent = nullptr);
|
explicit ParserBase(const SharedPtr<TagReaderClient> tagreader_client, const SharedPtr<CollectionBackendInterface> 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 QString name() const = 0;
|
||||||
virtual QStringList file_extensions() const = 0;
|
virtual QStringList file_extensions() const = 0;
|
||||||
virtual bool load_supported() 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.
|
// 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.
|
// 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).
|
// 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;
|
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:
|
Q_SIGNALS:
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ SongList PlaylistParser::LoadFromFile(const QString &filename) const {
|
|||||||
return SongList();
|
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();
|
file.close();
|
||||||
|
|
||||||
return songs;
|
return songs;
|
||||||
@@ -210,7 +210,7 @@ SongList PlaylistParser::LoadFromDevice(QIODevice *device, const QString &path_h
|
|||||||
return SongList();
|
return SongList();
|
||||||
}
|
}
|
||||||
|
|
||||||
return parser->Load(device, path_hint, dir_hint);
|
return parser->Load(device, path_hint, dir_hint).songs;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class CollectionBackendInterface;
|
|||||||
PLSParser::PLSParser(const SharedPtr<TagReaderClient> tagreader_client, const SharedPtr<CollectionBackendInterface> collection_backend, QObject *parent)
|
PLSParser::PLSParser(const SharedPtr<TagReaderClient> tagreader_client, const SharedPtr<CollectionBackendInterface> collection_backend, QObject *parent)
|
||||||
: ParserBase(tagreader_client, collection_backend, 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);
|
Q_UNUSED(playlist_path);
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class PLSParser : public ParserBase {
|
|||||||
|
|
||||||
bool TryMagic(const QByteArray &data) const override;
|
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;
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -46,21 +46,21 @@ bool WplParser::TryMagic(const QByteArray &data) const {
|
|||||||
return data.contains("<?wpl") || data.contains("<smil>");
|
return data.contains("<?wpl") || data.contains("<smil>");
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
Q_UNUSED(playlist_path);
|
||||||
|
|
||||||
SongList ret;
|
|
||||||
|
|
||||||
QXmlStreamReader reader(device);
|
QXmlStreamReader reader(device);
|
||||||
if (!Utilities::ParseUntilElement(&reader, u"smil"_s) || !Utilities::ParseUntilElement(&reader, u"body"_s)) {
|
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)) {
|
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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class WplParser : public XMLParser {
|
|||||||
|
|
||||||
bool TryMagic(const QByteArray &data) const override;
|
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;
|
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:
|
private:
|
||||||
|
|||||||
@@ -44,17 +44,27 @@ class CollectionBackendInterface;
|
|||||||
XSPFParser::XSPFParser(const SharedPtr<TagReaderClient> tagreader_client, const SharedPtr<CollectionBackendInterface> collection_backend, QObject *parent)
|
XSPFParser::XSPFParser(const SharedPtr<TagReaderClient> tagreader_client, const SharedPtr<CollectionBackendInterface> collection_backend, QObject *parent)
|
||||||
: XMLParser(tagreader_client, collection_backend, 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);
|
Q_UNUSED(playlist_path);
|
||||||
|
|
||||||
SongList songs;
|
QString playlist_name;
|
||||||
|
{
|
||||||
QXmlStreamReader reader(device);
|
QXmlStreamReader reader(device);
|
||||||
if (!Utilities::ParseUntilElement(&reader, u"playlist"_s) || !Utilities::ParseUntilElement(&reader, u"trackList"_s)) {
|
if (Utilities::ParseUntilElement(&reader, u"playlist"_s) && Utilities::ParseUntilElement(&reader, u"title"_s)) {
|
||||||
return songs;
|
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)) {
|
while (!reader.atEnd() && Utilities::ParseUntilElement(&reader, u"track"_s)) {
|
||||||
const Song song = ParseTrack(&reader, dir, collection_lookup);
|
const Song song = ParseTrack(&reader, dir, collection_lookup);
|
||||||
if (song.is_valid()) {
|
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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class XSPFParser : public XMLParser {
|
|||||||
|
|
||||||
bool TryMagic(const QByteArray &data) const override;
|
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;
|
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:
|
private:
|
||||||
|
|||||||
Reference in New Issue
Block a user