~ubuntu-branches/ubuntu/trusty/mpd/trusty

« back to all changes in this revision

Viewing changes to src/playlist_list.c

  • Committer: Bazaar Package Importer
  • Author(s): Angel Abad
  • Date: 2011-02-02 12:26:30 UTC
  • mfrom: (1.5.11 upstream)
  • Revision ID: james.westby@ubuntu.com-20110202122630-bdyx8w4k94doz4fs
Tags: 0.16.1-1ubuntu1
* Merge from debian unstable. Remaining changes:
  - debian/control:
    + Don't build-depend on libmikmod2-dev (Debian bug #510675).
    + Move avahi-daemon from Suggests field to Recommends field.
  - debian/mpd.init.d:
    + Read mpd user from mpd.conf.
  - debian/control, debian/rules:
    + Add libmp3lame-dev to the build dependencies and enable lame.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2003-2010 The Music Player Daemon Project
 
3
 * http://www.musicpd.org
 
4
 *
 
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.
 
9
 *
 
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.
 
14
 *
 
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.
 
18
 */
 
19
 
 
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/rss_playlist_plugin.h"
 
30
#include "playlist/cue_playlist_plugin.h"
 
31
#include "playlist/flac_playlist_plugin.h"
 
32
#include "input_stream.h"
 
33
#include "uri.h"
 
34
#include "utils.h"
 
35
#include "conf.h"
 
36
#include "glib_compat.h"
 
37
#include "mpd_error.h"
 
38
 
 
39
#include <assert.h>
 
40
#include <string.h>
 
41
#include <stdio.h>
 
42
 
 
43
static const struct playlist_plugin *const playlist_plugins[] = {
 
44
        &extm3u_playlist_plugin,
 
45
        &m3u_playlist_plugin,
 
46
        &xspf_playlist_plugin,
 
47
        &pls_playlist_plugin,
 
48
        &asx_playlist_plugin,
 
49
        &rss_playlist_plugin,
 
50
#ifdef ENABLE_LASTFM
 
51
        &lastfm_playlist_plugin,
 
52
#endif
 
53
#ifdef HAVE_CUE
 
54
        &cue_playlist_plugin,
 
55
#endif
 
56
#ifdef HAVE_FLAC
 
57
        &flac_playlist_plugin,
 
58
#endif
 
59
        NULL
 
60
};
 
61
 
 
62
/** which plugins have been initialized successfully? */
 
63
static bool playlist_plugins_enabled[G_N_ELEMENTS(playlist_plugins)];
 
64
 
 
65
/**
 
66
 * Find the "playlist" configuration block for the specified plugin.
 
67
 *
 
68
 * @param plugin_name the name of the playlist plugin
 
69
 * @return the configuration block, or NULL if none was configured
 
70
 */
 
71
static const struct config_param *
 
72
playlist_plugin_config(const char *plugin_name)
 
73
{
 
74
        const struct config_param *param = NULL;
 
75
 
 
76
        assert(plugin_name != NULL);
 
77
 
 
78
        while ((param = config_get_next_param(CONF_PLAYLIST_PLUGIN, param)) != NULL) {
 
79
                const char *name =
 
80
                        config_get_block_string(param, "name", NULL);
 
81
                if (name == NULL)
 
82
                        MPD_ERROR("playlist configuration without 'plugin' name in line %d",
 
83
                                param->line);
 
84
 
 
85
                if (strcmp(name, plugin_name) == 0)
 
86
                        return param;
 
87
        }
 
88
 
 
89
        return NULL;
 
90
}
 
91
 
 
92
void
 
93
playlist_list_global_init(void)
 
94
{
 
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);
 
99
 
 
100
                if (!config_get_block_bool(param, "enabled", true))
 
101
                        /* the plugin is disabled in mpd.conf */
 
102
                        continue;
 
103
 
 
104
                playlist_plugins_enabled[i] =
 
105
                        playlist_plugin_init(playlist_plugins[i], param);
 
106
        }
 
