1 /*****************************************************************************
2 * rss.c : rss/atom feed display video plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2003-2006 the VideoLAN team
7 * Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
25 * Atom : http://www.ietf.org/rfc/rfc4287.txt
26 * RSS : http://www.rssboard.org/rss-specification
27 *****************************************************************************/
29 /*****************************************************************************
31 *****************************************************************************/
32 #include <stdlib.h> /* malloc(), free() */
38 #include "vlc_filter.h"
39 #include "vlc_block.h"
42 #include "vlc_block.h"
43 #include "vlc_stream.h"
47 #include "vlc_image.h"
49 /*****************************************************************************
51 *****************************************************************************/
52 static int CreateFilter ( vlc_object_t * );
53 static void DestroyFilter( vlc_object_t * );
54 static subpicture_t *Filter( filter_t *, mtime_t );
56 static int FetchRSS( filter_t * );
57 static void FreeRSS( filter_t * );
59 static int pi_color_values[] = { 0xf0000000, 0x00000000, 0x00808080, 0x00C0C0C0,
60 0x00FFFFFF, 0x00800000, 0x00FF0000, 0x00FF00FF, 0x00FFFF00,
61 0x00808000, 0x00008000, 0x00008080, 0x0000FF00, 0x00800080,
62 0x00000080, 0x000000FF, 0x0000FFFF};
63 static char *ppsz_color_descriptions[] = { N_("Default"), N_("Black"),
64 N_("Gray"), N_("Silver"), N_("White"), N_("Maroon"), N_("Red"),
65 N_("Fuchsia"), N_("Yellow"), N_("Olive"), N_("Green"),
66 N_("Teal"), N_("Lime"), N_("Purple"), N_("Navy"), N_("Blue"),
69 /*****************************************************************************
70 * filter_sys_t: rss filter descriptor
71 *****************************************************************************/
76 char *psz_description;
83 char *psz_description;
89 struct rss_item_t *p_items;
97 int i_xoff, i_yoff; /* offsets for the display string in the video window */
98 int i_pos; /* permit relative positioning (top, bottom, left, right, center) */
102 char *psz_marquee; /* marquee string */
104 text_style_t *p_style; /* font control */
110 struct rss_feed_t *p_feeds;
113 time_t t_last_update;
121 #define MSG_TEXT N_("Feed URLs")
122 #define MSG_LONGTEXT N_("RSS/Atom feed '|' (pipe) seperated URLs.")
123 #define SPEED_TEXT N_("Speed of feeds")
124 #define SPEED_LONGTEXT N_("Speed of the RSS/Atom feeds (bigger is slower).")
125 #define LENGTH_TEXT N_("Max length")
126 #define LENGTH_LONGTEXT N_("Maximum number of characters displayed on the " \
128 #define TTL_TEXT N_("Refresh time")
129 #define TTL_LONGTEXT N_("Number of seconds between each forced refresh " \
130 "of the feeds. 0 means that the feeds are never updated." )
131 #define IMAGE_TEXT N_("Feed images")
132 #define IMAGE_LONGTEXT N_("Display feed images if available.")
134 #define POSX_TEXT N_("X offset")
135 #define POSX_LONGTEXT N_("X offset, from the left screen edge." )
136 #define POSY_TEXT N_("Y offset")
137 #define POSY_LONGTEXT N_("Y offset, down from the top." )
138 #define OPACITY_TEXT N_("Opacity")
139 #define OPACITY_LONGTEXT N_("Opacity (inverse of transparency) of " \
140 "overlay text. 0 = transparent, 255 = totally opaque." )
142 #define SIZE_TEXT N_("Font size, pixels")
143 #define SIZE_LONGTEXT N_("Font size, in pixels. Default is -1 (use default " \
146 #define COLOR_TEXT N_("Color")
147 #define COLOR_LONGTEXT N_("Color of the text that will be rendered on "\
148 "the video. This must be an hexadecimal (like HTML colors). The first two "\
149 "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
150 " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
152 #define POS_TEXT N_("Text position")
153 #define POS_LONGTEXT N_( \
154 "You can enforce the text position on the video " \
155 "(0=center, 1=left, 2=right, 4=top, 8=bottom; you can " \
156 "also use combinations of these values, eg 6 = top-right).")
158 static int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
159 static char *ppsz_pos_descriptions[] =
160 { N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
161 N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
163 #define CFG_PREFIX "rrs-"
165 /*****************************************************************************
167 *****************************************************************************/
169 set_capability( "sub filter", 0 );
170 set_shortname( "RSS / Atom" );
171 set_callbacks( CreateFilter, DestroyFilter );
172 set_category( CAT_VIDEO );
173 set_subcategory( SUBCAT_VIDEO_SUBPIC );
174 add_string( CFG_PREFIX "urls", "rss", NULL, MSG_TEXT, MSG_LONGTEXT, VLC_FALSE );
176 set_section( N_("Position"), NULL );
177 add_integer( CFG_PREFIX "x", -1, NULL, POSX_TEXT, POSX_LONGTEXT, VLC_TRUE );
178 add_integer( CFG_PREFIX "y", 0, NULL, POSY_TEXT, POSY_LONGTEXT, VLC_TRUE );
179 add_integer( CFG_PREFIX "position", 5, NULL, POS_TEXT, POS_LONGTEXT, VLC_FALSE );
180 change_integer_list( pi_pos_values, ppsz_pos_descriptions, 0 );
182 set_section( N_("Font"), NULL );
183 /* 5 sets the default to top [1] left [4] */
184 add_integer_with_range( CFG_PREFIX "opacity", 255, 0, 255, NULL,
185 OPACITY_TEXT, OPACITY_LONGTEXT, VLC_FALSE );
186 add_integer( CFG_PREFIX "color", 0xFFFFFF, NULL, COLOR_TEXT, COLOR_LONGTEXT,
188 change_integer_list( pi_color_values, ppsz_color_descriptions, 0 );
189 add_integer( CFG_PREFIX "size", -1, NULL, SIZE_TEXT, SIZE_LONGTEXT, VLC_FALSE );
191 set_section( N_("Misc"), NULL );
192 add_integer( CFG_PREFIX "speed", 100000, NULL, SPEED_TEXT, SPEED_LONGTEXT,
194 add_integer( CFG_PREFIX "length", 60, NULL, LENGTH_TEXT, LENGTH_LONGTEXT,
196 add_integer( CFG_PREFIX "ttl", 1800, NULL, TTL_TEXT, TTL_LONGTEXT, VLC_FALSE );
197 add_bool( CFG_PREFIX "images", 1, NULL, IMAGE_TEXT, IMAGE_LONGTEXT, VLC_FALSE );
199 set_description( _("RSS and Atom feed display") );
200 add_shortcut( "rss" );
201 add_shortcut( "atom" );
204 static const char *ppsz_filter_options[] = {
205 "urls", "x", "y", "position", "color", "size", "speed", "length",
206 "ttl", "images", NULL
209 /*****************************************************************************
210 * CreateFilter: allocates RSS video filter
211 *****************************************************************************/
212 static int CreateFilter( vlc_object_t *p_this )
214 filter_t *p_filter = (filter_t *)p_this;
218 /* Allocate structure */
219 p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
222 msg_Err( p_filter, "out of memory" );
226 vlc_mutex_init( p_filter, &p_sys->lock );
227 vlc_mutex_lock( &p_sys->lock );
229 config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
232 p_sys->psz_urls = var_CreateGetString( p_filter, "rss-urls" );
233 p_sys->i_cur_feed = 0;
234 p_sys->i_cur_item = 0;
235 p_sys->i_cur_char = 0;
237 p_sys->p_feeds = NULL;
238 p_sys->i_speed = var_CreateGetInteger( p_filter, "rss-speed" );
239 p_sys->i_length = var_CreateGetInteger( p_filter, "rss-length" );
240 p_sys->i_ttl = __MAX( 0, var_CreateGetInteger( p_filter, "rss-ttl" ) );
241 p_sys->b_images = var_CreateGetBool( p_filter, "rss-images" );
242 p_sys->psz_marquee = (char *)malloc( p_sys->i_length );
244 p_sys->p_style = malloc( sizeof( text_style_t ));
245 memcpy( p_sys->p_style, &default_text_style, sizeof( text_style_t ));
247 p_sys->i_xoff = var_CreateGetInteger( p_filter, "rss-x" );
248 p_sys->i_yoff = var_CreateGetInteger( p_filter, "rss-y" );
249 p_sys->i_pos = var_CreateGetInteger( p_filter, "rss-position" );
250 p_sys->p_style->i_font_alpha = 255 - var_CreateGetInteger( p_filter, "rss-opacity" );
251 p_sys->p_style->i_font_color = var_CreateGetInteger( p_filter, "rss-color" );
252 p_sys->p_style->i_font_size = var_CreateGetInteger( p_filter, "rss-size" );
254 if( p_sys->b_images == VLC_TRUE && p_sys->p_style->i_font_size == -1 )
256 msg_Warn( p_filter, "rrs-size wasn't specified. Feed images will thus be displayed without being resized" );
259 if( FetchRSS( p_filter ) )
261 msg_Err( p_filter, "failed while fetching RSS ... too bad" );
262 vlc_mutex_unlock( &p_sys->lock );
265 p_sys->t_last_update = time( NULL );
267 if( p_sys->i_feeds == 0 )
269 vlc_mutex_unlock( &p_sys->lock );
272 for( i_feed=0; i_feed < p_sys->i_feeds; i_feed ++ )
273 if( p_sys->p_feeds[i_feed].i_items == 0 )
275 vlc_mutex_unlock( &p_sys->lock );
280 p_filter->pf_sub_filter = Filter;
281 p_sys->last_date = (mtime_t)0;
283 vlc_mutex_unlock( &p_sys->lock );
287 /*****************************************************************************
288 * DestroyFilter: destroy RSS video filter
289 *****************************************************************************/
290 static void DestroyFilter( vlc_object_t *p_this )
292 filter_t *p_filter = (filter_t *)p_this;
293 filter_sys_t *p_sys = p_filter->p_sys;
295 vlc_mutex_lock( &p_sys->lock );
297 if( p_sys->p_style ) free( p_sys->p_style );
298 if( p_sys->psz_marquee ) free( p_sys->psz_marquee );
299 free( p_sys->psz_urls );
301 vlc_mutex_unlock( &p_sys->lock );
302 vlc_mutex_destroy( &p_sys->lock );
305 /* Delete the RSS variables */
306 var_Destroy( p_filter, "rss-urls" );
307 var_Destroy( p_filter, "rss-speed" );
308 var_Destroy( p_filter, "rss-length" );
309 var_Destroy( p_filter, "rss-ttl" );
310 var_Destroy( p_filter, "rss-images" );
311 var_Destroy( p_filter, "rss-x" );
312 var_Destroy( p_filter, "rss-y" );
313 var_Destroy( p_filter, "rss-position" );
314 var_Destroy( p_filter, "rss-color");
315 var_Destroy( p_filter, "rss-opacity");
316 var_Destroy( p_filter, "rss-size");
319 /****************************************************************************
320 * Filter: the whole thing
321 ****************************************************************************
322 * This function outputs subpictures at regular time intervals.
323 ****************************************************************************/
324 static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
326 filter_sys_t *p_sys = p_filter->p_sys;
328 video_format_t fmt = {0};
330 subpicture_region_t *p_region;
334 struct rss_feed_t *p_feed;
336 vlc_mutex_lock( &p_sys->lock );
339 + ( p_sys->i_cur_char == 0 && p_sys->i_cur_item == 0 ? 5 : 1 )
340 /* ( ... ? 5 : 1 ) means "wait more for the 1st char" */
341 * p_sys->i_speed > date )
343 vlc_mutex_unlock( &p_sys->lock );
347 /* Do we need to update the feeds ? */
349 && time( NULL ) > p_sys->t_last_update + (time_t)p_sys->i_ttl )
351 msg_Dbg( p_filter, "Forcing update of all the RSS feeds" );
352 if( FetchRSS( p_filter ) )
354 msg_Err( p_filter, "failed while fetching RSS ... too bad" );
355 vlc_mutex_unlock( &p_sys->lock );
356 return NULL; /* FIXME : we most likely messed up all the data,
357 * so we might need to do something about it */
359 p_sys->t_last_update = time( NULL );
362 p_sys->last_date = date;
364 if( p_sys->p_feeds[p_sys->i_cur_feed].p_items[p_sys->i_cur_item].psz_title[p_sys->i_cur_char] == 0 )
366 p_sys->i_cur_char = 0;
368 if( p_sys->i_cur_item >= p_sys->p_feeds[p_sys->i_cur_feed].i_items )
370 p_sys->i_cur_item = 0;
371 p_sys->i_cur_feed = (p_sys->i_cur_feed + 1)%p_sys->i_feeds;
375 p_spu = p_filter->pf_sub_buffer_new( p_filter );
378 vlc_mutex_unlock( &p_sys->lock );
382 fmt.i_chroma = VLC_FOURCC('T','E','X','T');
384 p_spu->p_region = p_spu->pf_create_region( VLC_OBJECT(p_filter), &fmt );
385 if( !p_spu->p_region )
387 p_filter->pf_sub_buffer_del( p_filter, p_spu );
388 vlc_mutex_unlock( &p_sys->lock );
392 /* Generate the string that will be displayed. This string is supposed to
393 be p_sys->i_length characters long. */
394 i_item = p_sys->i_cur_item;
395 i_feed = p_sys->i_cur_feed;
396 p_feed = &p_sys->p_feeds[p_sys->i_cur_feed];
400 /* Don't display the feed's title if we have an image */
401 snprintf( p_sys->psz_marquee, p_sys->i_length, "%s",
402 p_sys->p_feeds[i_feed].p_items[i_item].psz_title
403 +p_sys->i_cur_char );
407 snprintf( p_sys->psz_marquee, p_sys->i_length, "%s : %s",
408 p_sys->p_feeds[i_feed].psz_title,
409 p_sys->p_feeds[i_feed].p_items[i_item].psz_title
410 +p_sys->i_cur_char );
413 while( strlen( p_sys->psz_marquee ) < (unsigned int)p_sys->i_length )
416 if( i_item == p_sys->p_feeds[i_feed].i_items ) break;
417 snprintf( strchr( p_sys->psz_marquee, 0 ),
418 p_sys->i_length - strlen( p_sys->psz_marquee ),
420 p_sys->p_feeds[i_feed].p_items[i_item].psz_title );
423 /* Calls to snprintf might split multibyte UTF8 chars ...
424 * which freetype doesn't like. */
426 char *a = strdup( p_sys->psz_marquee );
428 char *b = p_sys->psz_marquee;
429 EnsureUTF8( p_sys->psz_marquee );
430 /* we want to use ' ' instead of '?' for erroneous chars */
433 if( *b != *a ) *b = ' ';
439 p_spu->p_region->psz_text = strdup(p_sys->psz_marquee);
440 p_spu->i_start = date;
442 p_spu->b_ephemer = VLC_TRUE;
444 /* where to locate the string: */
445 if( p_sys->i_xoff < 0 || p_sys->i_yoff < 0 )
446 { /* set to one of the 9 relative locations */
447 p_spu->i_flags = p_sys->i_pos;
450 p_spu->b_absolute = VLC_FALSE;
453 { /* set to an absolute xy, referenced to upper left corner */
454 p_spu->i_flags = OSD_ALIGN_LEFT | OSD_ALIGN_TOP;
455 p_spu->i_x = p_sys->i_xoff;
456 p_spu->i_y = p_sys->i_yoff;
457 p_spu->b_absolute = VLC_TRUE;
461 p_spu->p_region->p_style = p_sys->p_style;
465 /* Display the feed's image */
466 picture_t *p_pic = p_feed->p_pic;
467 video_format_t fmt_out = {0};
469 fmt_out.i_chroma = VLC_FOURCC('Y','U','V','A');
470 fmt_out.i_aspect = VOUT_ASPECT_FACTOR;
471 fmt_out.i_sar_num = fmt_out.i_sar_den = 1;
473 fmt_out.i_visible_width = p_pic->p[Y_PLANE].i_visible_pitch;
475 fmt_out.i_visible_height = p_pic->p[Y_PLANE].i_visible_lines;
477 p_region = p_spu->pf_create_region( VLC_OBJECT( p_filter ), &fmt_out );
480 msg_Err( p_filter, "cannot allocate SPU region" );
484 vout_CopyPicture( p_filter, &p_region->picture, p_pic );
485 p_spu->p_region->p_next = p_region;
488 /* Offset text to display right next to the image */
489 p_spu->p_region->i_x = p_pic->p[Y_PLANE].i_visible_pitch;
492 vlc_mutex_unlock( &p_sys->lock );
496 /****************************************************************************
497 * RSS related functions
498 ****************************************************************************
499 * You should always lock the p_filter mutex before using any of these
501 ***************************************************************************/
503 #undef LoadImage /* do not conflict with Win32 API */
505 /****************************************************************************
506 * download and resize image located at psz_url
507 ***************************************************************************/
508 picture_t *LoadImage( filter_t *p_filter, const char *psz_url )
510 filter_sys_t *p_sys = p_filter->p_sys;
512 video_format_t fmt_in={0}, fmt_out={0};
513 picture_t *p_orig, *p_pic=NULL;
514 image_handler_t *p_handler = image_HandlerCreate( p_filter );
518 psz_local = ToLocale( psz_url );
519 fmt_out.i_chroma = VLC_FOURCC('Y','U','V','A');
520 p_orig = image_ReadUrl( p_handler, psz_local, &fmt_in, &fmt_out );
521 LocaleFree( psz_local );
525 msg_Warn( p_filter, "Unable to read image %s", psz_url );
527 else if( p_sys->p_style->i_font_size > 0 )
530 fmt_in.i_chroma = VLC_FOURCC('Y','U','V','A');
531 fmt_in.i_height = p_orig->p[Y_PLANE].i_visible_lines;
532 fmt_in.i_width = p_orig->p[Y_PLANE].i_visible_pitch;
533 fmt_out.i_width = p_orig->p[Y_PLANE].i_visible_pitch
534 *p_sys->p_style->i_font_size/p_orig->p[Y_PLANE].i_visible_lines;
535 fmt_out.i_height = p_sys->p_style->i_font_size;
537 p_pic = image_Convert( p_handler, p_orig, &fmt_in, &fmt_out );
538 p_orig->pf_release( p_orig );
541 msg_Warn( p_filter, "Error while converting %s", psz_url );
549 image_HandlerDelete( p_handler );
554 /****************************************************************************
555 * remove all ' ' '\t' '\n' '\r' characters from the begining and end of the
557 ***************************************************************************/
558 char *removeWhiteChars( char *psz_src )
560 char *psz_src2 = strdup( psz_src );
561 char *psz_clean = strdup( psz_src2 );
564 while( ( *psz_clean == ' ' || *psz_clean == '\t'
565 || *psz_clean == '\n' || *psz_clean == '\r' )
566 && *psz_clean != '\0' )
570 i = strlen( psz_clean );
572 ( psz_clean[i] == ' ' || psz_clean[i] == '\t'
573 || psz_clean[i] == '\n' || psz_clean[i] == '\r' ) );
574 psz_clean[i+1] = '\0';
575 psz_clean2 = strdup( psz_clean );
580 /****************************************************************************
581 * FetchRSS (or Atom) feeds
582 ***************************************************************************/
583 static int FetchRSS( filter_t *p_filter)
585 filter_sys_t *p_sys = p_filter->p_sys;
587 stream_t *p_stream = NULL;
589 xml_reader_t *p_xml_reader = NULL;
591 char *psz_eltname = NULL;
592 char *psz_eltvalue = NULL;
593 char *psz_feed = NULL;
594 char *psz_buffer = NULL;
595 char *psz_buffer_2 = NULL;
599 vlc_bool_t b_is_item;
600 vlc_bool_t b_is_image;
606 while( p_sys->psz_urls[i_int] != 0 )
607 if( p_sys->psz_urls[i_int++] == '|' )
609 p_sys->p_feeds = (struct rss_feed_t *)malloc( p_sys->i_feeds
610 * sizeof( struct rss_feed_t ) );
612 p_xml = xml_Create( p_filter );
615 msg_Err( p_filter, "Failed to open XML parser" );
619 psz_buffer = strdup( p_sys->psz_urls );
620 psz_buffer_2 = psz_buffer; /* keep track so we can free it */
621 for( i_feed = 0; i_feed < p_sys->i_feeds; i_feed++ )
623 struct rss_feed_t *p_feed = p_sys->p_feeds+i_feed;
625 if( psz_buffer == NULL ) break;
626 if( psz_buffer[0] == 0 ) psz_buffer++;
627 psz_feed = psz_buffer;
628 psz_buffer = strchr( psz_buffer, '|' );
629 if( psz_buffer != NULL ) psz_buffer[0] = 0;
631 p_feed->psz_title = NULL;
632 p_feed->psz_description = NULL;
633 p_feed->psz_link = NULL;
634 p_feed->psz_image = NULL;
635 p_feed->p_pic = NULL;
637 p_feed->p_items = NULL;
639 msg_Dbg( p_filter, "opening %s RSS/Atom feed ...", psz_feed );
641 p_stream = stream_UrlNew( p_filter, psz_feed );
644 msg_Err( p_filter, "Failed to open %s for reading", psz_feed );
648 p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
651 msg_Err( p_filter, "Failed to open %s for parsing", psz_feed );
656 b_is_item = VLC_FALSE;
657 b_is_image = VLC_FALSE;
659 while( xml_ReaderRead( p_xml_reader ) == 1 )
661 switch( xml_ReaderNodeType( p_xml_reader ) )
667 case XML_READER_STARTELEM:
673 psz_eltname = xml_ReaderName( p_xml_reader );
679 msg_Dbg( p_filter, "element name: %s", psz_eltname );
681 if( !strcmp( psz_eltname, "item" ) /* rss */
682 || !strcmp( psz_eltname, "entry" ) ) /* atom */
684 b_is_item = VLC_TRUE;
686 p_feed->p_items = (struct rss_item_t *)realloc( p_feed->p_items, p_feed->i_items * sizeof( struct rss_item_t ) );
687 p_feed->p_items[p_feed->i_items-1].psz_title = NULL;
688 p_feed->p_items[p_feed->i_items-1].psz_description
690 p_feed->p_items[p_feed->i_items-1].psz_link = NULL;
692 else if( !strcmp( psz_eltname, "image" ) ) /* rss */
694 b_is_image = VLC_TRUE;
696 else if( !strcmp( psz_eltname, "link" ) ) /* atom */
698 char *psz_href = NULL;
699 char *psz_rel = NULL;
700 while( xml_ReaderNextAttr( p_xml_reader )
703 char *psz_name = xml_ReaderName( p_xml_reader );
704 char *psz_value = xml_ReaderValue( p_xml_reader );
705 if( !strcmp( psz_name, "rel" ) )
709 else if( !strcmp( psz_name, "href" ) )
711 psz_href = psz_value;
719 if( psz_rel && psz_href )
721 if( !strcmp( psz_rel, "alternate" )
722 && b_is_item == VLC_FALSE
723 && b_is_image == VLC_FALSE
724 && !p_feed->psz_link )
726 p_feed->psz_link = psz_href;
728 /* this isn't in the rfc but i found some ... */
729 else if( ( !strcmp( psz_rel, "logo" )
730 || !strcmp( psz_rel, "icon" ) )
731 && b_is_item == VLC_FALSE
732 && b_is_image == VLC_FALSE
733 && !p_feed->psz_image )
735 p_feed->psz_image = psz_href;
744 if( psz_href ) free( psz_href );
746 if( psz_rel ) free( psz_rel );
750 case XML_READER_ENDELEM:
756 psz_eltname = xml_ReaderName( p_xml_reader );
762 msg_Dbg( p_filter, "element end : %s", psz_eltname );
764 if( !strcmp( psz_eltname, "item" ) /* rss */
765 || !strcmp( psz_eltname, "entry" ) ) /* atom */
767 b_is_item = VLC_FALSE;
770 else if( !strcmp( psz_eltname, "image" ) ) /* rss */
772 b_is_image = VLC_FALSE;
778 case XML_READER_TEXT:
779 if( !psz_eltname ) break;
780 psz_eltvalue = xml_ReaderValue( p_xml_reader );
788 psz_clean = removeWhiteChars( psz_eltvalue );
789 free( psz_eltvalue ); psz_eltvalue = psz_clean;
792 msg_Dbg( p_filter, " text : <%s>", psz_eltvalue );
794 if( b_is_item == VLC_TRUE )
796 struct rss_item_t *p_item;
797 p_item = p_feed->p_items+i_item;
798 if( !strcmp( psz_eltname, "title" ) /* rss/atom */
799 && !p_item->psz_title )
801 p_item->psz_title = psz_eltvalue;
803 else if( !strcmp( psz_eltname, "link" ) /* rss */
804 && !p_item->psz_link )
806 p_item->psz_link = psz_eltvalue;
808 else if((!strcmp( psz_eltname, "description" ) /* rss */
809 || !strcmp( psz_eltname, "summary" ) ) /* atom */
810 && !p_item->psz_description )
812 p_item->psz_description = psz_eltvalue;
816 free( psz_eltvalue );
820 else if( b_is_image == VLC_TRUE )
822 if( !strcmp( psz_eltname, "url" ) /* rss */
823 && !p_feed->psz_image )
825 p_feed->psz_image = psz_eltvalue;
829 free( psz_eltvalue );
835 if( !strcmp( psz_eltname, "title" ) /* rss/atom */
836 && !p_feed->psz_title )
838 p_feed->psz_title = psz_eltvalue;
840 else if( !strcmp( psz_eltname, "link" ) /* rss */
841 && !p_feed->psz_link )
843 p_feed->psz_link = psz_eltvalue;
845 else if((!strcmp( psz_eltname, "description" ) /* rss */
846 || !strcmp( psz_eltname, "subtitle" ) ) /* atom */
847 && !p_feed->psz_description )
849 p_feed->psz_description = psz_eltvalue;
851 else if( ( !strcmp( psz_eltname, "logo" ) /* atom */
852 || !strcmp( psz_eltname, "icon" ) ) /* atom */
853 && !p_feed->psz_image )
855 p_feed->psz_image = psz_eltvalue;
859 free( psz_eltvalue );
867 if( p_sys->b_images == VLC_TRUE
868 && p_feed->psz_image && !p_feed->p_pic )
870 p_feed->p_pic = LoadImage( p_filter, p_feed->psz_image );
873 if( p_xml_reader && p_xml ) xml_ReaderDelete( p_xml, p_xml_reader );
874 if( p_stream ) stream_Delete( p_stream );
875 msg_Dbg( p_filter, "done with %s RSS/Atom feed", psz_feed );
877 free( psz_buffer_2 );
878 if( p_xml ) xml_Delete( p_xml );
883 /****************************************************************************
885 ***************************************************************************/
886 static void FreeRSS( filter_t *p_filter)
888 filter_sys_t *p_sys = p_filter->p_sys;
890 struct rss_item_t *p_item;
891 struct rss_feed_t *p_feed;
896 for( i_feed = 0; i_feed < p_sys->i_feeds; i_feed++ )
898 p_feed = p_sys->p_feeds+i_feed;
899 for( i_item = 0; i_item < p_feed->i_items; i_item++ )
901 p_item = p_feed->p_items+i_item;
902 free( p_item->psz_title );
903 free( p_item->psz_link );
904 free( p_item->psz_description );
906 free( p_feed->p_items );
907 free( p_feed->psz_title);
908 free( p_feed->psz_link );
909 free( p_feed->psz_description );
910 free( p_feed->psz_image );
911 if( p_feed->p_pic != NULL )
912 p_feed->p_pic->pf_release( p_feed->p_pic );
914 free( p_sys->p_feeds );