]> git.sesse.net Git - vlc/blobdiff - modules/video_filter/rss.c
Add --puzzle-black-slot option to change puzzle type
[vlc] / modules / video_filter / rss.c
index c810c9d47435110c37b82d268910e7c66c9406cb..bf63e0867b2afeea65d57f06b110fa15e25cbcf1 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
+/*****************************************************************************
+ * Atom : http://www.ietf.org/rfc/rfc4287.txt
+ * RSS : http://www.rssboard.org/rss-specification
+ *****************************************************************************/
+
 /*****************************************************************************
  * Preamble
  *****************************************************************************/
@@ -113,44 +118,50 @@ struct filter_sys_t
     int i_cur_char;
 };
 
-#define MSG_TEXT N_("RSS/Atom feed URLs")
-#define MSG_LONGTEXT N_("RSS/Atom feed '|' (pipe) seperated URLs")
-#define SPEED_TEXT N_("RSS/Atom feed speed")
-#define SPEED_LONGTEXT N_("RSS/Atom feed speed (bigger is slower)")
-#define LENGTH_TEXT N_("RSS/Atom feed max number of chars displayed")
-#define LENGTH_LONGTEXT N_("RSS/Atom feed max number of chars displayed")
-#define TTL_TEXT N_("Number of seconds between each forced refresh of the feeds")
-#define TTL_LONGTEXT N_("Number of seconds between each forced refresh of the feeds. If 0, the feeds will never be updated.")
-#define IMAGE_TEXT N_("Display feed images if available")
-#define IMAGE_LONGTEXT N_("Display feed images if available")
-
-#define POSX_TEXT N_("X offset, from left")
-#define POSX_LONGTEXT N_("X offset, from the left screen edge" )
-#define POSY_TEXT N_("Y offset, from the top")
-#define POSY_LONGTEXT N_("Y offset, down from the top" )
+#define MSG_TEXT N_("Feed URLs")
+#define MSG_LONGTEXT N_("RSS/Atom feed '|' (pipe) seperated URLs.")
+#define SPEED_TEXT N_("Speed of feeds")
+#define SPEED_LONGTEXT N_("Speed of the RSS/Atom feeds (bigger is slower).")
+#define LENGTH_TEXT N_("Max length")
+#define LENGTH_LONGTEXT N_("Maximum number of characters displayed on the " \
+                "screen." )
+#define TTL_TEXT N_("Refresh time")
+#define TTL_LONGTEXT N_("Number of seconds between each forced refresh " \
+        "of the feeds. 0 means that the feeds are never updated." )
+#define IMAGE_TEXT N_("Feed images")
+#define IMAGE_LONGTEXT N_("Display feed images if available.")
+
+#define POSX_TEXT N_("X offset")
+#define POSX_LONGTEXT N_("X offset, from the left screen edge." )
+#define POSY_TEXT N_("Y offset")
+#define POSY_LONGTEXT N_("Y offset, down from the top." )
 #define OPACITY_TEXT N_("Opacity")
-#define OPACITY_LONGTEXT N_("The opacity (inverse of transparency) of " \
-    "overlay text. 0 = transparent, 255 = totally opaque. " )
+#define OPACITY_LONGTEXT N_("Opacity (inverse of transparency) of " \
+    "overlay text. 0 = transparent, 255 = totally opaque." )
+
 #define SIZE_TEXT N_("Font size, pixels")
-#define SIZE_LONGTEXT N_("Specify the font size, in pixels, " \
-    "with -1 = use freetype-fontsize" )
+#define SIZE_LONGTEXT N_("Font size, in pixels. Default is -1 (use default " \
+    "font size)." )
 
-#define COLOR_TEXT N_("Text Default Color")
-#define COLOR_LONGTEXT N_("The color of overlay text. 1 byte for each color, hexadecimal. " \
-    "#000000 = all colors off, " \
-    "0xFF0000 = just Red, 0xFFFFFF = all color on [White]" )
+#define COLOR_TEXT N_("Color")
+#define COLOR_LONGTEXT N_("Color of the text that will be rendered on "\
+    "the video. This must be an hexadecimal (like HTML colors). The first two "\
+    "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
+    " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
 
-#define POS_TEXT N_("Marquee position")
+#define POS_TEXT N_("Text position")
 #define POS_LONGTEXT N_( \
