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 -1; /* 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 FREENULL( psz_name );
241 FREENULL( psz_eltname );
250 * <tunein base="/sbin/tunein-station.pls"></tunein>
251 * <station name="the name"
255 * genre="A big genre string"
256 * ct="current track name/author/..."
257 * lc="listener count"></station>
262 * <tunein base="/sbin/tunein-station.pls"></tunein>
263 * <station name="the name"
267 * load="server load ?"
268 * ct="current track name/author/..."
269 * genre="A big genre string"
270 * lc="listener count"></station>
273 static int DemuxStation( demux_t *p_demux )
275 demux_sys_t *p_sys = p_demux->p_sys;
276 input_item_t *p_input;
278 char *psz_base = NULL; /* */
280 char *psz_name = NULL; /* genre name */
281 char *psz_mt = NULL; /* mime type */
282 char *psz_id = NULL; /* id */
283 char *psz_br = NULL; /* bit rate */
284 char *psz_genre = NULL; /* genre */
285 char *psz_ct = NULL; /* current track */
286 char *psz_lc = NULL; /* listener count */
288 /* If these are set then it's *not* a radio but a TV */
289 char *psz_rt = NULL; /* rating for shoutcast TV */
290 char *psz_load = NULL; /* load for shoutcast TV */
292 char *psz_eltname = NULL; /* tag name */
294 while( xml_ReaderRead( p_sys->p_xml_reader ) == 1 )
299 i_type = xml_ReaderNodeType( p_sys->p_xml_reader );
307 case XML_READER_STARTELEM:
308 // Read the element name
309 psz_eltname = xml_ReaderName( p_sys->p_xml_reader );
310 if( !psz_eltname ) return -1;
312 // Read the attributes
313 if( !strcmp( psz_eltname, "tunein" ) )
315 while( xml_ReaderNextAttr( p_sys->p_xml_reader ) == VLC_SUCCESS )
317 char *psz_attrname = xml_ReaderName( p_sys->p_xml_reader );
318 char *psz_attrvalue =
319 xml_ReaderValue( p_sys->p_xml_reader );
320 if( !psz_attrname || !psz_attrvalue )
323 FREENULL(psz_attrname);
324 FREENULL(psz_attrvalue);
332 "unexpected attribure %s in element %s",
333 psz_attrname, psz_eltname );
335 free( psz_attrname );
336 free( psz_attrvalue );
339 else if( !strcmp( psz_eltname, "station" ) )
341 while( xml_ReaderNextAttr( p_sys->p_xml_reader ) == VLC_SUCCESS )
343 char *psz_attrname = xml_ReaderName( p_sys->p_xml_reader );
344 char *psz_attrvalue =
345 xml_ReaderValue( p_sys->p_xml_reader );
346 if( !psz_attrname || !psz_attrvalue )
349 FREENULL(psz_attrname);
350 FREENULL(psz_attrvalue);
358 else GET_VALUE( genre )
362 else GET_VALUE( load )
366 "unexpected attribute %s in element %s",
367 psz_attrname, psz_eltname );
369 free( psz_attrname );
370 free( psz_attrvalue );
376 case XML_READER_TEXT:
380 case XML_READER_ENDELEM:
381 // Read the element name
382 psz_eltname = xml_ReaderName( p_sys->p_xml_reader );
383 if( !psz_eltname ) return -1;
384 if( !strcmp( psz_eltname, "station" ) &&
385 ( psz_base || ( psz_rt && psz_load &&
386 ( p_sys->b_adult || strcmp( psz_rt, "NC17" ) ) ) ) )
388 char *psz_mrl = NULL;
389 if( psz_rt || psz_load )
392 psz_mrl = malloc( strlen( SHOUTCAST_TV_TUNEIN_URL )
393 + strlen( psz_id ) + 1 );
394 sprintf( psz_mrl, SHOUTCAST_TV_TUNEIN_URL "%s",
400 psz_mrl = malloc( strlen( SHOUTCAST_TUNEIN_BASE_URL )
401 + strlen( psz_base ) + strlen( "?id=" )
402 + strlen( psz_id ) + 1 );
403 sprintf( psz_mrl, SHOUTCAST_TUNEIN_BASE_URL "%s?id=%s",
406 p_input = input_ItemNewExt( p_sys->p_playlist, psz_mrl,
407 psz_name , 0, NULL, -1 );
410 input_ItemCopyOptions( p_sys->p_current_input,
413 #define SADD_INFO( type, field ) if( field ) { input_ItemAddInfo( \
414 p_input, _("Shoutcast"), _(type), "%s", field ) ; }
415 SADD_INFO( "Mime type", psz_mt );
416 SADD_INFO( "Bitrate", psz_br );
417 SADD_INFO( "Listeners", psz_lc );
418 SADD_INFO( "Load", psz_load );
420 input_item_SetGenre( p_input, psz_genre );
422 input_item_SetNowPlaying( p_input, psz_ct );
424 input_item_SetRating( p_input, psz_rt );
425 input_ItemAddSubItem( p_sys->p_current_input, p_input );
427 FREENULL( psz_name );
431 FREENULL( psz_genre )
443 static int Control( demux_t *p_demux, int i_query, va_list args )