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/cue_playlist_plugin.h"
30 #include "playlist/flac_playlist_plugin.h"
31 #include "input_stream.h"
42 static const struct playlist_plugin
*const playlist_plugins
[] = {
43 &extm3u_playlist_plugin
,
45 &xspf_playlist_plugin
,
49 &lastfm_playlist_plugin
,
55 &flac_playlist_plugin
,
60 /** which plugins have been initialized successfully? */
61 static bool playlist_plugins_enabled
[G_N_ELEMENTS(playlist_plugins
)];
64 * Find the "playlist" configuration block for the specified plugin.
66 * @param plugin_name the name of the playlist plugin
67 * @return the configuration block, or NULL if none was configured
69 static const struct config_param
*
70 playlist_plugin_config(const char *plugin_name
)
72 const struct config_param
*param
= NULL
;
74 assert(plugin_name
!= NULL
);
76 while ((param
= config_get_next_param(CONF_PLAYLIST_PLUGIN
, param
)) != NULL
) {
78 config_get_block_string(param
, "name", NULL
);
80 g_error("playlist configuration without 'plugin' name in line %d",
83 if (strcmp(name
, plugin_name
) == 0)
91 playlist_list_global_init(void)
93 for (unsigned i
= 0; playlist_plugins
[i
] != NULL
; ++i
) {
94 const struct playlist_plugin
*plugin
= playlist_plugins
[i
];
95 const struct config_param
*param
=
96 playlist_plugin_config(plugin
->name
);
98 if (!config_get_block_bool(param
, "enabled", true))
99 /* the plugin is disabled in mpd.conf */
102 playlist_plugins_enabled
[i
] =
103 playlist_plugin_init(playlist_plugins
[i
], param
);
108 playlist_list_global_finish(void)
110 for (unsigned i
= 0; playlist_plugins
[i
] != NULL
; ++i
)
111 if (playlist_plugins_enabled
[i
])
112 playlist_plugin_finish(playlist_plugins
[i
]);
115 /* g_uri_parse_scheme() was introduced in GLib 2.16 */
116 #if !GLIB_CHECK_VERSION(2,16,0)
118 g_uri_parse_scheme(const char *uri
)
120 const char *end
= strstr(uri
, "://");
123 return g_strndup(uri
, end
- uri
);
127 static struct playlist_provider
*
128 playlist_list_open_uri_scheme(const char *uri
, bool *tried
)
131 struct playlist_provider
*playlist
= NULL
;
135 scheme
= g_uri_parse_scheme(uri
);
139 for (unsigned i
= 0; playlist_plugins
[i
] != NULL
; ++i
) {
140 const struct playlist_plugin
*plugin
= playlist_plugins
[i
];
144 if (playlist_plugins_enabled
[i
] && plugin
->open_uri
!= NULL
&&
145 plugin
->schemes
!= NULL
&&
146 string_array_contains(plugin
->schemes
, scheme
)) {
147 playlist
= playlist_plugin_open_uri(plugin
, uri
);
148 if (playlist
!= NULL
)
159 static struct playlist_provider
*
160 playlist_list_open_uri_suffix(const char *uri
, const bool *tried
)
163 struct playlist_provider
*playlist
= NULL
;
167 suffix
= uri_get_suffix(uri
);
171 for (unsigned i
= 0; playlist_plugins
[i
] != NULL
; ++i
) {
172 const struct playlist_plugin
*plugin
= playlist_plugins
[i
];
174 if (playlist_plugins_enabled
[i
] && !tried
[i
] &&
175 plugin
->open_uri
!= NULL
&& plugin
->suffixes
!= NULL
&&
176 string_array_contains(plugin
->suffixes
, suffix
)) {
177 playlist
= playlist_plugin_open_uri(plugin
, uri
);
178 if (playlist
!= NULL
)
186 struct playlist_provider
*
187 playlist_list_open_uri(const char *uri
)
189 struct playlist_provider
*playlist
;
190 /** this array tracks which plugins have already been tried by
191 playlist_list_open_uri_scheme() */
192 bool tried
[G_N_ELEMENTS(playlist_plugins
) - 1];
196 memset(tried
, false, sizeof(tried
));
198 playlist
= playlist_list_open_uri_scheme(uri
, tried
);
199 if (playlist
== NULL
)
200 playlist
= playlist_list_open_uri_suffix(uri
, tried
);
205 static struct playlist_provider
*
206 playlist_list_open_stream_mime(struct input_stream
*is
)
208 struct playlist_provider
*playlist
;
211 assert(is
->mime
!= NULL
);
213 for (unsigned i
= 0; playlist_plugins
[i
] != NULL
; ++i
) {
214 const struct playlist_plugin
*plugin
= playlist_plugins
[i
];
216 if (playlist_plugins_enabled
[i
] &&
217 plugin
->open_stream
!= NULL
&&
218 plugin
->mime_types
!= NULL
&&
219 string_array_contains(plugin
->mime_types
, is
->mime
)) {
220 /* rewind the stream, so each plugin gets a
222 input_stream_seek(is
, 0, SEEK_SET
, NULL
);
224 playlist
= playlist_plugin_open_stream(plugin
, is
);
225 if (playlist
!= NULL
)
233 static struct playlist_provider
*
234 playlist_list_open_stream_suffix(struct input_stream
*is
, const char *suffix
)
236 struct playlist_provider
*playlist
;
239 assert(suffix
!= NULL
);
241 for (unsigned i
= 0; playlist_plugins
[i
] != NULL
; ++i
) {
242 const struct playlist_plugin
*plugin
= playlist_plugins
[i
];
244 if (playlist_plugins_enabled
[i
] &&
245 plugin
->open_stream
!= NULL
&&
246 plugin
->suffixes
!= NULL
&&
247 string_array_contains(plugin
->suffixes
, suffix
)) {
248 /* rewind the stream, so each plugin gets a
250 input_stream_seek(is
, 0, SEEK_SET
, NULL
);
252 playlist
= playlist_plugin_open_stream(plugin
, is
);
253 if (playlist
!= NULL
)
261 struct playlist_provider
*
262 playlist_list_open_stream(struct input_stream
*is
, const char *uri
)
265 struct playlist_provider
*playlist
;
267 if (is
->mime
!= NULL
) {
268 playlist
= playlist_list_open_stream_mime(is
);
269 if (playlist
!= NULL
)
273 suffix
= uri
!= NULL
? uri_get_suffix(uri
) : NULL
;
274 if (suffix
!= NULL
) {
275 playlist
= playlist_list_open_stream_suffix(is
, suffix
);
276 if (playlist
!= NULL
)
284 playlist_suffix_supported(const char *suffix
)
286 assert(suffix
!= NULL
);
288 for (unsigned i
= 0; playlist_plugins
[i
] != NULL
; ++i
) {
289 const struct playlist_plugin
*plugin
= playlist_plugins
[i
];
291 if (playlist_plugins_enabled
[i
] && plugin
->suffixes
!= NULL
&&
292 string_array_contains(plugin
->suffixes
, suffix
))
299 struct playlist_provider
*
300 playlist_list_open_path(const char *path_fs
)
302 GError
*error
= NULL
;
304 struct input_stream
*is
;
305 struct playlist_provider
*playlist
;
307 assert(path_fs
!= NULL
);
309 suffix
= uri_get_suffix(path_fs
);
310 if (suffix
== NULL
|| !playlist_suffix_supported(suffix
))
313 is
= input_stream_open(path_fs
, &error
);
316 g_warning("%s", error
->message
);
324 int ret
= input_stream_buffer(is
, &error
);
326 input_stream_close(is
);
327 g_warning("%s", error
->message
);
333 playlist
= playlist_list_open_stream_suffix(is
, suffix
);
334 if (playlist
== NULL
)
335 input_stream_close(is
);