-  "You can enforce the marquee position on the video " \
-  "(0=center, 1=left, 2=right, 4=top, 8=bottom, you can " \
-  "also use combinations of these values by adding them).")
+  "You can enforce the text position on the video " \
+  "(0=center, 1=left, 2=right, 4=top, 8=bottom; you can " \
+  "also use combinations of these values, eg 6 = top-right).")
 
 static int pi_pos_values[] = { 0, 1, 2, 4, 8, 5, 6, 9, 10 };
 static char *ppsz_pos_descriptions[] =
      { N_("Center"), N_("Left"), N_("Right"), N_("Top"), N_("Bottom"),
      N_("Top-Left"), N_("Top-Right"), N_("Bottom-Left"), N_("Bottom-Right") };
 
+#define CFG_PREFIX "rrs-"
+
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
@@ -160,36 +171,41 @@ vlc_module_begin();
     set_callbacks( CreateFilter, DestroyFilter );
     set_category( CAT_VIDEO );
     set_subcategory( SUBCAT_VIDEO_SUBPIC );
-    add_string( "rss-urls", "rss", NULL, MSG_TEXT, MSG_LONGTEXT, VLC_FALSE );
+    add_string( CFG_PREFIX "urls", "rss", NULL, MSG_TEXT, MSG_LONGTEXT, VLC_FALSE );
 
     set_section( N_("Position"), NULL );
-    add_integer( "rss-x", -1, NULL, POSX_TEXT, POSX_LONGTEXT, VLC_TRUE );
-    add_integer( "rss-y", 0, NULL, POSY_TEXT, POSY_LONGTEXT, VLC_TRUE );
-    add_integer( "rss-position", 5, NULL, POS_TEXT, POS_LONGTEXT, VLC_FALSE );
+    add_integer( CFG_PREFIX "x", -1, NULL, POSX_TEXT, POSX_LONGTEXT, VLC_TRUE );
+    add_integer( CFG_PREFIX "y", 0, NULL, POSY_TEXT, POSY_LONGTEXT, VLC_TRUE );
+    add_integer( CFG_PREFIX "position", 5, NULL, POS_TEXT, POS_LONGTEXT, VLC_FALSE );
         change_integer_list( pi_pos_values, ppsz_pos_descriptions, 0 );
 
     set_section( N_("Font"), NULL );
     /* 5 sets the default to top [1] left [4] */
