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"
45 #include <vlc_charset.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 );
516 fmt_out.i_chroma = VLC_FOURCC('Y','U','V','A');
517 p_orig = image_ReadUrl( p_handler, psz_url, &fmt_in, &fmt_out );
521 msg_Warn( p_filter, "Unable to read image %s", psz_url );
523 else if( p_sys->p_style->i_font_size > 0 )
526 fmt_in.i_chroma = VLC_FOURCC('Y','U','V','A');
527 fmt_in.i_height = p_orig->p[Y_PLANE].i_visible_lines;
528 fmt_in.i_width = p_orig->p[Y_PLANE].i_visible_pitch;
529 fmt_out.i_width = p_orig->p[Y_PLANE].i_visible_pitch
530 *p_sys->p_style->i_font_size/p_orig->p[Y_PLANE].i_visible_lines;
531 fmt_out.i_height = p_sys->p_style->i_font_size;
533 p_pic = image_Convert( p_handler, p_orig, &fmt_in, &fmt_out );
534 p_orig->pf_release( p_orig );
537 msg_Warn( p_filter, "Error while converting %s", psz_url );
545 image_HandlerDelete( p_handler );
550 /****************************************************************************
551 * remove all ' ' '\t' '\n' '\r' characters from the begining and end of the
553 ***************************************************************************/
554 char *removeWhiteChars( char *psz_src )
556 char *psz_src2 = strdup( psz_src );
557 char *psz_clean = strdup( psz_src2 );
560 while( ( *psz_clean == ' ' || *psz_clean == '\t'
561 || *psz_clean == '\n' || *psz_clean == '\r' )
562 && *psz_clean != '\0' )
566 i = strlen( psz_clean );
568 ( psz_clean[i] == ' ' || psz_clean[i] == '\t'
569 || psz_clean[i] == '\n' || psz_clean[i] == '\r' ) );
570 psz_clean[i+1] = '\0';
571 psz_clean2 = strdup( psz_clean );
576 /****************************************************************************
577 * FetchRSS (or Atom) feeds
578 ***************************************************************************/
579 static int FetchRSS( filter_t *p_filter)
581 filter_sys_t *p_sys = p_filter->p_sys;
583 stream_t *p_stream = NULL;
585 xml_reader_t *p_xml_reader = NULL;
587 char *psz_eltname = NULL;
588 char *psz_eltvalue = NULL;
589 char *psz_feed = NULL;
590 char *psz_buffer = NULL;
591 char *psz_buffer_2 = NULL;
595 vlc_bool_t b_is_item;
596 vlc_bool_t b_is_image;
602 while( p_sys->psz_urls[i_int] != 0 )
603 if( p_sys->psz_urls[i_int++] == '|' )
605 p_sys->p_feeds = (struct rss_feed_t *)malloc( p_sys->i_feeds
606 * sizeof( struct rss_feed_t ) );
608 p_xml = xml_Create( p_filter );
611 msg_Err( p_filter, "Failed to open XML parser" );
615 psz_buffer = strdup( p_sys->psz_urls );
616 psz_buffer_2 = psz_buffer; /* keep track so we can free it */
617 for( i_feed = 0; i_feed < p_sys->i_feeds; i_feed++ )
619 struct rss_feed_t *p_feed = p_sys->p_feeds+i_feed;
621 if( psz_buffer == NULL ) break;
622 if( psz_buffer[0] == 0 ) psz_buffer++;
623 psz_feed = psz_buffer;
624 psz_buffer = strchr( psz_buffer, '|' );
625 if( psz_buffer != NULL ) psz_buffer[0] = 0;
627 p_feed->psz_title = NULL;
628 p_feed->psz_description = NULL;
629 p_feed->psz_link = NULL;
630 p_feed->psz_image = NULL;
631 p_feed->p_pic = NULL;
633 p_feed->p_items = NULL;
635 msg_Dbg( p_filter, "opening %s RSS/Atom feed ...", psz_feed );
637 p_stream = stream_UrlNew( p_filter, psz_feed );
640 msg_Err( p_filter, "Failed to open %s for reading", psz_feed );
644 p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
647 msg_Err( p_filter, "Failed to open %s for parsing", psz_feed );
652 b_is_item = VLC_FALSE;
653 b_is_image = VLC_FALSE;
655 while( xml_ReaderRead( p_xml_reader ) == 1 )
657 switch( xml_ReaderNodeType( p_xml_reader ) )
663 case XML_READER_STARTELEM:
669 psz_eltname = xml_ReaderName( p_xml_reader );
675 msg_Dbg( p_filter, "element name: %s", psz_eltname );
677 if( !strcmp( psz_eltname, "item" ) /* rss */
678 || !strcmp( psz_eltname, "entry" ) ) /* atom */
680 b_is_item = VLC_TRUE;
682 p_feed->p_items = (struct rss_item_t *)realloc( p_feed->p_items, p_feed->i_items * sizeof( struct rss_item_t ) );
683 p_feed->p_items[p_feed->i_items-1].psz_title = NULL;
684 p_feed->p_items[p_feed->i_items-1].psz_description
686 p_feed->p_items[p_feed->i_items-1].psz_link = NULL;
688 else if( !strcmp( psz_eltname, "image" ) ) /* rss */
690 b_is_image = VLC_TRUE;
692 else if( !strcmp( psz_eltname, "link" ) ) /* atom */
694 char *psz_href = NULL;
695 char *psz_rel = NULL;
696 while( xml_ReaderNextAttr( p_xml_reader )
699 char *psz_name = xml_ReaderName( p_xml_reader );
700 char *psz_value = xml_ReaderValue( p_xml_reader );
701 if( !strcmp( psz_name, "rel" ) )
705 else if( !strcmp( psz_name, "href" ) )
707 psz_href = psz_value;
715 if( psz_rel && psz_href )
717 if( !strcmp( psz_rel, "alternate" )
718 && b_is_item == VLC_FALSE
719 && b_is_image == VLC_FALSE
720 && !p_feed->psz_link )
722 p_feed->psz_link = psz_href;
724 /* this isn't in the rfc but i found some ... */
725 else if( ( !strcmp( psz_rel, "logo" )
726 || !strcmp( psz_rel, "icon" ) )
727 && b_is_item == VLC_FALSE
728 && b_is_image == VLC_FALSE
729 && !p_feed->psz_image )
731 p_feed->psz_image = psz_href;
740 if( psz_href ) free( psz_href );
742 if( psz_rel ) free( psz_rel );
746 case XML_READER_ENDELEM:
752 psz_eltname = xml_ReaderName( p_xml_reader );
758 msg_Dbg( p_filter, "element end : %s", psz_eltname );
760 if( !strcmp( psz_eltname, "item" ) /* rss */
761 || !strcmp( psz_eltname, "entry" ) ) /* atom */
763 b_is_item = VLC_FALSE;
766 else if( !strcmp( psz_eltname, "image" ) ) /* rss */
768 b_is_image = VLC_FALSE;
774 case XML_READER_TEXT:
775 if( !psz_eltname ) break;
776 psz_eltvalue = xml_ReaderValue( p_xml_reader );
784 psz_clean = removeWhiteChars( psz_eltvalue );
785 free( psz_eltvalue ); psz_eltvalue = psz_clean;
788 msg_Dbg( p_filter, " text : <%s>", psz_eltvalue );
790 if( b_is_item == VLC_TRUE )
792 struct rss_item_t *p_item;
793 p_item = p_feed->p_items+i_item;
794 if( !strcmp( psz_eltname, "title" ) /* rss/atom */
795 && !p_item->psz_title )
797 p_item->psz_title = psz_eltvalue;
799 else if( !strcmp( psz_eltname, "link" ) /* rss */
800 && !p_item->psz_link )
802 p_item->psz_link = psz_eltvalue;
804 else if((!strcmp( psz_eltname, "description" ) /* rss */
805 || !strcmp( psz_eltname, "summary" ) ) /* atom */
806 && !p_item->psz_description )
808 p_item->psz_description = psz_eltvalue;
812 free( psz_eltvalue );
816 else if( b_is_image == VLC_TRUE )
818 if( !strcmp( psz_eltname, "url" ) /* rss */
819 && !p_feed->psz_image )
821 p_feed->psz_image = psz_eltvalue;
825 free( psz_eltvalue );
831 if( !strcmp( psz_eltname, "title" ) /* rss/atom */
832 && !p_feed->psz_title )
834 p_feed->psz_title = psz_eltvalue;
836 else if( !strcmp( psz_eltname, "link" ) /* rss */
837 && !p_feed->psz_link )
839 p_feed->psz_link = psz_eltvalue;
841 else if((!strcmp( psz_eltname, "description" ) /* rss */
842 || !strcmp( psz_eltname, "subtitle" ) ) /* atom */
843 && !p_feed->psz_description )
845 p_feed->psz_description = psz_eltvalue;
847 else if( ( !strcmp( psz_eltname, "logo" ) /* atom */
848 || !strcmp( psz_eltname, "icon" ) ) /* atom */
849 && !p_feed->psz_image )
851 p_feed->psz_image = psz_eltvalue;
855 free( psz_eltvalue );
863 if( p_sys->b_images == VLC_TRUE
864 && p_feed->psz_image && !p_feed->p_pic )
866 p_feed->p_pic = LoadImage( p_filter, p_feed->psz_image );
869 if( p_xml_reader && p_xml ) xml_ReaderDelete( p_xml, p_xml_reader );
870 if( p_stream ) stream_Delete( p_stream );
871 msg_Dbg( p_filter, "done with %s RSS/Atom feed", psz_feed );
873 free( psz_buffer_2 );
874 if( p_xml ) xml_Delete( p_xml );
879 /****************************************************************************
881 ***************************************************************************/
882 static void FreeRSS( filter_t *p_filter)
884 filter_sys_t *p_sys = p_filter->p_sys;
886 struct rss_item_t *p_item;
887 struct rss_feed_t *p_feed;
892 for( i_feed = 0; i_feed < p_sys->i_feeds; i_feed++ )
894 p_feed = p_sys->p_feeds+i_feed;
895 for( i_item = 0; i_item < p_feed->i_items; i_item++ )
897 p_item = p_feed->p_items+i_item;
898 free( p_item->psz_title );
899 free( p_item->psz_link );
900 free( p_item->psz_description );
902 free( p_feed->p_items );
903 free( p_feed->psz_title);
904 free( p_feed->psz_link );
905 free( p_feed->psz_description );
906 free( p_feed->psz_image );
907 if( p_feed->p_pic != NULL )
908 p_feed->p_pic->pf_release( p_feed->p_pic );
910 free( p_sys->p_feeds );