107
}
 
108
 
 
109
void
 
110
playlist_list_global_finish(void)
 
111
{
 
112
        for (unsigned i = 0; playlist_plugins[i] != NULL; ++i)
 
113
                if (playlist_plugins_enabled[i])
 
114
                        playlist_plugin_finish(playlist_plugins[i]);
 
115
}
 
116
 
 
117
static struct playlist_provider *
 
118
playlist_list_open_uri_scheme(const char *uri, bool *tried)
 
119
{
 
120
        char *scheme;
 
121
        struct playlist_provider *playlist = NULL;
 
122
 
 
123
        assert(uri != NULL);
 
124
 
 
125
        scheme = g_uri_parse_scheme(uri);
 
126
        if (scheme == NULL)
 
127
                return NULL;
 
128
 
 
129
        for (unsigned i = 0; playlist_plugins[i] != NULL; ++i) {
 
130
                const struct playlist_plugin *plugin = playlist_plugins[i];
 
131
 
 
132
                assert(!tried[i]);
 
133
 
 
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)
 
139
                                break;
 
140
 
 
141
                        tried[i] = true;
 
142
                }
 
143
        }
 
144
 
 
145
        g_free(scheme);
 
146
        return playlist;
 
147
}
 
148
 
 
149
static struct playlist_provider *
 
150
playlist_list_open_uri_suffix(const char *uri, const bool *tried)
 
151
{
 
152
        const char *suffix;
 
153
        struct playlist_provider *playlist = NULL;
 
154
 
 
155
        assert(uri != NULL);
 
156
 
 
157
        suffix = uri_get_suffix(uri);
 
158
        if (suffix == NULL)
 
159
                return NULL;
 
160
 
 
161
        for (unsigned i = 0; playlist_plugins[i] != NULL; ++i) {
 
162
                const struct playlist_plugin *plugin = playlist_plugins[i];
 
163
 
 
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)
 
169
                                break;
 
170
                }
 
171
        }
 
172
 
 
173
        return playlist;
 
174
}
 
175
 
 
176
struct playlist_provider *
 
177
playlist_list_open_uri(const char *uri)
 
178
{
 
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];
 
183
 
 
184
        assert(uri != NULL);
 
185
 
 
186
        memset(tried, false, sizeof(tried));
 
187
 
 
188
        playlist = playlist_list_open_uri_scheme(uri, tried);
 
189
        if (playlist == NULL)
 
190
                playlist = playlist_list_open_uri_suffix(uri, tried);
 
191
 
 
192
        return playlist;
 
193
}
 
194
 
 
195
static struct playlist_provider *
 
196
playlist_list_open_stream_mime2(struct input_stream *is, const char *mime)
 
197
{
 
198
        struct playlist_provider *playlist;
 
199
 
 
200
        assert(is != NULL);
 
201
        assert(mime != NULL);
 
202
 
 
203
        for (unsigned i = 0; playlist_plugins[i] != NULL; ++i) {
 
204
                const struct playlist_plugin *plugin = playlist_plugins[i];
 
205
 
 
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
 
211
                           fresh start */
 
212
                        input_stream_seek(is, 0, SEEK_SET, NULL);
 
213
 
 
214
                        playlist = playlist_plugin_open_stream(plugin, is);
 
215
                        if (playlist != NULL)
 
216
                                return playlist;
 
217
                }
 
218
        }
 
219
 
 
220
        return NULL;
 
221
}
 
222
 
 
223
static struct playlist_provider *
 
224
playlist_list_open_stream_mime(struct input_stream *is)
 
225
{
 
226
        assert(is->mime != NULL);
 
227
 
 
228
        const char *semicolon = strchr(is->mime, ';');
 
229
        if (semicolon == NULL)
 
230
                return playlist_list_open_stream_mime2(is, is->mime);
 
231
 
 
232
        if (semicolon == is->mime)
 
233
                return NULL;
 
234
 
 
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);
 
239
        g_free(mime);
 
