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 /*****************************************************************************
165 *****************************************************************************/
167 set_capability( "sub filter", 0 );
168 set_shortname( "RSS / Atom" );
169 set_callbacks( CreateFilter, DestroyFilter );
170 set_category( CAT_VIDEO );
171 set_subcategory( SUBCAT_VIDEO_SUBPIC );
172 add_string( "rss-urls", "rss", NULL, MSG_TEXT, MSG_LONGTEXT, VLC_FALSE );
174 set_section( N_("Position"), NULL );
175 add_integer( "rss-x", -1, NULL, POSX_TEXT, POSX_LONGTEXT, VLC_TRUE );
176 add_integer( "rss-y", 0, NULL, POSY_TEXT, POSY_LONGTEXT, VLC_TRUE );
177 add_integer( "rss-position", 5, NULL, POS_TEXT, POS_LONGTEXT, VLC_FALSE );
178 change_integer_list( pi_pos_values, ppsz_pos_descriptions, 0 );
180 set_section( N_("Font"), NULL );
181 /* 5 sets the default to top [1] left [4] */
182 add_integer_with_range( "rss-opacity", 255, 0, 255, NULL,
183 OPACITY_TEXT, OPACITY_LONGTEXT, VLC_FALSE );
184 add_integer( "rss-color", 0xFFFFFF, NULL, COLOR_TEXT, COLOR_LONGTEXT,
186 change_integer_list( pi_color_values, ppsz_color_descriptions, 0 );
187 add_integer( "rss-size", -1, NULL, SIZE_TEXT, SIZE_LONGTEXT, VLC_FALSE );
189 set_section( N_("Misc"), NULL );
190 add_integer( "rss-speed", 100000, NULL, SPEED_TEXT, SPEED_LONGTEXT,
192 add_integer( "rss-length", 60, NULL, LENGTH_TEXT, LENGTH_LONGTEXT,
194 add_integer( "rss-ttl", 1800, NULL, TTL_TEXT, TTL_LONGTEXT, VLC_FALSE );
195 add_bool( "rss-images", 1, NULL, IMAGE_TEXT, IMAGE_LONGTEXT, VLC_FALSE );
197 set_description( _("RSS and Atom feed display") );
198 add_shortcut( "rss" );
199 add_shortcut( "atom" );
202 /*****************************************************************************
203 * CreateFilter: allocates RSS video filter
204 *****************************************************************************/
205 static int CreateFilter( vlc_object_t *p_this )
207 filter_t *p_filter = (filter_t *)p_this;
211 /* Allocate structure */
212 p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
215 msg_Err( p_filter, "out of memory" );
219 vlc_mutex_init( p_filter, &p_sys->lock );
220 vlc_mutex_lock( &p_sys->lock );
222 p_sys->psz_urls = var_CreateGetString( p_filter, "rss-urls" );
223 p_sys->i_cur_feed = 0;
224 p_sys->i_cur_item = 0;
225 p_sys->i_cur_char = 0;
227 p_sys->p_feeds = NULL;
228 p_sys->i_speed = var_CreateGetInteger( p_filter, "rss-speed" );
229 p_sys->i_length = var_CreateGetInteger( p_filter, "rss-length" );
230 p_sys->i_ttl = __MAX( 0, var_CreateGetInteger( p_filter, "rss-ttl" ) );
231 p_sys->b_images = var_CreateGetBool( p_filter, "rss-images" );
232 p_sys->psz_marquee = (char *)malloc( p_sys->i_length );
234 p_sys->p_style = malloc( sizeof( text_style_t ));
235 memcpy( p_sys->p_style, &default_text_style, sizeof( text_style_t ));
237 p_sys->i_xoff = var_CreateGetInteger( p_filter, "rss-x" );
238 p_sys->i_yoff = var_CreateGetInteger( p_filter, "rss-y" );
239 p_sys->i_pos = var_CreateGetInteger( p_filter, "rss-position" );
240 p_sys->p_style->i_font_alpha = 255 - var_CreateGetInteger( p_filter, "rss-opacity" );
241 p_sys->p_style->i_font_color = var_CreateGetInteger( p_filter, "rss-color" );
242 p_sys->p_style->i_font_size = var_CreateGetInteger( p_filter, "rss-size" );
244 if( p_sys->b_images == VLC_TRUE && p_sys->p_style->i_font_size == -1 )
246 msg_Warn( p_filter, "rrs-size wasn't specified. Feed images will thus be displayed without being resized" );
249 if( FetchRSS( p_filter ) )
251 msg_Err( p_filter, "failed while fetching RSS ... too bad" );
252 vlc_mutex_unlock( &p_sys->lock );
255 p_sys->t_last_update = time( NULL );
257 if( p_sys->i_feeds == 0 )
259 vlc_mutex_unlock( &p_sys->lock );
262 for( i_feed=0; i_feed < p_sys->i_feeds; i_feed ++ )
263 if( p_sys->p_feeds[i_feed].i_items == 0 )
265 vlc_mutex_unlock( &p_sys->lock );
270 p_filter->pf_sub_filter = Filter;
271 p_sys->last_date = (mtime_t)0;
273 vlc_mutex_unlock( &p_sys->lock );
277 /*****************************************************************************
278 * DestroyFilter: destroy RSS video filter
279 *****************************************************************************/
280 static void DestroyFilter( vlc_object_t *p_this )
282 filter_t *p_filter = (filter_t *)p_this;
283 filter_sys_t *p_sys = p_filter->p_sys;
285 vlc_mutex_lock( &p_sys->lock );
287 if( p_sys->p_style ) free( p_sys->p_style );
288 if( p_sys->psz_marquee ) free( p_sys->psz_marquee );
289 free( p_sys->psz_urls );
291 vlc_mutex_unlock( &p_sys->lock );
292 vlc_mutex_destroy( &p_sys->lock );
295 /* Delete the RSS variables */
296 var_Destroy( p_filter, "rss-urls" );
297 var_Destroy( p_filter, "rss-speed" );
298 var_Destroy( p_filter, "rss-length" );
299 var_Destroy( p_filter, "rss-ttl" );
300 var_Destroy( p_filter, "rss-images" );
301 var_Destroy( p_filter, "rss-x" );
302 var_Destroy( p_filter, "rss-y" );
303 var_Destroy( p_filter, "rss-position" );
304 var_Destroy( p_filter, "rss-color");
305 var_Destroy( p_filter, "rss-opacity");
306 var_Destroy( p_filter, "rss-size");
309 /****************************************************************************
310 * Filter: the whole thing
311 ****************************************************************************
312 * This function outputs subpictures at regular time intervals.
313 ****************************************************************************/
314 static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
316 filter_sys_t *p_sys = p_filter->p_sys;
318 video_format_t fmt = {0};
320 subpicture_region_t *p_region;
324 struct rss_feed_t *p_feed;
326 vlc_mutex_lock( &p_sys->lock );
329 + ( p_sys->i_cur_char == 0 && p_sys->i_cur_item == 0 ? 5 : 1 )
330 /* ( ... ? 5 : 1 ) means "wait more for the 1st char" */
331 * p_sys->i_speed > date )
333 vlc_mutex_unlock( &p_sys->lock );
337 /* Do we need to update the feeds ? */
339 && time( NULL ) > p_sys->t_last_update + (time_t)p_sys->i_ttl )
341 msg_Dbg( p_filter, "Forcing update of all the RSS feeds" );
342 if( FetchRSS( p_filter ) )
344 msg_Err( p_filter, "failed while fetching RSS ... too bad" );
345 vlc_mutex_unlock( &p_sys->lock );
346 return NULL; /* FIXME : we most likely messed up all the data,
347 * so we might need to do something about it */
349 p_sys->t_last_update = time( NULL );
352 p_sys->last_date = date;
354 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 )
356 p_sys->i_cur_char = 0;
358 if( p_sys->i_cur_item >= p_sys->p_feeds[p_sys->i_cur_feed].i_items )
360 p_sys->i_cur_item = 0;
361 p_sys->i_cur_feed = (p_sys->i_cur_feed + 1)%p_sys->i_feeds;
365 p_spu = p_filter->pf_sub_buffer_new( p_filter );
368 vlc_mutex_unlock( &p_sys->lock );
372 fmt.i_chroma = VLC_FOURCC('T','E','X','T');
374 p_spu->p_region = p_spu->pf_create_region( VLC_OBJECT(p_filter), &fmt );
375 if( !p_spu->p_region )
377 p_filter->pf_sub_buffer_del( p_filter, p_spu );
378 vlc_mutex_unlock( &p_sys->lock );
382 /* Generate the string that will be displayed. This string is supposed to
383 be p_sys->i_length characters long. */
384 i_item = p_sys->i_cur_item;
385 i_feed = p_sys->i_cur_feed;
386 p_feed = &p_sys->p_feeds[p_sys->i_cur_feed];
390 /* Don't display the feed's title if we have an image */
391 snprintf( p_sys->psz_marquee, p_sys->i_length, "%s",
392 p_sys->p_feeds[i_feed].p_items[i_item].psz_title
393 +p_sys->i_cur_char );
397 snprintf( p_sys->psz_marquee, p_sys->i_length, "%s : %s",
398 p_sys->p_feeds[i_feed].psz_title,
399 p_sys->p_feeds[i_feed].p_items[i_item].psz_title
400 +p_sys->i_cur_char );
403 while( strlen( p_sys->psz_marquee ) < (unsigned int)p_sys->i_length )
406 if( i_item == p_sys->p_feeds[i_feed].i_items ) break;
407 snprintf( strchr( p_sys->psz_marquee, 0 ),
408 p_sys->i_length - strlen( p_sys->psz_marquee ),
410 p_sys->p_feeds[i_feed].p_items[i_item].psz_title );
413 /* Calls to snprintf might split multibyte UTF8 chars ...
414 * which freetype doesn't like. */
416 char *a = strdup( p_sys->psz_marquee );
418 char *b = p_sys->psz_marquee;
419 EnsureUTF8( p_sys->psz_marquee );
420 /* we want to use ' ' instead of '?' for erroneous chars */
423 if( *b != *a ) *b = ' ';
429 p_spu->p_region->psz_text = strdup(p_sys->psz_marquee);
430 p_spu->i_start = date;
432 p_spu->b_ephemer = VLC_TRUE;
434 /* where to locate the string: */
435 if( p_sys->i_xoff < 0 || p_sys->i_yoff < 0 )
436 { /* set to one of the 9 relative locations */
437 p_spu->i_flags = p_sys->i_pos;
440 p_spu->b_absolute = VLC_FALSE;
443 { /* set to an absolute xy, referenced to upper left corner */
444 p_spu->i_flags = OSD_ALIGN_LEFT | OSD_ALIGN_TOP;
445 p_spu->i_x = p_sys->i_xoff;
446 p_spu->i_y = p_sys->i_yoff;
447 p_spu->b_absolute = VLC_TRUE;
451 p_spu->p_region->p_style = p_sys->p_style;
455 /* Display the feed's image */
456 picture_t *p_pic = p_feed->p_pic;
457 video_format_t fmt_out = {0};
459 fmt_out.i_chroma = VLC_FOURCC('Y','U','V','A');
460 fmt_out.i_aspect = VOUT_ASPECT_FACTOR;
461 fmt_out.i_sar_num = fmt_out.i_sar_den = 1;
463 fmt_out.i_visible_width = p_pic->p[Y_PLANE].i_visible_pitch;
465 fmt_out.i_visible_height = p_pic->p[Y_PLANE].i_visible_lines;
467 p_region = p_spu->pf_create_region( VLC_OBJECT( p_filter ), &fmt_out );
470 msg_Err( p_filter, "cannot allocate SPU region" );
474 vout_CopyPicture( p_filter, &p_region->picture, p_pic );
475 p_spu->p_region->p_next = p_region;
478 /* Offset text to display right next to the image */
479 p_spu->p_region->i_x = p_pic->p[Y_PLANE].i_visible_pitch;
482 vlc_mutex_unlock( &p_sys->lock );
486 /****************************************************************************
487 * RSS related functions
488 ****************************************************************************
489 * You should always lock the p_filter mutex before using any of these
491 ***************************************************************************/
493 #undef LoadImage /* do not conflict with Win32 API */
495 /****************************************************************************
496 * download and resize image located at psz_url
497 ***************************************************************************/
498 picture_t *LoadImage( filter_t *p_filter, const char *psz_url )
500 filter_sys_t *p_sys = p_filter->p_sys;
502 video_format_t fmt_in={0}, fmt_out={0};
503 picture_t *p_orig, *p_pic=NULL;
504 image_handler_t *p_handler = image_HandlerCreate( p_filter );
508 psz_local = ToLocale( psz_url );
509 fmt_out.i_chroma = VLC_FOURCC('Y','U','V','A');
510 p_orig = image_ReadUrl( p_handler, psz_local, &fmt_in, &fmt_out );
511 LocaleFree( psz_local );
515 msg_Warn( p_filter, "Unable to read image %s", psz_url );
517 else if( p_sys->p_style->i_font_size > 0 )
520 fmt_in.i_chroma = VLC_FOURCC('Y','U','V','A');
521 fmt_in.i_height = p_orig->p[Y_PLANE].i_visible_lines;
522 fmt_in.i_width = p_orig->p[Y_PLANE].i_visible_pitch;
523 fmt_out.i_width = p_orig->p[Y_PLANE].i_visible_pitch
524 *p_sys->p_style->i_font_size/p_orig->p[Y_PLANE].i_visible_lines;
525 fmt_out.i_height = p_sys->p_style->i_font_size;
527 p_pic = image_Convert( p_handler, p_orig, &fmt_in, &fmt_out );
528 p_orig->pf_release( p_orig );
531 msg_Warn( p_filter, "Error while converting %s", psz_url );
539 image_HandlerDelete( p_handler );
544 /****************************************************************************
545 * remove all ' ' '\t' '\n' '\r' characters from the begining and end of the
547 ***************************************************************************/
548 char *removeWhiteChars( char *psz_src )
550 char *psz_src2 = strdup( psz_src );
551 char *psz_clean = strdup( psz_src2 );
554 while( ( *psz_clean == ' ' || *psz_clean == '\t'
555 || *psz_clean == '\n' || *psz_clean == '\r' )
556 && *psz_clean != '\0' )
560 i = strlen( psz_clean );
562 ( psz_clean[i] == ' ' || psz_clean[i] == '\t'
563 || psz_clean[i] == '\n' || psz_clean[i] == '\r' ) );
564 psz_clean[i+1] = '\0';
565 psz_clean2 = strdup( psz_clean );
570 /****************************************************************************
571 * FetchRSS (or Atom) feeds
572 ***************************************************************************/
573 static int FetchRSS( filter_t *p_filter)
575 filter_sys_t *p_sys = p_filter->p_sys;
577 stream_t *p_stream = NULL;
579 xml_reader_t *p_xml_reader = NULL;
581 char *psz_eltname = NULL;
582 char *psz_eltvalue = NULL;
583 char *psz_feed = NULL;
584 char *psz_buffer = NULL;
585 char *psz_buffer_2 = NULL;
589 vlc_bool_t b_is_item;
590 vlc_bool_t b_is_image;
596 while( p_sys->psz_urls[i_int] != 0 )
597 if( p_sys->psz_urls[i_int++] == '|' )
599 p_sys->p_feeds = (struct rss_feed_t *)malloc( p_sys->i_feeds
600 * sizeof( struct rss_feed_t ) );
602 p_xml = xml_Create( p_filter );
605 msg_Err( p_filter, "Failed to open XML parser" );
609 psz_buffer = strdup( p_sys->psz_urls );
610 psz_buffer_2 = psz_buffer; /* keep track so we can free it */
611 for( i_feed = 0; i_feed < p_sys->i_feeds; i_feed++ )
613 struct rss_feed_t *p_feed = p_sys->p_feeds+i_feed;
615 if( psz_buffer == NULL ) break;
616 if( psz_buffer[0] == 0 ) psz_buffer++;
617 psz_feed = psz_buffer;
618 psz_buffer = strchr( psz_buffer, '|' );
619 if( psz_buffer != NULL ) psz_buffer[0] = 0;
621 p_feed->psz_title = NULL;
622 p_feed->psz_description = NULL;
623 p_feed->psz_link = NULL;
624 p_feed->psz_image = NULL;
625 p_feed->p_pic = NULL;
627 p_feed->p_items = NULL;
629 msg_Dbg( p_filter, "opening %s RSS/Atom feed ...", psz_feed );
631 p_stream = stream_UrlNew( p_filter, psz_feed );
634 msg_Err( p_filter, "Failed to open %s for reading", psz_feed );
638 p_xml_reader = xml_ReaderCreate( p_xml, p_stream );
641 msg_Err( p_filter, "Failed to open %s for parsing", psz_feed );
646 b_is_item = VLC_FALSE;
647 b_is_image = VLC_FALSE;
649 while( xml_ReaderRead( p_xml_reader ) == 1 )
651 switch( xml_ReaderNodeType( p_xml_reader ) )
657 case XML_READER_STARTELEM:
663 psz_eltname = xml_ReaderName( p_xml_reader );
669 msg_Dbg( p_filter, "element name: %s", psz_eltname );
671 if( !strcmp( psz_eltname, "item" ) /* rss */
672 || !strcmp( psz_eltname, "entry" ) ) /* atom */
674 b_is_item = VLC_TRUE;
676 p_feed->p_items = (struct rss_item_t *)realloc( p_feed->p_items, p_feed->i_items * sizeof( struct rss_item_t ) );
677 p_feed->p_items[p_feed->i_items-1].psz_title = NULL;
678 p_feed->p_items[p_feed->i_items-1].psz_description
680 p_feed->p_items[p_feed->i_items-1].psz_link = NULL;
682 else if( !strcmp( psz_eltname, "image" ) ) /* rss */
684 b_is_image = VLC_TRUE;
686 else if( !strcmp( psz_eltname, "link" ) ) /* atom */
688 char *psz_href = NULL;
689 char *psz_rel = NULL;
690 while( xml_ReaderNextAttr( p_xml_reader )
693 char *psz_name = xml_ReaderName( p_xml_reader );
694 char *psz_value = xml_ReaderValue( p_xml_reader );
695 if( !strcmp( psz_name, "rel" ) )
699 else if( !strcmp( psz_name, "href" ) )
701 psz_href = psz_value;
709 if( psz_rel && psz_href )
711 if( !strcmp( psz_rel, "alternate" )
712 && b_is_item == VLC_FALSE
713 && b_is_image == VLC_FALSE
714 && !p_feed->psz_link )
716 p_feed->psz_link = psz_href;
718 /* this isn't in the rfc but i found some ... */
719 else if( ( !strcmp( psz_rel, "logo" )
720 || !strcmp( psz_rel, "icon" ) )
721 && b_is_item == VLC_FALSE
722 && b_is_image == VLC_FALSE
723 && !p_feed->psz_image )
725 p_feed->psz_image = psz_href;
734 if( psz_href ) free( psz_href );
736 if( psz_rel ) free( psz_rel );
740 case XML_READER_ENDELEM:
746 psz_eltname = xml_ReaderName( p_xml_reader );
752 msg_Dbg( p_filter, "element end : %s", psz_eltname );
754 if( !strcmp( psz_eltname, "item" ) /* rss */
755 || !strcmp( psz_eltname, "entry" ) ) /* atom */
757 b_is_item = VLC_FALSE;
760 else if( !strcmp( psz_eltname, "image" ) ) /* rss */
762 b_is_image = VLC_FALSE;
768 case XML_READER_TEXT:
769 if( !psz_eltname ) break;
770 psz_eltvalue = xml_ReaderValue( p_xml_reader );
778 psz_clean = removeWhiteChars( psz_eltvalue );
779 free( psz_eltvalue ); psz_eltvalue = psz_clean;
782 msg_Dbg( p_filter, " text : <%s>", psz_eltvalue );
784 if( b_is_item == VLC_TRUE )
786 struct rss_item_t *p_item;
787 p_item = p_feed->p_items+i_item;
788 if( !strcmp( psz_eltname, "title" ) /* rss/atom */
789 && !p_item->psz_title )
791 p_item->psz_title = psz_eltvalue;
793 else if( !strcmp( psz_eltname, "link" ) /* rss */
794 && !p_item->psz_link )
796 p_item->psz_link = psz_eltvalue;
798 else if((!strcmp( psz_eltname, "description" ) /* rss */
799 || !strcmp( psz_eltname, "summary" ) ) /* atom */
800 && !p_item->psz_description )
802 p_item->psz_description = psz_eltvalue;
806 free( psz_eltvalue );
810 else if( b_is_image == VLC_TRUE )
812 if( !strcmp( psz_eltname, "url" ) /* rss */
813 && !p_feed->psz_image )
815 p_feed->psz_image = psz_eltvalue;
819 free( psz_eltvalue );
825 if( !strcmp( psz_eltname, "title" ) /* rss/atom */
826 && !p_feed->psz_title )
828 p_feed->psz_title = psz_eltvalue;
830 else if( !strcmp( psz_eltname, "link" ) /* rss */
831 && !p_feed->psz_link )
833 p_feed->psz_link = psz_eltvalue;
835 else if((!strcmp( psz_eltname, "description" ) /* rss */
836 || !strcmp( psz_eltname, "subtitle" ) ) /* atom */
837 && !p_feed->psz_description )
839 p_feed->psz_description = psz_eltvalue;
841 else if( ( !strcmp( psz_eltname, "logo" ) /* atom */
842 || !strcmp( psz_eltname, "icon" ) ) /* atom */
843 && !p_feed->psz_image )
845 p_feed->psz_image = psz_eltvalue;
849 free( psz_eltvalue );
857 if( p_sys->b_images == VLC_TRUE
858 && p_feed->psz_image && !p_feed->p_pic )
860 p_feed->p_pic = LoadImage( p_filter, p_feed->psz_image );
863 if( p_xml_reader && p_xml ) xml_ReaderDelete( p_xml, p_xml_reader );
864 if( p_stream ) stream_Delete( p_stream );
865 msg_Dbg( p_filter, "done with %s RSS/Atom feed", psz_feed );
867 free( psz_buffer_2 );
868 if( p_xml ) xml_Delete( p_xml );
873 /****************************************************************************
875 ***************************************************************************/
876 static void FreeRSS( filter_t *p_filter)
878 filter_sys_t *p_sys = p_filter->p_sys;
880 struct rss_item_t *p_item;
881 struct rss_feed_t *p_feed;
886 for( i_feed = 0; i_feed < p_sys->i_feeds; i_feed++ )
888 p_feed = p_sys->p_feeds+i_feed;
889 for( i_item = 0; i_item < p_feed->i_items; i_item++ )
891 p_item = p_feed->p_items+i_item;
892 free( p_item->psz_title );
893 free( p_item->psz_link );
894 free( p_item->psz_description );
896 free( p_feed->p_items );
897 free( p_feed->psz_title);
898 free( p_feed->psz_link );
899 free( p_feed->psz_description );
900 free( p_feed->psz_image );
901 if( p_feed->p_pic != NULL )
902 p_feed->p_pic->pf_release( p_feed->p_pic );
904 free( p_sys->p_feeds );