]> git.sesse.net Git - vlc/blob - modules/services_discovery/shout.c
bonjour: probe support (untested)
[vlc] / modules / services_discovery / shout.c
1 /*****************************************************************************
2  * shout.c:  Shoutcast services discovery module
3  *****************************************************************************
4  * Copyright (C) 2005-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Sigmund Augdal Helberg <dnumgis@videolan.org>
8  *          Antoine Cellerier <dionoea -@T- videolan -d.t- org>
9  *          Pierre d'Herbemont <pdherbemont # videolan.org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Includes
28  *****************************************************************************/
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_services_discovery.h>
37
38 /*****************************************************************************
39  * Module descriptor
40  *****************************************************************************/
41
42 enum type_e { ShoutRadio = 0, ShoutTV = 1, Freebox = 2, FrenchTV = 3 };
43
44 static int  Open( vlc_object_t *, enum type_e );
45 static void Close( vlc_object_t * );
46
47 struct shout_item_t
48 {
49     const char *psz_url;
50     const char *psz_name;
51     const char *ppsz_options[2];
52     const struct shout_item_t * p_children;
53 };
54
55 #define endItem( ) { NULL, NULL, { NULL }, NULL }
56 #define item( title, url ) { url, title, { NULL }, NULL }
57 #define itemWithOption( title, url, option ) { url, title, { option, NULL }, NULL }
58 #define itemWithChildren( title, children ) { "vlc://nop", title, { NULL }, children }
59
60 /* WARN: We support only two levels */
61
62 static const struct shout_item_t p_frenchtv_canalplus[] = {
63     itemWithOption( N_("Les Guignols"), "http://www.canalplus.fr/index.php?pid=1784", "http-forward-cookies" ),
64     endItem()
65 };
66     
67 static const struct shout_item_t p_frenchtv[] = {
68     itemWithChildren( N_("Canal +"),  p_frenchtv_canalplus ),
69     endItem()
70 };
71
72 static const struct shout_item_t p_items[] = {
73     item(            N_("Shoutcast Radio"), "http/shout-winamp://www.shoutcast.com/sbin/newxml.phtml" ),
74     item(            N_("Shoutcast TV"),    "http/shout-winamp://www.shoutcast.com/sbin/newtvlister.phtml?alltv=1" ),
75     itemWithOption( N_("Freebox TV"),"http://mafreebox.freebox.fr/freeboxtv/playlist.m3u", "deinterlace=1"),
76     itemWithChildren(N_("French TV"),        p_frenchtv ),
77     endItem()
78 };
79
80 #undef endItem
81 #undef item
82 #undef itemWithOptions
83 #undef itemWithChildren
84
85 struct shout_category_t {
86     services_discovery_t * p_sd;
87     const char * psz_category;
88     const struct shout_item_t * p_parent;
89 };
90
91 /* Main functions */
92 #define OPEN( type )                                \
93 static int Open ## type ( vlc_object_t *p_this )    \
94 {                                                   \
95     msg_Dbg( p_this, "Starting " #type );           \
96     return Open( p_this, type );                    \
97 }
98
99 OPEN( ShoutRadio )
100 OPEN( ShoutTV )
101 OPEN( Freebox )
102 OPEN( FrenchTV )
103
104 #undef OPEN
105
106 vlc_module_begin ()
107     set_category( CAT_PLAYLIST )
108     set_subcategory( SUBCAT_PLAYLIST_SD )
109
110     add_obsolete_integer( "shoutcast-limit" )
111
112         set_shortname( "Shoutcast")
113         set_description( N_("Shoutcast Radio") )
114         set_capability( "services_discovery", 0 )
115         set_callbacks( OpenShoutRadio, Close )
116         add_shortcut( "shoutcast" )
117
118     add_submodule ()
119         set_shortname( "ShoutcastTV" )
120         set_description( N_("Shoutcast TV") )
121         set_capability( "services_discovery", 0 )
122         set_callbacks( OpenShoutTV, Close )
123         add_shortcut( "shoutcasttv" )
124
125     add_submodule ()
126         set_shortname( "frenchtv")
127         set_description( N_("French TV") )
128         set_capability( "services_discovery", 0 )
129         set_callbacks( OpenFrenchTV, Close )
130         add_shortcut( "frenchtv" )
131
132     add_submodule ()
133         set_shortname( "Freebox")
134         set_description( N_("Freebox TV") )
135         set_capability( "services_discovery", 0 )
136         set_callbacks( OpenFreebox, Close )
137         add_shortcut( "freebox" )
138
139 vlc_module_end ()
140
141
142 /*****************************************************************************
143  * Local prototypes
144  *****************************************************************************/
145
146 static void *Run( void * );
147 struct services_discovery_sys_t
148 {
149     vlc_thread_t thread;
150     enum type_e i_type;
151 };
152
153 /*****************************************************************************
154  * Open: initialize and create stuff
155  *****************************************************************************/
156 static int Open( vlc_object_t *p_this, enum type_e i_type )
157 {
158     services_discovery_t *p_sd = ( services_discovery_t* )p_this;
159
160     p_sd->p_sys = malloc (sizeof (*(p_sd->p_sys)));
161     if (p_sd->p_sys == NULL)
162         return VLC_ENOMEM;
163
164     p_sd->p_sys->i_type = i_type;
165     if (vlc_clone (&p_sd->p_sys->thread, Run, p_sd, VLC_THREAD_PRIORITY_LOW))
166     {
167         free (p_sd->p_sys);
168         return VLC_EGENERIC;
169     }
170     return VLC_SUCCESS;
171 }
172
173 /*****************************************************************************
174  * ItemAdded:
175  *****************************************************************************/
176 static void ItemAdded( const vlc_event_t * p_event, void * user_data )
177 {
178     struct shout_category_t * params = user_data;
179     const struct shout_item_t * p_parent = params->p_parent;
180     input_item_t * p_input = p_event->u.input_item_subitem_added.p_new_child;
181
182     for(int i = 0; p_parent->ppsz_options[i] != NULL; i++)
183         input_item_AddOption( p_input, p_parent->ppsz_options[i], VLC_INPUT_OPTION_TRUSTED);
184
185     services_discovery_AddItem( params->p_sd, p_input, params->psz_category );
186 }
187
188 /*****************************************************************************
189  * CreateInputItemFromShoutItem:
190  *****************************************************************************/
191 static input_item_t * CreateInputItemFromShoutItem( services_discovery_t *p_sd,
192                                          const struct shout_item_t * p_item )
193 {
194     /* Create the item */
195     input_item_t *p_input = input_item_New( p_sd, p_item->psz_url,
196                                             vlc_gettext(p_item->psz_name) );
197
198     /* Copy options */
199     for(int i = 0; p_item->ppsz_options[i] != NULL; i++)
200         input_item_AddOption( p_input, p_item->ppsz_options[i], VLC_INPUT_OPTION_TRUSTED );
201     input_item_AddOption( p_input, "no-playlist-autostart", VLC_INPUT_OPTION_TRUSTED );
202
203     return p_input;
204 }
205
206 /*****************************************************************************
207  * AddSubitemsOfShoutItemURL:
208  *****************************************************************************/
209 static void AddSubitemsOfShoutItemURL( services_discovery_t *p_sd,
210                                        const struct shout_item_t * p_item,
211                                        const char * psz_category )
212 {
213     struct shout_category_t category = { p_sd, psz_category, p_item };
214
215     /* Create the item */
216     input_item_t *p_input = CreateInputItemFromShoutItem( p_sd, p_item );
217
218     /* Read every subitems, and add them in ItemAdded */
219     vlc_event_attach( &p_input->event_manager, vlc_InputItemSubItemAdded,
220                       ItemAdded, &category );
221     input_Read( p_sd, p_input );
222     vlc_event_detach( &p_input->event_manager, vlc_InputItemSubItemAdded,
223                       ItemAdded, &category );
224
225     vlc_gc_decref( p_input );
226 }
227
228 /*****************************************************************************
229  * Run:
230  *****************************************************************************/
231 static void *Run( void *data )
232 {
233     services_discovery_t *p_sd = data;
234     services_discovery_sys_t *p_sys = p_sd->p_sys;
235     enum type_e i_type = p_sys->i_type;
236     int i, j;
237     int canc = vlc_savecancel();
238     
239     if( !p_items[i_type].p_children )
240     {
241         AddSubitemsOfShoutItemURL( p_sd, &p_items[i_type], NULL );
242         vlc_restorecancel(canc);
243         return NULL;
244     }
245     for( i = 0; p_items[i_type].p_children[i].psz_name; i++ )
246     {
247         const struct shout_item_t * p_subitem = &p_items[i_type].p_children[i];
248         if( !p_subitem->p_children )
249         {
250             AddSubitemsOfShoutItemURL( p_sd, p_subitem, p_subitem->psz_name );
251             continue;
252         }
253         for( j = 0; p_subitem->p_children[j].psz_name; j++ )
254         {
255             input_item_t *p_input = CreateInputItemFromShoutItem( p_sd, &p_subitem->p_children[j] );
256             services_discovery_AddItem( p_sd,
257                 p_input,
258                 p_subitem->psz_name );
259             vlc_gc_decref( p_input );
260         }
261     }
262     vlc_restorecancel(canc);
263     return NULL;
264 }
265
266 /*****************************************************************************
267  * Close:
268  *****************************************************************************/
269 static void Close( vlc_object_t *p_this )
270 {
271     services_discovery_t *p_sd = (services_discovery_t *)p_this;
272     services_discovery_sys_t *p_sys = p_sd->p_sys;
273
274     vlc_join (p_sys->thread, NULL);
275     free (p_sys);
276 }