1 /*****************************************************************************
2 * shoutcast.c: Winamp >=5.2 shoutcast demuxer
3 *****************************************************************************
4 * Copyright (C) 2006 the VideoLAN team
7 * Authors: Antoine Cellerier <dionoea -@t- videolan -Dot- org>
8 * based on b4s.c by Sigmund Augdal Helberg <dnumgis@videolan.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
30 #include <vlc_demux.h>
37 playlist_t *p_playlist;
38 input_item_t *p_current_input;
41 xml_reader_t *p_xml_reader;
46 /* duplicate from modules/services_discovery/shout.c */
47 #define SHOUTCAST_BASE_URL "http/shout-winamp://www.shoutcast.com/sbin/newxml.phtml"
48 #define SHOUTCAST_TUNEIN_BASE_URL "http://www.shoutcast.com"
49 #define SHOUTCAST_TV_TUNEIN_URL "http://www.shoutcast.com/sbin/tunein-tvstation.pls?id="
51 /*****************************************************************************
53 *****************************************************************************/
54 static int Demux( demux_t *p_demux);
55 static int Control( demux_t *p_demux, int i_query, va_list args );
57 static int DemuxGenre( demux_t *p_demux );
58 static int DemuxStation( demux_t *p_demux );
60 /*****************************************************************************
61 * Import_Shoutcast: main import function
62 *****************************************************************************/
63 int E_(Import_Shoutcast)( vlc_object_t *p_this )
65 demux_t *p_demux = (demux_t *)p_this;
67 if( !demux2_IsForced( p_demux, "shout-winamp" ) )
70 STANDARD_DEMUX_INIT_MSG( "using shoutcast playlist reader" );
71 p_demux->p_sys->p_playlist = NULL;
72 p_demux->p_sys->p_xml = NULL;
73 p_demux->p_sys->p_xml_reader = NULL;
75 /* Do we want to list adult content ? */
76 var_Create( p_demux, "shoutcast-show-adult",
77 VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
78 p_demux->p_sys->b_adult = var_GetBool( p_demux, "shoutcast-show-adult" );
83 /*****************************************************************************
84 * Deactivate: frees unused data
85 *****************************************************************************/
86 void E_(Close_Shoutcast)( vlc_object_t *p_this )
88 demux_t *p_demux = (demux_t *)p_this;
89 demux_sys_t *p_sys = p_demux->p_sys;
91 if( p_sys->p_playlist )
92 vlc_object_release( p_sys->p_playlist );
93 if( p_sys->p_xml_reader )
94 xml_ReaderDelete( p_sys->p_xml, p_sys->p_xml_reader );
96 xml_Delete( p_sys->p_xml );
100 static int Demux( demux_t *p_demux )
102 demux_sys_t *p_sys = p_demux->p_sys;
104 xml_reader_t *p_xml_reader;
105 char *psz_eltname = NULL;
107 p_sys->p_playlist = p_playlist;
108 p_sys->p_current_input = p_current_input;
110 p_xml = p_sys->p_xml = xml_Create( p_demux );
111 if( !p_xml ) return -1;
113 p_xml_reader = xml_ReaderCreate( p_xml, p_demux->s );
114 if( !p_xml_reader ) return -1;
115 p_sys->p_xml_reader = p_xml_reader;
117 /* check root node */
118 if( xml_ReaderRead( p_xml_reader ) != 1 )
120 msg_Err( p_demux, "invalid file (no root node)" );
124 if( xml_ReaderNodeType( p_xml_reader ) != XML_READER_STARTELEM ||
125 ( psz_eltname = xml_ReaderName( p_xml_reader ) ) == NULL ||
126 ( strcmp( psz_eltname, "genrelist" )
127 && strcmp( psz_eltname, "stationlist" ) ) )
129 msg_Err( p_demux, "invalid root node %i, %s",
130 xml_ReaderNodeType( p_xml_reader ), psz_eltname );
131 if( psz_eltname ) free( psz_eltname );
135 if( !strcmp( psz_eltname, "genrelist" ) )
137 /* we're reading a genre list */
139 if( DemuxGenre( p_demux ) ) return -1;
143 /* we're reading a station list */
145 if( DemuxStation( p_demux ) ) return -1;
148 HANDLE_PLAY_AND_RELEASE;
149 p_sys->p_playlist = NULL;
150 return 0; /* Needed for correct operation of go back */
153 #define GET_VALUE( a ) \
154 if( !strcmp( psz_attrname, #a ) ) \
156 psz_ ## a = strdup( psz_attrvalue ); \
159 * <genre name="the name"></genre>
163 static int DemuxGenre( demux_t *p_demux )
165 demux_sys_t *p_sys = p_demux->p_sys;
166 char *psz_name = NULL; /* genre name */
167 char *psz_eltname = NULL; /* tag name */
168 input_item_t *p_input;
170 while( xml_ReaderRead( p_sys->p_xml_reader ) == 1 )
175 i_type = xml_ReaderNodeType( p_sys->p_xml_reader );
183 case XML_READER_STARTELEM:
184 // Read the element name
185 psz_eltname = xml_ReaderName( p_sys->p_xml_reader );
186 if( !psz_eltname ) return -1;
188 if( !strcmp( psz_eltname, "genre" ) )
190 // Read the attributes
191 while( xml_ReaderNextAttr( p_sys->p_xml_reader ) == VLC_SUCCESS )
193 char *psz_attrname = xml_ReaderName( p_sys->p_xml_reader );
194 char *psz_attrvalue =
195 xml_ReaderValue( p_sys->p_xml_reader );
196 if( !psz_attrname || !psz_attrvalue )
198 FREENULL(psz_attrname);
199 FREENULL(psz_attrvalue);
201 /*FIXME: isn't return a bit too much. what about break*/
209 "unexpected attribure %s in element %s",
210 psz_attrname,psz_eltname );
212 free( psz_attrname );
213 free( psz_attrvalue );
216 free( psz_eltname ); psz_eltname = NULL;
219 case XML_READER_TEXT:
223 case XML_READER_ENDELEM:
224 // Read the element name
225 psz_eltname = xml_ReaderName( p_sys->p_xml_reader );
226 if( !psz_eltname ) return -1;
227 if( !strcmp( psz_eltname, "genre" ) )
229 char *psz_mrl = malloc( strlen( SHOUTCAST_BASE_URL )
230 + strlen( "?genre=" ) + strlen( psz_name ) + 1 );
231 sprintf( psz_mrl, SHOUTCAST_BASE_URL "?genre=%s",
233 p_input = input_ItemNewExt( p_sys->p_playlist, psz_mrl,
234 psz_name, 0, NULL, -1 );
235 input_ItemCopyOptions( p_sys->p_current_input,
238 input_ItemAddSubItem( p_sys->p_current_input, p_input );
239 vlc_gc_decref( p_input );
240 FREENULL( psz_name );
242 FREENULL( psz_eltname );
251 * <tunein base="/sbin/tunein-station.pls"></tunein>
252 * <station name="the name"
256 * genre="A big genre string"
257 * ct="current track name/author/..."
258 * lc="listener count"></station>
263 * <tunein base="/sbin/tunein-station.pls"></tunein>
264 * <station name="the name"
268 * load="server load ?"
269 * ct="current track name/author/..."
270 * genre="A big genre string"
271 * lc="listener count"></station>
274 static int DemuxStation( demux_t *p_demux )
276 demux_sys_t *p_sys = p_demux->p_sys;
277 input_item_t *p_input;
279 char *psz_base = NULL; /* */
281 char *psz_name = NULL; /* genre name */
282 char *psz_mt = NULL; /* mime type */
283 char *psz_id = NULL; /* id */
284 char *psz_br = NULL; /* bit rate */
285 char *psz_genre = NULL; /* genre */
286 char *psz_ct = NULL; /* current track */
287 char *psz_lc = NULL; /* listener count */
289 /* If these are set then it's *not* a radio but a TV */
290 char *psz_rt = NULL; /* rating for shoutcast TV */
291 char *psz_load = NULL; /* load for shoutcast TV */
293 char *psz_eltname = NULL; /* tag name */
295 while( xml_ReaderRead( p_sys->p_xml_reader ) == 1 )
300 i_type = xml_ReaderNodeType( p_sys->p_xml_reader );
308 case XML_READER_STARTELEM:
309 // Read the element name
310 psz_eltname = xml_ReaderName( p_sys->p_xml_reader );
311 if( !psz_eltname ) return -1;
313 // Read the attributes
314 if( !strcmp( psz_eltname, "tunein" ) )
316 while( xml_ReaderNextAttr( p_sys->p_xml_reader ) == VLC_SUCCESS )
318 char *psz_attrname = xml_ReaderName( p_sys->p_xml_reader );
319 char *psz_attrvalue =
320 xml_ReaderValue( p_sys->p_xml_reader );
321 if( !psz_attrname || !psz_attrvalue )
324 FREENULL(psz_attrname);
325 FREENULL(psz_attrvalue);
333 "unexpected attribure %s in element %s",
334 psz_attrname, psz_eltname );
336 free( psz_attrname );
337 free( psz_attrvalue );
340 else if( !strcmp( psz_eltname, "station" ) )
342 while( xml_ReaderNextAttr( p_sys->p_xml_reader ) == VLC_SUCCESS )
344 char *psz_attrname = xml_ReaderName( p_sys->p_xml_reader );
345 char *psz_attrvalue =
346 xml_ReaderValue( p_sys->p_xml_reader );
347 if( !psz_attrname || !psz_attrvalue )
350 FREENULL(psz_attrname);
351 FREENULL(psz_attrvalue);
359 else GET_VALUE( genre )
363 else GET_VALUE( load )
367 "unexpected attribute %s in element %s",
368 psz_attrname, psz_eltname );
370 free( psz_attrname );
371 free( psz_attrvalue );
377 case XML_READER_TEXT:
381 case XML_READER_ENDELEM:
382 // Read the element name
383 psz_eltname = xml_ReaderName( p_sys->p_xml_reader );
384 if( !psz_eltname ) return -1;
385 if( !strcmp( psz_eltname, "station" ) &&
386 ( psz_base || ( psz_rt && psz_load &&
387 ( p_sys->b_adult || strcmp( psz_rt, "NC17" ) ) ) ) )
389 char *psz_mrl = NULL;
390 if( psz_rt || psz_load )
393 psz_mrl = malloc( strlen( SHOUTCAST_TV_TUNEIN_URL )
394 + strlen( psz_id ) + 1 );
395 sprintf( psz_mrl, SHOUTCAST_TV_TUNEIN_URL "%s",
401 psz_mrl = malloc( strlen( SHOUTCAST_TUNEIN_BASE_URL )
402 + strlen( psz_base ) + strlen( "?id=" )
403 + strlen( psz_id ) + 1 );
404 sprintf( psz_mrl, SHOUTCAST_TUNEIN_BASE_URL "%s?id=%s",
407 p_input = input_ItemNewExt( p_sys->p_playlist, psz_mrl,
408 psz_name , 0, NULL, -1 );
411 input_ItemCopyOptions( p_sys->p_current_input,
414 #define SADD_INFO( type, field ) if( field ) { input_ItemAddInfo( \
415 p_input, _("Shoutcast"), _(type), "%s", field ) ; }
416 SADD_INFO( "Mime type", psz_mt );
417 SADD_INFO( "Bitrate", psz_br );
418 SADD_INFO( "Listeners", psz_lc );
419 SADD_INFO( "Load", psz_load );
421 input_item_SetGenre( p_input, psz_genre );
423 input_item_SetNowPlaying( p_input, psz_ct );
425 input_item_SetRating( p_input, psz_rt );
426 input_ItemAddSubItem( p_sys->p_current_input, p_input );
427 vlc_gc_decref( p_input );
428 FREENULL( psz_name );
432 FREENULL( psz_genre );
444 static int Control( demux_t *p_demux, int i_query, va_list args )