240
        return playlist;
 
241
}
 
242
 
 
243
static struct playlist_provider *
 
244
playlist_list_open_stream_suffix(struct input_stream *is, const char *suffix)
 
245
{
 
246
        struct playlist_provider *playlist;
 
247
 
 
248
        assert(is != NULL);
 
249
        assert(suffix != NULL);
 
250
 
 
251
        for (unsigned i = 0; playlist_plugins[i] != NULL; ++i) {
 
252
                const struct playlist_plugin *plugin = playlist_plugins[i];
 
253
 
 
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
 
259
                           fresh start */
 
260
                        input_stream_seek(is, 0, SEEK_SET, NULL);
 
261
 
 
262
                        playlist = playlist_plugin_open_stream(plugin, is);
 
263
                        if (playlist != NULL)
 
264
                                return playlist;
 
265
                }
 
266
        }
 
267
 
 
268
        return NULL;
 
269
}
 
270
 
 
271
struct playlist_provider *
 
272
playlist_list_open_stream(struct input_stream *is, const char *uri)
 
273
{
 
274
        const char *suffix;
 
275
        struct playlist_provider *playlist;
 
276
 
 
277
        GError *error = NULL;
 
278
        while (!is->ready) {
 
279
                int ret = input_stream_buffer(is, &error);
 
280
                if (ret < 0) {
 
281
                        input_stream_close(is);
 
282
                        g_warning("%s", error->message);
 
283
                        g_error_free(error);
 
284
                        return NULL;
 
285
                }
 
286
        }
 
287
 
 
288
        if (is->mime != NULL) {
 
289
                playlist = playlist_list_open_stream_mime(is);
 
290
                if (playlist != NULL)
 
291
                        return playlist;
 
292
        }
 
293
 
 
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)
 
298
                        return playlist;
 
299
        }
 
300
 
 
301
        return NULL;
 
302
}
 
303
 
 
304
bool
 
305
playlist_suffix_supported(const char *suffix)
 
306
{
 
307
        assert(suffix != NULL);
 
308
 
 
309
        for (unsigned i = 0; playlist_plugins[i] != NULL; ++i) {
 
310
                const struct playlist_plugin *plugin = playlist_plugins[i];
 
311
 
 
312
                if (playlist_plugins_enabled[i] && plugin->suffixes != NULL &&
 
313
                    string_array_contains(plugin->suffixes, suffix))
 
314
                        return true;
 
315
        }
 
316
 
 
317
        return false;
 
318
}
 
319
 
 
320
struct playlist_provider *
 
321
playlist_list_open_path(const char *path_fs, struct input_stream **is_r)
 
322
{
 
323
        GError *error = NULL;
 
324
        const char *suffix;
 
325
        struct input_stream *is;
 
326
        struct playlist_provider *playlist;
 
327
 
 
328
        assert(path_fs != NULL);
 
329
 
 
330
        suffix = uri_get_suffix(path_fs);
 
331
        if (suffix == NULL || !playlist_suffix_supported(suffix))
 
332
                return NULL;
 
333
 
 
334
        is = input_stream_open(path_fs, &error);
 
335
        if (is == NULL) {
 
336
                if (error != NULL) {
 
337
                        g_warning("%s", error->message);
 
338
                        g_error_free(error);
 
339
                }
 
340
 
 
341
                return NULL;
 
342
        }
 
343
 
 
344
        while (!is->ready) {
 
345
                int ret = input_stream_buffer(is, &error);
 
346
                if (ret < 0) {
 
347
                        input_stream_close(is);
 
348
                        g_warning("%s", error->message);
 
349
                        g_error_free(error);
 
350
                        return NULL;
 
351
                }
 
352
        }
 
353
 
 
354
        playlist = playlist_list_open_stream_suffix(is, suffix);
 
355
        if (playlist != NULL)
 
356
                *is_r = is;
 
357
        else
 
358
                input_stream_close(is);
 
359
 
 
360
        return playlist;
 
361
}