rpms/rhythmbox/devel rb-use-newer-plparser-9.patch, NONE, 1.1 rhythmbox.spec, 1.152, 1.153 rb-use-newer-plparser-7.patch, 1.2, NONE
Bastien Nocera (hadess)
fedora-extras-commits at redhat.com
Fri Nov 30 18:18:14 UTC 2007
Author: hadess
Update of /cvs/pkgs/rpms/rhythmbox/devel
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv1000
Modified Files:
rhythmbox.spec
Added Files:
rb-use-newer-plparser-9.patch
Removed Files:
rb-use-newer-plparser-7.patch
Log Message:
* Fri Nov 30 2007 - Bastien Nocera <bnocera at redhat.com> - 0.11.3-8
- Update patch for the Podcast parsing to include the browser plugin
for the iTunes detection
rb-use-newer-plparser-9.patch:
--- NEW FILE rb-use-newer-plparser-9.patch ---
Index: podcast/test-podcast-parse.c
===================================================================
--- podcast/test-podcast-parse.c (revision 5467)
+++ podcast/test-podcast-parse.c (working copy)
@@ -1,6 +1,7 @@
#include "config.h"
+#include <locale.h>
#include <glib.h>
#include <glib/gi18n.h>
@@ -47,6 +48,7 @@
GDate date = {0,};
char datebuf[1024];
+ setlocale (LC_ALL, "");
bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
@@ -66,7 +68,6 @@
g_date_strftime (datebuf, 1024, "%F %T", &date);
g_print ("Podcast title: %s\n", data->title);
- g_print ("Summary: %s\n", data->summary);
g_print ("Description: %s\n", data->description);
g_print ("Author: %s\n", data->author);
g_print ("Date: %s\n", datebuf);
Index: podcast/plugin.symbols
===================================================================
--- podcast/plugin.symbols (revision 0)
+++ podcast/plugin.symbols (revision 0)
@@ -0,0 +1,4 @@
+NP_GetMIMEDescription
+NP_GetValue
+NP_Initialize
+NP_Shutdown
Index: podcast/rb-podcast-manager.c
===================================================================
--- podcast/rb-podcast-manager.c (revision 5467)
+++ podcast/rb-podcast-manager.c (working copy)
@@ -833,7 +833,7 @@
RBPodcastThreadInfo *info;
gchar *valid_url;
- if (g_str_has_prefix (url, "feed://")) {
+ if (g_str_has_prefix (url, "feed://") || g_str_has_prefix (url, "itpc://")) {
char *tmp;
tmp = g_strdup_printf ("http://%s", url + strlen ("feed://"));
@@ -915,7 +915,7 @@
{
RBPodcastChannel *feed = g_new0 (RBPodcastChannel, 1);
- if (rb_podcast_parse_load_feed (feed, info->url)) {
+ if (rb_podcast_parse_load_feed (feed, info->url) && (feed->is_opml == FALSE)) {
RBPodcastManagerParseResult *result;
result = g_new0 (RBPodcastManagerParseResult, 1);
@@ -927,6 +927,16 @@
(GSourceFunc) rb_podcast_manager_parse_complete_cb,
result,
(GDestroyNotify) rb_podcast_manager_free_parse_result);
+ } else if (feed->is_opml) {
+ GList *l;
+
+ rb_debug ("Loading OPML feeds from %s", info->url);
+
+ for (l = feed->posts; l != NULL; l = l->next) {
+ RBPodcastItem *item = l->data;
+ rb_podcast_manager_subscribe_feed (info->pd, item->url);
+ }
+ rb_podcast_parse_channel_free (feed);
}
g_object_unref (info->pd);
@@ -1568,8 +1578,6 @@
{
GValue description_val = { 0, };
GValue title_val = { 0, };
- GValue subtitle_val = { 0, };
- GValue summary_val = { 0, };
GValue lang_val = { 0, };
GValue copyright_val = { 0, };
GValue image_val = { 0, };
@@ -1587,7 +1595,7 @@
GList *lst_songs;
- if (data->title == NULL) {
+ if (data->title == NULL) {
g_list_free (data->posts);
g_free (data);
return;
@@ -1640,13 +1648,6 @@
rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_ARTIST, &author_val);
g_value_unset (&author_val);
- if (data->subtitle) {
- g_value_init (&subtitle_val, G_TYPE_STRING);
- g_value_set_string (&subtitle_val, (gchar *) data->subtitle);
- rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_SUBTITLE, &subtitle_val);
- g_value_unset (&subtitle_val);
- }
-
if (data->description) {
g_value_init (&description_val, G_TYPE_STRING);
g_value_set_string (&description_val, (gchar *) data->description);
@@ -1654,13 +1655,6 @@
g_value_unset (&description_val);
}
- if (data->summary) {
- g_value_init (&summary_val, G_TYPE_STRING);
- g_value_set_string (&summary_val, (gchar *) data->summary);
- rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_SUMMARY, &summary_val);
- g_value_unset (&summary_val);
- }
-
if (data->lang) {
g_value_init (&lang_val, G_TYPE_STRING);
g_value_set_string (&lang_val, (gchar *) data->lang);
Index: podcast/rb-podcast-parse.c
===================================================================
--- podcast/rb-podcast-parse.c (revision 5467)
+++ podcast/rb-podcast-parse.c (working copy)
@@ -22,427 +22,116 @@
#include "config.h"
-#define _XOPEN_SOURCE
-#define __EXTENSIONS__ /* get strptime */
#include <string.h>
-#include <time.h>
-#include <libxml/entities.h>
-#include <libxml/SAX.h>
-#include <libxml/parserInternals.h>
+#include <totem-pl-parser.h>
#include <libgnomevfs/gnome-vfs.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "rb-debug.h"
#include "rb-podcast-parse.h"
+#include "rb-file-helpers.h"
-#define BUFFER_SIZE 256
-
-struct RBPoadcastLoadContext
-{
- guint in_unknown_elt;
- xmlParserCtxtPtr xmlctx;
- GString *prop_value;
- RBPodcastChannel *channel_data;
- RBPodcastItem *item_data;
-
- enum {
- RB_PODCAST_PARSER_STATE_START,
- RB_PODCAST_PARSER_STATE_RSS,
- RB_PODCAST_PARSER_STATE_CHANNEL,
- RB_PODCAST_PARSER_STATE_CHANNEL_PROPERTY,
- RB_PODCAST_PARSER_STATE_IMG,
- RB_PODCAST_PARSER_STATE_IMG_PROPERTY,
- RB_PODCAST_PARSER_STATE_ITEM,
- RB_PODCAST_PARSER_STATE_ITEM_PROPERTY,
- RB_PODCAST_PARSER_STATE_END,
- } state;
-};
-
-static gboolean rb_validate_channel_propert (const char *name);
-static gboolean rb_validate_item_propert (const char *name);
-static uintmax_t rb_podcast_parse_date (const char* date_str);
-static gulong rb_podcast_parse_time (const char *time_str);
-static void rb_podcast_parser_start_element (struct RBPoadcastLoadContext* ctx, const char *name, const char **attrs);
-static void rb_podcast_parser_end_element (struct RBPoadcastLoadContext* ctx, const char *name);
-static void rb_podcast_parser_characters (struct RBPoadcastLoadContext* ctx, const char *data, guint len);
-static void rb_set_channel_value (struct RBPoadcastLoadContext* ctx, const char* name, const char* value);
-static void rb_set_item_value (struct RBPoadcastLoadContext* ctx, const char* name, const char* value);
-
-static RBPodcastItem *
-rb_podcast_initializa_item ()
-{
- RBPodcastItem *data = g_new0 (RBPodcastItem, 1);
- return data;
-}
-
static void
-rb_set_channel_value (struct RBPoadcastLoadContext *ctx,
- const char *name,
- const char *value)
+playlist_metadata_foreach (const char *key,
+ const char *value,
+ gpointer data)
{
- xmlChar *dvalue;
+ RBPodcastChannel *channel = (RBPodcastChannel *) data;
- if (value == NULL)
- return;
-
- if (name == NULL)
- return;
-
- dvalue = xmlCharStrdup (value);
- g_strstrip ((char *)dvalue);
-
- if (!strcmp (name, "title")) {
- ctx->channel_data->title = dvalue;
- } else if (!strcmp (name, "language")) {
- ctx->channel_data->lang = dvalue;
- } else if (!strcmp (name, "itunes:subtitle")) {
- ctx->channel_data->subtitle = dvalue;
- } else if (!strcmp (name, "itunes:summary")) {
- ctx->channel_data->summary = dvalue;
- } else if (!strcmp (name, "description")) {
- ctx->channel_data->description = dvalue;
- } else if (!strcmp (name, "generator")) {
- if (ctx->channel_data->author == NULL)
- ctx->channel_data->author = dvalue;
- } else if (!strcmp (name, "itunes:author")) {
- g_free (ctx->channel_data->author);
- ctx->channel_data->author = dvalue;
- } else if (!strcmp (name, "webMaster")) {
- ctx->channel_data->contact = dvalue;
- } else if (!strcmp (name, "pubDate")) {
- ctx->channel_data->pub_date = rb_podcast_parse_date ((char *)dvalue);
- g_free (dvalue);
- } else if (!strcmp (name, "copyright")) {
- ctx->channel_data->copyright = dvalue;
- } else if (!strcmp (name, "img")) {
- ctx->channel_data->img = dvalue;
- } else {
- g_free (dvalue);
+ if (strcmp (key, TOTEM_PL_PARSER_FIELD_TITLE) == 0) {
+ channel->title = g_strdup (value);
+ } else if (strcmp (key, TOTEM_PL_PARSER_FIELD_LANGUAGE) == 0) {
+ channel->lang = g_strdup (value);
+ } else if (strcmp (key, TOTEM_PL_PARSER_FIELD_DESCRIPTION) == 0) {
+ channel->description = g_strdup (value);
+ } else if (strcmp (key, TOTEM_PL_PARSER_FIELD_AUTHOR) == 0) {
+ channel->author = g_strdup (value);
+ } else if (strcmp (key, TOTEM_PL_PARSER_FIELD_CONTACT) == 0) {
+ channel->contact = g_strdup (value);
+ } else if (strcmp (key, TOTEM_PL_PARSER_FIELD_IMAGE_URL) == 0) {
+ channel->img = g_strdup (value);
+ } else if (strcmp (key, TOTEM_PL_PARSER_FIELD_PUB_DATE) == 0) {
+ channel->pub_date = totem_pl_parser_parse_date (value, FALSE);
+ } else if (strcmp (key, TOTEM_PL_PARSER_FIELD_COPYRIGHT) == 0) {
+ channel->copyright = g_strdup (value);
}
}
static void
-rb_set_item_value (struct RBPoadcastLoadContext *ctx,
- const char *name,
- const char *value)
+playlist_started (TotemPlParser *parser,
+ const char *uri,
+ GHashTable *metadata,
+ gpointer data)
{
- xmlChar *dvalue;
-
- dvalue = xmlCharStrdup (value);
- g_strstrip ((char *)dvalue);
-
- if (!strcmp (name, "title")) {
- ctx->item_data->title = dvalue;
- } else if (!strcmp (name, "url")) {
- ctx->item_data->url = dvalue;
- } else if (!strcmp (name, "pubDate")) {
- ctx->item_data->pub_date = rb_podcast_parse_date ((char *)dvalue);
- g_free (dvalue);
- } else if (!strcmp (name, "description")) {
- ctx->item_data->description = dvalue;
- } else if (!strcmp (name, "author")) {
- ctx->item_data->author = dvalue;
- } else if (!strcmp (name, "itunes:duration")) {
- ctx->item_data->duration = rb_podcast_parse_time ((char *)dvalue);
- g_free (dvalue);
- } else if (!strcmp (name, "length")) {
- ctx->item_data->filesize = g_ascii_strtoull ((char *)dvalue, NULL, 10);
- } else {
- g_free (dvalue);
- }
+ g_hash_table_foreach (metadata, (GHFunc) playlist_metadata_foreach, data);
}
static void
-rb_insert_item (struct RBPoadcastLoadContext *ctx)
+playlist_ended (TotemPlParser *parser,
+ const char *uri,
+ gpointer data)
{
- RBPodcastItem *data = ctx->item_data;
+ RBPodcastChannel *channel = (RBPodcastChannel *) data;
- rb_debug ("Inserting item as post");
-
- if (!data->url) {
- rb_debug ("Item does not have a URL, skipping");
- return;
- }
-
- ctx->channel_data->posts = g_list_prepend (ctx->channel_data->posts, ctx->item_data);
+ channel->posts = g_list_reverse (channel->posts);
}
-static gboolean
-rb_validate_channel_propert (const char *name)
-{
- if (name == NULL) {
- return FALSE;
- }
-
- if (!strcmp (name, "title") ||
- !strcmp (name, "language") ||
- !strcmp (name, "itunes:subtitle") ||
- !strcmp (name, "itunes:summary") ||
- !strcmp (name, "description") ||
- !strcmp (name, "generator") ||
- !strcmp (name, "itunes:author") ||
- !strcmp (name, "webMaster") ||
- !strcmp (name, "lastBuildDate") ||
- !strcmp (name, "pubDate") ||
- !strcmp (name, "copyright")) {
- return TRUE;
- } else {
- return FALSE;
- }
-
-}
-
-static gboolean
-rb_validate_item_propert (const char *name)
-{
- if (name == NULL) {
- return FALSE;
- }
-
- if (!strcmp (name, "title") ||
- !strcmp (name, "url") ||
- !strcmp (name, "pubDate") ||
- !strcmp (name, "description") ||
- !strcmp (name, "author") ||
- !strcmp (name, "itunes:duration") ) {
-
- return TRUE;
- } else {
- return FALSE;
- }
-}
-
static void
-rb_podcast_parser_start_element (struct RBPoadcastLoadContext *ctx,
- const char *name,
- const char **attrs)
+entry_metadata_foreach (const char *key,
+ const char *value,
+ gpointer data)
{
+ RBPodcastItem *item = (RBPodcastItem *) data;
- rb_debug ("Start element: %s state: %d", name, ctx->state);
-
- switch (ctx->state) {
- case RB_PODCAST_PARSER_STATE_START:
- {
- if (!strcmp (name, "rss")) {
- ctx->state = RB_PODCAST_PARSER_STATE_RSS;
- } else {
- ctx->in_unknown_elt++;
- }
-
- break;
- }
-
- case RB_PODCAST_PARSER_STATE_RSS:
- {
- if (!strcmp (name, "channel")) {
- ctx->state = RB_PODCAST_PARSER_STATE_CHANNEL;
- } else {
- ctx->in_unknown_elt++;
- }
-
- break;
- }
-
- case RB_PODCAST_PARSER_STATE_CHANNEL:
- {
- if (strcmp (name, "image") == 0)
- {
- ctx->state = RB_PODCAST_PARSER_STATE_IMG;
- } else if (strcmp (name, "itunes:image") == 0) {
- for (; attrs && *attrs; attrs +=2) {
- if (!strcmp (*attrs, "href")) {
- const char *href_value = *(attrs + 1);
- rb_set_channel_value (ctx, "img", href_value);
- }
- }
-
- ctx->state = RB_PODCAST_PARSER_STATE_IMG;
-
- } else if (!strcmp (name, "item")) {
- ctx->item_data = rb_podcast_initializa_item ();
- ctx->state = RB_PODCAST_PARSER_STATE_ITEM;
- } else if (!rb_validate_channel_propert (name)) {
- rb_debug ("Unknown property");
- ctx->in_unknown_elt++;
- } else {
- ctx->state = RB_PODCAST_PARSER_STATE_CHANNEL_PROPERTY;
- }
-
- break;
- }
-
- case RB_PODCAST_PARSER_STATE_ITEM:
- {
- if (!strcmp (name, "enclosure")) {
- for (; *attrs; attrs +=2) {
- if (!strcmp (*attrs, "url")) {
- const char *url_value = *(attrs + 1);
- rb_set_item_value (ctx, "url", url_value);
- } else if (!strcmp (*attrs, "length")) {
- const char *length_value = *(attrs + 1);
- rb_set_item_value (ctx, "length", length_value);
- }
- }
-
- ctx->state = RB_PODCAST_PARSER_STATE_ITEM_PROPERTY;
-
- } else if (!rb_validate_item_propert (name)) {
- ctx->in_unknown_elt++;
- } else {
- ctx->state = RB_PODCAST_PARSER_STATE_ITEM_PROPERTY;
- }
-
- break;
- }
-
- case RB_PODCAST_PARSER_STATE_IMG:
- {
- if (strcmp (name, "url") != 0) {
- ctx->in_unknown_elt++;
- } else {
- ctx->state = RB_PODCAST_PARSER_STATE_IMG_PROPERTY;
- }
-
- break;
- }
-
- case RB_PODCAST_PARSER_STATE_CHANNEL_PROPERTY:
- case RB_PODCAST_PARSER_STATE_ITEM_PROPERTY:
- case RB_PODCAST_PARSER_STATE_IMG_PROPERTY:
- rb_debug ("nested element inside property; treating as unknown");
- ctx->in_unknown_elt++;
- break;
-
- case RB_PODCAST_PARSER_STATE_END:
- break;
- default:
- g_warning ("Unknown podcast parser state: %d", ctx->state);
- break;
+ if (strcmp (key, TOTEM_PL_PARSER_FIELD_TITLE) == 0) {
+ item->title = g_strdup (value);
+ } else if (strcmp (key, TOTEM_PL_PARSER_FIELD_URL) == 0) {
+ item->url = g_strdup (value);
+ } else if (strcmp (key, TOTEM_PL_PARSER_FIELD_DESCRIPTION) == 0) {
+ item->description = g_strdup (value);
+ } else if (strcmp (key, TOTEM_PL_PARSER_FIELD_AUTHOR) == 0) {
+ item->author = g_strdup (value);
+ } else if (strcmp (key, TOTEM_PL_PARSER_FIELD_PUB_DATE) == 0) {
+ item->pub_date = totem_pl_parser_parse_date (value, FALSE);
+ } else if (strcmp (key, TOTEM_PL_PARSER_FIELD_DURATION) == 0) {
+ item->duration = totem_pl_parser_parse_duration (value, FALSE);
+ } else if (strcmp (key, TOTEM_PL_PARSER_FIELD_FILESIZE) == 0) {
+ item->filesize = g_ascii_strtoull (value, NULL, 10);
}
}
static void
-rb_podcast_parser_end_element (struct RBPoadcastLoadContext *ctx,
- const char *name)
+entry_parsed (TotemPlParser *parser,
+ const char *uri,
+ GHashTable *metadata,
+ gpointer data)
{
- rb_debug ("End element: %s state: %d", name, ctx->state);
+ RBPodcastChannel *channel = (RBPodcastChannel *) data;
+ RBPodcastItem *item;
- if (ctx->in_unknown_elt > 0) {
- ctx->in_unknown_elt--;
- rb_debug ("Unknown element");
- return;
- }
-
- switch (ctx->state) {
- case RB_PODCAST_PARSER_STATE_START:
- ctx->state = RB_PODCAST_PARSER_STATE_END;
- break;
-
- case RB_PODCAST_PARSER_STATE_RSS:
- ctx->state = RB_PODCAST_PARSER_STATE_START;
- break;
-
- case RB_PODCAST_PARSER_STATE_CHANNEL:
- ctx->state = RB_PODCAST_PARSER_STATE_RSS;
- break;
-
- case RB_PODCAST_PARSER_STATE_CHANNEL_PROPERTY:
- {
- rb_set_channel_value (ctx, name, ctx->prop_value->str);
- ctx->state = RB_PODCAST_PARSER_STATE_CHANNEL;
- g_string_truncate (ctx->prop_value, 0);
- break;
- }
-
- case RB_PODCAST_PARSER_STATE_ITEM:
- {
- rb_insert_item (ctx);
- ctx->state = RB_PODCAST_PARSER_STATE_CHANNEL;
- break;
- }
-
- case RB_PODCAST_PARSER_STATE_ITEM_PROPERTY:
- {
- rb_set_item_value (ctx, name, ctx->prop_value->str);
- ctx->state = RB_PODCAST_PARSER_STATE_ITEM;
- g_string_truncate (ctx->prop_value, 0);
- break;
- }
-
- case RB_PODCAST_PARSER_STATE_IMG_PROPERTY:
- {
- rb_set_channel_value (ctx, "img", ctx->prop_value->str);
- ctx->state = RB_PODCAST_PARSER_STATE_IMG;
- g_string_truncate (ctx->prop_value, 0);
- break;
- }
-
- case RB_PODCAST_PARSER_STATE_IMG:
- ctx->state = RB_PODCAST_PARSER_STATE_CHANNEL;
- break;
-
- case RB_PODCAST_PARSER_STATE_END:
- break;
-
- default:
- g_warning ("Unknown podcast parser state: %d", ctx->state);
- break;
- }
+ item = g_new0 (RBPodcastItem, 1);
+ g_hash_table_foreach (metadata, (GHFunc) entry_metadata_foreach, item);
+ channel->posts = g_list_prepend (channel->posts, item);
}
-static void
-rb_podcast_parser_characters (struct RBPoadcastLoadContext *ctx,
- const char *data,
- guint len)
-{
- switch (ctx->state) {
- case RB_PODCAST_PARSER_STATE_CHANNEL_PROPERTY:
- case RB_PODCAST_PARSER_STATE_ITEM_PROPERTY:
- case RB_PODCAST_PARSER_STATE_IMG_PROPERTY:
- g_string_append_len (ctx->prop_value, data, len);
- break;
- case RB_PODCAST_PARSER_STATE_START:
- case RB_PODCAST_PARSER_STATE_IMG:
- case RB_PODCAST_PARSER_STATE_RSS:
- case RB_PODCAST_PARSER_STATE_CHANNEL:
- case RB_PODCAST_PARSER_STATE_ITEM:
- case RB_PODCAST_PARSER_STATE_END:
- break;
- default:
- g_warning ("Unknown podcast parser state: %d", ctx->state);
- break;
- }
-}
-
gboolean
rb_podcast_parse_load_feed (RBPodcastChannel *data,
const char *file_name)
{
- xmlParserCtxtPtr parser;
- xmlSAXHandlerPtr sax_handler = NULL;
GnomeVFSResult result;
GnomeVFSFileInfo *info;
- gint file_size;
- gchar *buffer = NULL;
- const char *query_string;
+ TotemPlParser *plparser;
- struct RBPoadcastLoadContext *ctx = NULL;
+ data->url = g_strdup (file_name);
- data->url = xmlCharStrdup (file_name);
-
- /* if the URL has a .rss or .xml extension (before the query string),
+ /* if the URL has a .rss, .xml or .atom extension (before the query string),
* don't bother checking the MIME type.
*/
- query_string = strchr (file_name, '?');
- if (query_string == NULL) {
- query_string = file_name + strlen (file_name);
- }
-
- if (strncmp (query_string - 4, ".rss", 4) == 0 ||
- strncmp (query_string - 4, ".xml", 4) == 0) {
- rb_debug ("not checking mime type for %s", file_name);
+ if (rb_uri_could_be_podcast (file_name, &data->is_opml)) {
+ rb_debug ("not checking mime type for %s (should be %s file)", file_name,
+ data->is_opml ? "OPML" : "Podcast");
} else {
gboolean invalid_mime_type;
@@ -451,22 +140,33 @@
result = gnome_vfs_get_file_info (file_name, info, GNOME_VFS_FILE_INFO_DEFAULT);
+ if ((result != GNOME_VFS_OK)) {
+ if (info->mime_type != NULL) {
+ rb_debug ("Invalid mime-type in podcast feed %s", info->mime_type);
+ } else {
+ rb_debug ("Couldn't get mime type for %s: %s", file_name,
+ gnome_vfs_result_to_string (result));
+ }
+ gnome_vfs_file_info_unref (info);
+ return TRUE;
+ }
+
if (info != NULL
&& info->mime_type != NULL
&& strstr (info->mime_type, "html") == NULL
&& strstr (info->mime_type, "xml") == NULL
- && strstr (info->mime_type, "rss") == NULL) {
+ && strstr (info->mime_type, "rss") == NULL
+ && strstr (info->mime_type, "opml") == NULL) {
invalid_mime_type = TRUE;
+ } else if (info != NULL
+ && info->mime_type != NULL
+ && strstr (info->mime_type, "opml") != NULL) {
+ data->is_opml = TRUE;
+ invalid_mime_type = FALSE;
} else {
invalid_mime_type = FALSE;
}
- if ((result != GNOME_VFS_OK)) {
- rb_debug ("Invalid mime-type in podcast feed %s", info->mime_type);
- gnome_vfs_file_info_unref (info);
- return TRUE;
- }
-
if (invalid_mime_type) {
GtkWidget *dialog;
@@ -492,173 +192,22 @@
return FALSE;
}
- /* first download file by gnome_vfs for use gnome network configuration */
- rb_debug ("reading podcast feed %s", file_name);
- result = gnome_vfs_read_entire_file (file_name, &file_size, &buffer);
- if (result != GNOME_VFS_OK)
- return TRUE;
+ plparser = totem_pl_parser_new ();
+ g_object_set (plparser, "recurse", FALSE, NULL);
+ g_signal_connect (G_OBJECT (plparser), "entry-parsed", G_CALLBACK (entry_parsed), data);
+ g_signal_connect (G_OBJECT (plparser), "playlist-started", G_CALLBACK (playlist_started), data);
+ g_signal_connect (G_OBJECT (plparser), "playlist-ended", G_CALLBACK (playlist_ended), data);
- /* initializing parse */
- sax_handler = g_new0 (xmlSAXHandler, 1);
- sax_handler->startElement = (startElementSAXFunc) rb_podcast_parser_start_element;
- sax_handler->endElement = (endElementSAXFunc) rb_podcast_parser_end_element;
- sax_handler->characters = (charactersSAXFunc) rb_podcast_parser_characters;
- xmlSubstituteEntitiesDefault (1);
-
- ctx = g_new0 (struct RBPoadcastLoadContext, 1);
- ctx->in_unknown_elt = 0;
- ctx->channel_data = data;
- ctx->prop_value = g_string_sized_new (512);
-
- parser = xmlCreateMemoryParserCtxt (buffer, file_size);
- if (parser == NULL) {
- g_free (sax_handler);
- g_free (buffer);
- g_string_free (ctx->prop_value, TRUE);
- g_free (ctx);
+ if (totem_pl_parser_parse (plparser, file_name, FALSE) != TOTEM_PL_PARSER_RESULT_SUCCESS) {
+ rb_debug ("Parsing %s as a Podcast failed", file_name);
+ g_object_unref (plparser);
return FALSE;
}
+ rb_debug ("Parsing %s as a Podcast succeeded", file_name);
- ctx->xmlctx = parser;
- parser->userData = ctx;
- parser->sax = sax_handler;
- xmlParseDocument (parser);
-
- g_free (sax_handler);
- parser->sax = NULL;
- xmlFreeParserCtxt (parser);
-
- g_free (buffer);
- g_string_free (ctx->prop_value, TRUE);
- g_free (ctx);
-
- data->posts = g_list_reverse (data->posts);
return TRUE;
}
-static uintmax_t
-rb_podcast_parse_date (const char *date_str)
-{
- struct tm tm;
- char *result;
-
- /* RFC 2822 date format */
- result = strptime (date_str, "%a, %d %b %Y %T", &tm);
-
- /* same as above, but without comma */
- if (result == NULL) {
- memset (&tm, 0, sizeof (struct tm));
- result = strptime (date_str, "%a %d %b %Y %T", &tm);
- }
-
- /* close-to-RFC 2822, but with extra 0 */
- if (result == NULL) {
- memset (&tm, 0, sizeof (struct tm));
- result = strptime (date_str, "%a, %d %b %Y 0%T", &tm);
- }
-
- /* close-to-RFC 2822, but with no seconds */
- if (result == NULL) {
- memset (&tm, 0, sizeof (struct tm));
- result = strptime (date_str, "%a, %d %b %Y %R", &tm);
- }
-
- /* format without weekday */
- if (result == NULL) {
- memset (&tm, 0, sizeof (struct tm));
- result = strptime (date_str, "%d %b %Y %T", &tm);
- }
-
- /* reversed day and long month */
- if (result == NULL) {
- memset (&tm, 0, sizeof (struct tm));
- result = strptime (date_str, "%a, %B %d %Y %T", &tm);
- }
-
- /* ISO date like */
- if (result == NULL) {
- memset (&tm, 0, sizeof (struct tm));
- result = strptime (date_str, "%Y-%m-%d %T", &tm);
- }
-
- /* ISO date like without timezone */
- if (result == NULL) {
- memset (&tm, 0, sizeof (struct tm));
- result = strptime (date_str, "%Y-%m-%d", &tm);
- }
-
- /* Broken weekday short names */
- if (result == NULL) {
- char *tmp;
-
- /* strip off the erroneous weekday */
- tmp = strstr (date_str, ",");
- if (tmp != NULL) {
- tmp++;
- memset (&tm, 0, sizeof (struct tm));
- result = strptime (tmp, "%d %b %Y %T", &tm);
- }
- }
-
- /* format with timezone offset from GMT */
- if (result == NULL) {
- memset (&tm, 0, sizeof (struct tm));
- result = strptime (date_str, "%a %b %d %T %z %Y", &tm);
- }
-
- /* format with timezone name */
- if (result == NULL) {
- char *tmp;
-
- memset (&tm, 0, sizeof (struct tm));
-
- /* match first part of time string */
- result = strptime (date_str, "%a %b %d %T ", &tm);
-
- /* look for anything with a timezone name-like format
- i.e. at least one all caps alphabetical character */
- if (result != NULL) {
- size_t n;
-
- n = strspn(result, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
- tmp = result+n;
-
- /* make sure there was at least one character that matched */
- if ((tmp != NULL) && n > 0)
- /* remaining part must be the year */
- result = strptime (tmp, "%Y", &tm);
- else
- result = NULL;
- }
- }
-
- if (result == NULL) {
- rb_debug ("unable to convert date string %s", date_str);
- }
-
- return (uintmax_t) ( (result==NULL) ? 0 : mktime (&tm) );
-}
-
-static gulong
-rb_podcast_parse_time (const char *time_str)
-{
- struct tm tm;
- char *result;
-
- memset (&tm, 0, sizeof (struct tm));
- result = strptime (time_str, "%H:%M:%S", &tm);
- if (result == NULL) {
- memset (&tm, 0, sizeof (struct tm));
- result = strptime (time_str, "%M:%S", &tm);
- }
- if (result == NULL) {
- memset (&tm, 0, sizeof (struct tm));
- rb_debug ("unable to convert duration string %s", time_str);
- }
-
- return ((tm.tm_hour * 60 + tm.tm_min) * 60 + tm.tm_sec);
-}
-
void
rb_podcast_parse_channel_free (RBPodcastChannel *data)
{
@@ -671,8 +220,6 @@
g_free (data->url);
g_free (data->title);
g_free (data->lang);
- g_free (data->subtitle);
- g_free (data->summary);
g_free (data->description);
g_free (data->author);
g_free (data->contact);
Index: podcast/Makefile.am
===================================================================
--- podcast/Makefile.am (revision 5467)
+++ podcast/Makefile.am (working copy)
@@ -6,6 +6,9 @@
rb-podcast-parse.c \
rb-podcast-parse.h
+librbpodcast_parse_la_LIBADD = \
+ $(top_builddir)/lib/librb.la
+
librbpodcast_la_SOURCES = \
rb-feed-podcast-properties-dialog.c \
rb-feed-podcast-properties-dialog.h \
@@ -23,9 +26,10 @@
test-podcast-parse.c
test_podcast_parse_LDADD = \
librbpodcast_parse.la \
- $(RHYTHMBOX_LIBS)
+ $(RHYTHMBOX_LIBS) \
+ $(TOTEM_PLPARSER_LIBS)
-INCLUDES = \
+AM_CFLAGS = \
-DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
-DG_LOG_DOMAIN=\"Rhythmbox\" \
-I$(top_srcdir) \
@@ -36,7 +40,25 @@
-I$(top_srcdir)/metadata \
-I$(top_srcdir)/library \
-I$(top_builddir)/lib \
- $(RHYTHMBOX_CFLAGS)
+ $(RHYTHMBOX_CFLAGS) \
+ $(TOTEM_PLPARSER_CFLAGS)
librbpodcast_la_LDFLAGS = -export-dynamic
+if ENABLE_BROWSER_PLUGIN
+plugindir = ${libdir}/mozilla/plugins
+plugin_LTLIBRARIES = librhythmbox-itms-detection-plugin.la
+librhythmbox_itms_detection_plugin_la_SOURCES = rhythmbox-itms-plugin.cpp
+librhythmbox_itms_detection_plugin_la_CXXFLAGS = $(BROWSER_PLUGIN_CFLAGS)
+librhythmbox_itms_detection_plugin_la_LIBADD = $(BROWSER_PLUGIN_LIBS)
+
+librhythmbox_itms_detection_plugin_la_LDFLAGS = \
+ -avoid-version \
+ -export-symbols $(srcdir)/plugin.symbols \
+ -module \
+ $(AM_LDFLAGS)
+
+endif
+
+EXTRA_DIST = rhythmbox-itms-plugin.cpp plugin.symbols
+
Index: podcast/rhythmbox-itms-plugin.cpp
===================================================================
--- podcast/rhythmbox-itms-plugin.cpp (revision 0)
+++ podcast/rhythmbox-itms-plugin.cpp (revision 0)
@@ -0,0 +1,215 @@
+/*
+ * Copyright © 2007 Bastien Nocera <hadess at hadess.net>
+ * Copyright © 2005 Jorn Baayen <jbaayen at gnome.org>
+ * Copyright © 2005 Christian Persch
+ *
+ * Based on the work of:
+ *
+ * Copyright © 2004 Bastien Nocera <hadess at hadess.net>
+ * Copyright © 2002 David A. Schleef <ds at schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <glib.h>
+#include <npupp.h>
+
+static NPNetscapeFuncs mozilla_functions;
+
+static NPError
+plugin_new_instance (NPMIMEType mime_type,
+ NPP instance,
+ guint16 mode,
+ gint16 argc,
+ char **argn,
+ char **argv,
+ NPSavedData *saved)
+{
+ return NPERR_INVALID_INSTANCE_ERROR;
+}
+
+static NPError
+plugin_destroy_instance (NPP instance,
+ NPSavedData **save)
+{
+ return NPERR_NO_ERROR;
+}
+
+static NPError
+plugin_new_stream (NPP instance,
+ NPMIMEType type,
+ NPStream *stream_ptr,
+ NPBool seekable,
+ guint16 *stype)
+{
+ return NPERR_INVALID_PARAM;
+}
+
+static NPError
+plugin_stream_as_file (NPP instance,
+ NPStream* stream,
+ const char *filename)
+{
+ return NPERR_INVALID_PARAM;
+}
+
+static NPError
+plugin_destroy_stream (NPP instance,
+ NPStream *stream,
+ NPError reason)
+{
+ return NPERR_NO_ERROR;
+}
+
+static int32
+plugin_write_ready (NPP instance,
+ NPStream *stream)
+{
+ return 0;
+}
+
+static int32
+plugin_write (NPP instance,
+ NPStream *stream,
+ int32 offset,
+ int32 len,
+ gpointer buffer)
+{
+ return -1;
+}
+
+static NPError
+plugin_get_value (NPP instance,
+ NPPVariable variable,
+ gpointer value)
+{
+ NPError err = NPERR_NO_ERROR;
+
+ switch (variable) {
+ case NPPVpluginNameString:
+ *((char **) value) = "iTunes Application Detector";
+ break;
+
+ case NPPVpluginDescriptionString:
+ *((char **) value) = "This plug-in detects the presence of iTunes when opening iTunes Store URLs in a web page with Firefox.";
+ break;
+
+ case NPPVpluginNeedsXEmbed:
+ *((NPBool *) value) = PR_FALSE;
+ break;
+
+ default:
+ err = NPERR_INVALID_PARAM;
+ break;
+ }
+
+ return err;
+}
+
+NPError
+NP_GetValue (void *future,
+ NPPVariable variable,
+ gpointer value)
+{
+ return plugin_get_value (NULL, variable, value);
+}
+
+char *
+NP_GetMIMEDescription (void)
+{
+ return "application/itunes-plugin::;";
+}
+
+NPError
+NP_Initialize (NPNetscapeFuncs *moz_funcs,
+ NPPluginFuncs *plugin_funcs)
+{
+ if (moz_funcs == NULL || plugin_funcs == NULL)
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+
+ if ((moz_funcs->version >> 8) > NP_VERSION_MAJOR)
+ return NPERR_INCOMPATIBLE_VERSION_ERROR;
+ if (moz_funcs->size < sizeof (NPNetscapeFuncs))
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+ if (plugin_funcs->size < sizeof (NPPluginFuncs))
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+
+ /*
+ * Copy all of the fields of the Mozilla function table into our
+ * copy so we can call back into Mozilla later. Note that we need
+ * to copy the fields one by one, rather than assigning the whole
+ * structure, because the Mozilla function table could actually be
+ * bigger than what we expect.
+ */
+ mozilla_functions.size = moz_funcs->size;
+ mozilla_functions.version = moz_funcs->version;
+ mozilla_functions.geturl = moz_funcs->geturl;
+ mozilla_functions.posturl = moz_funcs->posturl;
+ mozilla_functions.requestread = moz_funcs->requestread;
+ mozilla_functions.newstream = moz_funcs->newstream;
+ mozilla_functions.write = moz_funcs->write;
+ mozilla_functions.destroystream = moz_funcs->destroystream;
+ mozilla_functions.status = moz_funcs->status;
+ mozilla_functions.uagent = moz_funcs->uagent;
+ mozilla_functions.memalloc = moz_funcs->memalloc;
+ mozilla_functions.memfree = moz_funcs->memfree;
+ mozilla_functions.memflush = moz_funcs->memflush;
+ mozilla_functions.reloadplugins = moz_funcs->reloadplugins;
+ mozilla_functions.getJavaEnv = moz_funcs->getJavaEnv;
+ mozilla_functions.getJavaPeer = moz_funcs->getJavaPeer;
+ mozilla_functions.geturlnotify = moz_funcs->geturlnotify;
+ mozilla_functions.posturlnotify = moz_funcs->posturlnotify;
+ mozilla_functions.getvalue = moz_funcs->getvalue;
+ mozilla_functions.setvalue = moz_funcs->setvalue;
+ mozilla_functions.invalidaterect = moz_funcs->invalidaterect;
+ mozilla_functions.invalidateregion = moz_funcs->invalidateregion;
+ mozilla_functions.forceredraw = moz_funcs->forceredraw;
+ mozilla_functions.geturl = moz_funcs->geturl;
+
+ /*
+ * Set up a plugin function table that Mozilla will use to call
+ * into us. Mozilla needs to know about our version and size and
+ * have a UniversalProcPointer for every function we implement.
+ */
+
+ plugin_funcs->size = sizeof (NPPluginFuncs);
+ plugin_funcs->version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
+ plugin_funcs->newp = NewNPP_NewProc (plugin_new_instance);
+ plugin_funcs->destroy = NewNPP_DestroyProc (plugin_destroy_instance);
+ plugin_funcs->setwindow = NewNPP_SetWindowProc (NULL);
+ plugin_funcs->newstream = NewNPP_NewStreamProc (plugin_new_stream);
+ plugin_funcs->destroystream = NewNPP_DestroyStreamProc (plugin_destroy_stream);
+ plugin_funcs->asfile = NewNPP_StreamAsFileProc (plugin_stream_as_file);
+ plugin_funcs->writeready = NewNPP_WriteReadyProc (plugin_write_ready);
+ plugin_funcs->write = NewNPP_WriteProc (plugin_write);
+ plugin_funcs->print = NewNPP_PrintProc (NULL);
+ plugin_funcs->event = NewNPP_HandleEventProc (NULL);
+ plugin_funcs->urlnotify = NewNPP_URLNotifyProc (NULL);
+ plugin_funcs->javaClass = NULL;
+ plugin_funcs->getvalue = NewNPP_GetValueProc (plugin_get_value);
+ plugin_funcs->setvalue = NewNPP_SetValueProc (NULL);
+
+ return NPERR_NO_ERROR;
+}
+
+NPError
+NP_Shutdown (void)
+{
+ return NPERR_NO_ERROR;
+}
Index: podcast/rb-podcast-parse.h
===================================================================
--- podcast/rb-podcast-parse.h (revision 5467)
+++ podcast/rb-podcast-parse.h (working copy)
@@ -23,36 +23,34 @@
#define RB_PODCAST_PARSE_H
#include <glib.h>
-#include <libxml/xmlstring.h>
-#include <inttypes.h>
typedef struct
{
- xmlChar* title;
- xmlChar* url;
- xmlChar* description;
- xmlChar* author;
- uintmax_t pub_date;
+ char* title;
+ char* url;
+ char* description;
+ char* author;
+ guint64 pub_date;
gulong duration;
guint64 filesize;
-}RBPodcastItem;
+} RBPodcastItem;
typedef struct
{
- xmlChar* url;
- xmlChar* title;
- xmlChar* lang;
- xmlChar* subtitle;
- xmlChar* summary;
- xmlChar* description;
- xmlChar* author;
- xmlChar* contact;
- xmlChar* img;
- uintmax_t pub_date;
- xmlChar* copyright;
+ char* url;
+ char* title;
+ char* lang;
+ char* description;
+ char* author;
+ char* contact;
+ char* img;
+ guint64 pub_date;
+ char* copyright;
+ gboolean is_opml;
+
GList *posts;
-}RBPodcastChannel;
+} RBPodcastChannel;
gboolean rb_podcast_parse_load_feed (RBPodcastChannel *data, const char *file_name);
void rb_podcast_parse_channel_free (RBPodcastChannel *data);
Index: configure.ac
===================================================================
--- configure.ac (revision 5467)
+++ configure.ac (working copy)
@@ -19,8 +19,9 @@
AC_ISC_POSIX
AC_PROG_CC
+AC_PROG_CXX
AC_STDC_HEADERS
-AM_PROG_LIBTOOL
+AM_PROG_LIBTOOL()
AC_C_BIGENDIAN
AC_CHECK_SIZEOF(long)
@@ -35,7 +36,7 @@
LIBGPOD_REQS=0.4
MUSICBRAINZ_REQS=2.1.0
NCB_MIN_REQS=2.9.0
-TOTEM_PLPARSER_REQS=1.1.5
+TOTEM_PLPARSER_REQS=2.21.0
VALA_REQS=0.0.8
AC_MSG_CHECKING([for GNU extension fwrite_unlocked])
@@ -967,7 +968,58 @@
AM_PATH_CHECK([], have_check=yes, have_check=no)
AM_CONDITIONAL([HAVE_CHECK],[test "x$have_check" = "xyes"])
+dnl ================================================================
+dnl Browser plugin
+dnl ================================================================
+AC_ARG_ENABLE([browser-plugin],
+ [AS_HELP_STRING([--enable-browser-plugin],[compile the iTunes detection browser plugin])],
+ [],[enable_browser_plugin=autodetect])
+
+if test "$enable_browser_plugin" != "no" ; then
+ AC_MSG_CHECKING([which gecko to use])
+
+ AC_ARG_WITH([gecko],
+ [AS_HELP_STRING([--with-gecko],[Which gecko engine to use (default: autodetect)])])
+
+ GECKOS="xulrunner firefox mozilla-firefox seamonkey mozilla"
+ gecko=$with_gecko
+
+ if test -z "$with_gecko"; then
+ dnl Autodetect gecko
+ for g in $GECKOS; do
+ if $PKG_CONFIG --exists $g-plugin; then
+ gecko=$g
+ break;
+ fi
+ done
+ elif ! $PKG_CONFIG --exists $gecko-plugin; then
+ AC_MSG_ERROR([Gecko "$gecko" not found])
+ fi
+
+ if test -z "$gecko" -a "$enable_browser_plugin" = "autodetect"; then
+ dnl No gecko found, disable plugin
+ AC_MSG_WARN([No gecko found, disabling plugin])
+ enable_browser_plugin=no
+ elif test -z "$gecko"; then
+ AC_MSG_ERROR([No gecko found])
+ elif ! ( echo "$GECKOS" | egrep "(^| )$gecko(\$| )" > /dev/null); then
+ AC_MSG_ERROR([Unknown gecko "$gecko" specified])
+ else
+ enable_browser_plugin=yes
+ fi
+
+ AC_MSG_RESULT([$gecko])
+fi
+
+if test "$enable_browser_plugin" = "yes" ; then
+ PKG_CHECK_MODULES([BROWSER_PLUGIN],
+ [glib-2.0 $gecko-plugin],
+ [],[enable_browser_plugins=no])
+fi
+
+AM_CONDITIONAL([ENABLE_BROWSER_PLUGIN], test x$enable_browser_plugin = xyes)
+
dnl ================================================================
dnl end-game
dnl ================================================================
@@ -1168,4 +1220,10 @@
AC_MSG_NOTICE([ FM radio support disabled])
fi
+if test "x$enable_browser_plugin" != xno; then
+ AC_MSG_NOTICE([** iTunes detection browser plugin (for podcasts) enabled])
+else
+ AC_MSG_NOTICE([ iTunes detection browser plugin (for podcasts) disabled])
+fi
+
AC_MSG_NOTICE([End options])
Index: lib/rb-file-helpers.c
===================================================================
--- lib/rb-file-helpers.c (revision 5467)
+++ lib/rb-file-helpers.c (working copy)
@@ -774,6 +774,65 @@
return g_utf8_strrchr (text_uri, -1, GNOME_VFS_URI_PATH_CHR)[1] == '.';
}
+gboolean
+rb_uri_could_be_podcast (const char *uri, gboolean *is_opml)
+{
+ const char *query_string;
+
+ if (is_opml != NULL)
+ *is_opml = FALSE;
+
+ /* Check the scheme is a possible one first */
+ if (g_str_has_prefix (uri, "http") == FALSE &&
+ g_str_has_prefix (uri, "itpc:") == FALSE &&
+ g_str_has_prefix (uri, "itms:") == FALSE) {
+ rb_debug ("'%s' can't be a Podcast or OPML file, not the right scheme", uri);
+ return FALSE;
+ }
+
+ /* Now, check whether the iTunes Music Store link
+ * is a podcast */
+ if (g_str_has_prefix (uri, "itms:") != FALSE
+ && strstr (uri, "phobos.apple.com") != NULL
+ && strstr (uri, "viewPodcast") != NULL)
+ return TRUE;
+
+ query_string = strchr (uri, '?');
+ if (query_string == NULL) {
+ query_string = uri + strlen (uri);
+ }
+
+ /* FIXME hacks */
+ if (strstr (uri, "rss") != NULL ||
+ strstr (uri, "atom") != NULL ||
+ strstr (uri, "feed") != NULL) {
+ rb_debug ("'%s' should be Podcast file, HACK", uri);
+ return TRUE;
+ } else if (strstr (uri, "opml") != NULL) {
+ rb_debug ("'%s' should be an OPML file, HACK", uri);
+ if (is_opml != NULL)
+ *is_opml = TRUE;
+ return TRUE;
+ }
+
+ if (strncmp (query_string - 4, ".rss", 4) == 0 ||
+ strncmp (query_string - 4, ".xml", 4) == 0 ||
+ strncmp (query_string - 5, ".atom", 5) == 0 ||
+ strncmp (uri, "itpc", 4) == 0 ||
+ (strstr (uri, "phobos.apple.com/") != NULL && strstr (uri, "viewPodcast") != NULL) ||
+ strstr (uri, "itunes.com/podcast") != NULL) {
+ rb_debug ("'%s' should be Podcast file", uri);
+ return TRUE;
+ } else if (strncmp (query_string - 5, ".opml", 5) == 0) {
+ rb_debug ("'%s' should be an OPML file", uri);
+ if (is_opml != NULL)
+ *is_opml = TRUE;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
char *
rb_uri_make_hidden (const char *text_uri)
{
Index: lib/rb-file-helpers.h
===================================================================
--- lib/rb-file-helpers.h (revision 5467)
+++ lib/rb-file-helpers.h (working copy)
@@ -44,6 +44,7 @@
gboolean rb_uri_is_writable (const char *uri);
gboolean rb_uri_is_local (const char *uri);
gboolean rb_uri_is_hidden (const char *uri);
+gboolean rb_uri_could_be_podcast (const char *uri, gboolean *is_opml);
char * rb_uri_make_hidden (const char *uri);
char * rb_uri_get_dir_name (const char *uri);
char * rb_uri_get_short_path_name (const char *uri);
Index: shell/rb-shell.c
===================================================================
--- shell/rb-shell.c (revision 5467)
+++ shell/rb-shell.c (working copy)
@@ -3208,20 +3208,11 @@
gboolean source_is_entry;
} PlaylistParseData;
-#if TOTEM_PL_PARSER_CHECK_VERSION(2,19,0)
static void
handle_playlist_entry_cb (TotemPlParser *playlist,
const char *uri,
GHashTable *metadata,
PlaylistParseData *data)
-#else
-static void
-handle_playlist_entry_cb (TotemPlParser *playlist,
- const char *uri,
- const char *title,
- const char *genre,
- PlaylistParseData *data)
-#endif /* TOTEM_PL_PARSER_CHECK_VERSION */
{
RBSource *source;
@@ -3270,6 +3261,14 @@
entry = rhythmdb_entry_lookup_by_location (shell->priv->db, uri);
playlist_source = NULL;
+ /* If the URI points to a Podcast, pass it on to
+ * the Podcast source */
+ if (rb_uri_could_be_podcast (uri, NULL)) {
+ rb_podcast_source_add_feed (shell->priv->podcast_source, uri);
+ rb_shell_select_source (shell, RB_SOURCE (shell->priv->podcast_source));
+ return TRUE;
+ }
+
if (entry == NULL) {
TotemPlParser *parser;
TotemPlParserResult result;
@@ -3283,15 +3282,9 @@
rb_debug ("adding uri %s, play %d", uri, play);
parser = totem_pl_parser_new ();
-#if TOTEM_PL_PARSER_CHECK_VERSION(2,19,0)
g_signal_connect_data (G_OBJECT (parser), "entry-parsed",
G_CALLBACK (handle_playlist_entry_cb),
&data, NULL, 0);
-#else
- g_signal_connect_data (G_OBJECT (parser), "entry",
- G_CALLBACK (handle_playlist_entry_cb),
- &data, NULL, 0);
-#endif /* TOTEM_PL_PARSER_CHECK_VERSION */
totem_pl_parser_add_ignored_mimetype (parser, "x-directory/normal");
if (g_object_class_find_property (G_OBJECT_GET_CLASS (parser), "recurse"))
Index: shell/rb-playlist-manager.c
===================================================================
--- shell/rb-playlist-manager.c (revision 5467)
+++ shell/rb-playlist-manager.c (working copy)
@@ -502,20 +502,11 @@
return quark;
}
-#if TOTEM_PL_PARSER_CHECK_VERSION(2,19,0)
static void
handle_playlist_entry_cb (TotemPlParser *playlist,
const char *uri_maybe,
GHashTable *metadata,
RBPlaylistManager *mgr)
-#else
-static void
-handle_playlist_entry_cb (TotemPlParser *playlist,
- const char *uri_maybe,
- const char *title,
- const char *genre,
- RBPlaylistManager *mgr)
-#endif /* TOTEM_PL_PARSER_CHECK_VERSION */
{
char *uri;
#if TOTEM_PL_PARSER_CHECK_VERSION(2,19,0)
@@ -550,19 +541,29 @@
}
static void
-playlist_load_start_cb (TotemPlParser *parser, const char *title, RBPlaylistManager *mgr)
+playlist_load_started_cb (TotemPlParser *parser, const char *uri, GHashTable *metadata, RBPlaylistManager *mgr)
{
- rb_debug ("loading new playlist %s", title);
+ const char *title;
+ rb_debug ("loading new playlist %s", uri);
+
+ title = g_hash_table_lookup (metadata, TOTEM_PL_PARSER_FIELD_TITLE);
+ if (title == NULL)
+ title = _("Unnamed playlist");
+
mgr->priv->loading_playlist =
RB_STATIC_PLAYLIST_SOURCE (rb_playlist_manager_new_playlist (mgr, title, FALSE));
}
static void
-playlist_load_end_cb (TotemPlParser *parser, const char *title, RBPlaylistManager *mgr)
+playlist_load_ended_cb (TotemPlParser *parser, const char *uri, GHashTable *metadata, RBPlaylistManager *mgr)
{
- rb_debug ("finished loading playlist %s", title);
+ const char *title;
+ rb_debug ("finished loading playlist %s", uri);
+
+ title = g_hash_table_lookup (metadata, TOTEM_PL_PARSER_FIELD_TITLE);
+
if (title) {
g_object_set (mgr->priv->loading_playlist, "name", title, NULL);
mgr->priv->loading_playlist = NULL;
@@ -591,22 +592,16 @@
{
TotemPlParser *parser = totem_pl_parser_new ();
-#if TOTEM_PL_PARSER_CHECK_VERSION(2,19,0)
g_signal_connect_object (parser, "entry-parsed",
G_CALLBACK (handle_playlist_entry_cb),
mgr, 0);
-#else
- g_signal_connect_object (parser, "entry",
- G_CALLBACK (handle_playlist_entry_cb),
- mgr, 0);
-#endif /* TOTEM_PL_PARSER_CHECK_VERSION */
- g_signal_connect_object (parser, "playlist-start",
- G_CALLBACK (playlist_load_start_cb),
+ g_signal_connect_object (parser, "playlist-started",
+ G_CALLBACK (playlist_load_started_cb),
mgr, 0);
- g_signal_connect_object (parser, "playlist-end",
- G_CALLBACK (playlist_load_end_cb),
+ g_signal_connect_object (parser, "playlist-ended",
+ G_CALLBACK (playlist_load_ended_cb),
mgr, 0);
if (g_object_class_find_property (G_OBJECT_GET_CLASS (parser), "recurse"))
Index: shell/rb-shell-player.c
===================================================================
--- shell/rb-shell-player.c (revision 5467)
+++ shell/rb-shell-player.c (working copy)
@@ -120,10 +120,10 @@
static void rb_shell_player_entry_activated_cb (RBEntryView *view,
RhythmDBEntry *entry,
- RBShellPlayer *playa);
+ RBShellPlayer *player);
static void rb_shell_player_property_row_activated_cb (RBPropertyView *view,
const char *name,
- RBShellPlayer *playa);
+ RBShellPlayer *player);
static void rb_shell_player_sync_volume (RBShellPlayer *player, gboolean notify);
static void rb_shell_player_sync_replaygain (RBShellPlayer *player,
RhythmDBEntry *entry);
@@ -1299,20 +1299,11 @@
PlaybackStartType play_type;
} OpenLocationThreadData;
-#if TOTEM_PL_PARSER_CHECK_VERSION(2,19,0)
static void
playlist_entry_cb (TotemPlParser *playlist,
const char *uri,
GHashTable *metadata,
RBShellPlayer *player)
-#else
-static void
-playlist_entry_cb (TotemPlParser *playlist,
- const char *uri,
- const char *title,
- const char *genre,
- RBShellPlayer *player)
-#endif
{
rb_debug ("adding stream url %s", uri);
g_queue_push_tail (player->priv->playlist_urls, g_strdup (uri));
@@ -1326,15 +1317,9 @@
playlist = totem_pl_parser_new ();
-#if TOTEM_PL_PARSER_CHECK_VERSION(2,19,0)
g_signal_connect_data (G_OBJECT (playlist), "entry-parsed",
G_CALLBACK (playlist_entry_cb),
data->player, NULL, 0);
-#else
- g_signal_connect_data (G_OBJECT (playlist), "entry",
- G_CALLBACK (playlist_entry_cb),
- data->player, NULL, 0);
-#endif /* TOTEM_PL_PARSER_CHECK_VERSION */
totem_pl_parser_add_ignored_mimetype (playlist, "x-directory/normal");
@@ -1415,6 +1400,8 @@
gboolean ret = TRUE;
crossfade = rb_shell_player_get_crossfade (player, play_type);
+
+ g_object_ref (entry);
ret = ret && rb_player_open (player->priv->mmplayer, location, entry, (GDestroyNotify) rhythmdb_entry_unref, error);
ret = ret && rb_player_play (player->priv->mmplayer, crossfade, error);
@@ -2340,7 +2327,7 @@
static void
rb_shell_player_entry_activated_cb (RBEntryView *view,
RhythmDBEntry *entry,
- RBShellPlayer *playa)
+ RBShellPlayer *player)
{
gboolean was_from_queue = FALSE;
RhythmDBEntry *prev_entry = NULL;
@@ -2359,44 +2346,44 @@
/* skip entries with no playback uri */
playback_uri = rhythmdb_entry_get_playback_uri (entry);
- if (playback_uri == NULL) {
+ if (playback_uri == NULL)
return;
- }
+
g_free (playback_uri);
/* figure out where the previous entry came from */
- if ((playa->priv->queue_source != NULL) &&
- (playa->priv->current_playing_source == RB_SOURCE (playa->priv->queue_source))) {
- prev_entry = rb_shell_player_get_playing_entry (playa);
+ if ((player->priv->queue_source != NULL) &&
+ (player->priv->current_playing_source == RB_SOURCE (player->priv->queue_source))) {
+ prev_entry = rb_shell_player_get_playing_entry (player);
was_from_queue = TRUE;
}
- if (playa->priv->queue_source) {
+ if (player->priv->queue_source) {
RBEntryView *queue_sidebar;
- g_object_get (playa->priv->queue_source, "sidebar", &queue_sidebar, NULL);
+ g_object_get (player->priv->queue_source, "sidebar", &queue_sidebar, NULL);
- if (view == queue_sidebar || view == rb_source_get_entry_view (RB_SOURCE (playa->priv->queue_source))) {
+ if (view == queue_sidebar || view == rb_source_get_entry_view (RB_SOURCE (player->priv->queue_source))) {
/* fall back to the current selected source once the queue is empty */
- if (view == queue_sidebar && playa->priv->source == NULL) {
- rb_play_order_playing_source_changed (playa->priv->play_order,
- playa->priv->selected_source);
- playa->priv->source = playa->priv->selected_source;
+ if (view == queue_sidebar && player->priv->source == NULL) {
+ rb_play_order_playing_source_changed (player->priv->play_order,
+ player->priv->selected_source);
+ player->priv->source = player->priv->selected_source;
}
/* queue entry activated: move it to the start of the queue */
- rb_static_playlist_source_move_entry (RB_STATIC_PLAYLIST_SOURCE (playa->priv->queue_source), entry, 0);
- rb_shell_player_set_playing_source (playa, RB_SOURCE (playa->priv->queue_source));
+ rb_static_playlist_source_move_entry (RB_STATIC_PLAYLIST_SOURCE (player->priv->queue_source), entry, 0);
+ rb_shell_player_set_playing_source (player, RB_SOURCE (player->priv->queue_source));
was_from_queue = FALSE;
source_set = TRUE;
jump_to_entry = TRUE;
} else {
- if (playa->priv->queue_only) {
- rb_source_add_to_queue (playa->priv->selected_source,
- RB_SOURCE (playa->priv->queue_source));
- rb_shell_player_set_playing_source (playa, RB_SOURCE (playa->priv->queue_source));
+ if (player->priv->queue_only) {
+ rb_source_add_to_queue (player->priv->selected_source,
+ RB_SOURCE (player->priv->queue_source));
+ rb_shell_player_set_playing_source (player, RB_SOURCE (player->priv->queue_source));
source_set = TRUE;
}
}
@@ -2405,18 +2392,18 @@
}
/* bail out if queue only */
- if (playa->priv->queue_only) {
+ if (player->priv->queue_only) {
return;
}
if (!source_set) {
- rb_shell_player_set_playing_source (playa, playa->priv->selected_source);
+ rb_shell_player_set_playing_source (player, player->priv->selected_source);
source_set = TRUE;
}
- playa->priv->jump_to_playing_entry = jump_to_entry;
- if (!rb_shell_player_set_playing_entry (playa, entry, TRUE, FALSE, &error)) {
- rb_shell_player_error (playa, FALSE, error);
+ player->priv->jump_to_playing_entry = jump_to_entry;
+ if (!rb_shell_player_set_playing_entry (player, entry, TRUE, FALSE, &error)) {
+ rb_shell_player_error (player, FALSE, error);
g_clear_error (&error);
}
@@ -2424,7 +2411,7 @@
* so we'll start again from the start.
*/
if (was_from_queue && prev_entry != NULL) {
- rb_play_order_set_playing_entry (playa->priv->queue_play_order, NULL);
+ rb_play_order_set_playing_entry (player->priv->queue_play_order, NULL);
}
if (prev_entry != NULL) {
Index: data/rhythmbox.schemas
===================================================================
--- data/rhythmbox.schemas (revision 5467)
+++ data/rhythmbox.schemas (working copy)
@@ -136,9 +136,9 @@
<long>Main window X position.</long>
</locale>
</schema>
-
-<schema>
+
+ <schema>
<key>/schemas/apps/rhythmbox/state/window_position_y</key>
<applyto>/apps/rhythmbox/state/window_position_y</applyto>
<owner>rhythmbox</owner>
@@ -150,10 +150,7 @@
</locale>
</schema>
-
-
-
-<schema>
+ <schema>
<key>/schemas/apps/rhythmbox/state/window_height</key>
<applyto>/apps/rhythmbox/state/window_height</applyto>
<owner>rhythmbox</owner>
@@ -439,6 +436,106 @@
</locale>
</schema>
<schema>
+ <key>/schemas/desktop/gnome/url-handlers/itpc/command</key>
+ <applyto>/desktop/gnome/url-handlers/itpc/command</applyto>
+ <owner>rhythmbox</owner>
+ <type>string</type>
+ <default>rhythmbox "%s"</default>
+ <locale name="C">
+ <short>The command to handle ITPC scheme URLs</short>
+ <long>The command to handle ITPC scheme URLs.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/desktop/gnome/url-handlers/itpc/needs_terminal</key>
+ <applyto>/desktop/gnome/url-handlers/itpc/needs_terminal</applyto>
+ <owner>rhythmbox</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Whether command to handle ITPC scheme URLs needs a terminal</short>
+ <long>Whether command to handle ITPC scheme URLs needs a terminal.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/desktop/gnome/url-handlers/itpc/enabled</key>
+ <applyto>/desktop/gnome/url-handlers/itpc/enabled</applyto>
+ <owner>rhythmbox</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Whether command to handle ITPC scheme URLs is enabled</short>
+ <long>Whether command to handle ITPC scheme URLs is enabled.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/desktop/gnome/url-handlers/itms/command</key>
+ <applyto>/desktop/gnome/url-handlers/itms/command</applyto>
+ <owner>rhythmbox</owner>
+ <type>string</type>
+ <default>rhythmbox "%s"</default>
+ <locale name="C">
+ <short>The command to handle ITMS scheme URLs</short>
+ <long>The command to handle ITMS scheme URLs.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/desktop/gnome/url-handlers/itms/needs_terminal</key>
+ <applyto>/desktop/gnome/url-handlers/itms/needs_terminal</applyto>
+ <owner>rhythmbox</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Whether command to handle ITMS scheme URLs needs a terminal</short>
+ <long>Whether command to handle ITMS scheme URLs needs a terminal.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/desktop/gnome/url-handlers/itms/enabled</key>
+ <applyto>/desktop/gnome/url-handlers/itms/enabled</applyto>
+ <owner>rhythmbox</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Whether command to handle ITMS scheme URLs is enabled</short>
+ <long>Whether command to handle ITMS scheme URLs is enabled.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/desktop/gnome/url-handlers/feed/command</key>
+ <applyto>/desktop/gnome/url-handlers/feed/command</applyto>
+ <owner>rhythmbox</owner>
+ <type>string</type>
+ <default>rhythmbox "%s"</default>
+ <locale name="C">
+ <short>The command to handle FEED scheme URLs</short>
+ <long>The command to handle FEED scheme URLs.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/desktop/gnome/url-handlers/feed/needs_terminal</key>
+ <applyto>/desktop/gnome/url-handlers/feed/needs_terminal</applyto>
+ <owner>rhythmbox</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Whether command to handle FEED scheme URLs needs a terminal</short>
+ <long>Whether command to handle FEED scheme URLs needs a terminal.</long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/desktop/gnome/url-handlers/feed/enabled</key>
+ <applyto>/desktop/gnome/url-handlers/feed/enabled</applyto>
+ <owner>rhythmbox</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Whether command to handle FEED scheme URLs is enabled</short>
+ <long>Whether command to handle FEED scheme URLs is enabled.</long>
+ </locale>
+ </schema>
+
+ <schema>
<key>/schemas/apps/rhythmbox/state/podcast/show_browser</key>
<applyto>/apps/rhythmbox/state/podcast/show_browser</applyto>
<owner>rhythmbox</owner>
Index: rhythmbox.spec
===================================================================
RCS file: /cvs/pkgs/rpms/rhythmbox/devel/rhythmbox.spec,v
retrieving revision 1.152
retrieving revision 1.153
diff -u -r1.152 -r1.153
--- rhythmbox.spec 30 Nov 2007 14:02:43 -0000 1.152
+++ rhythmbox.spec 30 Nov 2007 18:17:41 -0000 1.153
@@ -3,7 +3,7 @@
Name: rhythmbox
Summary: Music Management Application
Version: 0.11.3
-Release: 7%{?dist}
+Release: 8%{?dist}
License: GPLv2+ and GFDL+
Group: Applications/Multimedia
URL: http://www.gnome.org/projects/rhythmbox/
@@ -45,6 +45,7 @@
BuildRequires: libmtp-devel
BuildRequires: gstreamer-python
BuildRequires: perl(XML::Parser)
+BuildRequires: xulrunner-devel
# For the playlist parser patch
BuildRequires: intltool autoconf automake libtool gettext check-devel
@@ -53,7 +54,7 @@
# http://bugzilla.gnome.org/show_bug.cgi?id=346434
Patch1: rb-delete-ipod-tracks.patch
# http://bugzilla.gnome.org/show_bug.cgi?id=484768
-Patch2: rb-use-newer-plparser-7.patch
+Patch2: rb-use-newer-plparser-9.patch
# http://bugzilla.gnome.org/show_bug.cgi?id=338308
Patch3: rhythmbox-0.11.3-add-missing-plugins-support.patch
# http://bugzilla.gnome.org/show_bug.cgi?id=497430
@@ -209,6 +210,10 @@
%{_libdir}/rhythmbox/plugins/upnp_coherence
%changelog
+* Fri Nov 30 2007 - Bastien Nocera <bnocera at redhat.com> - 0.11.3-8
+- Update patch for the Podcast parsing to include the browser plugin
+ for the iTunes detection
+
* Fri Nov 30 2007 - Bastien Nocera <bnocera at redhat.com> - 0.11.3-7
- Add patch to avoid crashing if no Python plugins are enabled by default
(#393531)
--- rb-use-newer-plparser-7.patch DELETED ---
More information about the fedora-extras-commits
mailing list