]> git.sesse.net Git - vlc/blob - modules/demux/playlist/podcast.c
build fix
[vlc] / modules / demux / playlist / podcast.c
1 /*****************************************************************************
2  * podcast.c : podcast playlist imports
3  *****************************************************************************
4  * Copyright (C) 2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28 #include <ctype.h>                                              /* isspace() */
29
30 #include <vlc/vlc.h>
31 #include <vlc/input.h>
32 #include <vlc/intf.h>
33
34 #include <errno.h>                                                 /* ENOMEM */
35 #include "playlist.h"
36 #include "vlc_xml.h"
37
38 struct demux_sys_t
39 {
40     char *psz_prefix;
41     playlist_t *p_playlist;
42     xml_t *p_xml;
43     xml_reader_t *p_xml_reader;
44 };
45
46 /*****************************************************************************
47  * Local prototypes
48  *****************************************************************************/
49 static int Demux( demux_t *p_demux);
50 static int Control( demux_t *p_demux, int i_query, va_list args );
51
52 /*****************************************************************************
53  * Import_podcast: main import function
54  *****************************************************************************/
55 int E_(Import_podcast)( vlc_object_t *p_this )
56 {
57     demux_t *p_demux = (demux_t *)p_this;
58     demux_sys_t *p_sys;
59
60     char    *psz_ext;
61
62     psz_ext = strrchr ( p_demux->psz_path, '.' );
63
64     if( p_demux->psz_demux && !strcmp(p_demux->psz_demux, "podcast") )
65     {
66         ;
67     }
68     else
69     {
70         return VLC_EGENERIC;
71     }
72     msg_Dbg( p_demux, "using podcast playlist import");
73
74     p_demux->pf_control = Control;
75     p_demux->pf_demux = Demux;
76     p_demux->p_sys = p_sys = malloc( sizeof(demux_sys_t) );
77     if( p_sys == NULL )
78     {
79         msg_Err( p_demux, "Out of memory" );
80         return VLC_ENOMEM;
81     }
82     p_sys->psz_prefix = E_(FindPrefix)( p_demux );
83     p_sys->p_playlist = NULL;
84     p_sys->p_xml = NULL;
85     p_sys->p_xml_reader = NULL;
86
87     return VLC_SUCCESS;
88 }
89
90 /*****************************************************************************
91  * Deactivate: frees unused data
92  *****************************************************************************/
93 void E_(Close_podcast)( vlc_object_t *p_this )
94 {
95     demux_t *p_demux = (demux_t *)p_this;
96     demux_sys_t *p_sys = p_demux->p_sys;
97
98     if( p_sys->psz_prefix ) free( p_sys->psz_prefix );
99     if( p_sys->p_playlist ) vlc_object_release( p_sys->p_playlist );
100     if( p_sys->p_xml_reader ) xml_ReaderDelete( p_sys->p_xml, p_sys->p_xml_reader );
101     if( p_sys->p_xml ) xml_Delete( p_sys->p_xml );
102     free( p_sys );
103 }
104
105 /* "specs" : http://phobos.apple.com/static/iTunesRSS.html */
106 static int Demux( demux_t *p_demux )
107 {
108     demux_sys_t *p_sys = p_demux->p_sys;
109     playlist_t *p_playlist;
110     playlist_item_t *p_item, *p_current;
111
112     vlc_bool_t b_play;
113     vlc_bool_t b_item = VLC_FALSE;
114     vlc_bool_t b_image = VLC_FALSE;
115     int i_ret;
116
117     xml_t *p_xml;
118     xml_reader_t *p_xml_reader;
119     char *psz_elname = NULL;
120     char *psz_item_mrl = NULL;
121     char *psz_item_size = NULL;
122     char *psz_item_type = NULL;
123     char *psz_item_name = NULL;
124     char *psz_item_date = NULL;
125     char *psz_item_author = NULL;
126     char *psz_item_category = NULL;
127     char *psz_item_duration = NULL;
128     char *psz_item_keywords = NULL;
129     char *psz_item_subtitle = NULL;
130     char *psz_item_summary = NULL;
131     int i_type;
132
133     p_playlist = (playlist_t *) vlc_object_find( p_demux, VLC_OBJECT_PLAYLIST,
134                                                  FIND_ANYWHERE );
135     if( !p_playlist )
136     {
137         msg_Err( p_demux, "can't find playlist" );
138         return -1;
139     }
140     p_sys->p_playlist = p_playlist;
141
142     b_play = E_(FindItem)( p_demux, p_playlist, &p_current );
143
144     playlist_ItemToNode( p_playlist, p_current );
145     p_current->input.i_type = ITEM_TYPE_PLAYLIST;
146
147     p_xml = p_sys->p_xml = xml_Create( p_demux );
148     if( !p_xml ) return -1;
149
150     psz_elname = stream_ReadLine( p_demux->s );
151     if( psz_elname ) free( psz_elname );
152     psz_elname = 0;
153
154     p_xml_reader = xml_ReaderCreate( p_xml, p_demux->s );
155     if( !p_xml_reader ) return -1;
156     p_sys->p_xml_reader = p_xml_reader;
157
158     /* xml */
159     /* check root node */
160     if( xml_ReaderRead( p_xml_reader ) != 1 )
161     {
162         msg_Err( p_demux, "invalid file (no root node)" );
163         return -1;
164     }
165     if( xml_ReaderNodeType( p_xml_reader ) != XML_READER_STARTELEM ||
166         ( psz_elname = xml_ReaderName( p_xml_reader ) ) == NULL ||
167         strcmp( psz_elname, "rss" ) )
168     {
169         msg_Err( p_demux, "invalid root node %i, %s",
170                  xml_ReaderNodeType( p_xml_reader ), psz_elname );
171         if( psz_elname ) free( psz_elname );
172         return -1;
173     }
174     free( psz_elname ); psz_elname = NULL;
175
176     while( (i_ret = xml_ReaderRead( p_xml_reader )) == 1 )
177     {
178         // Get the node type
179         i_type = xml_ReaderNodeType( p_xml_reader );
180         switch( i_type )
181         {
182             // Error
183             case -1:
184                 return -1;
185                 break;
186
187             case XML_READER_STARTELEM:
188             {
189                 // Read the element name
190                 if( psz_elname ) free( psz_elname );
191                 psz_elname = xml_ReaderName( p_xml_reader );
192                 if( !psz_elname ) return -1;
193
194                 if( !strcmp( psz_elname, "item" ) )
195                 {
196                     b_item = VLC_TRUE;
197                 }
198                 else if( !strcmp( psz_elname, "image" ) )
199                 {
200                     b_item = VLC_TRUE;
201                 }
202
203                 // Read the attributes
204                 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
205                 {
206                     char *psz_name = xml_ReaderName( p_xml_reader );
207                     char *psz_value = xml_ReaderValue( p_xml_reader );
208                     if( !psz_name || !psz_value ) return -1;
209                     if( !strcmp( psz_elname, "enclosure" ) &&
210                         !strcmp( psz_name, "url" ) )
211                     {
212                         psz_item_mrl = strdup( psz_value );
213                     }
214                     else if( !strcmp( psz_elname, "enclosure" ) &&
215                         !strcmp( psz_name, "length" ) )
216                     {
217                         psz_item_size = strdup( psz_value );
218                     }
219                     else if( !strcmp( psz_elname, "enclosure" ) &&
220                         !strcmp( psz_name, "type" ) )
221                     {
222                         psz_item_type = strdup( psz_value );
223                     }
224                     else
225                     {
226                         msg_Dbg( p_demux,"unhandled attribure %s in element %s",
227                                   psz_name, psz_elname );
228                     }
229                     free( psz_name );
230                     free( psz_value );
231                 }
232                 break;
233             }
234             case XML_READER_TEXT:
235             {
236                 char *psz_text = xml_ReaderValue( p_xml_reader );
237                 /* item specific meta data */
238                 if( b_item == VLC_TRUE && !strcmp( psz_elname, "title" ) )
239                 {
240                     psz_item_name = strdup( psz_text );
241                 }
242                 else if( b_item == VLC_TRUE
243                          && !strcmp( psz_elname, "pubDate" ) )
244                 {
245                     psz_item_date = strdup( psz_text );
246                 }
247                 else if( b_item == VLC_TRUE
248                          && ( !strcmp( psz_elname, "itunes:author" )
249                             ||!strcmp( psz_elname, "author" ) ) )
250                 { /* <author> isn't standard iTunes podcast stuff */
251                     psz_item_author = strdup( psz_text );
252                 }
253                 else if( b_item == VLC_TRUE
254                          && !strcmp( psz_elname, "itunes:category" ) )
255                 {
256                     psz_item_category = strdup( psz_text );
257                 }
258                 else if( b_item == VLC_TRUE
259                          && !strcmp( psz_elname, "itunes:duration" ) )
260                 {
261                     psz_item_duration = strdup( psz_text );
262                 }
263                 else if( b_item == VLC_TRUE
264                          && !strcmp( psz_elname, "itunes:keywords" ) )
265                 {
266                     psz_item_keywords = strdup( psz_text );
267                 }
268                 else if( b_item == VLC_TRUE
269                          && !strcmp( psz_elname, "itunes:subtitle" ) )
270                 {
271                     psz_item_subtitle = strdup( psz_text );
272                 }
273                 else if( b_item == VLC_TRUE
274                          && ( !strcmp( psz_elname, "itunes:summary" )
275                             ||!strcmp( psz_elname, "description" ) ) )
276                 { /* <description> isn't standard iTunes podcast stuff */
277                     psz_item_summary = strdup( psz_text );
278                 }
279                 /* toplevel meta data */
280                 else if( b_item == VLC_FALSE && b_image == VLC_FALSE
281                          && !strcmp( psz_elname, "title" ) )
282                 {
283                     playlist_ItemSetName( p_current, psz_text );
284                 }
285                 else if( b_item == VLC_FALSE && b_image == VLC_FALSE
286                          && !strcmp( psz_elname, "link" ) )
287                 {
288                     vlc_input_item_AddInfo( &(p_current->input),
289                                             _("Meta-information"),
290                                             _( "Podcast Link" ),
291                                             "%s",
292                                             psz_text );
293                 }
294                 else if( b_item == VLC_FALSE && b_image == VLC_FALSE
295                          && !strcmp( psz_elname, "copyright" ) )
296                 {
297                     vlc_input_item_AddInfo( &(p_current->input),
298                                             _("Meta-information"),
299                                             _( "Podcast Copyright" ),
300                                             "%s",
301                                             psz_text );
302                 }
303                 else if( b_item == VLC_FALSE && b_image == VLC_FALSE
304                          && !strcmp( psz_elname, "itunes:category" ) )
305                 {
306                     vlc_input_item_AddInfo( &(p_current->input),
307                                             _("Meta-information"),
308                                             _( "Podcast Category" ),
309                                             "%s",
310                                             psz_text );
311                 }
312                 else if( b_item == VLC_FALSE && b_image == VLC_FALSE
313                          && !strcmp( psz_elname, "itunes:keywords" ) )
314                 {
315                     vlc_input_item_AddInfo( &(p_current->input),
316                                             _("Meta-information"),
317                                             _( "Podcast Keywords" ),
318                                             "%s",
319                                             psz_text );
320                 }
321                 else if( b_item == VLC_FALSE && b_image == VLC_FALSE
322                          && !strcmp( psz_elname, "itunes:subtitle" ) )
323                 {
324                     vlc_input_item_AddInfo( &(p_current->input),
325                                             _("Meta-information"),
326                                             _( "Podcast Subtitle" ),
327                                             "%s",
328                                             psz_text );
329                 }
330                 else if( b_item == VLC_FALSE && b_image == VLC_FALSE
331                          && ( !strcmp( psz_elname, "itunes:summary" )
332                             ||!strcmp( psz_elname, "description" ) ) )
333                 { /* <description> isn't standard iTunes podcast stuff */
334                     vlc_input_item_AddInfo( &(p_current->input),
335                                             _("Meta-information"),
336                                             _( "Podcast Summary" ),
337                                             "%s",
338                                             psz_text );
339                 }
340                 else
341                 {
342                     msg_Dbg( p_demux, "unhandled text in element '%s'",
343                               psz_elname );
344                 }
345                 free( psz_text );
346                 break;
347             }
348             // End element
349             case XML_READER_ENDELEM:
350             {
351                 // Read the element name
352                 free( psz_elname );
353                 psz_elname = xml_ReaderName( p_xml_reader );
354                 if( !psz_elname ) return -1;
355                 if( !strcmp( psz_elname, "item" ) )
356                 {
357                     p_item = playlist_ItemNew( p_playlist, psz_item_mrl,
358                                                psz_item_name );
359                     if( p_item == NULL ) break;
360                     playlist_NodeAddItem( p_playlist, p_item,
361                                           p_current->pp_parents[0]->i_view,
362                                           p_current, PLAYLIST_APPEND,
363                                           PLAYLIST_END );
364
365                     /* We need to declare the parents of the node as the
366                      *                  * same of the parent's ones */
367                     playlist_CopyParents( p_current, p_item );
368
369                     if( psz_item_date )
370                     {
371                         vlc_input_item_AddInfo( &p_item->input,
372                                                 _("Meta-information"),
373                                                 _( "Podcast Publication Date" ),
374                                                 "%s",
375                                                 psz_item_date );
376                     }
377                     if( psz_item_author )
378                     {
379                         vlc_input_item_AddInfo( &p_item->input,
380                                                 _("Meta-information"),
381                                                 _( "Podcast Author" ),
382                                                 "%s",
383                                                 psz_item_author );
384                     }
385                     if( psz_item_category )
386                     {
387                         vlc_input_item_AddInfo( &p_item->input,
388                                                 _("Meta-information"),
389                                                 _( "Podcast Subcategory" ),
390                                                 "%s",
391                                                 psz_item_category );
392                     }
393                     if( psz_item_duration )
394                     {
395                         vlc_input_item_AddInfo( &p_item->input,
396                                                 _("Meta-information"),
397                                                 _( "Podcast Duration" ),
398                                                 "%s",
399                                                 psz_item_duration );
400                     }
401                     if( psz_item_keywords )
402                     {
403                         vlc_input_item_AddInfo( &p_item->input,
404                                                 _("Meta-information"),
405                                                 _( "Podcast Keywords" ),
406                                                 "%s",
407                                                 psz_item_keywords );
408                     }
409                     if( psz_item_subtitle )
410                     {
411                         vlc_input_item_AddInfo( &p_item->input,
412                                                 _("Meta-information"),
413                                                 _( "Podcast Subtitle" ),
414                                                 "%s",
415                                                 psz_item_subtitle );
416                     }
417                     if( psz_item_summary )
418                     {
419                         vlc_input_item_AddInfo( &p_item->input,
420                                                 _("Meta-information"),
421                                                 _( "Podcast Summary" ),
422                                                 "%s",
423                                                 psz_item_summary );
424                     }
425                     if( psz_item_size )
426                     {
427                         vlc_input_item_AddInfo( &p_item->input,
428                                                 _("Meta-information"),
429                                                 _( "Podcast Size" ),
430                                                 "%s bytes",
431                                                 psz_item_size );
432                     }
433                     if( psz_item_type )
434                     {
435                         vlc_input_item_AddInfo( &p_item->input,
436                                                 _("Meta-information"),
437                                                 _( "Podcast Type" ),
438                                                 "%s",
439                                                 psz_item_type );
440                     }
441
442 #define FREE(a) if( a ) free( a ); a = NULL;
443                     FREE( psz_item_name );
444                     FREE( psz_item_mrl );
445                     FREE( psz_item_size );
446                     FREE( psz_item_type );
447                     FREE( psz_item_date );
448                     FREE( psz_item_author );
449                     FREE( psz_item_category );
450                     FREE( psz_item_duration );
451                     FREE( psz_item_keywords );
452                     FREE( psz_item_subtitle );
453                     FREE( psz_item_summary );
454 #undef FREE
455
456                     b_item = VLC_FALSE;
457                 }
458                 else if( !strcmp( psz_elname, "image" ) )
459                 {
460                     b_image = VLC_FALSE;
461                 }
462                 free( psz_elname );
463                 psz_elname = strdup("");
464
465                 break;
466             }
467         }
468     }
469
470     if( i_ret != 0 )
471     {
472         msg_Warn( p_demux, "error while parsing data" );
473     }
474
475     /* Go back and play the playlist */
476     if( b_play && p_playlist->status.p_item &&
477         p_playlist->status.p_item->i_children > 0 )
478     {
479         playlist_Control( p_playlist, PLAYLIST_VIEWPLAY,
480                           p_playlist->status.i_view,
481                           p_playlist->status.p_item,
482                           p_playlist->status.p_item->pp_children[0] );
483     }
484
485     vlc_object_release( p_playlist );
486     p_sys->p_playlist = NULL;
487     return VLC_SUCCESS;
488 }
489
490 static int Control( demux_t *p_demux, int i_query, va_list args )
491 {
492     return VLC_EGENERIC;
493 }