playlist/*: move to playlist/plugins/

This commit is contained in:
Max Kellermann
2014-01-23 23:30:12 +01:00
parent 655ad34414
commit f1f19841bd
45 changed files with 178 additions and 125 deletions

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "MemorySongEnumerator.hxx"
DetachedSong *
MemorySongEnumerator::NextSong()
{
if (songs.empty())
return nullptr;
auto result = new DetachedSong(std::move(songs.front()));
songs.pop_front();
return result;
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_MEMORY_PLAYLIST_PROVIDER_HXX
#define MPD_MEMORY_PLAYLIST_PROVIDER_HXX
#include "SongEnumerator.hxx"
#include "DetachedSong.hxx"
#include <forward_list>
class MemorySongEnumerator final : public SongEnumerator {
std::forward_list<DetachedSong> songs;
public:
MemorySongEnumerator(std::forward_list<DetachedSong> &&_songs)
:songs(std::move(_songs)) {}
virtual DetachedSong *NextSong() override;
};
#endif

View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "PlaylistAny.hxx"
#include "PlaylistMapper.hxx"
#include "PlaylistRegistry.hxx"
#include "util/UriUtil.hxx"
#include "util/Error.hxx"
#include "InputStream.hxx"
#include "Log.hxx"
#include <assert.h>
static SongEnumerator *
playlist_open_remote(const char *uri, Mutex &mutex, Cond &cond,
InputStream **is_r)
{
assert(uri_has_scheme(uri));
SongEnumerator *playlist = playlist_list_open_uri(uri, mutex, cond);
if (playlist != nullptr) {
*is_r = nullptr;
return playlist;
}
Error error;
InputStream *is = InputStream::OpenReady(uri, mutex, cond, error);
if (is == nullptr) {
if (error.IsDefined())
FormatError(error, "Failed to open %s", uri);
return nullptr;
}
playlist = playlist_list_open_stream(*is, uri);
if (playlist == nullptr) {
is->Close();
return nullptr;
}
*is_r = is;
return playlist;
}
SongEnumerator *
playlist_open_any(const char *uri, Mutex &mutex, Cond &cond,
InputStream **is_r)
{
return uri_has_scheme(uri)
? playlist_open_remote(uri, mutex, cond, is_r)
: playlist_mapper_open(uri, mutex, cond, is_r);
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_PLAYLIST_ANY_HXX
#define MPD_PLAYLIST_ANY_HXX
class Mutex;
class Cond;
class SongEnumerator;
struct InputStream;
/**
* Opens a playlist from the specified URI, which can be either an
* absolute remote URI (with a scheme) or a relative path to the
* music orplaylist directory.
*
* @param is_r on success, an input_stream object may be returned
* here, which must be closed after the playlist_provider object is
* freed
*/
SongEnumerator *
playlist_open_any(const char *uri, Mutex &mutex, Cond &cond,
InputStream **is_r);
#endif

View File

