1
0
mirror of https://github.com/strawberrymusicplayer/strawberry synced 2025-02-08 15:58:47 +01:00

PlaylistParser: Refactor code and exclude CUE from save playlist filters

Fixes #953
This commit is contained in:
Jonas Kvinge 2022-05-13 23:14:56 +02:00
parent a2dad982f8
commit 18a2692dc1
30 changed files with 213 additions and 187 deletions

View File

@ -2190,7 +2190,7 @@ void MainWindow::AddFile() {
PlaylistParser parser(app_->collection_backend()); PlaylistParser parser(app_->collection_backend());
// Show dialog // Show dialog
QStringList file_names = QFileDialog::getOpenFileNames(this, tr("Add file"), directory, QString("%1 (%2);;%3;;%4").arg(tr("Music"), FileView::kFileFilter, parser.filters(), tr(kAllFilesFilterSpec))); QStringList file_names = QFileDialog::getOpenFileNames(this, tr("Add file"), directory, QString("%1 (%2);;%3;;%4").arg(tr("Music"), FileView::kFileFilter, parser.filters(PlaylistParser::Type_Load), tr(kAllFilesFilterSpec)));
if (file_names.isEmpty()) return; if (file_names.isEmpty()) return;

View File

@ -290,7 +290,7 @@ SongLoader::Result SongLoader::LoadLocalAsync(const QString &filename) {
ParserBase *parser = playlist_parser_->ParserForMagic(data); ParserBase *parser = playlist_parser_->ParserForMagic(data);
if (!parser) { if (!parser) {
// Check the file extension as well, maybe the magic failed, or it was a basic M3U file which is just a plain list of filenames. // Check the file extension as well, maybe the magic failed, or it was a basic M3U file which is just a plain list of filenames.
parser = playlist_parser_->ParserForExtension(fileinfo.suffix().toLower()); parser = playlist_parser_->ParserForExtension(PlaylistParser::Type_Load, fileinfo.suffix().toLower());
} }
if (parser) { // It's a playlist! if (parser) { // It's a playlist!

View File

@ -111,9 +111,6 @@ const QRgb Playlist::kDynamicHistoryColor = qRgb(0x80, 0x80, 0x80);
const char *Playlist::kSettingsGroup = "Playlist"; const char *Playlist::kSettingsGroup = "Playlist";
const char *Playlist::kPathType = "path_type";
const char *Playlist::kWriteMetadata = "write_metadata";
const int Playlist::kUndoStackSize = 20; const int Playlist::kUndoStackSize = 20;
const int Playlist::kUndoItemLimit = 500; const int Playlist::kUndoItemLimit = 500;

View File

@ -143,13 +143,6 @@ class Playlist : public QAbstractListModel {
Role_CanSetRating, Role_CanSetRating,
}; };
enum Path {
Path_Automatic = 0, // Automatically select path type
Path_Absolute, // Always use absolute paths
Path_Relative, // Always use relative paths
Path_Ask_User, // Only used in preferences: to ask user which of the previous values he wants to use.
};
enum AutoScroll { enum AutoScroll {
AutoScroll_Never, AutoScroll_Never,
AutoScroll_Maybe, AutoScroll_Maybe,
@ -168,9 +161,6 @@ class Playlist : public QAbstractListModel {
static const char *kSettingsGroup; static const char *kSettingsGroup;
static const char *kPathType;
static const char *kWriteMetadata;
static const int kUndoStackSize; static const int kUndoStackSize;
static const int kUndoItemLimit; static const int kUndoItemLimit;

View File

@ -345,7 +345,7 @@ void PlaylistContainer::NewPlaylist() { manager_->New(tr("Playlist")); }
void PlaylistContainer::LoadPlaylist() { void PlaylistContainer::LoadPlaylist() {
QString filename = settings_.value("last_load_playlist").toString(); QString filename = settings_.value("last_load_playlist").toString();
filename = QFileDialog::getOpenFileName(this, tr("Load playlist"), filename, manager_->parser()->filters()); filename = QFileDialog::getOpenFileName(this, tr("Load playlist"), filename, manager_->parser()->filters(PlaylistParser::Type_Load));
if (filename.isNull()) return; if (filename.isNull()) return;

View File

@ -45,6 +45,7 @@
#include <QScrollBar> #include <QScrollBar>
#include <QSettings> #include <QSettings>
#include <QtDebug> #include <QtDebug>
#include <QMessageBox>
#include "core/application.h" #include "core/application.h"
#include "core/logging.h" #include "core/logging.h"
@ -55,6 +56,7 @@
#include "covermanager/albumcoverloaderresult.h" #include "covermanager/albumcoverloaderresult.h"
#include "covermanager/currentalbumcoverloader.h" #include "covermanager/currentalbumcoverloader.h"
#include "organize/organizeformat.h" #include "organize/organizeformat.h"
#include "settings/playlistsettingspage.h"
#include "playlist.h" #include "playlist.h"
#include "playlistbackend.h" #include "playlistbackend.h"
#include "playlistcontainer.h" #include "playlistcontainer.h"
@ -200,22 +202,22 @@ void PlaylistManager::New(const QString &name, const SongList &songs, const QStr
void PlaylistManager::Load(const QString &filename) { void PlaylistManager::Load(const QString &filename) {
QFileInfo info(filename); QFileInfo fileinfo(filename);
int id = playlist_backend_->CreatePlaylist(info.completeBaseName(), QString()); int id = playlist_backend_->CreatePlaylist(fileinfo.completeBaseName(), QString());
if (id == -1) { if (id == -1) {
emit Error(tr("Couldn't create playlist")); emit Error(tr("Couldn't create playlist"));
return; return;
} }
Playlist *playlist = AddPlaylist(id, info.completeBaseName(), QString(), QString(), false); Playlist *playlist = AddPlaylist(id, fileinfo.completeBaseName(), QString(), QString(), false);
playlist->InsertUrls(QList<QUrl>() << QUrl::fromLocalFile(filename)); playlist->InsertUrls(QList<QUrl>() << QUrl::fromLocalFile(filename));
} }
void PlaylistManager::Save(const int id, const QString &filename, const Playlist::Path path_type) { void PlaylistManager::Save(const int id, const QString &filename, const PlaylistSettingsPage::PathType path_type) {
if (playlists_.contains(id)) { if (playlists_.contains(id)) {
parser_->Save(playlist(id)->GetAllSongs(), filename, path_type); parser_->Save(playlist(id)->GetAllSongs(), filename, path_type);
@ -237,7 +239,7 @@ void PlaylistManager::Save(const int id, const QString &filename, const Playlist
} }
void PlaylistManager::ItemsLoadedForSavePlaylist(const SongList &songs, const QString &filename, const Playlist::Path path_type) { void PlaylistManager::ItemsLoadedForSavePlaylist(const SongList &songs, const QString &filename, const PlaylistSettingsPage::PathType path_type) {
parser_->Save(songs, filename, path_type); parser_->Save(songs, filename, path_type);
@ -245,67 +247,43 @@ void PlaylistManager::ItemsLoadedForSavePlaylist(const SongList &songs, const QS
void PlaylistManager::SaveWithUI(const int id, const QString &playlist_name) { void PlaylistManager::SaveWithUI(const int id, const QString &playlist_name) {
QSettings settings; QSettings s;
settings.beginGroup(Playlist::kSettingsGroup); s.beginGroup(Playlist::kSettingsGroup);
QString filename = settings.value("last_save_playlist").toString(); QString last_save_filter = s.value("last_save_filter", parser()->default_filter()).toString();
QString extension = settings.value("last_save_extension", parser()->default_extension()).toString(); QString last_save_path = s.value("last_save_path", QDir::homePath()).toString();
QString filter = settings.value("last_save_filter", parser()->default_filter()).toString(); QString last_save_extension = s.value("last_save_extension", parser()->default_extension()).toString();
s.endGroup();
QString suggested_filename = playlist_name; QString suggested_filename = playlist_name;
suggested_filename = suggested_filename.remove(OrganizeFormat::kProblematicCharacters); QString filename = last_save_path + "/" + suggested_filename.remove(OrganizeFormat::kProblematicCharacters) + "." + last_save_extension;
qLog(Debug) << "Using extension:" << extension; QFileInfo fileinfo;
// We want to use the playlist tab name (with disallowed characters removed)
// as a default filename, but in the same directory as the last saved file.
// Strip off filename components until we find something that's a folder
forever { forever {
QFileInfo fileinfo(filename); 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() || fileinfo.isDir()) break; if (filename.isEmpty()) return;
fileinfo.setFile(filename);
filename = filename.section('/', 0, -2); 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."));
} }
// Use the home directory as a fallback in case the path is empty. s.beginGroup(PlaylistSettingsPage::kSettingsGroup);
if (filename.isEmpty()) filename = QDir::homePath(); PlaylistSettingsPage::PathType path_type = static_cast<PlaylistSettingsPage::PathType>(s.value("path_type", PlaylistSettingsPage::PathType_Automatic).toInt());
s.endGroup();
// Add the suggested filename if (path_type == PlaylistSettingsPage::PathType_Ask_User) {
filename += "/" + suggested_filename + "." + extension; PlaylistSaveOptionsDialog optionsdialog(nullptr);
qLog(Debug) << "Suggested filename:" << filename; optionsdialog.setModal(true);
if (optionsdialog.exec() != QDialog::Accepted) return;
filename = QFileDialog::getSaveFileName(nullptr, tr("Save playlist", "Title of the playlist save dialog."), filename, parser()->filters(), &filter); path_type = optionsdialog.path_type();
if (filename.isNull()) {
return;
} }
// Check if the file extension is valid. Fallback to the default if not. s.beginGroup(Playlist::kSettingsGroup);
QFileInfo info(filename); s.setValue("last_save_filter", last_save_filter);
ParserBase *parser = parser_->ParserForExtension(info.suffix()); s.setValue("last_save_path", fileinfo.path());
if (!parser) { s.setValue("last_save_extension", fileinfo.suffix());
qLog(Warning) << "Unknown file extension:" << info.suffix(); s.endGroup();
filename = info.absolutePath() + "/" + info.fileName() + "." + parser_->default_extension();
info.setFile(filename);
filter = info.suffix();
}
int p = settings.value(Playlist::kPathType, Playlist::Path_Automatic).toInt(); Save(id == -1 ? current_id() : id, filename, path_type);
Playlist::Path path = static_cast<Playlist::Path>(p);
if (path == Playlist::Path_Ask_User) {
PlaylistSaveOptionsDialog optionsDialog(nullptr);
optionsDialog.setModal(true);
if (optionsDialog.exec() != QDialog::Accepted) {
return;
}
path = optionsDialog.path_type();
}
settings.setValue("last_save_playlist", filename);
settings.setValue("last_save_filter", filter);
settings.setValue("last_save_extension", info.suffix());
Save(id == -1 ? current_id() : id, filename, path);
} }
@ -658,7 +636,7 @@ void PlaylistManager::SaveAllPlaylists() {
for (QMap<int, Data>::const_iterator it = playlists_.constBegin(); it != playlists_.constEnd(); ++it) { for (QMap<int, Data>::const_iterator it = playlists_.constBegin(); it != playlists_.constEnd(); ++it) {
const Data &data = *it; const Data &data = *it;
const QString filepath = path + "/" + data.name + ".m3u"; const QString filepath = path + "/" + data.name + ".m3u";
Save(it.key(), filepath, Playlist::Path_Absolute); Save(it.key(), filepath, PlaylistSettingsPage::PathType_Absolute);
} }
} }

View File

@ -34,6 +34,7 @@
#include <QUrl> #include <QUrl>
#include "core/song.h" #include "core/song.h"
#include "settings/playlistsettingspage.h"
#include "playlist.h" #include "playlist.h"
#include "smartplaylists/playlistgenerator.h" #include "smartplaylists/playlistgenerator.h"
@ -83,7 +84,7 @@ class PlaylistManagerInterface : public QObject {
public slots: public slots:
virtual void New(const QString &name, const SongList &songs = SongList(), const QString &special_type = QString()) = 0; virtual void New(const QString &name, const SongList &songs = SongList(), const QString &special_type = QString()) = 0;
virtual void Load(const QString &filename) = 0; virtual void Load(const QString &filename) = 0;
virtual void Save(const int id, const QString &filename, const Playlist::Path path_type) = 0; virtual void Save(const int id, const QString &filename, const PlaylistSettingsPage::PathType path_type) = 0;
virtual void Rename(const int id, const QString &new_name) = 0; virtual void Rename(const int id, const QString &new_name) = 0;
virtual void Delete(const int id) = 0; virtual void Delete(const int id) = 0;
virtual bool Close(const int id) = 0; virtual bool Close(const int id) = 0;
@ -181,7 +182,7 @@ class PlaylistManager : public PlaylistManagerInterface {
public slots: public slots:
void New(const QString &name, const SongList &songs = SongList(), const QString &special_type = QString()) override; void New(const QString &name, const SongList &songs = SongList(), const QString &special_type = QString()) override;
void Load(const QString &filename) override; void Load(const QString &filename) override;
void Save(const int id, const QString &filename, const Playlist::Path path_type) override; void Save(const int id, const QString &filename, const PlaylistSettingsPage::PathType path_type) override;
// Display a file dialog to let user choose a file before saving the file // Display a file dialog to let user choose a file before saving the file
void SaveWithUI(const int id, const QString &playlist_name); void SaveWithUI(const int id, const QString &playlist_name);
void Rename(const int id, const QString &new_name) override; void Rename(const int id, const QString &new_name) override;
@ -232,7 +233,7 @@ class PlaylistManager : public PlaylistManagerInterface {
void OneOfPlaylistsChanged(); void OneOfPlaylistsChanged();
void UpdateSummaryText(); void UpdateSummaryText();
void SongsDiscovered(const SongList &songs); void SongsDiscovered(const SongList &songs);
void ItemsLoadedForSavePlaylist(const SongList &songs, const QString &filename, const Playlist::Path path_type); void ItemsLoadedForSavePlaylist(const SongList &songs, const QString &filename, const PlaylistSettingsPage::PathType path_type);
void PlaylistLoaded(); void PlaylistLoaded();
private: private:

View File

@ -27,7 +27,7 @@
#include <QComboBox> #include <QComboBox>
#include <QSettings> #include <QSettings>
#include "playlist.h" #include "settings/playlistsettingspage.h"
#include "playlistsaveoptionsdialog.h" #include "playlistsaveoptionsdialog.h"
#include "ui_playlistsaveoptionsdialog.h" #include "ui_playlistsaveoptionsdialog.h"
@ -37,9 +37,10 @@ PlaylistSaveOptionsDialog::PlaylistSaveOptionsDialog(QWidget *parent) : QDialog(
ui->setupUi(this); ui->setupUi(this);
ui->filePaths->addItem(tr("Automatic"), Playlist::Path_Automatic); ui->filePaths->addItem(tr("Automatic"), PlaylistSettingsPage::PathType_Automatic);
ui->filePaths->addItem(tr("Relative"), Playlist::Path_Relative); ui->filePaths->addItem(tr("Relative"), PlaylistSettingsPage::PathType_Relative);
ui->filePaths->addItem(tr("Absolute"), Playlist::Path_Absolute); ui->filePaths->addItem(tr("Absolute"), PlaylistSettingsPage::PathType_Absolute);
} }
PlaylistSaveOptionsDialog::~PlaylistSaveOptionsDialog() { delete ui; } PlaylistSaveOptionsDialog::~PlaylistSaveOptionsDialog() { delete ui; }
@ -48,14 +49,15 @@ void PlaylistSaveOptionsDialog::accept() {
if (ui->remember_user_choice->isChecked()) { if (ui->remember_user_choice->isChecked()) {
QSettings s; QSettings s;
s.beginGroup(Playlist::kSettingsGroup); s.beginGroup(PlaylistSettingsPage::kSettingsGroup);
s.setValue(Playlist::kPathType, ui->filePaths->itemData(ui->filePaths->currentIndex()).toInt()); s.setValue("path_type", ui->filePaths->itemData(ui->filePaths->currentIndex()).toInt());
s.endGroup();
} }
QDialog::accept(); QDialog::accept();
} }
Playlist::Path PlaylistSaveOptionsDialog::path_type() const { PlaylistSettingsPage::PathType PlaylistSaveOptionsDialog::path_type() const {
return static_cast<Playlist::Path>(ui->filePaths->itemData(ui->filePaths->currentIndex()).toInt()); return static_cast<PlaylistSettingsPage::PathType>(ui->filePaths->itemData(ui->filePaths->currentIndex()).toInt());
} }

View File

@ -27,7 +27,7 @@
#include <QDialog> #include <QDialog>
#include <QString> #include <QString>
#include "playlist.h" #include "settings/playlistsettingspage.h"
class QWidget; class QWidget;
@ -43,7 +43,7 @@ class PlaylistSaveOptionsDialog : public QDialog {
~PlaylistSaveOptionsDialog() override; ~PlaylistSaveOptionsDialog() override;
void accept() override; void accept() override;
Playlist::Path path_type() const; PlaylistSettingsPage::PathType path_type() const;
private: private:
static const char *kSettingsGroup; static const char *kSettingsGroup;

View File

@ -26,8 +26,9 @@
#include <QString> #include <QString>
#include <QTextStream> #include <QTextStream>
#include "settings/playlistsettingspage.h"
#include "parserbase.h"
#include "asxiniparser.h" #include "asxiniparser.h"
#include "playlistparsers/parserbase.h"
class CollectionBackendInterface; class CollectionBackendInterface;
@ -68,7 +69,7 @@ SongList AsxIniParser::Load(QIODevice *device, const QString &playlist_path, con
} }
void AsxIniParser::Save(const SongList &songs, QIODevice *device, const QDir &dir, Playlist::Path path_type) const { void AsxIniParser::Save(const SongList &songs, QIODevice *device, const QDir &dir, const PlaylistSettingsPage::PathType path_type) const {
QTextStream s(device); QTextStream s(device);
s << "[Reference]" << qt_endl; s << "[Reference]" << qt_endl;

View File

@ -29,8 +29,8 @@
#include "config.h" #include "config.h"
#include "core/song.h" #include "core/song.h"
#include "settings/playlistsettingspage.h"
#include "parserbase.h" #include "parserbase.h"
#include "playlist/playlist.h"
class QIODevice; class QIODevice;
class CollectionBackendInterface; class CollectionBackendInterface;
@ -43,11 +43,13 @@ class AsxIniParser : public ParserBase {
QString name() const override { return "ASX/INI"; } QString name() const override { return "ASX/INI"; }
QStringList file_extensions() const override { return QStringList() << "asxini"; } QStringList file_extensions() const override { return QStringList() << "asxini"; }
bool load_supported() const override { return true; }
bool save_supported() const override { return true; }
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 = QDir(), const bool collection_search = true) const override; SongList Load(QIODevice *device, const QString &playlist_path = "", const QDir &dir = QDir(), const bool collection_search = true) const override;
void Save(const SongList &songs, QIODevice *device, const QDir &dir = QDir(), Playlist::Path path_type = Playlist::Path_Automatic) const override; void Save(const SongList &songs, QIODevice *device, const QDir &dir = QDir(), const PlaylistSettingsPage::PathType path_type = PlaylistSettingsPage::PathType_Automatic) const override;
}; };
#endif // ASXINIPARSER_H #endif // ASXINIPARSER_H

View File

@ -32,9 +32,10 @@
#include <QXmlStreamReader> #include <QXmlStreamReader>
#include <QXmlStreamWriter> #include <QXmlStreamWriter>
#include "asxparser.h"
#include "core/utilities.h" #include "core/utilities.h"
#include "playlistparsers/xmlparser.h" #include "settings/playlistsettingspage.h"
#include "xmlparser.h"
#include "asxparser.h"
class CollectionBackendInterface; class CollectionBackendInterface;
@ -131,7 +132,7 @@ return_song:
} }
void ASXParser::Save(const SongList &songs, QIODevice *device, const QDir&, Playlist::Path) const { void ASXParser::Save(const SongList &songs, QIODevice *device, const QDir&, const PlaylistSettingsPage::PathType) const {
QXmlStreamWriter writer(device); QXmlStreamWriter writer(device);
writer.setAutoFormatting(true); writer.setAutoFormatting(true);

View File

@ -29,7 +29,7 @@
#include "config.h" #include "config.h"
#include "core/song.h" #include "core/song.h"
#include "playlist/playlist.h" #include "settings/playlistsettingspage.h"
#include "xmlparser.h" #include "xmlparser.h"
class QIODevice; class QIODevice;
@ -45,11 +45,13 @@ class ASXParser : public XMLParser {
QString name() const override { return "ASX"; } QString name() const override { return "ASX"; }
QStringList file_extensions() const override { return QStringList() << "asx"; } QStringList file_extensions() const override { return QStringList() << "asx"; }
bool load_supported() const override { return true; }
bool save_supported() const override { return true; }
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 = QDir(), const bool collection_search = true) const override; SongList Load(QIODevice *device, const QString &playlist_path = "", const QDir &dir = QDir(), const bool collection_search = true) const override;
void Save(const SongList &songs, QIODevice *device, const QDir &dir = QDir(), Playlist::Path path_type = Playlist::Path_Automatic) const override; void Save(const SongList &songs, QIODevice *device, const QDir &dir = QDir(), const PlaylistSettingsPage::PathType path_type = PlaylistSettingsPage::PathType_Automatic) const override;
private: private:
Song ParseTrack(QXmlStreamReader *reader, const QDir &dir, const bool collection_search) const; Song ParseTrack(QXmlStreamReader *reader, const QDir &dir, const bool collection_search) const;

View File

@ -35,8 +35,9 @@
#include "core/logging.h" #include "core/logging.h"
#include "core/timeconstants.h" #include "core/timeconstants.h"
#include "settings/playlistsettingspage.h"
#include "parserbase.h"
#include "cueparser.h" #include "cueparser.h"
#include "playlistparsers/parserbase.h"
class CollectionBackendInterface; class CollectionBackendInterface;
@ -350,7 +351,7 @@ qint64 CueParser::IndexToMarker(const QString &index) {
} }
void CueParser::Save(const SongList &songs, QIODevice *device, const QDir &dir, Playlist::Path path_type) const { void CueParser::Save(const SongList &songs, QIODevice *device, const QDir &dir, const PlaylistSettingsPage::PathType path_type) const {
Q_UNUSED(songs); Q_UNUSED(songs);
Q_UNUSED(device); Q_UNUSED(device);

View File

@ -32,8 +32,8 @@
#include <QDir> #include <QDir>
#include "core/song.h" #include "core/song.h"
#include "settings/playlistsettingspage.h"
#include "parserbase.h" #include "parserbase.h"
#include "playlist/playlist.h"
class QIODevice; class QIODevice;
class CollectionBackendInterface; class CollectionBackendInterface;
@ -64,11 +64,13 @@ class CueParser : public ParserBase {
QString name() const override { return "CUE"; } QString name() const override { return "CUE"; }
QStringList file_extensions() const override { return QStringList() << "cue"; } QStringList file_extensions() const override { return QStringList() << "cue"; }
QString mime_type() const override { return "application/x-cue"; } QString mime_type() const override { return "application/x-cue"; }
bool load_supported() const override { return true; }
bool save_supported() const override { return false; }
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 = QDir(), const bool collection_search = true) const override; SongList Load(QIODevice *device, const QString &playlist_path = "", const QDir &dir = QDir(), const bool collection_search = true) const override;
void Save(const SongList &songs, QIODevice *device, const QDir &dir = QDir(), Playlist::Path path_type = Playlist::Path_Automatic) const override; void Save(const SongList &songs, QIODevice *device, const QDir &dir = QDir(), const PlaylistSettingsPage::PathType path_type = PlaylistSettingsPage::PathType_Automatic) const override;
static QString FindCueFilename(const QString &filename); static QString FindCueFilename(const QString &filename);

View File

@ -33,9 +33,9 @@
#include "core/logging.h" #include "core/logging.h"
#include "core/timeconstants.h" #include "core/timeconstants.h"
#include "settings/playlistsettingspage.h"
#include "parserbase.h"
#include "m3uparser.h" #include "m3uparser.h"
#include "playlist/playlist.h"
#include "playlistparsers/parserbase.h"
class CollectionBackendInterface; class CollectionBackendInterface;
@ -125,13 +125,13 @@ bool M3UParser::ParseMetadata(const QString &line, M3UParser::Metadata *metadata
} }
void M3UParser::Save(const SongList &songs, QIODevice *device, const QDir &dir, Playlist::Path path_type) const { void M3UParser::Save(const SongList &songs, QIODevice *device, const QDir &dir, const PlaylistSettingsPage::PathType path_type) const {
device->write("#EXTM3U\n"); device->write("#EXTM3U\n");
QSettings s; QSettings s;
s.beginGroup(Playlist::kSettingsGroup); s.beginGroup(PlaylistSettingsPage::kSettingsGroup);
bool write_metadata = s.value(Playlist::kWriteMetadata, true).toBool(); bool write_metadata = s.value("write_metadata", true).toBool();
s.endGroup(); s.endGroup();
for (const Song &song : songs) { for (const Song &song : songs) {

View File

@ -31,8 +31,8 @@
#include <QDir> #include <QDir>
#include "core/song.h" #include "core/song.h"
#include "settings/playlistsettingspage.h"
#include "parserbase.h" #include "parserbase.h"
#include "playlist/playlist.h"
class QIODevice; class QIODevice;
class CollectionBackendInterface; class CollectionBackendInterface;
@ -46,11 +46,13 @@ class M3UParser : public ParserBase {
QString name() const override { return "M3U"; } QString name() const override { return "M3U"; }
QStringList file_extensions() const override { return QStringList() << "m3u" << "m3u8"; } QStringList file_extensions() const override { return QStringList() << "m3u" << "m3u8"; }
QString mime_type() const override { return "text/uri-list"; } QString mime_type() const override { return "text/uri-list"; }
bool load_supported() const override { return true; }
bool save_supported() const override { return true; }
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 = QDir(), const bool collection_search = true) const override; SongList Load(QIODevice *device, const QString &playlist_path = "", const QDir &dir = QDir(), const bool collection_search = true) const override;
void Save(const SongList &songs, QIODevice *device, const QDir &dir = QDir(), Playlist::Path path_type = Playlist::Path_Automatic) const override; void Save(const SongList &songs, QIODevice *device, const QDir &dir = QDir(), const PlaylistSettingsPage::PathType path_type = PlaylistSettingsPage::PathType_Automatic) const override;
private: private:
enum M3UType { enum M3UType {

View File

@ -30,7 +30,7 @@
#include "core/logging.h" #include "core/logging.h"
#include "core/tagreaderclient.h" #include "core/tagreaderclient.h"
#include "collection/collectionbackend.h" #include "collection/collectionbackend.h"
#include "playlist/playlist.h" #include "settings/playlistsettingspage.h"
#include "parserbase.h" #include "parserbase.h"
ParserBase::ParserBase(CollectionBackendInterface *collection, QObject *parent) ParserBase::ParserBase(CollectionBackendInterface *collection, QObject *parent)
@ -101,19 +101,20 @@ Song ParserBase::LoadSong(const QString &filename_or_url, const qint64 beginning
} }
QString ParserBase::URLOrFilename(const QUrl &url, const QDir &dir, Playlist::Path path_type) { QString ParserBase::URLOrFilename(const QUrl &url, const QDir &dir, const PlaylistSettingsPage::PathType path_type) {
if (!url.isLocalFile()) return url.toString(); if (!url.isLocalFile()) return url.toString();
const QString filename = url.toLocalFile(); const QString filename = url.toLocalFile();
if (path_type != Playlist::Path_Absolute && QDir::isAbsolutePath(filename)) { if (path_type != PlaylistSettingsPage::PathType_Absolute && QDir::isAbsolutePath(filename)) {
const QString relative = dir.relativeFilePath(filename); const QString relative = dir.relativeFilePath(filename);
if (!relative.startsWith("../") || path_type == Playlist::Path_Relative) { if (!relative.startsWith("../") || path_type == PlaylistSettingsPage::PathType_Relative) {
return relative; return relative;
} }
} }
return filename; return filename;
} }

View File

@ -32,7 +32,7 @@
#include "config.h" #include "config.h"
#include "core/song.h" #include "core/song.h"
#include "playlist/playlist.h" #include "settings/playlistsettingspage.h"
class QIODevice; class QIODevice;
class CollectionBackendInterface; class CollectionBackendInterface;
@ -45,6 +45,8 @@ class ParserBase : public QObject {
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 save_supported() const = 0;
virtual QString mime_type() const { return QString(); } virtual QString mime_type() const { return QString(); }
virtual bool TryMagic(const QByteArray &data) const = 0; virtual bool TryMagic(const QByteArray &data) const = 0;
@ -55,7 +57,7 @@ class ParserBase : public QObject {
// 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 = "", const QDir &dir = QDir(), const bool collection_lookup = true) const = 0; virtual SongList Load(QIODevice *device, const QString &playlist_path = "", const QDir &dir = QDir(), const bool collection_lookup = true) const = 0;
virtual void Save(const SongList &songs, QIODevice *device, const QDir &dir = QDir(), Playlist::Path path_type = Playlist::Path_Automatic) const = 0; virtual void Save(const SongList &songs, QIODevice *device, const QDir &dir = QDir(), const PlaylistSettingsPage::PathType path_type = PlaylistSettingsPage::PathType_Automatic) const = 0;
protected: protected:
// Loads a song. If filename_or_url is a URL (with a scheme other than "file") then it is set on the song and the song marked as a stream. // Loads a song. If filename_or_url is a URL (with a scheme other than "file") then it is set on the song and the song marked as a stream.
@ -67,7 +69,7 @@ class ParserBase : public QObject {
// If the URL is a file:// URL then returns its path, absolute or relative to the directory depending on the path_type option. // If the URL is a file:// URL then returns its path, absolute or relative to the directory depending on the path_type option.
// Otherwise returns the URL as is. This function should always be used when saving a playlist. // Otherwise returns the URL as is. This function should always be used when saving a playlist.
static QString URLOrFilename(const QUrl &url, const QDir &dir, Playlist::Path path_type); static QString URLOrFilename(const QUrl &url, const QDir &dir, const PlaylistSettingsPage::PathType path_type);
private: private:
CollectionBackendInterface *collection_; CollectionBackendInterface *collection_;

View File

@ -31,13 +31,14 @@
#include <QStringList> #include <QStringList>
#include <QtDebug> #include <QtDebug>
#include "core/logging.h"
#include "settings/playlistsettingspage.h"
#include "playlistparser.h"
#include "parserbase.h"
#include "asxiniparser.h" #include "asxiniparser.h"
#include "asxparser.h" #include "asxparser.h"
#include "core/logging.h"
#include "cueparser.h" #include "cueparser.h"
#include "m3uparser.h" #include "m3uparser.h"
#include "playlistparser.h"
#include "playlistparsers/parserbase.h"
#include "plsparser.h" #include "plsparser.h"
#include "wplparser.h" #include "wplparser.h"
#include "xspfparser.h" #include "xspfparser.h"
@ -47,8 +48,8 @@ const int PlaylistParser::kMagicSize = 512;
PlaylistParser::PlaylistParser(CollectionBackendInterface *collection, QObject *parent) : QObject(parent) { PlaylistParser::PlaylistParser(CollectionBackendInterface *collection, QObject *parent) : QObject(parent) {
default_parser_ = new XSPFParser(collection, this); default_parser_ = new XSPFParser(collection, this);
parsers_ << new M3UParser(collection, this);
parsers_ << default_parser_; parsers_ << default_parser_;
parsers_ << new M3UParser(collection, this);
parsers_ << new PLSParser(collection, this); parsers_ << new PLSParser(collection, this);
parsers_ << new ASXParser(collection, this); parsers_ << new ASXParser(collection, this);
parsers_ << new AsxIniParser(collection, this); parsers_ << new AsxIniParser(collection, this);
@ -57,12 +58,14 @@ PlaylistParser::PlaylistParser(CollectionBackendInterface *collection, QObject *
} }
QStringList PlaylistParser::file_extensions() const { QStringList PlaylistParser::file_extensions(const Type type) const {
QStringList ret; QStringList ret;
for (ParserBase *parser : parsers_) { for (ParserBase *parser : parsers_) {
ret << parser->file_extensions(); if (ParserIsSupported(type, parser)) {
ret << parser->file_extensions();
}
} }
std::stable_sort(ret.begin(), ret.end()); std::stable_sort(ret.begin(), ret.end());
@ -70,29 +73,36 @@ QStringList PlaylistParser::file_extensions() const {
} }
QStringList PlaylistParser::mime_types() const { QStringList PlaylistParser::mime_types(const Type type) const {
QStringList ret; QStringList ret;
for (ParserBase *parser : parsers_) { for (ParserBase *parser : parsers_) {
if (!parser->mime_type().isEmpty()) ret << parser->mime_type(); if (ParserIsSupported(type, parser) && !parser->mime_type().isEmpty()) {
ret << parser->mime_type();
}
} }
std::stable_sort(ret.begin(), ret.end()); std::stable_sort(ret.begin(), ret.end());
return ret; return ret;
} }
QString PlaylistParser::filters() const { QString PlaylistParser::filters(const Type type) const {
QStringList filters; QStringList filters;
filters.reserve(parsers_.count() + 1); filters.reserve(parsers_.count() + 1);
QStringList all_extensions; QStringList all_extensions;
for (ParserBase *parser : parsers_) { for (ParserBase *parser : parsers_) {
filters << FilterForParser(parser, &all_extensions); if (ParserIsSupported(type, parser)) {
filters << FilterForParser(parser, &all_extensions);
}
} }
filters.prepend(tr("All playlists (%1)").arg(all_extensions.join(" "))); if (type == Type_Load) {
filters.prepend(tr("All playlists (%1)").arg(all_extensions.join(" ")));
}
return filters.join(";;"); return filters.join(";;");
@ -122,20 +132,22 @@ QString PlaylistParser::default_filter() const {
return FilterForParser(default_parser_); return FilterForParser(default_parser_);
} }
ParserBase *PlaylistParser::ParserForExtension(const QString &suffix) const { ParserBase *PlaylistParser::ParserForExtension(const Type type, const QString &suffix) const {
for (ParserBase *p : parsers_) { for (ParserBase *parser : parsers_) {
if (p->file_extensions().contains(suffix)) return p; if (ParserIsSupported(type, parser) && parser->file_extensions().contains(suffix)) {
return parser;
}
} }
return nullptr; return nullptr;
} }
ParserBase *PlaylistParser::ParserForMimeType(const QString &mime_type) const { ParserBase *PlaylistParser::ParserForMimeType(const Type type, const QString &mime_type) const {
for (ParserBase *p : parsers_) { for (ParserBase *parser : parsers_) {
if (!p->mime_type().isEmpty() && (QString::compare(p->mime_type(), mime_type, Qt::CaseInsensitive) == 0)) { if (ParserIsSupported(type, parser) && !parser->mime_type().isEmpty() && QString::compare(parser->mime_type(), mime_type, Qt::CaseInsensitive) == 0) {
return p; return parser;
} }
} }
return nullptr; return nullptr;
@ -144,9 +156,9 @@ ParserBase *PlaylistParser::ParserForMimeType(const QString &mime_type) const {
ParserBase *PlaylistParser::ParserForMagic(const QByteArray &data, const QString &mime_type) const { ParserBase *PlaylistParser::ParserForMagic(const QByteArray &data, const QString &mime_type) const {
for (ParserBase *p : parsers_) { for (ParserBase *parser : parsers_) {
if ((!mime_type.isEmpty() && mime_type == p->mime_type()) || p->TryMagic(data)) { if ((!mime_type.isEmpty() && mime_type == parser->mime_type()) || parser->TryMagic(data)) {
return p; return parser;
} }
} }
return nullptr; return nullptr;
@ -155,10 +167,10 @@ ParserBase *PlaylistParser::ParserForMagic(const QByteArray &data, const QString
SongList PlaylistParser::LoadFromFile(const QString &filename) const { SongList PlaylistParser::LoadFromFile(const QString &filename) const {
QFileInfo info(filename); QFileInfo fileinfo(filename);
// Find a parser that supports this file extension // Find a parser that supports this file extension
ParserBase *parser = ParserForExtension(info.suffix()); ParserBase *parser = ParserForExtension(Type_Load, fileinfo.suffix());
if (!parser) { if (!parser) {
qLog(Warning) << "Unknown filetype:" << filename; qLog(Warning) << "Unknown filetype:" << filename;
return SongList(); return SongList();
@ -168,7 +180,7 @@ SongList PlaylistParser::LoadFromFile(const QString &filename) const {
QFile file(filename); QFile file(filename);
if (!file.open(QIODevice::ReadOnly)) return SongList(); if (!file.open(QIODevice::ReadOnly)) return SongList();
SongList ret = parser->Load(&file, filename, info.absolutePath()); SongList ret = parser->Load(&file, filename, fileinfo.absolutePath());
file.close(); file.close();
return ret; return ret;
@ -187,12 +199,12 @@ SongList PlaylistParser::LoadFromDevice(QIODevice *device, const QString &path_h
} }
void PlaylistParser::Save(const SongList &songs, const QString &filename, const Playlist::Path path_type) const { void PlaylistParser::Save(const SongList &songs, const QString &filename, const PlaylistSettingsPage::PathType path_type) const {
QFileInfo info(filename); QFileInfo fileinfo(filename);
// Find a parser that supports this file extension // Find a parser that supports this file extension
ParserBase *parser = ParserForExtension(info.suffix()); ParserBase *parser = ParserForExtension(Type_Save, fileinfo.suffix());
if (!parser) { if (!parser) {
qLog(Warning) << "Unknown filetype:" << filename; qLog(Warning) << "Unknown filetype:" << filename;
return; return;
@ -202,8 +214,14 @@ void PlaylistParser::Save(const SongList &songs, const QString &filename, const
QFile file(filename); QFile file(filename);
if (!file.open(QIODevice::WriteOnly)) return; if (!file.open(QIODevice::WriteOnly)) return;
parser->Save(songs, &file, info.absolutePath(), path_type); parser->Save(songs, &file, fileinfo.absolutePath(), path_type);
file.close(); file.close();
} }
bool PlaylistParser::ParserIsSupported(const Type type, ParserBase *parser) const {
return ((type == Type_Load && parser->load_supported()) || (type == Type_Save && parser->save_supported()));
}

View File

@ -21,6 +21,8 @@
#ifndef PLAYLISTPARSER_H #ifndef PLAYLISTPARSER_H
#define PLAYLISTPARSER_H #define PLAYLISTPARSER_H
#include "config.h"
#include <QObject> #include <QObject>
#include <QDir> #include <QDir>
#include <QByteArray> #include <QByteArray>
@ -28,9 +30,8 @@
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
#include "config.h"
#include "core/song.h" #include "core/song.h"
#include "playlist/playlist.h" #include "settings/playlistsettingspage.h"
class QIODevice; class QIODevice;
class CollectionBackendInterface; class CollectionBackendInterface;
@ -42,28 +43,34 @@ class PlaylistParser : public QObject {
public: public:
explicit PlaylistParser(CollectionBackendInterface *collection = nullptr, QObject *parent = nullptr); explicit PlaylistParser(CollectionBackendInterface *collection = nullptr, QObject *parent = nullptr);
enum Type {
Type_Load,
Type_Save,
};
static const int kMagicSize; static const int kMagicSize;
QStringList file_extensions() const; QStringList file_extensions(const Type type) const;
QString filters() const; QString filters(const Type type) const;
QStringList mime_types() const; QStringList mime_types(const Type type) const;
QString default_extension() const; QString default_extension() const;
QString default_filter() const; QString default_filter() const;
ParserBase *ParserForMagic(const QByteArray &data, const QString &mime_type = QString()) const; ParserBase *ParserForMagic(const QByteArray &data, const QString &mime_type = QString()) const;
ParserBase *ParserForExtension(const QString &suffix) const; ParserBase *ParserForExtension(const Type type, const QString &suffix) const;
ParserBase *ParserForMimeType(const QString &mime) const; ParserBase *ParserForMimeType(const Type type, const QString &mime) const;
SongList LoadFromFile(const QString &filename) const; SongList LoadFromFile(const QString &filename) const;
SongList LoadFromDevice(QIODevice *device, const QString &path_hint = QString(), const QDir &dir_hint = QDir()) const; SongList LoadFromDevice(QIODevice *device, const QString &path_hint = QString(), const QDir &dir_hint = QDir()) const;
void Save(const SongList &songs, const QString &filename, const Playlist::Path) const; void Save(const SongList &songs, const QString &filename, const PlaylistSettingsPage::PathType) const;
private: private:
bool ParserIsSupported(const Type type, ParserBase *parser) const;
static QString FilterForParser(const ParserBase *parser, QStringList *all_extensions = nullptr); static QString FilterForParser(const ParserBase *parser, QStringList *all_extensions = nullptr);
private: private:
QList<ParserBase*> parsers_; QList<ParserBase*> parsers_;
ParserBase *default_parser_; ParserBase *default_parser_;
}; };

View File

@ -30,7 +30,8 @@
#include <QTextStream> #include <QTextStream>
#include "core/timeconstants.h" #include "core/timeconstants.h"
#include "playlistparsers/parserbase.h" #include "settings/playlistsettingspage.h"
#include "parserbase.h"
#include "plsparser.h" #include "plsparser.h"
class CollectionBackendInterface; class CollectionBackendInterface;
@ -86,7 +87,7 @@ SongList PLSParser::Load(QIODevice *device, const QString &playlist_path, const
} }
void PLSParser::Save(const SongList &songs, QIODevice *device, const QDir &dir, Playlist::Path path_type) const { void PLSParser::Save(const SongList &songs, QIODevice *device, const QDir &dir, const PlaylistSettingsPage::PathType path_type) const {
QTextStream s(device); QTextStream s(device);
s << "[playlist]" << qt_endl; s << "[playlist]" << qt_endl;

View File

@ -21,16 +21,17 @@
#ifndef PLSPARSER_H #ifndef PLSPARSER_H
#define PLSPARSER_H #define PLSPARSER_H
#include "config.h"
#include <QObject> #include <QObject>
#include <QDir> #include <QDir>
#include <QByteArray> #include <QByteArray>
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
#include "config.h"
#include "core/song.h" #include "core/song.h"
#include "settings/playlistsettingspage.h"
#include "parserbase.h" #include "parserbase.h"
#include "playlist/playlist.h"
class QIODevice; class QIODevice;
class CollectionBackendInterface; class CollectionBackendInterface;
@ -44,11 +45,13 @@ class PLSParser : public ParserBase {
QString name() const override { return "PLS"; } QString name() const override { return "PLS"; }
QStringList file_extensions() const override { return QStringList() << "pls"; } QStringList file_extensions() const override { return QStringList() << "pls"; }
QString mime_type() const override { return "audio/x-scpls"; } QString mime_type() const override { return "audio/x-scpls"; }
bool load_supported() const override { return true; }
bool save_supported() const override { return true; }
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 = QDir(), const bool collection_search = true) const override; SongList Load(QIODevice *device, const QString &playlist_path = "", const QDir &dir = QDir(), const bool collection_search = true) const override;
void Save(const SongList &songs, QIODevice *device, const QDir &dir = QDir(), Playlist::Path path_type = Playlist::Path_Automatic) const override; void Save(const SongList &songs, QIODevice *device, const QDir &dir = QDir(), const PlaylistSettingsPage::PathType path_type = PlaylistSettingsPage::PathType_Automatic) const override;
}; };
#endif // PLSPARSER_H #endif // PLSPARSER_H

View File

@ -18,6 +18,8 @@
* *
*/ */
#include "version.h"
#include <QtGlobal> #include <QtGlobal>
#include <QObject> #include <QObject>
#include <QIODevice> #include <QIODevice>
@ -28,8 +30,8 @@
#include <QXmlStreamWriter> #include <QXmlStreamWriter>
#include "core/utilities.h" #include "core/utilities.h"
#include "playlistparsers/xmlparser.h" #include "settings/playlistsettingspage.h"
#include "version.h" #include "xmlparser.h"
#include "wplparser.h" #include "wplparser.h"
class CollectionBackendInterface; class CollectionBackendInterface;
@ -93,7 +95,7 @@ void WplParser::ParseSeq(const QDir &dir, QXmlStreamReader *reader, SongList *so
} }
void WplParser::Save(const SongList &songs, QIODevice *device, const QDir &dir, Playlist::Path path_type) const { void WplParser::Save(const SongList &songs, QIODevice *device, const QDir &dir, const PlaylistSettingsPage::PathType path_type) const {
QXmlStreamWriter writer(device); QXmlStreamWriter writer(device);
writer.setAutoFormatting(true); writer.setAutoFormatting(true);

View File

@ -21,15 +21,16 @@
#ifndef WPLPARSER_H #ifndef WPLPARSER_H
#define WPLPARSER_H #define WPLPARSER_H
#include "config.h"
#include <QObject> #include <QObject>
#include <QDir> #include <QDir>
#include <QByteArray> #include <QByteArray>
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
#include "config.h"
#include "core/song.h" #include "core/song.h"
#include "playlist/playlist.h" #include "settings/playlistsettingspage.h"
#include "xmlparser.h" #include "xmlparser.h"
class QIODevice; class QIODevice;
@ -47,11 +48,13 @@ class WplParser : public XMLParser {
QString name() const override { return "WPL"; } QString name() const override { return "WPL"; }
QStringList file_extensions() const override { return QStringList() << "wpl"; } QStringList file_extensions() const override { return QStringList() << "wpl"; }
QString mime_type() const override { return "application/vnd.ms-wpl"; } QString mime_type() const override { return "application/vnd.ms-wpl"; }
bool load_supported() const override { return true; }
bool save_supported() const override { return true; }
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_search = true) const override; SongList Load(QIODevice *device, const QString &playlist_path, const QDir &dir, const bool collection_search = true) const override;
void Save(const SongList &songs, QIODevice *device, const QDir &dir, Playlist::Path path_type = Playlist::Path_Automatic) const override; void Save(const SongList &songs, QIODevice *device, const QDir &dir, const PlaylistSettingsPage::PathType path_type = PlaylistSettingsPage::PathType_Automatic) const override;
private: private:
void ParseSeq(const QDir &dir, QXmlStreamReader *reader, SongList *songs, const bool collection_search = true) const; void ParseSeq(const QDir &dir, QXmlStreamReader *reader, SongList *songs, const bool collection_search = true) const;

View File

@ -18,11 +18,11 @@
* *
*/ */
#include "playlistparsers/parserbase.h"
#include "xmlparser.h"
#include <QObject> #include <QObject>
#include "parserbase.h"
#include "xmlparser.h"
class CollectionBackendInterface; class CollectionBackendInterface;
XMLParser::XMLParser(CollectionBackendInterface *collection, QObject *parent) XMLParser::XMLParser(CollectionBackendInterface *collection, QObject *parent)

View File

@ -33,8 +33,8 @@
#include "core/timeconstants.h" #include "core/timeconstants.h"
#include "core/utilities.h" #include "core/utilities.h"
#include "playlist/playlist.h" #include "settings/playlistsettingspage.h"
#include "playlistparsers/xmlparser.h" #include "xmlparser.h"
#include "xspfparser.h" #include "xspfparser.h"
class CollectionBackendInterface; class CollectionBackendInterface;
@ -137,7 +137,7 @@ return_song:
} }
void XSPFParser::Save(const SongList &songs, QIODevice *device, const QDir &dir, Playlist::Path path_type) const { void XSPFParser::Save(const SongList &songs, QIODevice *device, const QDir &dir, const PlaylistSettingsPage::PathType path_type) const {
QXmlStreamWriter writer(device); QXmlStreamWriter writer(device);
writer.setAutoFormatting(true); writer.setAutoFormatting(true);
@ -148,8 +148,8 @@ void XSPFParser::Save(const SongList &songs, QIODevice *device, const QDir &dir,
writer.writeDefaultNamespace("http://xspf.org/ns/0/"); writer.writeDefaultNamespace("http://xspf.org/ns/0/");
QSettings s; QSettings s;
s.beginGroup(Playlist::kSettingsGroup); s.beginGroup(PlaylistSettingsPage::kSettingsGroup);
bool write_metadata = s.value(Playlist::kWriteMetadata, true).toBool(); bool write_metadata = s.value("write_metadata", true).toBool();
s.endGroup(); s.endGroup();
StreamElement tracklist("trackList", &writer); StreamElement tracklist("trackList", &writer);

View File

@ -30,7 +30,7 @@
#include <QStringList> #include <QStringList>
#include "core/song.h" #include "core/song.h"
#include "playlist/playlist.h" #include "settings/playlistsettingspage.h"
#include "xmlparser.h" #include "xmlparser.h"
class QIODevice; class QIODevice;
@ -45,11 +45,13 @@ class XSPFParser : public XMLParser {
QString name() const override { return "XSPF"; } QString name() const override { return "XSPF"; }
QStringList file_extensions() const override { return QStringList() << "xspf"; } QStringList file_extensions() const override { return QStringList() << "xspf"; }
bool load_supported() const override { return true; }
bool save_supported() const override { return true; }
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 = QDir(), const bool collection_search = true) const override; SongList Load(QIODevice *device, const QString &playlist_path = "", const QDir &dir = QDir(), const bool collection_search = true) const override;
void Save(const SongList &songs, QIODevice *device, const QDir &dir = QDir(), Playlist::Path path_type = Playlist::Path_Automatic) const override; void Save(const SongList &songs, QIODevice *device, const QDir &dir = QDir(), const PlaylistSettingsPage::PathType path_type = PlaylistSettingsPage::PathType_Automatic) const override;
private: private:
Song ParseTrack(QXmlStreamReader *reader, const QDir &dir, const bool collection_search) const; Song ParseTrack(QXmlStreamReader *reader, const QDir &dir, const bool collection_search) const;

View File

@ -72,23 +72,23 @@ void PlaylistSettingsPage::Load() {
ui_->checkbox_playlist_clear->setChecked(s.value("playlist_clear", true).toBool()); ui_->checkbox_playlist_clear->setChecked(s.value("playlist_clear", true).toBool());
ui_->checkbox_auto_sort->setChecked(s.value("auto_sort", false).toBool()); ui_->checkbox_auto_sort->setChecked(s.value("auto_sort", false).toBool());
Playlist::Path path = Playlist::Path(s.value(Playlist::kPathType, Playlist::Path_Automatic).toInt()); PathType path_type = PathType(s.value("path_type", PathType_Automatic).toInt());
switch (path) { switch (path_type) {
case Playlist::Path_Automatic: case PathType_Automatic:
ui_->radiobutton_automaticpath->setChecked(true); ui_->radiobutton_automaticpath->setChecked(true);
break; break;
case Playlist::Path_Absolute: case PathType_Absolute:
ui_->radiobutton_absolutepath->setChecked(true); ui_->radiobutton_absolutepath->setChecked(true);
break; break;
case Playlist::Path_Relative: case PathType_Relative:
ui_->radiobutton_relativepath->setChecked(true); ui_->radiobutton_relativepath->setChecked(true);
break; break;
case Playlist::Path_Ask_User: case PathType_Ask_User:
ui_->radiobutton_askpath->setChecked(true); ui_->radiobutton_askpath->setChecked(true);
} }
ui_->checkbox_editmetadatainline->setChecked(s.value("editmetadatainline", false).toBool()); ui_->checkbox_editmetadatainline->setChecked(s.value("editmetadatainline", false).toBool());
ui_->checkbox_writemetadata->setChecked(s.value(Playlist::kWriteMetadata, false).toBool()); ui_->checkbox_writemetadata->setChecked(s.value("write_metadata", false).toBool());
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
ui_->checkbox_delete_files->setChecked(s.value("delete_files", false).toBool()); ui_->checkbox_delete_files->setChecked(s.value("delete_files", false).toBool());
@ -107,18 +107,18 @@ void PlaylistSettingsPage::Load() {
void PlaylistSettingsPage::Save() { void PlaylistSettingsPage::Save() {
Playlist::Path path = Playlist::Path_Automatic; PathType path_type = PathType_Automatic;
if (ui_->radiobutton_automaticpath->isChecked()) { if (ui_->radiobutton_automaticpath->isChecked()) {
path = Playlist::Path_Automatic; path_type = PathType_Automatic;
} }
else if (ui_->radiobutton_absolutepath->isChecked()) { else if (ui_->radiobutton_absolutepath->isChecked()) {
path = Playlist::Path_Absolute; path_type = PathType_Absolute;
} }
else if (ui_->radiobutton_relativepath->isChecked()) { else if (ui_->radiobutton_relativepath->isChecked()) {
path = Playlist::Path_Relative; path_type = PathType_Relative;
} }
else if (ui_->radiobutton_askpath->isChecked()) { else if (ui_->radiobutton_askpath->isChecked()) {
path = Playlist::Path_Ask_User; path_type = PathType_Ask_User;
} }
QSettings s; QSettings s;
@ -132,9 +132,9 @@ void PlaylistSettingsPage::Save() {
s.setValue("select_track", ui_->checkbox_select_track->isChecked()); s.setValue("select_track", ui_->checkbox_select_track->isChecked());
s.setValue("show_toolbar", ui_->checkbox_show_toolbar->isChecked()); s.setValue("show_toolbar", ui_->checkbox_show_toolbar->isChecked());
s.setValue("playlist_clear", ui_->checkbox_playlist_clear->isChecked()); s.setValue("playlist_clear", ui_->checkbox_playlist_clear->isChecked());
s.setValue(Playlist::kPathType, static_cast<int>(path)); s.setValue("path_type", static_cast<int>(path_type));
s.setValue("editmetadatainline", ui_->checkbox_editmetadatainline->isChecked()); s.setValue("editmetadatainline", ui_->checkbox_editmetadatainline->isChecked());
s.setValue(Playlist::kWriteMetadata, ui_->checkbox_writemetadata->isChecked()); s.setValue("write_metadata", ui_->checkbox_writemetadata->isChecked());
s.setValue("delete_files", ui_->checkbox_delete_files->isChecked()); s.setValue("delete_files", ui_->checkbox_delete_files->isChecked());
s.setValue("auto_sort", ui_->checkbox_auto_sort->isChecked()); s.setValue("auto_sort", ui_->checkbox_auto_sort->isChecked());
s.endGroup(); s.endGroup();

View File

@ -38,8 +38,16 @@ class PlaylistSettingsPage : public SettingsPage {
public: public:
explicit PlaylistSettingsPage(SettingsDialog *dialog, QWidget *parent = nullptr); explicit PlaylistSettingsPage(SettingsDialog *dialog, QWidget *parent = nullptr);
~PlaylistSettingsPage() override; ~PlaylistSettingsPage() override;
static const char *kSettingsGroup; static const char *kSettingsGroup;
enum PathType {
PathType_Automatic = 0, // Automatically select path type
PathType_Absolute, // Always use absolute paths
PathType_Relative, // Always use relative paths
PathType_Ask_User, // Only used in preferences: to ask user which of the previous values he wants to use.
};
void Load() override; void Load() override;
void Save() override; void Save() override;