2
* Copyright (C) 2003-2010 The Music Player Daemon Project
3
* http://www.musicpd.org
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License along
16
* with this program; if not, write to the Free Software Foundation, Inc.,
17
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21
#include "playlist_list.h"
22
#include "playlist_plugin.h"
23
#include "playlist/extm3u_playlist_plugin.h"
24
#include "playlist/m3u_playlist_plugin.h"
25
#include "playlist/xspf_playlist_plugin.h"
26
#include "playlist/lastfm_playlist_plugin.h"
27
#include "playlist/pls_playlist_plugin.h"
28
#include "playlist/asx_playlist_plugin.h"
29
#include "playlist/rss_playlist_plugin.h"
30
#include "playlist/cue_playlist_plugin.h"
31
#include "playlist/flac_playlist_plugin.h"
32
#include "input_stream.h"
36
#include "glib_compat.h"
37
#include "mpd_error.h"
43
static const struct playlist_plugin *const playlist_plugins[] = {
44
&extm3u_playlist_plugin,
46
&xspf_playlist_plugin,
51
&lastfm_playlist_plugin,
57
&flac_playlist_plugin,
62
/** which plugins have been initialized successfully? */
63
static bool playlist_plugins_enabled[G_N_ELEMENTS(playlist_plugins)];
66
* Find the "playlist" configuration block for the specified plugin.
68
* @param plugin_name the name of the playlist plugin
69
* @return the configuration block, or NULL if none was configured
71
static const struct config_param *
72
playlist_plugin_config(const char *plugin_name)
74
const struct config_param *param = NULL;
76
assert(plugin_name != NULL);
78
while ((param = config_get_next_param(CONF_PLAYLIST_PLUGIN, param)) != NULL) {
80
config_get_block_string(param, "name", NULL);
82
MPD_ERROR("playlist configuration without 'plugin' name in line %d",
85
if (strcmp(name, plugin_name) == 0)
93
playlist_list_global_init(void)
95
for (unsigned i = 0; playlist_plugins[i] != NULL; ++i) {
96
const struct playlist_plugin *plugin = playlist_plugins[i];
97
const struct config_param *param =
98
playlist_plugin_config(plugin->name);
100
if (!config_get_block_bool(param, "enabled", true))
101
/* the plugin is disabled in mpd.conf */
104
playlist_plugins_enabled[i] =
105
playlist_plugin_init(playlist_plugins[i], param);
110
playlist_list_global_finish(void)
112
for (unsigned i = 0; playlist_plugins[i] != NULL; ++i)
113
if (playlist_plugins_enabled[i])
114
playlist_plugin_finish(playlist_plugins[i]);
117
static struct playlist_provider *
118
playlist_list_open_uri_scheme(const char *uri, bool *tried)
121
struct playlist_provider *playlist = NULL;
125
scheme = g_uri_parse_scheme(uri);
129
for (unsigned i = 0; playlist_plugins[i] != NULL; ++i) {
130
const struct playlist_plugin *plugin = playlist_plugins[i];
134
if (playlist_plugins_enabled[i] && plugin->open_uri != NULL &&
135
plugin->schemes != NULL &&
136
string_array_contains(plugin->schemes, scheme)) {
137
playlist = playlist_plugin_open_uri(plugin, uri);
138
if (playlist != NULL)
149
static struct playlist_provider *
150
playlist_list_open_uri_suffix(const char *uri, const bool *tried)
153
struct playlist_provider *playlist = NULL;
157
suffix = uri_get_suffix(uri);
161
for (unsigned i = 0; playlist_plugins[i] != NULL; ++i) {
162
const struct playlist_plugin *plugin = playlist_plugins[i];
164
if (playlist_plugins_enabled[i] && !tried[i] &&
165
plugin->open_uri != NULL && plugin->suffixes != NULL &&
166
string_array_contains(plugin->suffixes, suffix)) {
167
playlist = playlist_plugin_open_uri(plugin, uri);
168
if (playlist != NULL)
176
struct playlist_provider *
177
playlist_list_open_uri(const char *uri)
179
struct playlist_provider *playlist;
180
/** this array tracks which plugins have already been tried by
181
playlist_list_open_uri_scheme() */
182
bool tried[G_N_ELEMENTS(playlist_plugins) - 1];
186
memset(tried, false, sizeof(tried));
188
playlist = playlist_list_open_uri_scheme(uri, tried);
189
if (playlist == NULL)
190
playlist = playlist_list_open_uri_suffix(uri, tried);
195
static struct playlist_provider *
196
playlist_list_open_stream_mime2(struct input_stream *is, const char *mime)
198
struct playlist_provider *playlist;
201
assert(mime != NULL);
203
for (unsigned i = 0; playlist_plugins[i] != NULL; ++i) {
204
const struct playlist_plugin *plugin = playlist_plugins[i];
206
if (playlist_plugins_enabled[i] &&
207
plugin->open_stream != NULL &&
208
plugin->mime_types != NULL &&
209
string_array_contains(plugin->mime_types, mime)) {
210
/* rewind the stream, so each plugin gets a
212
input_stream_seek(is, 0, SEEK_SET, NULL);
214
playlist = playlist_plugin_open_stream(plugin, is);
215
if (playlist != NULL)
223
static struct playlist_provider *
224
playlist_list_open_stream_mime(struct input_stream *is)
226
assert(is->mime != NULL);
228
const char *semicolon = strchr(is->mime, ';');
229
if (semicolon == NULL)
230
return playlist_list_open_stream_mime2(is, is->mime);
232
if (semicolon == is->mime)
235
/* probe only the portion before the semicolon*/
236
char *mime = g_strndup(is->mime, semicolon - is->mime);
237
struct playlist_provider *playlist =
238
playlist_list_open_stream_mime2(is, mime);
243
static struct playlist_provider *
244
playlist_list_open_stream_suffix(struct input_stream *is, const char *suffix)
246
struct playlist_provider *playlist;
249
assert(suffix != NULL);
251
for (unsigned i = 0; playlist_plugins[i] != NULL; ++i) {
252
const struct playlist_plugin *plugin = playlist_plugins[i];
254
if (playlist_plugins_enabled[i] &&
255
plugin->open_stream != NULL &&
256
plugin->suffixes != NULL &&
257
string_array_contains(plugin->suffixes, suffix)) {
258
/* rewind the stream, so each plugin gets a
260
input_stream_seek(is, 0, SEEK_SET, NULL);
262
playlist = playlist_plugin_open_stream(plugin, is);
263
if (playlist != NULL)
271
struct playlist_provider *
272
playlist_list_open_stream(struct input_stream *is, const char *uri)
275
struct playlist_provider *playlist;
277
GError *error = NULL;
279
int ret = input_stream_buffer(is, &error);
281
input_stream_close(is);
282
g_warning("%s", error->message);
288
if (is->mime != NULL) {
289
playlist = playlist_list_open_stream_mime(is);
290
if (playlist != NULL)
294
suffix = uri != NULL ? uri_get_suffix(uri) : NULL;
295
if (suffix != NULL) {
296
playlist = playlist_list_open_stream_suffix(is, suffix);
297
if (playlist != NULL)
305
playlist_suffix_supported(const char *suffix)
307
assert(suffix != NULL);
309
for (unsigned i = 0; playlist_plugins[i] != NULL; ++i) {
310
const struct playlist_plugin *plugin = playlist_plugins[i];
312
if (playlist_plugins_enabled[i] && plugin->suffixes != NULL &&
313
string_array_contains(plugin->suffixes, suffix))
320
struct playlist_provider *
321
playlist_list_open_path(const char *path_fs, struct input_stream **is_r)
323
GError *error = NULL;
325
struct input_stream *is;
326
struct playlist_provider *playlist;
328
assert(path_fs != NULL);
330
suffix = uri_get_suffix(path_fs);
331
if (suffix == NULL || !playlist_suffix_supported(suffix))
334
is = input_stream_open(path_fs, &error);
337
g_warning("%s", error->message);
345
int ret = input_stream_buffer(is, &error);
347
input_stream_close(is);
348
g_warning("%s", error->message);
354
playlist = playlist_list_open_stream_suffix(is, suffix);
355
if (playlist != NULL)
358
input_stream_close(is);