X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fservices_discovery%2Fshout.c;h=276e9b2d060676e6d6b5ddab9c533fca25dcb57b;hb=ccfd6a88445732ec03d8e0977e3c3a27f80c86b3;hp=9e782df20faecd4ec9591abf852f709ab8355180;hpb=ace4087ec6c9171876a9b24e820d50f0b4624f6a;p=vlc diff --git a/modules/services_discovery/shout.c b/modules/services_discovery/shout.c index 9e782df20f..276e9b2d06 100644 --- a/modules/services_discovery/shout.c +++ b/modules/services_discovery/shout.c @@ -1,11 +1,12 @@ /***************************************************************************** * shout.c: Shoutcast services discovery module ***************************************************************************** - * Copyright (C) 2005 the VideoLAN team + * Copyright (C) 2005-2007 the VideoLAN team * $Id$ * * Authors: Sigmund Augdal Helberg * Antoine Cellerier + * Pierre d'Herbemont * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,184 +26,267 @@ /***************************************************************************** * Includes *****************************************************************************/ -#include /* malloc(), free() */ -#include -#include -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif -#include +#include +#include +#include -#include "network.h" +/***************************************************************************** + * Module descriptor + *****************************************************************************/ -#include /* ENOMEM */ +enum type_e { ShoutRadio = 0, ShoutTV = 1, Freebox = 2, FrenchTV = 3 }; -#ifdef HAVE_UNISTD_H -# include -#endif -#ifdef HAVE_SYS_TIME_H -# include -#endif +static int Open( vlc_object_t *, enum type_e ); +static void Close( vlc_object_t * ); -/************************************************************************ - * Macros and definitions - ************************************************************************/ +struct shout_item_t +{ + const char *psz_url; + const char *psz_name; + const char *ppsz_options[2]; + const struct shout_item_t * p_children; +}; -#define MAX_LINE_LENGTH 256 -#define SHOUTCAST_BASE_URL "http/shout-winamp://www.shoutcast.com/sbin/newxml.phtml" -#define SHOUTCAST_TV_BASE_URL "http/shout-winamp://www.shoutcast.com/sbin/newtvlister.phtml?alltv=1" +#define endItem( ) { NULL, NULL, { NULL }, NULL } +#define item( title, url ) { url, title, { NULL }, NULL } +#define itemWithOption( title, url, option ) { url, title, { option, NULL }, NULL } +#define itemWithChildren( title, children ) { "vlc://nop", title, { NULL }, children } -/***************************************************************************** - * Module descriptor - *****************************************************************************/ +/* WARN: We support only two levels */ -/* Callbacks */ - static int Open ( vlc_object_t *, int ); - static int OpenRadio ( vlc_object_t * ); - static int OpenTV ( vlc_object_t * ); - static void Close( vlc_object_t * ); +static const struct shout_item_t p_frenchtv_canalplus[] = { + itemWithOption( N_("Les Guignols"), "http://www.canalplus.fr/index.php?pid=1784", "http-forward-cookies" ), + endItem() +}; + +static const struct shout_item_t p_frenchtv[] = { + itemWithChildren( N_("Canal +"), p_frenchtv_canalplus ), + endItem() +}; -vlc_module_begin(); - set_shortname( "Shoutcast"); - set_description( _("Shoutcast radio listings") ); - add_shortcut( "shoutcast" ); - set_category( CAT_PLAYLIST ); - set_subcategory( SUBCAT_PLAYLIST_SD ); +static const struct shout_item_t p_items[] = { + item( N_("Shoutcast Radio"), "http/shout-winamp://www.shoutcast.com/sbin/newxml.phtml" ), + item( N_("Shoutcast TV"), "http/shout-winamp://www.shoutcast.com/sbin/newtvlister.phtml?alltv=1" ), + itemWithOption( N_("Freebox TV"),"http://mafreebox.freebox.fr/freeboxtv/playlist.m3u", "deinterlace=1"), + itemWithChildren(N_("French TV"), p_frenchtv ), + endItem() +}; - add_suppressed_integer( "shoutcast-limit" ); +#undef endItem +#undef item +#undef itemWithOptions +#undef itemWithChildren - set_capability( "services_discovery", 0 ); - set_callbacks( OpenRadio, Close ); +struct shout_category_t { + services_discovery_t * p_sd; + const char * psz_category; + const struct shout_item_t * p_parent; +}; + +/* Main functions */ +#define OPEN( type ) \ +static int Open ## type ( vlc_object_t *p_this ) \ +{ \ + msg_Dbg( p_this, "Starting " #type ); \ + return Open( p_this, type ); \ +} - add_submodule(); - set_shortname( "ShoutcastTV" ); - set_description( _("Shoutcast TV listings") ); - set_capability( "services_discovery", 0 ); - set_callbacks( OpenTV, Close ); - add_shortcut( "shoutcasttv" ); +OPEN( ShoutRadio ) +OPEN( ShoutTV ) +OPEN( Freebox ) +OPEN( FrenchTV ) -vlc_module_end(); +#undef OPEN + +static int vlc_sd_probe_Open( vlc_object_t * ); + +vlc_module_begin () + set_category( CAT_PLAYLIST ) + set_subcategory( SUBCAT_PLAYLIST_SD ) + + add_obsolete_integer( "shoutcast-limit" ) + + set_shortname( "Shoutcast") + set_description( N_("Shoutcast Radio") ) + set_capability( "services_discovery", 0 ) + set_callbacks( OpenShoutRadio, Close ) + add_shortcut( "shoutcast" ) + + add_submodule () + set_shortname( "ShoutcastTV" ) + set_description( N_("Shoutcast TV") ) + set_capability( "services_discovery", 0 ) + set_callbacks( OpenShoutTV, Close ) + add_shortcut( "shoutcasttv" ) + + add_submodule () + set_shortname( "frenchtv") + set_description( N_("French TV") ) + set_capability( "services_discovery", 0 ) + set_callbacks( OpenFrenchTV, Close ) + add_shortcut( "frenchtv" ) + + add_submodule () + set_shortname( "Freebox") + set_description( N_("Freebox TV") ) + set_capability( "services_discovery", 0 ) + set_callbacks( OpenFreebox, Close ) + add_shortcut( "freebox" ) + + VLC_SD_PROBE_SUBMODULE +vlc_module_end () /***************************************************************************** - * Local structures + * Local prototypes *****************************************************************************/ +static void *Run( void * ); struct services_discovery_sys_t { - playlist_item_t *p_node_cat,*p_node_one; - input_item_t *p_input; - vlc_bool_t b_dialog; + vlc_thread_t thread; + enum type_e i_type; }; -#define RADIO 0 -#define TV 1 - /***************************************************************************** - * Local prototypes + * Open: initialize and create stuff *****************************************************************************/ +static int Open( vlc_object_t *p_this, enum type_e i_type ) +{ + services_discovery_t *p_sd = ( services_discovery_t* )p_this; -/* Main functions */ - static void Run ( services_discovery_t *p_intf ); + p_sd->p_sys = malloc (sizeof (*(p_sd->p_sys))); + if (p_sd->p_sys == NULL) + return VLC_ENOMEM; -static int OpenRadio( vlc_object_t *p_this ) -{ - return Open( p_this, RADIO ); + p_sd->p_sys->i_type = i_type; + if (vlc_clone (&p_sd->p_sys->thread, Run, p_sd, VLC_THREAD_PRIORITY_LOW)) + { + free (p_sd->p_sys); + return VLC_EGENERIC; + } + return VLC_SUCCESS; } -static int OpenTV( vlc_object_t *p_this ) +/***************************************************************************** + * ItemAdded: + *****************************************************************************/ +static void ItemAdded( const vlc_event_t * p_event, void * user_data ) { - return Open( p_this, TV ); + struct shout_category_t * params = user_data; + const struct shout_item_t * p_parent = params->p_parent; + input_item_t * p_input = p_event->u.input_item_subitem_added.p_new_child; + + for(int i = 0; p_parent->ppsz_options[i] != NULL; i++) + input_item_AddOption( p_input, p_parent->ppsz_options[i], VLC_INPUT_OPTION_TRUSTED); + + services_discovery_AddItem( params->p_sd, p_input, params->psz_category ); } /***************************************************************************** - * Open: initialize and create stuff + * CreateInputItemFromShoutItem: *****************************************************************************/ -static int Open( vlc_object_t *p_this, int i_type ) +static input_item_t * CreateInputItemFromShoutItem( services_discovery_t *p_sd, + const struct shout_item_t * p_item ) { - services_discovery_t *p_sd = ( services_discovery_t* )p_this; - services_discovery_sys_t *p_sys = malloc( - sizeof( services_discovery_sys_t ) ); + /* Create the item */ + input_item_t *p_input = input_item_New( p_sd, p_item->psz_url, + vlc_gettext(p_item->psz_name) ); - vlc_value_t val; - playlist_t *p_playlist; - playlist_view_t *p_view; + /* Copy options */ + for(int i = 0; p_item->ppsz_options[i] != NULL; i++) + input_item_AddOption( p_input, p_item->ppsz_options[i], VLC_INPUT_OPTION_TRUSTED ); + input_item_AddOption( p_input, "no-playlist-autostart", VLC_INPUT_OPTION_TRUSTED ); - p_sd->pf_run = Run; - p_sd->p_sys = p_sys; + return p_input; +} - /* Create our playlist node */ - p_playlist = (playlist_t *)vlc_object_find( p_sd, VLC_OBJECT_PLAYLIST, - FIND_ANYWHERE ); - if( !p_playlist ) - { - msg_Warn( p_sd, "unable to find playlist, cancelling"); - return VLC_EGENERIC; - } +/***************************************************************************** + * AddSubitemsOfShoutItemURL: + *****************************************************************************/ +static void AddSubitemsOfShoutItemURL( services_discovery_t *p_sd, + const struct shout_item_t * p_item, + const char * psz_category ) +{ + struct shout_category_t category = { p_sd, psz_category, p_item }; - switch( i_type ) - { - case TV: - p_sys->p_input = input_ItemNewExt( p_playlist, - SHOUTCAST_TV_BASE_URL, _("Shoutcast TV"), - 0, NULL, -1 ); - break; - case RADIO: - default: - p_sys->p_input = input_ItemNewExt( p_playlist, - SHOUTCAST_BASE_URL, _("Shoutcast"), - 0, NULL, -1 ); - break; - } - vlc_input_item_AddOption( p_sys->p_input, "no-playlist-autostart" ); - p_sys->p_input->b_prefers_tree = VLC_TRUE; - p_sys->p_node_cat = playlist_NodeAddInput( p_playlist, p_sys->p_input, - p_playlist->p_root_category, - PLAYLIST_APPEND, PLAYLIST_END ); - p_sys->p_node_one = playlist_NodeAddInput( p_playlist, p_sys->p_input, - p_playlist->p_root_onelevel, - PLAYLIST_APPEND, PLAYLIST_END ); - p_sys->p_node_cat->i_flags |= PLAYLIST_RO_FLAG; - p_sys->p_node_cat->i_flags |= PLAYLIST_SKIP_FLAG; - p_sys->p_node_one->i_flags |= PLAYLIST_RO_FLAG; - p_sys->p_node_one->i_flags |= PLAYLIST_SKIP_FLAG; - p_sys->p_node_one->p_input->i_id = p_sys->p_node_cat->p_input->i_id; - - val.b_bool = VLC_TRUE; - var_Set( p_playlist, "intf-change", val ); - - vlc_object_release( p_playlist ); + /* Create the item */ + input_item_t *p_input = CreateInputItemFromShoutItem( p_sd, p_item ); - return VLC_SUCCESS; + /* Read every subitems, and add them in ItemAdded */ + vlc_event_attach( &p_input->event_manager, vlc_InputItemSubItemAdded, + ItemAdded, &category ); + input_Read( p_sd, p_input ); + vlc_event_detach( &p_input->event_manager, vlc_InputItemSubItemAdded, + ItemAdded, &category ); + + vlc_gc_decref( p_input ); } /***************************************************************************** - * Close: + * Run: *****************************************************************************/ -static void Close( vlc_object_t *p_this ) +static void *Run( void *data ) { - services_discovery_t *p_sd = ( services_discovery_t* )p_this; - services_discovery_sys_t *p_sys = p_sd->p_sys; - playlist_t *p_playlist = (playlist_t *) vlc_object_find( p_sd, - VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); - if( p_playlist ) + services_discovery_t *p_sd = data; + services_discovery_sys_t *p_sys = p_sd->p_sys; + enum type_e i_type = p_sys->i_type; + int i, j; + int canc = vlc_savecancel(); + + if( !p_items[i_type].p_children ) + { + AddSubitemsOfShoutItemURL( p_sd, &p_items[i_type], NULL ); + vlc_restorecancel(canc); + return NULL; + } + for( i = 0; p_items[i_type].p_children[i].psz_name; i++ ) { - playlist_NodeDelete( p_playlist, p_sys->p_node_cat, VLC_TRUE, VLC_TRUE ); - playlist_NodeDelete( p_playlist, p_sys->p_node_one, VLC_TRUE, VLC_TRUE ); - vlc_object_release( p_playlist ); + const struct shout_item_t * p_subitem = &p_items[i_type].p_children[i]; + if( !p_subitem->p_children ) + { + AddSubitemsOfShoutItemURL( p_sd, p_subitem, p_subitem->psz_name ); + continue; + } + for( j = 0; p_subitem->p_children[j].psz_name; j++ ) + { + input_item_t *p_input = CreateInputItemFromShoutItem( p_sd, &p_subitem->p_children[j] ); + services_discovery_AddItem( p_sd, + p_input, + p_subitem->psz_name ); + vlc_gc_decref( p_input ); + } } - free( p_sys ); + vlc_restorecancel(canc); + return NULL; } /***************************************************************************** - * Run: main thread + * Close: *****************************************************************************/ -static void Run( services_discovery_t *p_sd ) +static void Close( vlc_object_t *p_this ) { + services_discovery_t *p_sd = (services_discovery_t *)p_this; services_discovery_sys_t *p_sys = p_sd->p_sys; - int i_id = input_Read( p_sd, p_sys->p_input, VLC_FALSE ); - while( !p_sd->b_die ) - { - msleep( 10*INTF_IDLE_SLEEP ); - } + + vlc_join (p_sys->thread, NULL); + free (p_sys); +} + +static int vlc_sd_probe_Open( vlc_object_t *obj ) +{ + vlc_probe_t *probe = (vlc_probe_t *)obj; + + vlc_sd_probe_Add( probe, "shoutcast{longname=\"Shoutcast Radio\"}", + N_("Shoutcast Radio") ); + vlc_sd_probe_Add( probe, "shoutcasttv{longname=\"Shoutcast TV\"}", + N_("Shoutcast TV") ); + vlc_sd_probe_Add( probe, "frenchtv{longname=\"French TV\"}", + N_("French TV") ); + return VLC_PROBE_CONTINUE; }