]> git.sesse.net Git - vlc/blob - modules/demux/playlist/podcast.c
Add a bunch of helper functions/macros and start using them:
[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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <ctype.h>                                              /* isspace() */
28
29 #include <vlc/vlc.h>
30 #include <vlc/input.h>
31 #include <vlc/intf.h>
32
33 #include "playlist.h"
34 #include "vlc_xml.h"
35
36 struct demux_sys_t
37 {
38     char *psz_prefix;
39     playlist_t *p_playlist;
40     xml_t *p_xml;
41     xml_reader_t *p_xml_reader;
42 };
43
44 /*****************************************************************************
45  * Local prototypes
46  *****************************************************************************/
47 static int Demux( demux_t *p_demux);
48 static int Control( demux_t *p_demux, int i_query, va_list args );
49
50 /*****************************************************************************
51  * Import_podcast: main import function
52  *****************************************************************************/
53 int E_(Import_podcast)( vlc_object_t *p_this )
54 {
55     demux_t *p_demux = (demux_t *)p_this;
56
57     if( !isDemux( p_demux, "podcast" ) )
58         return VLC_EGENERIC;
59     
60     STANDARD_DEMUX_INIT_MSG( "using podcast reader" );
61     p_demux->p_sys->psz_prefix = E_(FindPrefix)( p_demux );
62     p_demux->p_sys->p_playlist = NULL;
63     p_demux->p_sys->p_xml = NULL;
64     p_demux->p_sys->p_xml_reader = NULL;
65
66     return VLC_SUCCESS;
67 }
68
69 /*****************************************************************************
70  * Deactivate: frees unused data
71  *****************************************************************************/
72 void E_(Close_podcast)( vlc_object_t *p_this )
73 {
74     demux_t *p_demux = (demux_t *)p_this;
75     demux_sys_t *p_sys = p_demux->p_sys;
76
77     if( p_sys->psz_prefix ) free( p_sys->psz_prefix );
78     if( p_sys->p_playlist ) vlc_object_release( p_sys->p_playlist );
79     if( p_sys->p_xml_reader ) xml_ReaderDelete( p_sys->p_xml, p_sys->p_xml_reader );
80     if( p_sys->p_xml ) xml_Delete( p_sys->p_xml );
81     free( p_sys );
82 }
83
84 /* "specs" : http://phobos.apple.com/static/iTunesRSS.html */
85 static int Demux( demux_t *p_demux )
86 {
87     demux_sys_t *p_sys = p_demux->p_sys;
88
89     vlc_bool_t b_item = VLC_FALSE;
90     vlc_bool_t b_image = VLC_FALSE;
91     int i_ret;
92
93     xml_t *p_xml;
94     xml_reader_t *p_xml_reader;
95     char *psz_elname = NULL;
96     char *psz_item_mrl = NULL;
97     char *psz_item_size = NULL;
98     char *psz_item_type = NULL;
99     char *psz_item_name = NULL;
100     char *psz_item_date = NULL;
101     char *psz_item_author = NULL;
102     char *psz_item_category = NULL;
103     char *psz_item_duration = NULL;
104     char *psz_item_keywords = NULL;
105     char *psz_item_subtitle = NULL;
106     char *psz_item_summary = NULL;
107     int i_type;
108
109     INIT_PLAYLIST_STUFF;
110
111     p_xml = p_sys->p_xml = xml_Create( p_demux );
112     if( !p_xml ) return -1;
113
114 /*    psz_elname = stream_ReadLine( p_demux->s );
115     if( psz_elname ) free( psz_elname );
116     psz_elname = 0;*/
117
118     p_xml_reader = xml_ReaderCreate( p_xml, p_demux->s );
119     if( !p_xml_reader ) return -1;
120     p_sys->p_xml_reader = p_xml_reader;
121
122     /* xml */
123     /* check root node */
124     if( xml_ReaderRead( p_xml_reader ) != 1 )
125     {
126         msg_Err( p_demux, "invalid file (no root node)" );
127         return -1;
128     }
129     if( xml_ReaderNodeType( p_xml_reader ) != XML_READER_STARTELEM ||
130         ( psz_elname = xml_ReaderName( p_xml_reader ) ) == NULL ||
131         strcmp( psz_elname, "rss" ) )
132     {
133         msg_Err( p_demux, "invalid root node %i, %s",
134                  xml_ReaderNodeType( p_xml_reader ), psz_elname );
135         if( psz_elname ) free( psz_elname );
136         return -1;
137     }
138     free( psz_elname ); psz_elname = NULL;
139
140     while( (i_ret = xml_ReaderRead( p_xml_reader )) == 1 )
141     {
142         // Get the node type
143         i_type = xml_ReaderNodeType( p_xml_reader );
144         switch( i_type )
145         {
146             // Error
147             case -1:
148                 return -1;
149                 break;
150
151             case XML_READER_STARTELEM:
152             {
153                 // Read the element name
154                 if( psz_elname ) free( psz_elname );
155                 psz_elname = xml_ReaderName( p_xml_reader );
156                 if( !psz_elname ) return -1;
157
158                 if( !strcmp( psz_elname, "item" ) )
159                 {
160                     b_item = VLC_TRUE;
161                 }
162                 else if( !strcmp( psz_elname, "image" ) )
163                 {
164                     b_item = VLC_TRUE;
165                 }
166
167                 // Read the attributes
168                 while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
169                 {
170                     char *psz_name = xml_ReaderName( p_xml_reader );
171                     char *psz_value = xml_ReaderValue( p_xml_reader );
172                     if( !psz_name || !psz_value ) return -1;
173                     if( !strcmp( psz_elname, "enclosure" ) &&
174                         !strcmp( psz_name, "url" ) )
175                     {
176                         psz_item_mrl = strdup( psz_value );
177                     }
178                     else if( !strcmp( psz_elname, "enclosure" ) &&
179                         !strcmp( psz_name, "length" ) )
180                     {
181                         psz_item_size = strdup( psz_value );
182                     }
183                     else if( !strcmp( psz_elname, "enclosure" ) &&
184                         !strcmp( psz_name, "type" ) )
185                     {
186                         psz_item_type = strdup( psz_value );
187                     }
188                     else
189                     {
190                         msg_Dbg( p_demux,"unhandled attribure %s in element %s",
191                                   psz_name, psz_elname );
192                     }
193                     free( psz_name );
194                     free( psz_value );
195                 }
196                 break;
197             }
198             case XML_READER_TEXT:
199             {
200                 char *psz_text = xml_ReaderValue( p_xml_reader );
201                 /* item specific meta data */
202                 if( b_item == VLC_TRUE && !strcmp( psz_elname, "title" ) )
203                 {
204                     psz_item_name = strdup( psz_text );
205                 }
206                 else if( b_item == VLC_TRUE
207                          && !strcmp( psz_elname, "pubDate" ) )
208                 {
209                     psz_item_date = strdup( psz_text );
210                 }
211                 else if( b_item == VLC_TRUE
212                          && ( !strcmp( psz_elname, "itunes:author" )
213                             ||!strcmp( psz_elname, "author" ) ) )
214                 { /* <author> isn't standard iTunes podcast stuff */
215                     psz_item_author = strdup( psz_text );
216                 }
217                 else if( b_item == VLC_TRUE
218                          && !strcmp( psz_elname, "itunes:category" ) )
219                 {
220                     psz_item_category = strdup( psz_text );
221                 }
222                 else if( b_item == VLC_TRUE
223                          && !strcmp( psz_elname, "itunes:duration" ) )
224                 {
225                     psz_item_duration = strdup( psz_text );
226                 }
227                 else if( b_item == VLC_TRUE
228                          && !strcmp( psz_elname, "itunes:keywords" ) )
229                 {
230                     psz_item_keywords = strdup( psz_text );
231                 }
232                 else if( b_item == VLC_TRUE
233                          && !strcmp( psz_elname, "itunes:subtitle" ) )
234                 {
235                     psz_item_subtitle = strdup( psz_text );
236                 }
237                 else if( b_item == VLC_TRUE
238                          && ( !strcmp( psz_elname, "itunes:summary" )
239                             ||!strcmp( psz_elname, "description" ) ) )
240                 { /* <description> isn't standard iTunes podcast stuff */
241                     psz_item_summary = strdup( psz_text );
242                 }
243                 /* toplevel meta data */
244                 else if( b_item == VLC_FALSE && b_image == VLC_FALSE
245                          && !strcmp( psz_elname, "title" ) )
246                 {
247                     playlist_ItemSetName( p_current, psz_text );
248                 }
249                 else if( b_item == VLC_FALSE && b_image == VLC_FALSE
250                          && !strcmp( psz_elname, "link" ) )
251                 {
252                     vlc_input_item_AddInfo( p_current->p_input,
253                                             _( "Podcast Info" ),
254                                             _( "Podcast Link" ),
255                                             "%s",
256                                             psz_text );
257                 }
258                 else if( b_item == VLC_FALSE && b_image == VLC_FALSE
259                          && !strcmp( psz_elname, "copyright" ) )
260                 {
261                     vlc_input_item_AddInfo( p_current->p_input,
262                                             _( "Podcast Info" ),
263                                             _( "Podcast Copyright" ),
264                                             "%s",
265                                             psz_text );
266                 }
267                 else if( b_item == VLC_FALSE && b_image == VLC_FALSE
268                          && !strcmp( psz_elname, "itunes:category" ) )
269                 {
270                     vlc_input_item_AddInfo( p_current->p_input,
271                                             _( "Podcast Info" ),
272                                             _( "Podcast Category" ),
273                                             "%s",
274                                             psz_text );
275                 }
276                 else if( b_item == VLC_FALSE && b_image == VLC_FALSE
277                          && !strcmp( psz_elname, "itunes:keywords" ) )
278                 {
279                     vlc_input_item_AddInfo( p_current->p_input,
280                                             _( "Podcast Info" ),
281                                             _( "Podcast Keywords" ),
282                                             "%s",
283                                             psz_text );
284                 }
285                 else if( b_item == VLC_FALSE && b_image == VLC_FALSE
286                          && !strcmp( psz_elname, "itunes:subtitle" ) )
287                 {
288                     vlc_input_item_AddInfo( p_current->p_input,
289                                             _( "Podcast Info" ),
290                                             _( "Podcast Subtitle" ),
291                                             "%s",
292                                             psz_text );
293                 }
294                 else if( b_item == VLC_FALSE && b_image == VLC_FALSE
295                          && ( !strcmp( psz_elname, "itunes:summary" )
296                             ||!strcmp( psz_elname, "description" ) ) )
297                 { /* <description> isn't standard iTunes podcast stuff */
298                     vlc_input_item_AddInfo( p_current->p_input,
299                                             _( "Podcast Info" ),
300                                             _( "Podcast Summary" ),
301                                             "%s",
302                                             psz_text );
303                 }
304                 else
305                 {
306                     msg_Dbg( p_demux, "unhandled text in element '%s'",
307                               psz_elname );
308                 }
309                 free( psz_text );
310                 break;
311             }
312             // End element
313             case XML_READER_ENDELEM:
314             {
315                 // Read the element name
316                 free( psz_elname );
317                 psz_elname = xml_ReaderName( p_xml_reader );
318                 if( !psz_elname ) return -1;
319                 if( !strcmp( psz_elname, "item" ) )
320                 {
321                     p_input = input_ItemNewExt( p_playlist, psz_item_mrl,
322                                                 psz_item_name, 0, NULL, -1 );
323                     if( p_input == NULL ) break;
324                     if( psz_item_date )
325                     {
326                         vlc_input_item_AddInfo( p_input,
327                                                 _( "Podcast Info" ),
328                                                 _( "Podcast Publication Date" ),
329                                                 "%s",
330                                                 psz_item_date );
331                     }
332                     if( psz_item_author )
333                     {
334                         vlc_input_item_AddInfo( p_input,
335                                                 _( "Podcast Info" ),
336                                                 _( "Podcast Author" ),
337                                                 "%s",
338                                                 psz_item_author );
339                     }
340                     if( psz_item_category )
341                     {
342                         vlc_input_item_AddInfo( p_input,
343                                                 _( "Podcast Info" ),
344                                                 _( "Podcast Subcategory" ),
345                                                 "%s",
346                                                 psz_item_category );
347                     }
348                     if( psz_item_duration )
349                     {
350                         vlc_input_item_AddInfo( p_input,
351                                                 _( "Podcast Info" ),
352                                                 _( "Podcast Duration" ),
353                                                 "%s",
354                                                 psz_item_duration );
355                     }
356                     if( psz_item_keywords )
357                     {
358                         vlc_input_item_AddInfo( p_input,
359                                                 _( "Podcast Info" ),
360                                                 _( "Podcast Keywords" ),
361                                                 "%s",
362                                                 psz_item_keywords );
363                     }
364                     if( psz_item_subtitle )
365                     {
366                         vlc_input_item_AddInfo( p_input,
367                                                 _( "Podcast Info" ),
368                                                 _( "Podcast Subtitle" ),
369                                                 "%s",
370                                                 psz_item_subtitle );
371                     }
372                     if( psz_item_summary )
373                     {
374                         vlc_input_item_AddInfo( p_input,
375                                                 _( "Podcast Info" ),
376                                                 _( "Podcast Summary" ),
377                                                 "%s",
378                                                 psz_item_summary );
379                     }
380                     if( psz_item_size )
381                     {
382                         vlc_input_item_AddInfo( p_input,
383                                                 _( "Podcast Info" ),
384                                                 _( "Podcast Size" ),
385                                                 "%s bytes",
386                                                 psz_item_size );
387                     }
388                     if( psz_item_type )
389                     {
390                         vlc_input_item_AddInfo( p_input,
391                                                 _( "Podcast Info" ),
392                                                 _( "Podcast Type" ),
393                                                 "%s",
394                                                 psz_item_type );
395                     }
396
397                     msg_Dbg( p_demux, "Adding WHEREVER\n" );
398                     playlist_AddWhereverNeeded( p_playlist, p_input, p_current,
399                           p_item_in_category, (i_parent_id > 0 ) ? VLC_TRUE:
400                                                 VLC_FALSE, PLAYLIST_APPEND );
401 #define FREE(a) if( a ) free( a ); a = NULL;
402                     FREE( psz_item_name );
403                     FREE( psz_item_mrl );
404                     FREE( psz_item_size );
405                     FREE( psz_item_type );
406                     FREE( psz_item_date );
407                     FREE( psz_item_author );
408                     FREE( psz_item_category );
409                     FREE( psz_item_duration );
410                     FREE( psz_item_keywords );
411                     FREE( psz_item_subtitle );
412                     FREE( psz_item_summary );
413 #undef FREE
414
415                     b_item = VLC_FALSE;
416                 }
417                 else if( !strcmp( psz_elname, "image" ) )
418                 {
419                     b_image = VLC_FALSE;
420                 }
421                 free( psz_elname );
422                 psz_elname = strdup("");
423
424                 break;
425             }
426         }
427     }
428
429     if( i_ret != 0 )
430     {
431         msg_Warn( p_demux, "error while parsing data" );
432     }
433
434     HANDLE_PLAY_AND_RELEASE;
435     return VLC_SUCCESS;
436 }
437
438 static int Control( demux_t *p_demux, int i_query, va_list args )
439 {
440     return VLC_EGENERIC;
441 }