configure.ac: Move OggVorbis Encoder to Encoder Plugins.
[mpd-mk.git] / src / playlist_list.c
bloba836beb3527d2fa938d39b7b31b51ac1a81cce86
1 /*
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.
20 #include "config.h"
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"
32 #include "uri.h"
33 #include "utils.h"
34 #include "conf.h"
36 #include <glib.h>
38 #include <assert.h>
39 #include <string.h>
40 #include <stdio.h>
42 static const struct playlist_plugin *const playlist_plugins[] = {
43 &extm3u_playlist_plugin,
44 &m3u_playlist_plugin,
45 &xspf_playlist_plugin,
46 &pls_playlist_plugin,
47 &asx_playlist_plugin,
48 #ifdef ENABLE_LASTFM
49 &lastfm_playlist_plugin,
50 #endif
51 #ifdef HAVE_CUE
52 &cue_playlist_plugin,
53 #endif
54 #ifdef HAVE_FLAC
55 &flac_playlist_plugin,
56 #endif
57 NULL
60 /** which plugins have been initialized successfully? */
61 static bool playlist_plugins_enabled[G_N_ELEMENTS(playlist_plugins)];
63 /**
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) {
77 const char *name =
78 config_get_block_string(param, "name", NULL);
79 if (name == NULL)
80 g_error("playlist configuration without 'plugin' name in line %d",
81 param->line);
83 if (strcmp(name, plugin_name) == 0)
84 return param;
87 return NULL;
90 void
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 */
100 continue;
102 playlist_plugins_enabled[i] =
103 playlist_plugin_init(playlist_plugins[i], param);
107 void
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)
117 static char *
118 g_uri_parse_scheme(const char *uri)
120 const char *end = strstr(uri, "://");
121 if (end == NULL)
122 return NULL;
123 return g_strndup(uri, end - uri);
125 #endif
127 static struct playlist_provider *
128 playlist_list_open_uri_scheme(const char *uri, bool *tried)
130 char *scheme;
131 struct playlist_provider *playlist = NULL;
133 assert(uri != NULL);
135 scheme = g_uri_parse_scheme(uri);
136 if (scheme == NULL)
137 return NULL;
139 for (unsigned i = 0; playlist_plugins[i] != NULL; ++i) {
140 const struct playlist_plugin *plugin = playlist_plugins[i];
142 assert(!tried[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)
149 break;
151 tried[i] = true;
155 g_free(scheme);
156 return playlist;
159 static struct playlist_provider *
160 playlist_list_open_uri_suffix(const char *uri, const bool *tried)
162 const char *suffix;
163 struct playlist_provider *playlist = NULL;
165 assert(uri != NULL);
167 suffix = uri_get_suffix(uri);
168 if (suffix == NULL)
169 return NULL;
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)
179 break;
183 return playlist;
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];
194 assert(uri != NULL);
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);
202 return playlist;
205 static struct playlist_provider *
206 playlist_list_open_stream_mime(struct input_stream *is)
208 struct playlist_provider *playlist;
210 assert(is != NULL);
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
221 fresh start */
222 input_stream_seek(is, 0, SEEK_SET, NULL);
224 playlist = playlist_plugin_open_stream(plugin, is);
225 if (playlist != NULL)
226 return playlist;
230 return NULL;
233 static struct playlist_provider *
234 playlist_list_open_stream_suffix(struct input_stream *is, const char *suffix)
236 struct playlist_provider *playlist;
238 assert(is != NULL);
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
249 fresh start */
250 input_stream_seek(is, 0, SEEK_SET, NULL);
252 playlist = playlist_plugin_open_stream(plugin, is);
253 if (playlist != NULL)
254 return playlist;
258 return NULL;
261 struct playlist_provider *
262 playlist_list_open_stream(struct input_stream *is, const char *uri)
264 const char *suffix;
265 struct playlist_provider *playlist;
267 if (is->mime != NULL) {
268 playlist = playlist_list_open_stream_mime(is);
269 if (playlist != NULL)
270 return playlist;
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)
277 return playlist;
280 return NULL;
283 static bool
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))
293 return true;
296 return false;
299 struct playlist_provider *
300 playlist_list_open_path(const char *path_fs)
302 GError *error = NULL;
303 const char *suffix;
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))
311 return NULL;
313 is = input_stream_open(path_fs, &error);
314 if (is == NULL) {
315 if (error != NULL) {
316 g_warning("%s", error->message);
317 g_error_free(error);
320 return NULL;
323 while (!is->ready) {
324 int ret = input_stream_buffer(is, &error);
325 if (ret < 0) {
326 input_stream_close(is);
327 g_warning("%s", error->message);
328 g_error_free(error);
329 return NULL;
333 playlist = playlist_list_open_stream_suffix(is, suffix);
334 if (playlist == NULL)
335 input_stream_close(is);
337 return playlist;