@@ -0,0 +1,102 @@
/*
* Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "PlaylistMapper.hxx"
#include "PlaylistFile.hxx"
#include "PlaylistRegistry.hxx"
#include "Mapper.hxx"
#include "fs/AllocatedPath.hxx"
#include "util/UriUtil.hxx"
#include <assert.h>
static SongEnumerator *
playlist_open_path(const char *path_fs, Mutex &mutex, Cond &cond,
InputStream **is_r)
{
auto playlist = playlist_list_open_uri(path_fs, mutex, cond);
if (playlist != nullptr)
*is_r = nullptr;
else
playlist = playlist_list_open_path(path_fs, mutex, cond, is_r);
return playlist;
}
/**
* Load a playlist from the configured playlist directory.
*/
static SongEnumerator *
playlist_open_in_playlist_dir(const char *uri, Mutex &mutex, Cond &cond,
InputStream **is_r)
{
assert(spl_valid_name(uri));
const auto &playlist_directory_fs = map_spl_path();
if (playlist_directory_fs.IsNull())
return nullptr;
const auto uri_fs = AllocatedPath::FromUTF8(uri);
if (uri_fs.IsNull())
return nullptr;
const auto path_fs =
AllocatedPath::Build(playlist_directory_fs, uri_fs);
assert(!path_fs.IsNull());
return playlist_open_path(path_fs.c_str(), mutex, cond, is_r);
}
/**
* Load a playlist from the configured music directory.
*/
static SongEnumerator *
playlist_open_in_music_dir(const char *uri, Mutex &mutex, Cond &cond,
InputStream **is_r)
{
assert(uri_safe_local(uri));
const auto path = map_uri_fs(uri);
if (path.IsNull())
return nullptr;
return playlist_open_path(path.c_str(), mutex, cond, is_r);
}
SongEnumerator *
playlist_mapper_open(const char *uri, Mutex &mutex, Cond &cond,
InputStream **is_r)
{
if (spl_valid_name(uri)) {
auto playlist = playlist_open_in_playlist_dir(uri, mutex, cond,
is_r);
if (playlist != nullptr)
return playlist;
}
if (uri_safe_local(uri)) {
auto playlist = playlist_open_in_music_dir(uri, mutex, cond,
is_r);
if (playlist != nullptr)
return playlist;
}
return nullptr;
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_PLAYLIST_MAPPER_HXX
#define MPD_PLAYLIST_MAPPER_HXX
class Mutex;
class Cond;
class SongEnumerator;
struct InputStream;
/**
* Opens a playlist from an URI relative to the playlist or music
* directory.
*
* @param is_r on success, an input_stream object may be returned
* here, which must be closed after the playlist_provider object is
* freed
*/
SongEnumerator *
playlist_mapper_open(const char *uri, Mutex &mutex, Cond &cond,
InputStream **is_r);
#endif

View File

@@ -0,0 +1,109 @@
/*
* Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_PLAYLIST_PLUGIN_HXX
#define MPD_PLAYLIST_PLUGIN_HXX
struct config_param;
struct InputStream;
struct Tag;
class Mutex;
class Cond;
class SongEnumerator;
struct playlist_plugin {
const char *name;
/**
* Initialize the plugin. Optional method.
*
* @param param a configuration block for this plugin, or nullptr
* if none is configured
* @return true if the plugin was initialized successfully,
* false if the plugin is not available
*/
bool (*init)(const config_param &param);
/**
* Deinitialize a plugin which was initialized successfully.
* Optional method.
*/
void (*finish)(void);
/**
* Opens the playlist on the specified URI. This URI has
* either matched one of the schemes or one of the suffixes.
*/
SongEnumerator *(*open_uri)(const char *uri,
Mutex &mutex, Cond &cond);
/**
* Opens the playlist in the specified input stream. It has
* either matched one of the suffixes or one of the MIME
* types.
*/
SongEnumerator *(*open_stream)(InputStream &is);
const char *const*schemes;
const char *const*suffixes;
const char *const*mime_types;
};
/**
* Initialize a plugin.
*
* @param param a configuration block for this plugin, or nullptr if none
* is configured
* @return true if the plugin was initialized successfully, false if
* the plugin is not available
*/
static inline bool
playlist_plugin_init(const struct playlist_plugin *plugin,
const config_param &param)
{
return plugin->init != nullptr
? plugin->init(param)
: true;
}
/**
* Deinitialize a plugin which was initialized successfully.
*/
static inline void
playlist_plugin_finish(const struct playlist_plugin *plugin)
{
if (plugin->finish != nullptr)
plugin->finish();
}
static inline SongEnumerator *
playlist_plugin_open_uri(const struct playlist_plugin *plugin, const char *uri,
Mutex &mutex, Cond &cond)
{
return plugin->open_uri(uri, mutex, cond);
}
static inline SongEnumerator *
playlist_plugin_open_stream(const struct playlist_plugin *plugin,
InputStream &is)
{
return plugin->open_stream(is);
}
#endif

