/* * Strawberry Music Player * This file was part of Clementine. * Copyright 2010, David Sansome * * Strawberry is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Strawberry is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Strawberry. If not, see . * */ #include #include #include #include #include #include #include #include #include #include "core/logging.h" #include "settings/playlistsettingspage.h" #include "playlistparser.h" #include "parserbase.h" #include "asxiniparser.h" #include "asxparser.h" #include "cueparser.h" #include "m3uparser.h" #include "plsparser.h" #include "wplparser.h" #include "xspfparser.h" const int PlaylistParser::kMagicSize = 512; PlaylistParser::PlaylistParser(CollectionBackendInterface *collection, QObject *parent) : QObject(parent) { default_parser_ = new XSPFParser(collection, this); parsers_ << default_parser_; parsers_ << new M3UParser(collection, this); parsers_ << new PLSParser(collection, this); parsers_ << new ASXParser(collection, this); parsers_ << new AsxIniParser(collection, this); parsers_ << new CueParser(collection, this); parsers_ << new WplParser(collection, this); } QStringList PlaylistParser::file_extensions(const Type type) const { QStringList ret; for (ParserBase *parser : parsers_) { if (ParserIsSupported(type, parser)) { ret << parser->file_extensions(); } } std::stable_sort(ret.begin(), ret.end()); return ret; } QStringList PlaylistParser::mime_types(const Type type) const { QStringList ret; for (ParserBase *parser : parsers_) { if (ParserIsSupported(type, parser) && !parser->mime_type().isEmpty()) { ret << parser->mime_type(); } } std::stable_sort(ret.begin(), ret.end()); return ret; } QString PlaylistParser::filters(const Type type) const { QStringList filters; filters.reserve(parsers_.count() + 1); QStringList all_extensions; for (ParserBase *parser : parsers_) { if (ParserIsSupported(type, parser)) { filters << FilterForParser(parser, &all_extensions); } } if (type == Type_Load) { filters.prepend(tr("All playlists (%1)").arg(all_extensions.join(" "))); } return filters.join(";;"); } QString PlaylistParser::FilterForParser(const ParserBase *parser, QStringList *all_extensions) { const QStringList file_extensions = parser->file_extensions(); QStringList extensions; extensions.reserve(file_extensions.count()); for (const QString &extension : file_extensions) { extensions << "*." + extension; } if (all_extensions) *all_extensions << extensions; return tr("%1 playlists (%2)").arg(parser->name(), extensions.join(" ")); } QString PlaylistParser::default_extension() const { QStringList file_extensions = default_parser_->file_extensions(); return file_extensions[0]; } QString PlaylistParser::default_filter() const { return FilterForParser(default_parser_); } ParserBase *PlaylistParser::ParserForExtension(const Type type, const QString &suffix) const { for (ParserBase *parser : parsers_) { if (ParserIsSupported(type, parser) && parser->file_extensions().contains(suffix, Qt::CaseInsensitive)) { return parser; } } return nullptr; } ParserBase *PlaylistParser::ParserForMimeType(const Type type, const QString &mime_type) const { for (ParserBase *parser : parsers_) { if (ParserIsSupported(type, parser) && !parser->mime_type().isEmpty() && QString::compare(parser->mime_type(), mime_type, Qt::CaseInsensitive) == 0) { return parser; } } return nullptr; } ParserBase *PlaylistParser::ParserForMagic(const QByteArray &data, const QString &mime_type) const { for (ParserBase *parser : parsers_) { if ((!mime_type.isEmpty() && mime_type == parser->mime_type()) || parser->TryMagic(data)) { return parser; } } return nullptr; } SongList PlaylistParser::LoadFromFile(const QString &filename) const { QFileInfo fileinfo(filename); // Find a parser that supports this file extension ParserBase *parser = ParserForExtension(Type_Load, fileinfo.suffix()); if (!parser) { qLog(Warning) << "Unknown filetype:" << filename; return SongList(); } // Open the file QFile file(filename); if (!file.open(QIODevice::ReadOnly)) return SongList(); SongList ret = parser->Load(&file, filename, fileinfo.absolutePath()); file.close(); return ret; } SongList PlaylistParser::LoadFromDevice(QIODevice *device, const QString &path_hint, const QDir &dir_hint) const { // Find a parser that supports this data ParserBase *parser = ParserForMagic(device->peek(kMagicSize)); if (!parser) { return SongList(); } return parser->Load(device, path_hint, dir_hint); } void PlaylistParser::Save(const SongList &songs, const QString &filename, const PlaylistSettingsPage::PathType path_type) const { QFileInfo fileinfo(filename); QDir dir(fileinfo.path()); if (!dir.exists()) { qLog(Warning) << "Directory does not exist" << dir.path(); return; } // Find a parser that supports this file extension ParserBase *parser = ParserForExtension(Type_Save, fileinfo.suffix()); if (!parser) { qLog(Warning) << "Unknown filetype" << filename; return; } if (path_type == PlaylistSettingsPage::PathType_Absolute && dir.path() != dir.absolutePath()) { dir.setPath(dir.absolutePath()); } else if (path_type != PlaylistSettingsPage::PathType_Absolute && !dir.canonicalPath().isEmpty() && dir.path() != dir.canonicalPath()) { dir.setPath(dir.canonicalPath()); } // Open the file QFile file(fileinfo.absoluteFilePath()); if (!file.open(QIODevice::WriteOnly)) { qLog(Warning) << "Failed to open" << filename << "for writing."; return; } parser->Save(songs, &file, dir, path_type); file.close(); } bool PlaylistParser::ParserIsSupported(const Type type, ParserBase *parser) const { return ((type == Type_Load && parser->load_supported()) || (type == Type_Save && parser->save_supported())); }