services/discovery/shout.c: Add a French TV service discovery. For now it only has...
[vlc.git] / 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 #include <vlc/vlc.h>
31 #include <vlc_services_discovery.h>
32
33 /*****************************************************************************
34  * Module descriptor
35  *****************************************************************************/
36
37 enum type_e { ShoutRadio = 0, ShoutTV = 1, Freebox = 2, FrenchTV = 3 };
38
39 static int  Open( vlc_object_t *, enum type_e );
40 static void Close( vlc_object_t * );
41
42 struct shout_item_t
43 {
44     const char *psz_url;
45     const char *psz_name;
46     const char *ppsz_options[2];
47     const struct shout_item_t * p_children;
48 };
49
50 #define endItem( ) { NULL, NULL, { NULL }, NULL }
51 #define item( title, url ) { url, title, { NULL }, NULL }
52 #define itemWithOption( title, url, option ) { url, title, { option, NULL }, NULL }
53 #define itemWithChildren( title, children ) { "vlc:skip", title, { NULL }, children }
54
55 /* WARN: We support only two levels */
56
57 static const struct shout_item_t p_frenchtv_canalplus[] = {
58     item( N_("Les Guignols"), "http://www.canalplus.fr/index.php?pid=1784" ),
59     endItem()
60 };
61     
62 static const struct shout_item_t p_frenchtv[] = {
63     itemWithChildren( N_("Canal +"),  p_frenchtv_canalplus ),
64     endItem()
65 };
66
67 static const struct shout_item_t p_items[] = {
68     item(            N_("Shoutcast Radio"), "http/shout-winamp://www.shoutcast.com/sbin/newxml.phtml" ),
69     item(            N_("Shoutcast TV"),    "http/shout-winamp://www.shoutcast.com/sbin/newtvlister.phtml?alltv=1" ),
70     itemWithOption ( N_("Freebox TV"),      "http://mafreebox.freebox.fr/freeboxtv/playlist.m3u", "m3u-extvlcopt=1" ),
71     itemWithChildren(N_("French TV"),        p_frenchtv ),
72     endItem()
73 };
74
75 #undef endItem
76 #undef item
77 #undef itemWithOptions
78 #undef itemWithChildren
79
80 struct shout_category_t {
81     services_discovery_t * p_sd;
82     const char * psz_category;
83 };
84
85 /* Main functions */
86 #define OPEN( type )                                \
87 static int Open ## type ( vlc_object_t *p_this )    \
88 {                                                   \
89     msg_Dbg( p_this, "Starting " #type );           \
90     return Open( p_this, type );                    \
91 }
92
93 OPEN( ShoutRadio )
94 OPEN( ShoutTV )
95 OPEN( Freebox )
96 OPEN( FrenchTV )
97
98 vlc_module_begin();
99     set_category( CAT_PLAYLIST );
100     set_subcategory( SUBCAT_PLAYLIST_SD );
101
102     add_obsolete_integer( "shoutcast-limit" );
103
104         set_shortname( "Shoutcast");
105         set_description( _("Shoutcast radio listings") );
106         set_capability( "services_discovery", 0 );
107         set_callbacks( OpenShoutRadio, Close );
108         add_shortcut( "shoutcast" );
109
110     add_submodule();
111         set_shortname( "ShoutcastTV" );
112         set_description( _("Shoutcast TV listings") );
113         set_capability( "services_discovery", 0 );
114         set_callbacks( OpenShoutTV, Close );
115         add_shortcut( "shoutcasttv" );
116
117     add_submodule();
118         set_shortname( "frenchtv");
119         set_description( _("French TV") );
120         set_capability( "services_discovery", 0 );
121         set_callbacks( OpenFrenchTV, Close );
122         add_shortcut( "frenchtv" );
123
124     add_submodule();
125         set_shortname( "Freebox");
126         set_description( _("Freebox TV listing (French ISP free.fr services)") );
127         set_capability( "services_discovery", 0 );
128         set_callbacks( OpenFreebox, Close );
129         add_shortcut( "freebox" );
130
131 vlc_module_end();
132
133
134 /*****************************************************************************
135  * Local prototypes
136  *****************************************************************************/
137
138 static void Run( services_discovery_t *p_sd );
139
140
141 /*****************************************************************************
142  * Open: initialize and create stuff
143  *****************************************************************************/
144 static int Open( vlc_object_t *p_this, enum type_e i_type )
145 {
146     services_discovery_t *p_sd = ( services_discovery_t* )p_this;
147     services_discovery_SetLocalizedName( p_sd, _(p_items[i_type].psz_name) );
148     p_sd->pf_run = Run;
149     p_sd->p_sys = (void *)i_type;
150     return VLC_SUCCESS;
151 }
152
153 /*****************************************************************************
154  * ItemAdded:
155  *****************************************************************************/
156 static void ItemAdded( const vlc_event_t * p_event, void * user_data )
157 {
158     struct shout_category_t * params = user_data;
159     services_discovery_AddItem( params->p_sd,
160             p_event->u.input_item_subitem_added.p_new_child,
161             params->psz_category );
162 }
163
164 /*****************************************************************************
165  * CreateInputItemFromShoutItem:
166  *****************************************************************************/
167 static input_item_t * CreateInputItemFromShoutItem( services_discovery_t *p_sd,
168                                          const struct shout_item_t * p_item )
169 {
170     int i;
171     /* Create the item */
172     input_item_t *p_input = input_ItemNewExt( p_sd,
173                     p_item->psz_url, _(p_item->psz_name),
174                     0, NULL, -1 );
175
176     /* Copy options */
177     for( i = 0; p_item->ppsz_options[i] != NULL; i++ )
178         input_ItemAddOption( p_input, p_item->ppsz_options[i] );
179     input_ItemAddOption( p_input, "no-playlist-autostart" );
180
181     return p_input;
182 }
183
184 /*****************************************************************************
185  * AddSubitemsOfShoutItemURL:
186  *****************************************************************************/
187 static void AddSubitemsOfShoutItemURL( services_discovery_t *p_sd,
188                                        const struct shout_item_t * p_item,
189                                        const char * psz_category )
190 {
191     struct shout_category_t category = { p_sd, psz_category };
192
193     /* Create the item */
194     input_item_t *p_input = CreateInputItemFromShoutItem( p_sd, p_item );
195
196     /* Read every subitems, and add them in ItemAdded */
197     vlc_event_attach( &p_input->event_manager, vlc_InputItemSubItemAdded,
198                       ItemAdded, &category );
199     input_Read( p_sd, p_input, VLC_TRUE );
200     vlc_event_detach( &p_input->event_manager, vlc_InputItemSubItemAdded,
201                       ItemAdded, &category );
202
203     vlc_gc_decref( p_input );
204 }
205
206 /*****************************************************************************
207  * Run:
208  *****************************************************************************/
209 static void Run( services_discovery_t *p_sd )
210 {
211     enum type_e i_type = (enum type_e)p_sd->p_sys;
212     int i, j;
213     
214     if( !p_items[i_type].p_children )
215     {
216         AddSubitemsOfShoutItemURL( p_sd, &p_items[i_type], NULL );
217         return;
218     }
219     for( i = 0; p_items[i_type].p_children[i].psz_name; i++ )
220     {
221         const struct shout_item_t * p_subitem = &p_items[i_type].p_children[i];
222         if( !p_subitem->p_children )
223         {
224             AddSubitemsOfShoutItemURL( p_sd, p_subitem, p_subitem->psz_name );
225             continue;
226         }
227         for( j = 0; p_subitem->p_children[j].psz_name; j++ )
228         {
229             input_item_t *p_input = CreateInputItemFromShoutItem( p_sd, &p_subitem->p_children[j] );
230             services_discovery_AddItem( p_sd,
231                 p_input,
232                 p_subitem->psz_name );
233             vlc_gc_decref( p_input );
234         }
235     }
236 }
237
238 /*****************************************************************************
239  * Close:
240  *****************************************************************************/
241 static void Close( vlc_object_t *p_this )
242 {
243 }