shout.c 9.57 KB
Newer Older
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
12
13
14
15
16
17
18
19
20
21
22
 *
 * 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
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
dionoea's avatar
dionoea committed
23
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24
25
26
27
28
29
 *****************************************************************************/

/*****************************************************************************
 * Includes
 *****************************************************************************/

30
31
32
33
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

34
#include <vlc_common.h>
35
#include <vlc_plugin.h>
36
#include <vlc_services_discovery.h>
37

38
39
40
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
41

42
enum type_e { ShoutRadio = 0, ShoutTV = 1, Freebox = 2, FrenchTV = 3 };
43

44
45
static int  Open( vlc_object_t *, enum type_e );
static void Close( vlc_object_t * );
46

47
struct shout_item_t
48
49
50
{
    const char *psz_url;
    const char *psz_name;
51
    const char *ppsz_options[2];
52
53
54
55
56
57
    const struct shout_item_t * p_children;
};

#define endItem( ) { NULL, NULL, { NULL }, NULL }
#define item( title, url ) { url, title, { NULL }, NULL }
#define itemWithOption( title, url, option ) { url, title, { option, NULL }, NULL }
58
#define itemWithChildren( title, children ) { "vlc://nop", title, { NULL }, children }
59
60
61
62

/* WARN: We support only two levels */

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
65
66
67
68
69
70
71
72
73
74
    endItem()
};
    
static const struct shout_item_t p_frenchtv[] = {
    itemWithChildren( N_("Canal +"),  p_frenchtv_canalplus ),
    endItem()
};

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" ),
75
    itemWithOption( N_("Freebox TV"),"http://mafreebox.freebox.fr/freeboxtv/playlist.m3u", "deinterlace=1"),
76
77
78
79
80
81
82
83
84
85
86
87
    itemWithChildren(N_("French TV"),        p_frenchtv ),
    endItem()
};

#undef endItem
#undef item
#undef itemWithOptions
#undef itemWithChildren

struct shout_category_t {
    services_discovery_t * p_sd;
    const char * psz_category;
88
    const struct shout_item_t * p_parent;
89
};
90

91
92
93
94
/* Main functions */
#define OPEN( type )                                \
static int Open ## type ( vlc_object_t *p_this )    \
{                                                   \
95
    msg_Dbg( p_this, "Starting " #type );           \
96
97
    return Open( p_this, type );                    \
}
98

99
100
101
OPEN( ShoutRadio )
OPEN( ShoutTV )
OPEN( Freebox )
102
OPEN( FrenchTV )
103

ivoire's avatar
ivoire committed
104
105
#undef OPEN

106
107
108
109
110
111
112
vlc_module_begin ()
    set_category( CAT_PLAYLIST )
    set_subcategory( SUBCAT_PLAYLIST_SD )

    add_obsolete_integer( "shoutcast-limit" )

        set_shortname( "Shoutcast")
Pierre's avatar
Pierre committed
113
        set_description( N_("Shoutcast Radio") )
114
115
116
117
118
119
        set_capability( "services_discovery", 0 )
        set_callbacks( OpenShoutRadio, Close )
        add_shortcut( "shoutcast" )

    add_submodule ()
        set_shortname( "ShoutcastTV" )
Pierre's avatar
Pierre committed
120
        set_description( N_("Shoutcast TV") )
121
122
123
124
125
126
127
128
129
130
131
132
133
        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")
Pierre's avatar
Pierre committed
134
        set_description( N_("Freebox TV") )
135
136
137
138
139
        set_capability( "services_discovery", 0 )
        set_callbacks( OpenFreebox, Close )
        add_shortcut( "freebox" )

vlc_module_end ()
140

141

142
143
144
145
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/

146
147
148
149
150
151
static void *Run( void * );
struct services_discovery_sys_t
{
    vlc_thread_t thread;
    enum type_e i_type;
};
152

153
154
155
/*****************************************************************************
 * Open: initialize and create stuff
 *****************************************************************************/
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
161
162
163
164
165
166
167
168
169

    p_sd->p_sys = malloc (sizeof (*(p_sd->p_sys)));
    if (p_sd->p_sys == NULL)
        return VLC_ENOMEM;

    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;
    }
170
171
172
    return VLC_SUCCESS;
}

173
174
175
176
177
/*****************************************************************************
 * ItemAdded:
 *****************************************************************************/
static void ItemAdded( const vlc_event_t * p_event, void * user_data )
{
178
    struct shout_category_t * params = user_data;
179
180
181
    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;

182
    for(int i = 0; p_parent->ppsz_options[i] != NULL; i++)
183
184
185
        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 );
186
187
}

188
/*****************************************************************************
189
 * CreateInputItemFromShoutItem:
190
 *****************************************************************************/
191
192
static input_item_t * CreateInputItemFromShoutItem( services_discovery_t *p_sd,
                                         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
201
        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 );
202

203
204
205
206
207
208
209
210
211
212
    return p_input;
}

/*****************************************************************************
 * AddSubitemsOfShoutItemURL:
 *****************************************************************************/
static void AddSubitemsOfShoutItemURL( services_discovery_t *p_sd,
                                       const struct shout_item_t * p_item,
                                       const char * psz_category )
{
213
    struct shout_category_t category = { p_sd, psz_category, p_item };
214
215
216
217
218

    /* Create the item */
    input_item_t *p_input = CreateInputItemFromShoutItem( p_sd, p_item );

    /* 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
224
                      ItemAdded, &category );

225
    vlc_gc_decref( p_input );
226
227
}

228
229
230
/*****************************************************************************
 * Run:
 *****************************************************************************/
231
static void *Run( void *data )
232
{
233
234
235
    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;
236
    int i, j;
237
    int canc = vlc_savecancel();
238
239
240
241
    
    if( !p_items[i_type].p_children )
    {
        AddSubitemsOfShoutItemURL( p_sd, &p_items[i_type], NULL );
242
243
        vlc_restorecancel(canc);
        return NULL;
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
    }
    for( i = 0; p_items[i_type].p_children[i].psz_name; i++ )
    {
        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 );
        }
    }
262
    vlc_restorecancel(canc);
263
    return NULL;
264
265
}

266
267
268
269
270
/*****************************************************************************
 * Close:
 *****************************************************************************/
static void Close( vlc_object_t *p_this )
{
271
272
273
274
275
    services_discovery_t *p_sd = (services_discovery_t *)p_this;
    services_discovery_sys_t *p_sys = p_sd->p_sys;

    vlc_join (p_sys->thread, NULL);
    free (p_sys);
276
}