2
arch-tag: Implementation of Rhythmbox playlist parser
4
Copyright (C) 2002, 2003 Bastien Nocera
5
Copyright (C) 2003 Colin Walters <walters@rhythmbox.org>
7
The Gnome Library is free software; you can redistribute it and/or
8
modify it under the terms of the GNU Library General Public License as
9
published by the Free Software Foundation; either version 2 of the
10
License, or (at your option) any later version.
12
The Gnome Library is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
Library General Public License for more details.
17
You should have received a copy of the GNU Library General Public
18
License along with the Gnome Library; see the file COPYING.LIB. If not,
19
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20
Boston, MA 02111-1307, USA.
22
Author: Bastien Nocera <hadess@hadess.net>
26
#include "rb-playlist.h"
28
#include "rb-marshal.h"
29
#include "rb-file-helpers.h"
33
#include <libxml/tree.h>
34
#include <libxml/parser.h>
35
#include <glade/glade.h>
36
#include <gconf/gconf-client.h>
37
#if HAVE_LIBGNOME_DESKTOP
38
#include <libgnome/gnome-desktop-item.h>
40
#include <libgnomevfs/gnome-vfs.h>
41
#include <libgnomevfs/gnome-vfs-mime-utils.h>
43
#include <libgnome/gnome-i18n.h>
46
rb_playlist_parse_recurse (RBPlaylist *playlist, const char *uri,
49
#define READ_CHUNK_SIZE 8192
50
#define MIME_READ_CHUNK_SIZE 1024
52
typedef gboolean (*PlaylistCallback) (RBPlaylist *playlist, const char *url,
53
guint recurse_level, gpointer data);
57
PlaylistCallback func;
60
struct RBPlaylistPrivate
73
static int rb_playlist_table_signals[LAST_SIGNAL] = { 0 };
75
static GObjectClass *parent_class = NULL;
77
static void rb_playlist_class_init (RBPlaylistClass *class);
78
static void rb_playlist_init (RBPlaylist *playlist);
79
static void rb_playlist_finalize (GObject *object);
81
const char * my_gnome_vfs_get_mime_type_with_data (const char *uri, gpointer *data);
85
rb_playlist_get_type (void)
87
static GtkType rb_playlist_type = 0;
89
if (!rb_playlist_type) {
90
static const GTypeInfo rb_playlist_info = {
91
sizeof (RBPlaylistClass),
93
(GBaseFinalizeFunc) NULL,
94
(GClassInitFunc) rb_playlist_class_init,
95
(GClassFinalizeFunc) NULL,
96
NULL /* class_data */,
99
(GInstanceInitFunc) rb_playlist_init,
102
rb_playlist_type = g_type_register_static (G_TYPE_OBJECT,
103
"RBPlaylist", &rb_playlist_info,
107
return rb_playlist_type;
111
rb_playlist_class_init (RBPlaylistClass *klass)
113
GObjectClass *object_class = G_OBJECT_CLASS (klass);
115
parent_class = g_type_class_peek_parent (klass);
117
object_class->finalize = rb_playlist_finalize;
120
rb_playlist_table_signals[ENTRY] =
121
g_signal_new ("entry",
122
G_TYPE_FROM_CLASS (klass),
124
G_STRUCT_OFFSET (RBPlaylistClass, entry),
126
rb_marshal_VOID__STRING_STRING_STRING,
127
G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
131
rb_playlist_error_quark (void)
135
quark = g_quark_from_static_string ("rb_playlist_error");
141
rb_playlist_new (void)
143
return RB_PLAYLIST (g_object_new (RB_TYPE_PLAYLIST, NULL));
147
my_gnome_vfs_get_mime_type_with_data (const char *uri, gpointer *data)
149
GnomeVFSResult result;
150
GnomeVFSHandle *handle;
152
const char *mimetype;
153
GnomeVFSFileSize total_bytes_read;
154
GnomeVFSFileSize bytes_read;
159
result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
160
if (result != GNOME_VFS_OK)
163
/* Read the whole thing. */
165
total_bytes_read = 0;
167
buffer = g_realloc (buffer, total_bytes_read
168
+ MIME_READ_CHUNK_SIZE);
169
result = gnome_vfs_read (handle,
170
buffer + total_bytes_read,
171
MIME_READ_CHUNK_SIZE,
173
if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_EOF) {
175
gnome_vfs_close (handle);
179
/* Check for overflow. */
180
if (total_bytes_read + bytes_read < total_bytes_read) {
182
gnome_vfs_close (handle);
186
total_bytes_read += bytes_read;
187
} while (result == GNOME_VFS_OK
188
&& total_bytes_read < MIME_READ_CHUNK_SIZE);
190
/* Close the file. */
191
result = gnome_vfs_close (handle);
192
if (result != GNOME_VFS_OK) {
197
/* Return the file. */
198
*data = g_realloc (buffer, total_bytes_read);
199
mimetype = gnome_vfs_get_mime_type_for_data (*data, total_bytes_read);
205
write_string (GnomeVFSHandle *handle, const char *buf, GError **error)
208
GnomeVFSFileSize written;
212
res = gnome_vfs_write (handle, buf, len, &written);
213
if (res != GNOME_VFS_OK || written < len) {
216
RB_PLAYLIST_ERROR_VFS_WRITE,
217
_("Couldn't write playlist: %s"),
218
gnome_vfs_result_to_string (res));
219
gnome_vfs_close (handle);
227
rb_playlist_write (RBPlaylist *playlist, GtkTreeModel *model,
228
RBPlaylistIterFunc func, const char *output, GError **error)
230
GnomeVFSHandle *handle;
236
num_entries = gtk_tree_model_iter_n_children (model, NULL);
237
res = gnome_vfs_open (&handle, output, GNOME_VFS_OPEN_WRITE);
238
if (res == GNOME_VFS_ERROR_NOT_FOUND) {
239
res = gnome_vfs_create (&handle, output,
240
GNOME_VFS_OPEN_WRITE, FALSE,
241
GNOME_VFS_PERM_USER_WRITE
242
| GNOME_VFS_PERM_USER_READ
243
| GNOME_VFS_PERM_GROUP_READ);
246
if (res != GNOME_VFS_OK) {
249
RB_PLAYLIST_ERROR_VFS_OPEN,
250
_("Couldn't open playlist: %s"),
251
gnome_vfs_result_to_string (res));
255
buf = g_strdup ("[playlist]\n");
256
success = write_string (handle, buf, error);
258
if (success == FALSE)
261
buf = g_strdup_printf ("numberofentries=%d\n", num_entries);
262
success = write_string (handle, buf, error);
264
if (success == FALSE)
267
for (i = 1; i <= num_entries; i++) {
269
char *path, *url, *title;
271
path = g_strdup_printf ("%d", i - 1);
272
gtk_tree_model_get_iter_from_string (model, &iter, path);
275
func (model, &iter, &url, &title);
277
buf = g_strdup_printf ("file%d=%s\n", i, url);
278
success = write_string (handle, buf, error);
281
if (success == FALSE)
287
buf = g_strdup_printf ("title%d=%s\n", i, title);
288
success = write_string (handle, buf, error);
291
if (success == FALSE)
295
gnome_vfs_close (handle);
299
static GnomeVFSResult
300
my_eel_read_entire_file (const char *uri,
302
char **file_contents)
304
GnomeVFSResult result;
305
GnomeVFSHandle *handle;
307
GnomeVFSFileSize total_bytes_read;
308
GnomeVFSFileSize bytes_read;
311
*file_contents = NULL;
314
result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ);
315
if (result != GNOME_VFS_OK) {
319
/* Read the whole thing. */
321
total_bytes_read = 0;
323
buffer = g_realloc (buffer, total_bytes_read + READ_CHUNK_SIZE);
324
result = gnome_vfs_read (handle,
325
buffer + total_bytes_read,
328
if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_EOF) {
330
gnome_vfs_close (handle);
334
/* Check for overflow. */
335
if (total_bytes_read + bytes_read < total_bytes_read) {
337
gnome_vfs_close (handle);
338
return GNOME_VFS_ERROR_TOO_BIG;
341
total_bytes_read += bytes_read;
342
} while (result == GNOME_VFS_OK);
344
/* Close the file. */
345
result = gnome_vfs_close (handle);
346
if (result != GNOME_VFS_OK) {
351
/* Return the file. */
352
*file_size = total_bytes_read;
353
*file_contents = g_realloc (buffer, total_bytes_read);
359
rb_playlist_base_url (const char *url)
361
/* Yay, let's reconstruct the base by hand */
362
GnomeVFSURI *uri, *parent;
365
uri = gnome_vfs_uri_new (url);
366
parent = gnome_vfs_uri_get_parent (uri);
367
base = gnome_vfs_uri_to_string (parent, 0);
369
gnome_vfs_uri_unref (uri);
370
gnome_vfs_uri_unref (parent);
376
read_ini_line_int (char **lines, const char *key)
381
if (lines == NULL || key == NULL)
384
for (i = 0; (lines[i] != NULL && retval == -1); i++) {
385
if (g_ascii_strncasecmp (lines[i], key, strlen (key)) == 0) {
388
bits = g_strsplit (lines[i], "=", 2);
389
if (bits[0] == NULL || bits [1] == NULL) {
394
retval = (gint) g_strtod (bits[1], NULL);
403
read_ini_line_string (char **lines, const char *key, gboolean dos_mode)
408
if (lines == NULL || key == NULL)
411
for (i = 0; (lines[i] != NULL && retval == NULL); i++) {
412
if (g_ascii_strncasecmp (lines[i], key, strlen (key)) == 0) {
416
bits = g_strsplit (lines[i], "=", 2);
417
if (bits[0] == NULL || bits [1] == NULL) {
422
retval = g_strdup (bits[1]);
423
len = strlen (retval);
424
if (dos_mode && len >= 2 && retval[len-2] == '\r') {
425
retval[len-2] = '\n';
426
retval[len-1] = '\0';
437
rb_playlist_init (RBPlaylist *playlist)
439
playlist->priv = g_new0 (RBPlaylistPrivate, 1);
443
rb_playlist_finalize (GObject *object)
445
RBPlaylist *playlist = RB_PLAYLIST (object);
447
g_return_if_fail (object != NULL);
448
g_return_if_fail (playlist->priv != NULL);
450
if (G_OBJECT_CLASS (parent_class)->finalize != NULL) {
451
(* G_OBJECT_CLASS (parent_class)->finalize) (object);
456
rb_playlist_add_one_url (RBPlaylist *playlist, const char *url, const char *title)
459
g_signal_emit (G_OBJECT (playlist), rb_playlist_table_signals[ENTRY],
460
0, url, title, NULL);
464
rb_playlist_add_one_url_ext (RBPlaylist *playlist, const char *url, const char *title,
467
g_signal_emit (G_OBJECT (playlist), rb_playlist_table_signals[ENTRY],
468
0, url, title, genre);
472
rb_playlist_add_ram (RBPlaylist *playlist, const char *url,
473
guint recurse_level, gpointer data)
475
gboolean retval = FALSE;
476
char *contents, **lines;
478
const char *split_char;
480
if (my_eel_read_entire_file (url, &size, &contents) != GNOME_VFS_OK)
483
contents = g_realloc (contents, size + 1);
484
contents[size] = '\0';
486
/* figure out whether we're a unix or dos RAM file */
487
if (strstr(contents,"\x0d") == NULL)
490
split_char = "\x0d\n";
492
lines = g_strsplit (contents, split_char, 0);
495
for (i = 0; lines[i] != NULL; i++) {
496
if (strcmp (lines[i], "") == 0)
499
/* Either it's a URI, or it has a proper path ... */
500
if (strstr(lines[i], "://") != NULL
501
|| lines[i][0] == G_DIR_SEPARATOR) {
502
/* .ram files can contain .smil entries */
503
rb_playlist_parse_recurse (playlist, lines[i],
505
rb_playlist_add_one_url (playlist, lines[i], NULL);
506
} else if (strcmp (lines[i], "--stop--") == 0) {
507
/* For Real Media playlists, handle the stop command */
510
char *fullpath, *base;
512
/* Try with a base */
513
base = rb_playlist_base_url (url);
515
fullpath = g_strdup_printf ("%s/%s", base, lines[i]);
516
if (rb_playlist_parse_recurse (playlist, fullpath,
517
recurse_level) == TRUE)
531
rb_playlist_get_extinfo_title (gboolean extinfo, char **lines, int i)
535
if (extinfo == FALSE)
541
retval = strstr (lines[i-1], "#EXTINF:");
542
retval = strstr (retval, ",");
543
if (retval == NULL || retval[0] == '\0')
552
rb_playlist_add_m3u (RBPlaylist *playlist, const char *url,
553
guint recurse_level, gpointer data)
555
gboolean retval = FALSE;
556
char *contents, **lines;
561
if (my_eel_read_entire_file (url, &size, &contents) != GNOME_VFS_OK)
564
contents = g_realloc (contents, size + 1);
565
contents[size] = '\0';
567
/* is TRUE if there's an EXTINF on the previous line */
570
/* figure out whether we're a unix m3u or dos m3u */
571
if (strstr(contents,"\x0d") == NULL)
574
split_char = "\x0d\n";
576
lines = g_strsplit (contents, split_char, 0);
579
for (i = 0; lines[i] != NULL; i++) {
580
if (lines[i][0] == '\0')
583
/* Ignore comments, but mark it if we have extra info */
584
if (lines[i][0] == '#') {
585
if (strstr (lines[i], "#EXTINF") != NULL)
590
/* Either it's a URI, or it has a proper path ... */
591
if (strstr(lines[i], "://") != NULL
592
|| lines[i][0] == G_DIR_SEPARATOR) {
593
rb_playlist_parse_recurse (playlist, lines[i],
595
rb_playlist_add_one_url (playlist, lines[i],
596
rb_playlist_get_extinfo_title (extinfo, lines, i));
599
} else if (lines[i][0] == '\\' && lines[i][1] == '\\') {
600
/* ... Or it's in the windows smb form
601
* (\\machine\share\filename), Note drive names
602
* (C:\ D:\ etc) are unhandled (unknown base for
606
lines[i] = g_strdelimit (lines[i], "\\", '/');
607
tmpurl = g_strjoin (NULL, "smb:", lines[i], NULL);
609
rb_playlist_add_one_url (playlist, tmpurl, NULL);
615
/* Try with a base */
616
char *fullpath, *base, sep;
620
base = rb_playlist_base_url (url);
621
sep = (split_char[0] == '\n' ? '/' : '\\');
623
lines[i] = g_strdelimit (lines[i], "\\", '/');
624
fullpath = g_strdup_printf ("%s/%s", base, lines[i]);
625
if (!rb_playlist_parse_recurse (playlist, fullpath,
627
rb_playlist_add_one_url (playlist, fullpath, NULL);
640
rb_playlist_add_asf_parser (RBPlaylist *playlist, const char *url,
641
guint recurse_level, gpointer data)
643
gboolean retval = FALSE;
644
char *contents, **lines, *ref;
647
if (my_eel_read_entire_file (url, &size, &contents) != GNOME_VFS_OK)
650
contents = g_realloc (contents, size + 1);
651
contents[size] = '\0';
653
lines = g_strsplit (contents, "\n", 0);
656
ref = read_ini_line_string (lines, "Ref1", FALSE);
661
/* change http to mms, thanks Microsoft */
662
if (strncmp ("http", ref, 4) == 0)
663
memcpy(ref, "mmsh", 4);
665
rb_playlist_add_one_url (playlist, ref, NULL);
676
rb_playlist_add_pls (RBPlaylist *playlist, const char *url,
677
guint recurse_level, gpointer data)
679
gboolean retval = FALSE;
680
char *contents, **lines;
681
int size, i, num_entries;
683
gboolean dos_mode = FALSE;
685
if (my_eel_read_entire_file (url, &size, &contents) != GNOME_VFS_OK)
688
contents = g_realloc (contents, size + 1);
689
contents[size] = '\0';
691
/* figure out whether we're a unix pls or dos pls */
692
if (strstr(contents,"\x0d") == NULL)
695
split_char = "\x0d\n";
698
lines = g_strsplit (contents, split_char, 0);
703
|| g_ascii_strncasecmp (lines[0], "[playlist]",
704
(gsize)strlen ("[playlist]")) != 0)
707
/* numberofentries=? */
708
num_entries = read_ini_line_int (lines, "numberofentries");
709
if (num_entries == -1)
712
for (i = 1; i <= num_entries; i++) {
713
char *file, *title, *genre;
714
char *file_key, *title_key, *genre_key;
716
file_key = g_strdup_printf ("file%d", i);
717
title_key = g_strdup_printf ("title%d", i);
718
/* Genre is our own little extension */
719
genre_key = g_strdup_printf ("genre%d", i);
721
file = read_ini_line_string (lines, (const char*)file_key, dos_mode);
722
title = read_ini_line_string (lines, (const char*)title_key, dos_mode);
723
genre = read_ini_line_string (lines, (const char*)genre_key, dos_mode);
730
rb_playlist_add_one_url_ext (playlist, file, title, genre);
746
parse_asx_entry (RBPlaylist *playlist, guint recurse_level,
747
char *base, xmlDocPtr doc, xmlNodePtr parent)
751
gboolean retval = FALSE;
756
for (node = parent->children; node != NULL; node = node->next) {
757
if (node->name == NULL)
760
/* ENTRY should only have one ref and one title nodes */
761
if (g_ascii_strcasecmp (node->name, "ref") == 0) {
762
url = xmlGetProp (node, "href");
766
if (g_ascii_strcasecmp (node->name, "title") == 0)
767
title = xmlNodeListGetString (doc, node->children, 1);
775
if (strstr (url, "://") != NULL || url[0] == '/') {
776
rb_playlist_add_one_url (playlist, url, title);
781
fullpath = g_strdup_printf ("%s/%s", base, url);
782
/* .asx files can contain references to other .asx files */
783
rb_playlist_parse_recurse (playlist, fullpath, recurse_level);
795
parse_asx_entries (RBPlaylist *playlist, guint recurse_level,
796
char *base, xmlDocPtr doc, xmlNodePtr parent)
799
gboolean retval = FALSE;
801
for (node = parent->children; node != NULL; node = node->next) {
802
if (node->name == NULL)
805
if (g_ascii_strcasecmp (node->name, "entry") == 0) {
806
/* Whee found an entry here, find the REF and TITLE */
807
if (parse_asx_entry (playlist, recurse_level, base, doc, node) == TRUE)
816
rb_playlist_add_asx (RBPlaylist *playlist, const char *url,
817
guint recurse_level, gpointer data)
821
char *contents = NULL, *base;
823
gboolean retval = FALSE;
825
if (my_eel_read_entire_file (url, &size, &contents) != GNOME_VFS_OK)
828
contents = g_realloc (contents, size + 1);
829
contents[size] = '\0';
831
doc = xmlParseMemory (contents, size);
833
doc = xmlRecoverMemory (contents, size);
836
/* If the document has no root, or no name */
837
if(!doc || !doc->children || !doc->children->name) {
843
base = rb_playlist_base_url (url);
845
for (node = doc->children; node != NULL; node = node->next)
846
if (parse_asx_entries (playlist, recurse_level, base, doc, node) == TRUE)
855
rb_playlist_add_ra (RBPlaylist *playlist, const char *url,
856
guint recurse_level, gpointer data)
859
|| (strncmp (data, "http://", strlen ("http://")) != 0
860
&& strncmp (data, "rtsp://", strlen ("rtsp://")) != 0
861
&& strncmp (data, "pnm://", strlen ("pnm://")) != 0)) {
862
rb_playlist_add_one_url (playlist, url, NULL);
866
return rb_playlist_add_ram (playlist, url, recurse_level, NULL);
870
parse_smil_video_entry (RBPlaylist *playlist, char *base,
871
char *url, char *title)
873
if (strstr (url, "://") != NULL || url[0] == '/') {
874
rb_playlist_add_one_url (playlist, url, title);
878
fullpath = g_strdup_printf ("%s/%s", base, url);
879
rb_playlist_add_one_url (playlist, fullpath, title);
888
parse_smil_entry (RBPlaylist *playlist, guint recurse_level, char *base,
889
xmlDocPtr doc, xmlNodePtr parent)
893
gboolean retval = FALSE;
898
if (recurse_level > 5)
901
for (node = parent->children; node != NULL; node = node->next) {
902
if (node->name == NULL)
905
/* ENTRY should only have one ref and one title nodes */
906
if (g_ascii_strcasecmp (node->name, "video") == 0) {
907
url = xmlGetProp (node, "src");
908
title = xmlGetProp (node, "title");
911
if (parse_smil_video_entry (playlist,
912
base, url, title) == TRUE)
919
if (parse_smil_entry (playlist, recurse_level+1,
920
base, doc, node) == TRUE)
929
parse_smil_entries (RBPlaylist *playlist, guint recurse_level,
930
char *base, xmlDocPtr doc, xmlNodePtr parent)
933
gboolean retval = FALSE;
935
for (node = parent->children; node != NULL; node = node->next) {
936
if (node->name == NULL)
939
if (g_ascii_strcasecmp (node->name, "body") == 0) {
940
if (parse_smil_entry (playlist, recurse_level,
941
base, doc, node) == TRUE)
951
rb_playlist_add_smil (RBPlaylist *playlist, const char *url,
952
guint recurse_level, gpointer data)
956
char *contents = NULL, *base;
958
gboolean retval = FALSE;
960
if (my_eel_read_entire_file (url, &size, &contents) != GNOME_VFS_OK)
963
contents = g_realloc (contents, size + 1);
964
contents[size] = '\0';
966
doc = xmlParseMemory (contents, size);
968
doc = xmlRecoverMemory (contents, size);
971
/* If the document has no root, or no name */
972
if(!doc || !doc->children
973
|| !doc->children->name
974
|| g_ascii_strcasecmp (doc->children->name,
981
base = rb_playlist_base_url (url);
983
for (node = doc->children; node != NULL; node = node->next)
984
if (parse_smil_entries (playlist, recurse_level, base, doc, node) == TRUE)
991
rb_playlist_add_asf (RBPlaylist *playlist, const char *url,
992
guint recurse_level, gpointer data)
995
rb_playlist_add_one_url (playlist, url, NULL);
999
if (strncmp (data, "[Reference]", strlen ("[Reference]")) != 0) {
1000
rb_playlist_add_one_url (playlist, url, NULL);
1004
return rb_playlist_add_asf_parser (playlist, url, recurse_level, data);
1007
#if HAVE_LIBGNOME_DESKTOP
1009
rb_playlist_add_desktop (RBPlaylist *playlist, const char *url,
1010
guint recurse_level, gpointer data)
1012
GnomeDesktopItem *ditem;
1015
const char *path, *display_name;
1017
ditem = gnome_desktop_item_new_from_file (url, 0, NULL);
1021
type = gnome_desktop_item_get_entry_type (ditem);
1022
if (type != GNOME_DESKTOP_ITEM_TYPE_LINK) {
1023
gnome_desktop_item_unref (ditem);
1027
path = gnome_desktop_item_get_string (ditem, "URL");
1029
gnome_desktop_item_unref (ditem);
1032
display_name = gnome_desktop_item_get_localestring (ditem, "Name");
1033
retval = rb_playlist_add_url (playlist, path, display_name);
1034
gnome_desktop_item_unref (ditem);
1040
/* These ones need a special treatment, mostly playlist formats */
1041
static PlaylistTypes special_types[] = {
1042
{ "audio/x-mpegurl", rb_playlist_add_m3u },
1043
{ "audio/x-ms-asx", rb_playlist_add_asx },
1044
{ "audio/x-scpls", rb_playlist_add_pls },
1045
{ "application/x-smil", rb_playlist_add_smil },
1046
#if HAVE_LIBGNOME_DESKTOP
1047
{ "application/x-gnome-app-info", rb_playlist_add_desktop },
1049
{ "video/x-ms-wvx", rb_playlist_add_asx },
1050
{ "video/x-ms-wax", rb_playlist_add_asx },
1053
/* These ones are "dual" types, might be a video, might be a playlist */
1054
static PlaylistTypes dual_types[] = {
1055
{ "audio/x-real-audio", rb_playlist_add_ra },
1056
{ "audio/x-pn-realaudio", rb_playlist_add_ra },
1057
{ "application/vnd.rn-realmedia", rb_playlist_add_ra },
1058
{ "audio/x-pn-realaudio-plugin", rb_playlist_add_ra },
1059
{ "text/plain", rb_playlist_add_ra },
1060
{ "video/x-ms-asf", rb_playlist_add_asf },
1061
{ "video/x-ms-wmv", rb_playlist_add_asf },
1065
rb_playlist_add_url_from_data (RBPlaylist *playlist, const char *url,
1066
guint recurse_level)
1068
const char *mimetype;
1073
mimetype = my_gnome_vfs_get_mime_type_with_data (url, &data);
1074
if (mimetype == NULL)
1077
for (i = 0; i < G_N_ELEMENTS(special_types); i++) {
1078
if (mimetype == NULL)
1080
if (strcmp (special_types[i].mimetype, mimetype) == 0) {
1081
retval = (* special_types[i].func) (playlist, url,
1082
recurse_level, data);
1088
for (i = 0; i < G_N_ELEMENTS(dual_types); i++) {
1089
if (strcmp (dual_types[i].mimetype, mimetype) == 0) {
1090
retval = (* dual_types[i].func) (playlist, url,
1091
recurse_level, data);
1103
rb_playlist_parse_recurse (RBPlaylist *playlist, const char *uri,
1109
g_return_val_if_fail (uri != NULL, FALSE);
1111
if (recurse_level > 3)
1114
if (recurse_level > 1 && rb_uri_is_iradio (uri)) {
1115
rb_playlist_add_one_url (playlist, uri, NULL);
1121
mimetype = gnome_vfs_get_mime_type (uri);
1123
if (mimetype == NULL)
1124
return rb_playlist_add_url_from_data (playlist, uri, recurse_level);
1126
for (i = 0; i < G_N_ELEMENTS(special_types); i++) {
1127
if (strcmp (special_types[i].mimetype, mimetype) == 0) {
1129
return (* special_types[i].func) (playlist, uri, recurse_level, NULL);
1133
for (i = 0; i < G_N_ELEMENTS(dual_types); i++) {
1134
if (strcmp (dual_types[i].mimetype, mimetype) == 0) {
1136
return rb_playlist_add_url_from_data (playlist, uri, recurse_level);
1145
rb_playlist_parse (RBPlaylist *playlist, const char *url)
1147
return rb_playlist_parse_recurse (playlist, url, 1);
1151
rb_playlist_can_handle (const char *url)
1153
const char *mimetype;
1156
g_return_val_if_fail (url != NULL, FALSE);
1158
mimetype = gnome_vfs_get_mime_type (url);
1160
if (mimetype == NULL)
1163
for (i = 0; i < G_N_ELEMENTS(special_types); i++)
1164
if (strcmp (special_types[i].mimetype, mimetype) == 0)
1167
for (i = 0; i < G_N_ELEMENTS(dual_types); i++)
1168
if (strcmp (dual_types[i].mimetype, mimetype) == 0)