-    add_integer_with_range( "rss-opacity", 255, 0, 255, NULL,
+    add_integer_with_range( CFG_PREFIX "opacity", 255, 0, 255, NULL,
         OPACITY_TEXT, OPACITY_LONGTEXT, VLC_FALSE );
-    add_integer( "rss-color", 0xFFFFFF, NULL, COLOR_TEXT, COLOR_LONGTEXT,
+    add_integer( CFG_PREFIX "color", 0xFFFFFF, NULL, COLOR_TEXT, COLOR_LONGTEXT,
                   VLC_FALSE );
         change_integer_list( pi_color_values, ppsz_color_descriptions, 0 );
-    add_integer( "rss-size", -1, NULL, SIZE_TEXT, SIZE_LONGTEXT, VLC_FALSE );
+    add_integer( CFG_PREFIX "size", -1, NULL, SIZE_TEXT, SIZE_LONGTEXT, VLC_FALSE );
 
     set_section( N_("Misc"), NULL );
-    add_integer( "rss-speed", 100000, NULL, SPEED_TEXT, SPEED_LONGTEXT,
+    add_integer( CFG_PREFIX "speed", 100000, NULL, SPEED_TEXT, SPEED_LONGTEXT,
                  VLC_FALSE );
-    add_integer( "rss-length", 60, NULL, LENGTH_TEXT, LENGTH_LONGTEXT,
+    add_integer( CFG_PREFIX "length", 60, NULL, LENGTH_TEXT, LENGTH_LONGTEXT,
                  VLC_FALSE );
-    add_integer( "rss-ttl", 1800, NULL, TTL_TEXT, TTL_LONGTEXT, VLC_FALSE );
-    add_bool( "rss-images", 1, NULL, IMAGE_TEXT, IMAGE_LONGTEXT, VLC_FALSE );
+    add_integer( CFG_PREFIX "ttl", 1800, NULL, TTL_TEXT, TTL_LONGTEXT, VLC_FALSE );
+    add_bool( CFG_PREFIX "images", 1, NULL, IMAGE_TEXT, IMAGE_LONGTEXT, VLC_FALSE );
 
     set_description( _("RSS and Atom feed display") );
     add_shortcut( "rss" );
     add_shortcut( "atom" );
 vlc_module_end();
 
+static const char *ppsz_filter_options[] = {
+    "urls", "x", "y", "position", "color", "size", "speed", "length",
+    "ttl", "images", NULL
+};
+
 /*****************************************************************************
  * CreateFilter: allocates RSS video filter
  *****************************************************************************/
@@ -210,6 +226,9 @@ static int CreateFilter( vlc_object_t *p_this )
     vlc_mutex_init( p_filter, &p_sys->lock );
     vlc_mutex_lock( &p_sys->lock );
 
+    config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
+                       p_filter->p_cfg );
+
     p_sys->psz_urls = var_CreateGetString( p_filter, "rss-urls" );
     p_sys->i_cur_feed = 0;
     p_sys->i_cur_item = 0;
@@ -481,6 +500,8 @@ static subpicture_t *Filter( filter_t *p_filter, mtime_t date )
  * functions
  ***************************************************************************/
 
+#undef LoadImage /* do not conflict with Win32 API */
+
 /****************************************************************************
  * download and resize image located at psz_url
  ***************************************************************************/
@@ -557,7 +578,7 @@ char *removeWhiteChars( char *psz_src )
 }
 
 /****************************************************************************
- * FetchRSS
+ * FetchRSS (or Atom) feeds
  ***************************************************************************/
 static int FetchRSS( filter_t *p_filter)
 {
@@ -615,7 +636,7 @@ static int FetchRSS( filter_t *p_filter)
         p_feed->i_items = 0;
         p_feed->p_items = NULL;
 
-        msg_Dbg( p_filter, "Opening %s RSS feed ...", psz_feed );
+        msg_Dbg( p_filter, "opening %s RSS/Atom feed ...", psz_feed );
 
         p_stream = stream_UrlNew( p_filter, psz_feed );
         if( !p_stream )
@@ -654,12 +675,11 @@ static int FetchRSS( filter_t *p_filter)
                     {
                         return 1;
                     }
-#                   define RSS_DEBUG
 #                   ifdef RSS_DEBUG
-                    msg_Dbg( p_filter, "element name : %s", psz_eltname );
+                    msg_Dbg( p_filter, "element name: %s", psz_eltname );
 #                   endif
-                    if( !strcmp( psz_eltname, "item" )
-                     || !strcmp( psz_eltname, "entry" ) )
+                    if( !strcmp( psz_eltname, "item" ) /* rss */
+                     || !strcmp( psz_eltname, "entry" ) ) /* atom */
                     {
                         b_is_item = VLC_TRUE;
                         p_feed->i_items++;
@@ -669,10 +689,62 @@ static int FetchRSS( filter_t *p_filter)
                                                                      = NULL;
                         p_feed->p_items[p_feed->i_items-1].psz_link = NULL;
                     }
-                    else if( !strcmp( psz_eltname, "image" ) )
+                    else if( !strcmp( psz_eltname, "image" ) ) /* rss */
                     {
                         b_is_image = VLC_TRUE;
                     }
+                    else if( !strcmp( psz_eltname, "link" ) ) /* atom */
+                    {
+                        char *psz_href = NULL;
+                        char *psz_rel = NULL;
+                        while( xml_ReaderNextAttr( p_xml_reader )
+                               == VLC_SUCCESS )
+                        {
+                            char *psz_name = xml_ReaderName( p_xml_reader );
+                            char *psz_value = xml_ReaderValue( p_xml_reader );
+                            if( !strcmp( psz_name, "rel" ) )
+                            {
+                                psz_rel = psz_value;
+                            }
+                            else if( !strcmp( psz_name, "href" ) )
+                            {
+                                psz_href = psz_value;
+                            }
+                            else
+                            {
+                                free( psz_value );
+                            }
+                            free( psz_name );
+                        }
+                        if( psz_rel && psz_href )
+                        {
+                            if( !strcmp( psz_rel, "alternate" )
+                                && b_is_item == VLC_FALSE
+                                && b_is_image == VLC_FALSE
+                                && !p_feed->psz_link )
+                            {
+                                p_feed->psz_link = psz_href;
+                            }
+                            /* this isn't in the rfc but i found some ... */
+                            else if( ( !strcmp( psz_rel, "logo" )
+                                    || !strcmp( psz_rel, "icon" ) )
+                                    && b_is_item == VLC_FALSE
+                                    && b_is_image == VLC_FALSE
+                                    && !p_feed->psz_image )
+                            {
+                                p_feed->psz_image = psz_href;
+                            }
+                            else
+                            {
+                                free( psz_href );
+                            }
+                        }
+                        else
+                        {
+                            if( psz_href ) free( psz_href );
+                        }
+                        if( psz_rel ) free( psz_rel );
+                    }
                     break;
 
                 case XML_READER_ENDELEM:
@@ -689,13 +761,13 @@ static int FetchRSS( filter_t *p_filter)
 #                   ifdef RSS_DEBUG
                     msg_Dbg( p_filter, "element end : %s", psz_eltname );
 #                   endif
-                    if( !strcmp( psz_eltname, "item" )
-                     || !strcmp( psz_eltname, "entry" ) )
+                    if( !strcmp( psz_eltname, "item" ) /* rss */
+                     || !strcmp( psz_eltname, "entry" ) ) /* atom */
                     {
                         b_is_item = VLC_FALSE;
                         i_item++;
                     }
-                    else if( !strcmp( psz_eltname, "image" ) )
+                    else if( !strcmp( psz_eltname, "image" ) ) /* rss */
                     {
                         b_is_image = VLC_FALSE;
                     }
@@ -723,15 +795,19 @@ static int FetchRSS( filter_t *p_filter)
                     {
                         struct rss_item_t *p_item;
                         p_item = p_feed->p_items+i_item;
-                        if( !strcmp( psz_eltname, "title" ) )
+                        if( !strcmp( psz_eltname, "title" ) /* rss/atom */
+                            && !p_item->psz_title )
                         {
                             p_item->psz_title = psz_eltvalue;
                         }
-                        else if( !strcmp( psz_eltname, "link" ) )
+                        else if( !strcmp( psz_eltname, "link" ) /* rss */
+                                 && !p_item->psz_link )
                         {
                             p_item->psz_link = psz_eltvalue;
                         }
-                        else if( !strcmp( psz_eltname, "description" ) )
+                        else if((!strcmp( psz_eltname, "description" ) /* rss */
+                              || !strcmp( psz_eltname, "summary" ) ) /* atom */
+                              && !p_item->psz_description )
                         {
                             p_item->psz_description = psz_eltvalue;
                         }
@@ -743,12 +819,10 @@ static int FetchRSS( filter_t *p_filter)
                     }
                     else if( b_is_image == VLC_TRUE )
                     {
-                        if( !strcmp( psz_eltname, "url" ) )
+                        if( !strcmp( psz_eltname, "url" ) /* rss */
+                            && !p_feed->psz_image )
                         {
                             p_feed->psz_image = psz_eltvalue;
-                            if( p_sys->b_images == VLC_TRUE )
-                                p_feed->p_pic = LoadImage( p_filter,
-                                                           p_feed->psz_image );
                         }
                         else
                         {
@@ -758,19 +832,28 @@ static int FetchRSS( filter_t *p_filter)
                     }
                     else
                     {
-                        if( !strcmp( psz_eltname, "title" ) )
+                        if( !strcmp( psz_eltname, "title" ) /* rss/atom */
+                            && !p_feed->psz_title )
                         {
                             p_feed->psz_title = psz_eltvalue;
                         }
-                        else if( !strcmp( psz_eltname, "link" ) )
+                        else if( !strcmp( psz_eltname, "link" ) /* rss */
+                                 && !p_feed->psz_link )
                         {
                             p_feed->psz_link = psz_eltvalue;
                         }
-                        else if( !strcmp( psz_eltname, "description" )
-                              || !strcmp( psz_eltname, "subtitle" ) )
+                        else if((!strcmp( psz_eltname, "description" ) /* rss */
+                              || !strcmp( psz_eltname, "subtitle" ) ) /* atom */
+                              && !p_feed->psz_description )
                         {
                             p_feed->psz_description = psz_eltvalue;
                         }
+                        else if( ( !strcmp( psz_eltname, "logo" ) /* atom */
+                              || !strcmp( psz_eltname, "icon" ) ) /* atom */
+                              && !p_feed->psz_image )
+                        {
+                            p_feed->psz_image = psz_eltvalue;
+                        }
                         else
                         {
                             free( psz_eltvalue );
@@ -781,9 +864,15 @@ static int FetchRSS( filter_t *p_filter)
             }
         }
 
+        if( p_sys->b_images == VLC_TRUE
+            && p_feed->psz_image && !p_feed->p_pic )
+        {
+            p_feed->p_pic = LoadImage( p_filter, p_feed->psz_image );
+        }
+
         if( p_xml_reader && p_xml ) xml_ReaderDelete( p_xml, p_xml_reader );
         if( p_stream ) stream_Delete( p_stream );
-        msg_Dbg( p_filter, "Done with %s RSS feed.", psz_feed );
+        msg_Dbg( p_filter, "done with %s RSS/Atom feed", psz_feed );
     }
     free( psz_buffer_2 );
     if( p_xml ) xml_Delete( p_xml );