View File

@@ -0,0 +1,90 @@
/*
* Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "PlaylistQueue.hxx"
#include "PlaylistAny.hxx"
#include "PlaylistSong.hxx"
#include "Playlist.hxx"
#include "InputStream.hxx"
#include "SongEnumerator.hxx"
#include "DetachedSong.hxx"
#include "thread/Cond.hxx"
#include "fs/Traits.hxx"
PlaylistResult
playlist_load_into_queue(const char *uri, SongEnumerator &e,
unsigned start_index, unsigned end_index,
playlist &dest, PlayerControl &pc,
bool secure)
{
const std::string base_uri = uri != nullptr
? PathTraitsUTF8::GetParent(uri)
: std::string(".");
DetachedSong *song;
for (unsigned i = 0;
i < end_index && (song = e.NextSong()) != nullptr;
++i) {
if (i < start_index) {
/* skip songs before the start index */
delete song;
continue;
}
if (!playlist_check_translate_song(*song, base_uri.c_str(),
secure)) {
delete song;
continue;
}
PlaylistResult result = dest.AppendSong(pc, std::move(*song));
delete song;
if (result != PlaylistResult::SUCCESS)
return result;
}
return PlaylistResult::SUCCESS;
}
PlaylistResult
playlist_open_into_queue(const char *uri,
unsigned start_index, unsigned end_index,
playlist &dest, PlayerControl &pc,
bool secure)
{
Mutex mutex;
Cond cond;
InputStream *is;
auto playlist = playlist_open_any(uri, mutex, cond, &is);
if (playlist == nullptr)
return PlaylistResult::NO_SUCH_LIST;
PlaylistResult result =
playlist_load_into_queue(uri, *playlist,
start_index, end_index,
dest, pc, secure);
delete playlist;
if (is != nullptr)
is->Close();
return result;
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*! \file
* \brief Glue between playlist plugin and the play queue
*/
#ifndef MPD_PLAYLIST_QUEUE_HXX
#define MPD_PLAYLIST_QUEUE_HXX
#include "PlaylistError.hxx"
class SongEnumerator;
struct playlist;
struct PlayerControl;
/**
* Loads the contents of a playlist and append it to the specified
* play queue.
*
* @param uri the URI of the playlist, used to resolve relative song
* URIs
* @param start_index the index of the first song
* @param end_index the index of the last song (excluding)
*/
PlaylistResult
playlist_load_into_queue(const char *uri, SongEnumerator &e,
unsigned start_index, unsigned end_index,
playlist &dest, PlayerControl &pc,
bool secure);
/**
* Opens a playlist with a playlist plugin and append to the specified
* play queue.
*/
PlaylistResult
playlist_open_into_queue(const char *uri,
unsigned start_index, unsigned end_index,
playlist &dest, PlayerControl &pc,
bool secure);
#endif

View File

@@ -0,0 +1,335 @@
/*
* Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "PlaylistRegistry.hxx"
#include "PlaylistPlugin.hxx"
#include "plugins/ExtM3uPlaylistPlugin.hxx"
#include "plugins/M3uPlaylistPlugin.hxx"
#include "plugins/XspfPlaylistPlugin.hxx"
#include "plugins/DespotifyPlaylistPlugin.hxx"
#include "plugins/SoundCloudPlaylistPlugin.hxx"
#include "plugins/PlsPlaylistPlugin.hxx"
#include "plugins/AsxPlaylistPlugin.hxx"
#include "plugins/RssPlaylistPlugin.hxx"
#include "plugins/CuePlaylistPlugin.hxx"
#include "plugins/EmbeddedCuePlaylistPlugin.hxx"
#include "InputStream.hxx"
#include "util/UriUtil.hxx"
#include "util/StringUtil.hxx"
#include "util/Error.hxx"
#include "util/Macros.hxx"
#include "ConfigGlobal.hxx"
#include "ConfigData.hxx"
#include "system/FatalError.hxx"
#include "Log.hxx"
#include <assert.h>
#include <string.h>
const struct playlist_plugin *const playlist_plugins[] = {
&extm3u_playlist_plugin,
&m3u_playlist_plugin,
&pls_playlist_plugin,
#ifdef HAVE_EXPAT
&xspf_playlist_plugin,
&asx_playlist_plugin,
&rss_playlist_plugin,
#endif
#ifdef ENABLE_DESPOTIFY
&despotify_playlist_plugin,
#endif
#ifdef ENABLE_SOUNDCLOUD
&soundcloud_playlist_plugin,
#endif
&cue_playlist_plugin,
&embcue_playlist_plugin,
nullptr
};
static constexpr unsigned n_playlist_plugins =
ARRAY_SIZE(playlist_plugins) - 1;
/** which plugins have been initialized successfully? */
static bool playlist_plugins_enabled[n_playlist_plugins];
#define playlist_plugins_for_each_enabled(plugin) \
playlist_plugins_for_each(plugin) \
if (playlist_plugins_enabled[playlist_plugin_iterator - playlist_plugins])
/**
* Find the "playlist" configuration block for the specified plugin.
*
* @param plugin_name the name of the playlist plugin
* @return the configuration block, or nullptr if none was configured
*/
static const struct config_param *
playlist_plugin_config(const char *plugin_name)
{
const struct config_param *param = nullptr;
assert(plugin_name != nullptr);
while ((param = config_get_next_param(CONF_PLAYLIST_PLUGIN, param)) != nullptr) {
const char *name = param->GetBlockValue("name");
if (name == nullptr)
FormatFatalError("playlist configuration without 'plugin' name in line %d",
param->line);
if (strcmp(name, plugin_name) == 0)
return param;
}
return nullptr;
}
void
playlist_list_global_init(void)
{
const config_param empty;
for (unsigned i = 0; playlist_plugins[i] != nullptr; ++i) {
const struct playlist_plugin *plugin = playlist_plugins[i];
const struct config_param *param =
playlist_plugin_config(plugin->name);
if (param == nullptr)
param = &empty;
else if (!param->GetBlockValue("enabled", true))
/* the plugin is disabled in mpd.conf */
continue;
playlist_plugins_enabled[i] =
playlist_plugin_init(playlist_plugins[i], *param);
}
}
void
playlist_list_global_finish(void)
{
playlist_plugins_for_each_enabled(plugin)
playlist_plugin_finish(plugin);
}
static SongEnumerator *
playlist_list_open_uri_scheme(const char *uri, Mutex &mutex, Cond &cond,
bool *tried)
{
SongEnumerator *playlist = nullptr;
assert(uri != nullptr);
const auto scheme = uri_get_scheme(uri);
if (scheme.empty())
return nullptr;
for (unsigned i = 0; playlist_plugins[i] != nullptr; ++i) {
const struct playlist_plugin *plugin = playlist_plugins[i];
assert(!tried[i]);
if (playlist_plugins_enabled[i] && plugin->open_uri != nullptr &&
plugin->schemes != nullptr &&
string_array_contains(plugin->schemes, scheme.c_str())) {
playlist = playlist_plugin_open_uri(plugin, uri,
mutex, cond);
if (playlist != nullptr)
break;
tried[i] = true;
}
}
return playlist;
}
static SongEnumerator *
playlist_list_open_uri_suffix(const char *uri, Mutex &mutex, Cond &cond,
const bool *tried)
{
const char *suffix;
SongEnumerator *playlist = nullptr;
assert(uri != nullptr);
suffix = uri_get_suffix(uri);
if (suffix == nullptr)
return nullptr;
for (unsigned i = 0; playlist_plugins[i] != nullptr; ++i) {
const struct playlist_plugin *plugin = playlist_plugins[i];
if (playlist_plugins_enabled[i] && !tried[i] &&
plugin->open_uri != nullptr && plugin->suffixes != nullptr &&
string_array_contains(plugin->suffixes, suffix)) {
playlist = playlist_plugin_open_uri(plugin, uri,
mutex, cond);
if (playlist != nullptr)
break;
}
}
return playlist;
}
SongEnumerator *
playlist_list_open_uri(const char *uri, Mutex &mutex, Cond &cond)
{
/** this array tracks which plugins have already been tried by
playlist_list_open_uri_scheme() */
bool tried[n_playlist_plugins];
assert(uri != nullptr);
memset(tried, false, sizeof(tried));
auto playlist = playlist_list_open_uri_scheme(uri, mutex, cond, tried);
if (playlist == nullptr)
playlist = playlist_list_open_uri_suffix(uri, mutex, cond,
tried);
return playlist;
}
static SongEnumerator *
playlist_list_open_stream_mime2(InputStream &is, const char *mime)
{
assert(mime != nullptr);
playlist_plugins_for_each_enabled(plugin) {
if (plugin->open_stream != nullptr &&
plugin->mime_types != nullptr &&
string_array_contains(plugin->mime_types, mime)) {
/* rewind the stream, so each plugin gets a
fresh start */
is.Rewind(IgnoreError());
auto playlist = playlist_plugin_open_stream(plugin,
is);
if (playlist != nullptr)
return playlist;
}
}
return nullptr;
}
static SongEnumerator *
playlist_list_open_stream_mime(InputStream &is, const char *full_mime)
{
assert(full_mime != nullptr);
const char *semicolon = strchr(full_mime, ';');
if (semicolon == nullptr)
return playlist_list_open_stream_mime2(is, full_mime);
if (semicolon == full_mime)
return nullptr;
/* probe only the portion before the semicolon*/
const std::string mime(full_mime, semicolon);
return playlist_list_open_stream_mime2(is, mime.c_str());
}
static SongEnumerator *
playlist_list_open_stream_suffix(InputStream &is, const char *suffix)
{
assert(suffix != nullptr);
playlist_plugins_for_each_enabled(plugin) {
if (plugin->open_stream != nullptr &&
plugin->suffixes != nullptr &&
string_array_contains(plugin->suffixes, suffix)) {
/* rewind the stream, so each plugin gets a
fresh start */
is.Rewind(IgnoreError());
auto playlist = playlist_plugin_open_stream(plugin, is);
if (playlist != nullptr)
return playlist;
}
}
return nullptr;
}
SongEnumerator *
playlist_list_open_stream(InputStream &is, const char *uri)
{
assert(is.ready);
const char *const mime = is.GetMimeType();
if (mime != nullptr) {
auto playlist = playlist_list_open_stream_mime(is, mime);
if (playlist != nullptr)
return playlist;
}
const char *suffix = uri != nullptr ? uri_get_suffix(uri) : nullptr;
if (suffix != nullptr) {
auto playlist = playlist_list_open_stream_suffix(is, suffix);
if (playlist != nullptr)
return playlist;
}
return nullptr;
}
bool
playlist_suffix_supported(const char *suffix)
{
assert(suffix != nullptr);
playlist_plugins_for_each_enabled(plugin) {
if (plugin->suffixes != nullptr &&
string_array_contains(plugin->suffixes, suffix))
return true;
}
return false;
}
SongEnumerator *
playlist_list_open_path(const char *path_fs, Mutex &mutex, Cond &cond,
InputStream **is_r)
{
const char *suffix;
assert(path_fs != nullptr);
suffix = uri_get_suffix(path_fs);
if (suffix == nullptr || !playlist_suffix_supported(suffix))
return nullptr;
Error error;
InputStream *is = InputStream::OpenReady(path_fs, mutex, cond, error);
if (is == nullptr) {
if (error.IsDefined())
LogError(error);
return nullptr;
}
auto playlist = playlist_list_open_stream_suffix(*is, suffix);
if (playlist != nullptr)
*is_r = is;
else
is->Close();
return playlist;
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_PLAYLIST_REGISTRY_HXX
#define MPD_PLAYLIST_REGISTRY_HXX
class Mutex;
class Cond;
class SongEnumerator;
struct InputStream;
extern const struct playlist_plugin *const playlist_plugins[];
#define playlist_plugins_for_each(plugin) \
for (const struct playlist_plugin *plugin, \
*const*playlist_plugin_iterator = &playlist_plugins[0]; \
(plugin = *playlist_plugin_iterator) != nullptr; \
++playlist_plugin_iterator)
/**
* Initializes all playlist plugins.
*/
void
playlist_list_global_init(void);
/**
* Deinitializes all playlist plugins.
*/
void
playlist_list_global_finish(void);
/**
* Opens a playlist by its URI.
*/
SongEnumerator *
playlist_list_open_uri(const char *uri, Mutex &mutex, Cond &cond);
/**
* Opens a playlist from an input stream.
*
* @param is an #input_stream object which is open and ready
* @param uri optional URI which was used to open the stream; may be
* used to select the appropriate playlist plugin
*/
SongEnumerator *
playlist_list_open_stream(InputStream &is, const char *uri);
/**
* Determines if there is a playlist plugin which can handle the
* specified file name suffix.
*/
bool
playlist_suffix_supported(const char *suffix);
/**
* Opens a playlist from a local file.
*
* @param path_fs the path of the playlist file
* @param is_r on success, an input_stream object is returned here,
* which must be closed after the playlist_provider object is freed
* @return a playlist, or nullptr on error
*/
SongEnumerator *
playlist_list_open_path(const char *path_fs, Mutex &mutex, Cond &cond,
InputStream **is_r);
#endif

View File

@@ -0,0 +1,131 @@
/*
* Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "PlaylistSong.hxx"
#include "Mapper.hxx"
#include "DatabaseSong.hxx"
#include "ls.hxx"
#include "tag/Tag.hxx"
#include "tag/TagBuilder.hxx"
#include "fs/AllocatedPath.hxx"
#include "fs/Traits.hxx"
#include "util/UriUtil.hxx"
#include "util/Error.hxx"
#include "DetachedSong.hxx"
#include <assert.h>
#include <string.h>
static void
merge_song_metadata(DetachedSong &add, const DetachedSong &base)
{
{
TagBuilder builder(add.GetTag());
builder.Complement(base.GetTag());
add.SetTag(builder.Commit());
}
add.SetLastModified(base.GetLastModified());
}
static void
apply_song_metadata(DetachedSong &dest, const DetachedSong &src)
{
if (!src.GetTag().IsDefined() &&
src.GetStartMS() == 0 && src.GetEndMS() == 0)
return;
merge_song_metadata(dest, src);
if (dest.GetTag().IsDefined() && dest.GetTag().time > 0 &&
src.GetStartMS() > 0 && src.GetEndMS() == 0 &&
src.GetStartMS() / 1000 < (unsigned)dest.GetTag().time)
/* the range is open-ended, and the playlist plugin
did not know the total length of the song file
(e.g. last track on a CUE file); fix it up here */
dest.WritableTag().time =
dest.GetTag().time - src.GetStartMS() / 1000;
}
static bool
playlist_check_load_song(DetachedSong &song)
{
const char *const uri = song.GetURI();
if (uri_has_scheme(uri)) {
return true;
} else if (PathTraitsUTF8::IsAbsolute(uri)) {
DetachedSong tmp(uri);
if (!tmp.Update())
return false;
apply_song_metadata(song, tmp);
return true;
} else {
DetachedSong *tmp = DatabaseDetachSong(uri, IgnoreError());
if (tmp == nullptr)
return false;
apply_song_metadata(song, *tmp);
delete tmp;
return true;
}
}
bool
playlist_check_translate_song(DetachedSong &song, const char *base_uri,
bool secure)
{
const char *const uri = song.GetURI();
if (uri_has_scheme(uri))
/* valid remote song? */
return uri_supported_scheme(uri);
if (base_uri != nullptr && strcmp(base_uri, ".") == 0)
/* PathTraitsUTF8::GetParent() returns "." when there
is no directory name in the given path; clear that
now, because it would break the database lookup
functions */
base_uri = nullptr;
if (PathTraitsUTF8::IsAbsolute(uri)) {
/* XXX fs_charset vs utf8? */
const char *suffix = map_to_relative_path(uri);
assert(suffix != nullptr);
if (suffix != uri)
song.SetURI(std::string(suffix));
else if (!secure)
/* local files must be relative to the music
directory when "secure" is enabled */
return false;
base_uri = nullptr;
}
if (base_uri != nullptr) {
song.SetURI(PathTraitsUTF8::Build(base_uri, uri));
/* repeat the above checks */
return playlist_check_translate_song(song, nullptr, secure);
}
return playlist_check_load_song(song);
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_PLAYLIST_SONG_HXX
#define MPD_PLAYLIST_SONG_HXX
class DetachedSong;
/**
* Verifies the song, returns false if it is unsafe. Translate the
* song to a song within the database, if it is a local file.
*
* @param secure if true, then local files are only allowed if they
* are relative to base_uri
* @return true on success, false if the song should not be used
*/
bool
playlist_check_translate_song(DetachedSong &song, const char *base_uri,
bool secure);
#endif

71
src/playlist/Print.cxx Normal file
View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "Print.hxx"
#include "PlaylistAny.hxx"
#include "PlaylistSong.hxx"
#include "SongEnumerator.hxx"
#include "SongPrint.hxx"
#include "InputStream.hxx"
#include "DetachedSong.hxx"
#include "fs/Traits.hxx"
#include "thread/Cond.hxx"
static void
playlist_provider_print(Client &client, const char *uri,
SongEnumerator &e, bool detail)
{
const std::string base_uri = uri != nullptr
? PathTraitsUTF8::GetParent(uri)
: std::string(".");
DetachedSong *song;
while ((song = e.NextSong()) != nullptr) {
if (playlist_check_translate_song(*song, base_uri.c_str(),
false)) {
if (detail)
song_print_info(client, *song);
else
song_print_uri(client, *song);
}
delete song;
}
}
bool
playlist_file_print(Client &client, const char *uri, bool detail)
{
Mutex mutex;
Cond cond;
InputStream *is;
SongEnumerator *playlist = playlist_open_any(uri, mutex, cond, &is);
if (playlist == nullptr)
return false;
playlist_provider_print(client, uri, *playlist, detail);
delete playlist;
if (is != nullptr)
is->Close();
return true;
}

36
src/playlist/Print.hxx Normal file
View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_PLAYLIST__PRINT_HXX
#define MPD_PLAYLIST__PRINT_HXX
class Client;
/**
* Send the playlist file to the client.
*
* @param client the client which requested the playlist
* @param uri the URI of the playlist file in UTF-8 encoding
* @param detail true if all details should be printed
* @return true on success, false if the playlist does not exist
*/
bool
playlist_file_print(Client &client, const char *uri, bool detail);
#endif

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_SONG_ENUMERATOR_HXX
#define MPD_SONG_ENUMERATOR_HXX
class DetachedSong;
/**
* An object which provides serial access to a number of #Song
* objects. It is used to enumerate the contents of a playlist file.
*/
class SongEnumerator {
public:
virtual ~SongEnumerator() {}
/**
* Obtain the next song. The caller is responsible for
* freeing the returned #Song object. Returns nullptr if
* there are no more songs.
*/
virtual DetachedSong *NextSong() = 0;
};
#endif

View File

@@ -19,8 +19,8 @@
#include "config.h"
#include "AsxPlaylistPlugin.hxx"
#include "PlaylistPlugin.hxx"
#include "MemorySongEnumerator.hxx"
#include "../PlaylistPlugin.hxx"
#include "../MemorySongEnumerator.hxx"
#include "tag/TagBuilder.hxx"
#include "util/ASCII.hxx"
#include "util/Error.hxx"

View File

@@ -19,8 +19,8 @@
#include "config.h"
#include "CuePlaylistPlugin.hxx"
#include "PlaylistPlugin.hxx"
#include "SongEnumerator.hxx"
#include "../PlaylistPlugin.hxx"
#include "../SongEnumerator.hxx"
#include "cue/CueParser.hxx"
#include "TextInputStream.hxx"

View File

@@ -20,8 +20,8 @@
#include "config.h"
#include "DespotifyPlaylistPlugin.hxx"
#include "DespotifyUtils.hxx"
#include "PlaylistPlugin.hxx"
#include "MemorySongEnumerator.hxx"
#include "../PlaylistPlugin.hxx"
#include "../MemorySongEnumerator.hxx"
#include "tag/Tag.hxx"
#include "DetachedSong.hxx"
#include "Log.hxx"

View File

@@ -25,8 +25,8 @@
#include "config.h"
#include "EmbeddedCuePlaylistPlugin.hxx"
#include "PlaylistPlugin.hxx"
#include "SongEnumerator.hxx"
#include "../PlaylistPlugin.hxx"
#include "../SongEnumerator.hxx"
#include "tag/TagHandler.hxx"
#include "tag/TagId3.hxx"
#include "tag/ApeTag.hxx"

View File

@@ -19,8 +19,8 @@
#include "config.h"
#include "ExtM3uPlaylistPlugin.hxx"
#include "PlaylistPlugin.hxx"
#include "SongEnumerator.hxx"
#include "../PlaylistPlugin.hxx"
#include "../SongEnumerator.hxx"
#include "DetachedSong.hxx"
#include "tag/Tag.hxx"
#include "tag/TagBuilder.hxx"

View File

@@ -19,8 +19,8 @@
#include "config.h"
#include "M3uPlaylistPlugin.hxx"
#include "PlaylistPlugin.hxx"
#include "SongEnumerator.hxx"
#include "../PlaylistPlugin.hxx"
#include "../SongEnumerator.hxx"
#include "DetachedSong.hxx"
#include "util/StringUtil.hxx"
#include "TextInputStream.hxx"

View File

@@ -19,8 +19,8 @@
#include "config.h"
#include "PlsPlaylistPlugin.hxx"
#include "PlaylistPlugin.hxx"
#include "MemorySongEnumerator.hxx"
#include "../PlaylistPlugin.hxx"
#include "../MemorySongEnumerator.hxx"
#include "InputStream.hxx"
#include "DetachedSong.hxx"
#include "tag/TagBuilder.hxx"

View File

@@ -19,8 +19,8 @@
#include "config.h"
#include "RssPlaylistPlugin.hxx"
#include "PlaylistPlugin.hxx"
#include "MemorySongEnumerator.hxx"
#include "../PlaylistPlugin.hxx"
#include "../MemorySongEnumerator.hxx"
#include "tag/TagBuilder.hxx"
#include "util/ASCII.hxx"
#include "util/Error.hxx"

View File

@@ -19,8 +19,8 @@
#include "config.h"
#include "SoundCloudPlaylistPlugin.hxx"
#include "PlaylistPlugin.hxx"
#include "MemorySongEnumerator.hxx"
#include "../PlaylistPlugin.hxx"
#include "../MemorySongEnumerator.hxx"
#include "ConfigData.hxx"
#include "InputStream.hxx"
#include "tag/TagBuilder.hxx"

View File

@@ -19,8 +19,8 @@
#include "config.h"
#include "XspfPlaylistPlugin.hxx"
#include "PlaylistPlugin.hxx"
#include "MemorySongEnumerator.hxx"
#include "../PlaylistPlugin.hxx"
#include "../MemorySongEnumerator.hxx"
#include "DetachedSong.hxx"
#include "InputStream.hxx"
#include "tag/TagBuilder.hxx"