[totem-pl-parser] Add asynchronous parsing support to totem-pl-parser



commit ccfcf8ab8d2657f9ac198a82d49d8b4c878595e3
Author: Philip Withnall <philip tecnocode co uk>
Date:   Wed Jun 17 14:52:31 2009 +0100

    Add asynchronous parsing support to totem-pl-parser
    
    2009-06-17  Philip Withnall  <philip tecnocode co uk>
    
    	* docs/reference/totem-pl-parser-sections.txt:
    	* plparse/plparser.symbols:
    	* plparse/totem-pl-parser-builtins.c
    	(totem_pl_parser_result_get_type):
    	* plparse/totem-pl-parser-lines.c (totem_pl_parser_add_ram),
    	(totem_pl_parser_add_m3u), (totem_pl_parser_add_ra):
    	* plparse/totem-pl-parser-lines.h:
    	* plparse/totem-pl-parser-media.c (totem_pl_parser_add_iso),
    	(totem_pl_parser_add_cue), (totem_pl_parser_add_directory),
    	(totem_pl_parser_add_block):
    	* plparse/totem-pl-parser-media.h:
    	* plparse/totem-pl-parser-misc.c (totem_pl_parser_add_gvp),
    	(totem_pl_parser_add_desktop):
    	* plparse/totem-pl-parser-misc.h:
    	* plparse/totem-pl-parser-pla.c (totem_pl_parser_add_pla):
    	* plparse/totem-pl-parser-pla.h:
    	* plparse/totem-pl-parser-pls.c
    	(totem_pl_parser_add_pls_with_contents), (totem_pl_parser_add_pls):
    	* plparse/totem-pl-parser-pls.h:
    	* plparse/totem-pl-parser-podcast.c (totem_pl_parser_add_rss),
    	(totem_pl_parser_add_itpc), (totem_pl_parser_add_zune),
    	(totem_pl_parser_add_atom), (totem_pl_parser_add_xml_feed),
    	(totem_pl_parser_add_itms), (totem_pl_parser_add_opml):
    	* plparse/totem-pl-parser-podcast.h:
    	* plparse/totem-pl-parser-private.h:
    	* plparse/totem-pl-parser-qt.c
    	(totem_pl_parser_add_quicktime_rtsptext),
    	(totem_pl_parser_add_quicktime_metalink),
    	(totem_pl_parser_add_quicktime):
    	* plparse/totem-pl-parser-qt.h:
    	* plparse/totem-pl-parser-smil.c (totem_pl_parser_add_smil):
    	* plparse/totem-pl-parser-smil.h:
    	* plparse/totem-pl-parser-wm.c
    	(totem_pl_parser_add_asf_reference_parser),
    	(totem_pl_parser_add_asf_parser), (parse_asx_entry),
    	(parse_asx_entryref), (parse_asx_entries),
    	(totem_pl_parser_add_asx), (totem_pl_parser_add_asf):
    	* plparse/totem-pl-parser-wm.h:
    	* plparse/totem-pl-parser-xspf.c (totem_pl_parser_add_xspf):
    	* plparse/totem-pl-parser-xspf.h:
    	* plparse/totem-pl-parser.c (totem_pl_parser_class_init),
    	(emit_playlist_ended_signal), (totem_pl_parser_playlist_end),
    	(totem_pl_parser_is_debugging_enabled), (totem_pl_parser_init),
    	(totem_pl_parser_finalize), (emit_entry_parsed_signal),
    	(totem_pl_parser_add_uri_valist),
    	(totem_pl_parser_scheme_is_ignored),
    	(totem_pl_parser_mimetype_is_ignored),
    	(totem_pl_parser_parse_internal), (parse_async_data_free),
    	(parse_thread), (totem_pl_parser_parse_with_base_async),
    	(totem_pl_parser_parse_with_base), (totem_pl_parser_parse_async),
    	(totem_pl_parser_parse_finish),
    	(totem_pl_parser_add_ignored_scheme),
    	(totem_pl_parser_add_ignored_mimetype):
    	* plparse/totem-pl-parser.h: Add asynchronous playlist parsing
    	functions, totem_pl_parser_parse_async, *_parse_with_base_async and
    	totem_pl_parser_parse_finish. This includes making TotemPlParser
    	threadsafe, and ensuring it emits all its signals in the main thread.
    	It also includes refactoring of recursive parsing so that global
    	options are copied and preserved throughout the parse operation,
    	and can't be changed mid-operation from another thread.
    	(Closes: #561444)

 ChangeLog                                   |   64 +++++
 docs/reference/totem-pl-parser-sections.txt |    3 +
 plparse/plparser.symbols                    |    3 +
 plparse/totem-pl-parser-builtins.c          |    1 +
 plparse/totem-pl-parser-lines.c             |   15 +-
 plparse/totem-pl-parser-lines.h             |    4 +
 plparse/totem-pl-parser-media.c             |    9 +-
 plparse/totem-pl-parser-media.h             |    5 +
 plparse/totem-pl-parser-misc.c              |    4 +-
 plparse/totem-pl-parser-misc.h              |    3 +
 plparse/totem-pl-parser-pla.c               |    1 +
 plparse/totem-pl-parser-pla.h               |    2 +
 plparse/totem-pl-parser-pls.c               |   20 +-
 plparse/totem-pl-parser-pls.h               |    5 +-
 plparse/totem-pl-parser-podcast.c           |   19 +-
 plparse/totem-pl-parser-podcast.h           |    8 +
 plparse/totem-pl-parser-private.h           |   17 +-
 plparse/totem-pl-parser-qt.c                |   10 +-
 plparse/totem-pl-parser-qt.h                |    2 +
 plparse/totem-pl-parser-smil.c              |    4 +-
 plparse/totem-pl-parser-smil.h              |    2 +
 plparse/totem-pl-parser-wm.c                |   30 ++-
 plparse/totem-pl-parser-wm.h                |    3 +
 plparse/totem-pl-parser-xspf.c              |    1 +
 plparse/totem-pl-parser-xspf.h              |    2 +
 plparse/totem-pl-parser.c                   |  352 +++++++++++++++++++++++----
 plparse/totem-pl-parser.h                   |   21 ++-
 27 files changed, 504 insertions(+), 106 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 55a69c0..5cbb1cb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,67 @@
+2009-06-17  Philip Withnall  <philip tecnocode co uk>
+
+	* docs/reference/totem-pl-parser-sections.txt:
+	* plparse/plparser.symbols:
+	* plparse/totem-pl-parser-builtins.c
+	(totem_pl_parser_result_get_type):
+	* plparse/totem-pl-parser-lines.c (totem_pl_parser_add_ram),
+	(totem_pl_parser_add_m3u), (totem_pl_parser_add_ra):
+	* plparse/totem-pl-parser-lines.h:
+	* plparse/totem-pl-parser-media.c (totem_pl_parser_add_iso),
+	(totem_pl_parser_add_cue), (totem_pl_parser_add_directory),
+	(totem_pl_parser_add_block):
+	* plparse/totem-pl-parser-media.h:
+	* plparse/totem-pl-parser-misc.c (totem_pl_parser_add_gvp),
+	(totem_pl_parser_add_desktop):
+	* plparse/totem-pl-parser-misc.h:
+	* plparse/totem-pl-parser-pla.c (totem_pl_parser_add_pla):
+	* plparse/totem-pl-parser-pla.h:
+	* plparse/totem-pl-parser-pls.c
+	(totem_pl_parser_add_pls_with_contents), (totem_pl_parser_add_pls):
+	* plparse/totem-pl-parser-pls.h:
+	* plparse/totem-pl-parser-podcast.c (totem_pl_parser_add_rss),
+	(totem_pl_parser_add_itpc), (totem_pl_parser_add_zune),
+	(totem_pl_parser_add_atom), (totem_pl_parser_add_xml_feed),
+	(totem_pl_parser_add_itms), (totem_pl_parser_add_opml):
+	* plparse/totem-pl-parser-podcast.h:
+	* plparse/totem-pl-parser-private.h:
+	* plparse/totem-pl-parser-qt.c
+	(totem_pl_parser_add_quicktime_rtsptext),
+	(totem_pl_parser_add_quicktime_metalink),
+	(totem_pl_parser_add_quicktime):
+	* plparse/totem-pl-parser-qt.h:
+	* plparse/totem-pl-parser-smil.c (totem_pl_parser_add_smil):
+	* plparse/totem-pl-parser-smil.h:
+	* plparse/totem-pl-parser-wm.c
+	(totem_pl_parser_add_asf_reference_parser),
+	(totem_pl_parser_add_asf_parser), (parse_asx_entry),
+	(parse_asx_entryref), (parse_asx_entries),
+	(totem_pl_parser_add_asx), (totem_pl_parser_add_asf):
+	* plparse/totem-pl-parser-wm.h:
+	* plparse/totem-pl-parser-xspf.c (totem_pl_parser_add_xspf):
+	* plparse/totem-pl-parser-xspf.h:
+	* plparse/totem-pl-parser.c (totem_pl_parser_class_init),
+	(emit_playlist_ended_signal), (totem_pl_parser_playlist_end),
+	(totem_pl_parser_is_debugging_enabled), (totem_pl_parser_init),
+	(totem_pl_parser_finalize), (emit_entry_parsed_signal),
+	(totem_pl_parser_add_uri_valist),
+	(totem_pl_parser_scheme_is_ignored),
+	(totem_pl_parser_mimetype_is_ignored),
+	(totem_pl_parser_parse_internal), (parse_async_data_free),
+	(parse_thread), (totem_pl_parser_parse_with_base_async),
+	(totem_pl_parser_parse_with_base), (totem_pl_parser_parse_async),
+	(totem_pl_parser_parse_finish),
+	(totem_pl_parser_add_ignored_scheme),
+	(totem_pl_parser_add_ignored_mimetype):
+	* plparse/totem-pl-parser.h: Add asynchronous playlist parsing
+	functions, totem_pl_parser_parse_async, *_parse_with_base_async and
+	totem_pl_parser_parse_finish. This includes making TotemPlParser
+	threadsafe, and ensuring it emits all its signals in the main thread.
+	It also includes refactoring of recursive parsing so that global
+	options are copied and preserved throughout the parse operation,
+	and can't be changed mid-operation from another thread.
+	(Closes: #561444)
+
 2009-05-31  Philip Withnall  <philip tecnocode co uk>
 
         * docs/reference/Makefile.am: Add the builddir to gtkdoc-mkhtml's
diff --git a/docs/reference/totem-pl-parser-sections.txt b/docs/reference/totem-pl-parser-sections.txt
index 96d8c1c..bab4e35 100644
--- a/docs/reference/totem-pl-parser-sections.txt
+++ b/docs/reference/totem-pl-parser-sections.txt
@@ -9,7 +9,10 @@ TotemPlParserError
 TotemPlParserIterFunc
 totem_pl_parser_new
 totem_pl_parser_parse
+totem_pl_parser_parse_async
+totem_pl_parser_parse_finish
 totem_pl_parser_parse_with_base
+totem_pl_parser_parse_with_base_async
 totem_pl_parser_write
 totem_pl_parser_write_with_title
 totem_pl_parser_parse_duration
diff --git a/plparse/plparser.symbols b/plparse/plparser.symbols
index 180fe64..25572d0 100644
--- a/plparse/plparser.symbols
+++ b/plparse/plparser.symbols
@@ -14,9 +14,12 @@ totem_pl_parser_get_type
 totemplparser_marshal_VOID__STRING_STRING_STRING
 totem_pl_parser_new
 totem_pl_parser_parse
+totem_pl_parser_parse_async
+totem_pl_parser_parse_finish
 totem_pl_parser_parse_date
 totem_pl_parser_parse_duration
 totem_pl_parser_parse_with_base
+totem_pl_parser_parse_with_base_async
 totem_pl_parser_relative
 totem_pl_parser_resolve_uri
 totem_pl_parser_result_get_type
diff --git a/plparse/totem-pl-parser-builtins.c b/plparse/totem-pl-parser-builtins.c
index 40c2b75..f672201 100644
--- a/plparse/totem-pl-parser-builtins.c
+++ b/plparse/totem-pl-parser-builtins.c
@@ -15,6 +15,7 @@ totem_pl_parser_result_get_type (void)
       { TOTEM_PL_PARSER_RESULT_ERROR, "TOTEM_PL_PARSER_RESULT_ERROR", "error" },
       { TOTEM_PL_PARSER_RESULT_SUCCESS, "TOTEM_PL_PARSER_RESULT_SUCCESS", "success" },
       { TOTEM_PL_PARSER_RESULT_IGNORED, "TOTEM_PL_PARSER_RESULT_IGNORED", "ignored" },
+      { TOTEM_PL_PARSER_RESULT_CANCELLED, "TOTEM_PL_PARSER_RESULT_CANCELLED", "cancelled" },
       { 0, NULL, NULL }
     };
     etype = g_enum_register_static ("TotemPlParserResult", values);
diff --git a/plparse/totem-pl-parser-lines.c b/plparse/totem-pl-parser-lines.c
index 96e7074..b114028 100644
--- a/plparse/totem-pl-parser-lines.c
+++ b/plparse/totem-pl-parser-lines.c
@@ -244,7 +244,7 @@ totem_pl_parser_parse_ram_uri (TotemPlParser *parser, const char *uri)
 }
 
 TotemPlParserResult
-totem_pl_parser_add_ram (TotemPlParser *parser, GFile *file, gpointer data)
+totem_pl_parser_add_ram (TotemPlParser *parser, GFile *file, TotemPlParseData *parse_data, gpointer data)
 {
 	gboolean retval = TOTEM_PL_PARSER_RESULT_UNHANDLED;
 	char *contents, **lines;
@@ -271,7 +271,7 @@ totem_pl_parser_add_ram (TotemPlParser *parser, GFile *file, gpointer data)
 
 			line_file = g_file_new_for_uri (lines[i]);
 			/* .ram files can contain .smil entries */
-			if (totem_pl_parser_parse_internal (parser, line_file, NULL) != TOTEM_PL_PARSER_RESULT_SUCCESS)
+			if (totem_pl_parser_parse_internal (parser, line_file, NULL, parse_data) != TOTEM_PL_PARSER_RESULT_SUCCESS)
 				totem_pl_parser_parse_ram_uri (parser, lines[i]);
 			g_object_unref (line_file);
 		} else if (strcmp (lines[i], "--stop--") == 0) {
@@ -338,6 +338,7 @@ TotemPlParserResult
 totem_pl_parser_add_m3u (TotemPlParser *parser,
 			 GFile *file,
 			 GFile *base_file,
+			 TotemPlParseData *parse_data,
 			 gpointer data)
 {
 	TotemPlParserResult retval = TOTEM_PL_PARSER_RESULT_UNHANDLED;
@@ -354,7 +355,7 @@ totem_pl_parser_add_m3u (TotemPlParser *parser,
 	if (g_str_has_prefix (contents, "[playlist]") != FALSE
 			|| g_str_has_prefix (contents, "[Playlist]") != FALSE
 			|| g_str_has_prefix (contents, "[PLAYLIST]") != FALSE) {
-		retval = totem_pl_parser_add_pls_with_contents (parser, file, base_file, contents);
+		retval = totem_pl_parser_add_pls_with_contents (parser, file, base_file, contents, parse_data);
 		g_free (contents);
 		return retval;
 	}
@@ -403,7 +404,7 @@ totem_pl_parser_add_m3u (TotemPlParser *parser,
 			GFile *uri;
 
 			uri = g_file_new_for_commandline_arg (lines[i]);
-			if (totem_pl_parser_parse_internal (parser, uri, NULL) != TOTEM_PL_PARSER_RESULT_SUCCESS) {
+			if (totem_pl_parser_parse_internal (parser, uri, NULL, parse_data) != TOTEM_PL_PARSER_RESULT_SUCCESS) {
 				totem_pl_parser_add_one_uri (parser, lines[i],
 						totem_pl_parser_get_extinfo_title (extinfo));
 			}
@@ -463,14 +464,16 @@ totem_pl_parser_add_m3u (TotemPlParser *parser,
 TotemPlParserResult
 totem_pl_parser_add_ra (TotemPlParser *parser,
 			GFile *file,
-			GFile *base_file, gpointer data)
+			GFile *base_file,
+			TotemPlParseData *parse_data,
+			gpointer data)
 {
 	if (data == NULL || totem_pl_parser_is_uri_list (data, strlen (data)) == NULL) {
 		totem_pl_parser_add_one_file (parser, file, NULL);
 		return TOTEM_PL_PARSER_RESULT_SUCCESS;
 	}
 
-	return totem_pl_parser_add_ram (parser, file, NULL);
+	return totem_pl_parser_add_ram (parser, file, parse_data, NULL);
 }
 
 #endif /* !TOTEM_PL_PARSER_MINI */
diff --git a/plparse/totem-pl-parser-lines.h b/plparse/totem-pl-parser-lines.h
index 9130871..3d7728e 100644
--- a/plparse/totem-pl-parser-lines.h
+++ b/plparse/totem-pl-parser-lines.h
@@ -27,6 +27,7 @@ G_BEGIN_DECLS
 
 #ifndef TOTEM_PL_PARSER_MINI
 #include "totem-pl-parser.h"
+#include "totem-pl-parser-private.h"
 #include <gio/gio.h>
 #else
 #include "totem-pl-parser-mini.h"
@@ -44,14 +45,17 @@ gboolean totem_pl_parser_write_m3u (TotemPlParser *parser,
 				    GError **error);
 TotemPlParserResult totem_pl_parser_add_ram (TotemPlParser *parser,
 					     GFile *file,
+					     TotemPlParseData *parse_data,
 					     gpointer data);
 TotemPlParserResult totem_pl_parser_add_m3u (TotemPlParser *parser,
 					     GFile *file,
 					     GFile *base_file,
+					     TotemPlParseData *parse_data,
 					     gpointer data);
 TotemPlParserResult totem_pl_parser_add_ra (TotemPlParser *parser,
 					    GFile *file,
 					    GFile *base_file,
+					    TotemPlParseData *parse_data,
 					    gpointer data);
 #endif /* !TOTEM_PL_PARSER_MINI */
 
diff --git a/plparse/totem-pl-parser-media.c b/plparse/totem-pl-parser-media.c
index 00cfe0a..935aa72 100644
--- a/plparse/totem-pl-parser-media.c
+++ b/plparse/totem-pl-parser-media.c
@@ -117,6 +117,7 @@ TotemPlParserResult
 totem_pl_parser_add_iso (TotemPlParser *parser,
 			 GFile *file,
 			 GFile *base_file,
+			 TotemPlParseData *parse_data,
 			 gpointer data)
 {
 	TotemDiscMediaType type;
@@ -141,7 +142,9 @@ totem_pl_parser_add_iso (TotemPlParser *parser,
 TotemPlParserResult
 totem_pl_parser_add_cue (TotemPlParser *parser,
 			 GFile *file,
-			 GFile *base_file, gpointer data)
+			 GFile *base_file,
+			 TotemPlParseData *parse_data,
+			 gpointer data)
 {
 	char *vcduri, *path;
 
@@ -224,6 +227,7 @@ TotemPlParserResult
 totem_pl_parser_add_directory (TotemPlParser *parser,
 			       GFile *file,
 			       GFile *base_file,
+			       TotemPlParseData *parse_data,
 			       gpointer data)
 {
 	TotemDiscMediaType type;
@@ -265,7 +269,7 @@ totem_pl_parser_add_directory (TotemPlParser *parser,
 
 		item = g_file_get_child (file, g_file_info_get_name (info));
 
-		ret = totem_pl_parser_parse_internal (parser, item, NULL);
+		ret = totem_pl_parser_parse_internal (parser, item, NULL, parse_data);
 		if (ret != TOTEM_PL_PARSER_RESULT_SUCCESS && ret != TOTEM_PL_PARSER_RESULT_IGNORED) {
 			char *item_uri;
 
@@ -290,6 +294,7 @@ TotemPlParserResult
 totem_pl_parser_add_block (TotemPlParser *parser,
 			   GFile *file,
 			   GFile *base_file,
+			   TotemPlParseData *parse_data,
 			   gpointer data)
 {
 	TotemDiscMediaType type;
diff --git a/plparse/totem-pl-parser-media.h b/plparse/totem-pl-parser-media.h
index db1d0c2..d115b13 100644
--- a/plparse/totem-pl-parser-media.h
+++ b/plparse/totem-pl-parser-media.h
@@ -27,6 +27,7 @@ G_BEGIN_DECLS
 
 #ifndef TOTEM_PL_PARSER_MINI
 #include "totem-pl-parser.h"
+#include "totem-pl-parser-private.h"
 #include <gio/gio.h>
 #endif /* !TOTEM_PL_PARSER_MINI */
 
@@ -34,18 +35,22 @@ G_BEGIN_DECLS
 TotemPlParserResult totem_pl_parser_add_iso (TotemPlParser *parser,
 					     GFile *file,
 					     GFile *base_file,
+					     TotemPlParseData *parse_data,
 					     gpointer data);
 TotemPlParserResult totem_pl_parser_add_cue (TotemPlParser *parser,
 					     GFile *file,
 					     GFile *base_file,
+					     TotemPlParseData *parse_data,
 					     gpointer data);
 TotemPlParserResult totem_pl_parser_add_directory (TotemPlParser *parser,
 						   GFile *file,
 						   GFile *base_file,
+						   TotemPlParseData *parse_data,
 						   gpointer data);
 TotemPlParserResult totem_pl_parser_add_block (TotemPlParser *parser,
 					       GFile *file,
 					       GFile *base_file,
+					       TotemPlParseData *parse_data,
 					       gpointer data);
 #endif /* !TOTEM_PL_PARSER_MINI */
 
diff --git a/plparse/totem-pl-parser-misc.c b/plparse/totem-pl-parser-misc.c
index 36ec824..a65f823 100644
--- a/plparse/totem-pl-parser-misc.c
+++ b/plparse/totem-pl-parser-misc.c
@@ -41,6 +41,7 @@ TotemPlParserResult
 totem_pl_parser_add_gvp (TotemPlParser *parser,
 			 GFile *file,
 			 GFile *base_file,
+			 TotemPlParseData *parse_data,
 			 gpointer data)
 {
 	TotemPlParserResult retval = TOTEM_PL_PARSER_RESULT_UNHANDLED;
@@ -90,6 +91,7 @@ TotemPlParserResult
 totem_pl_parser_add_desktop (TotemPlParser *parser,
 			     GFile *file,
 			     GFile *base_file,
+			     TotemPlParseData *parse_data,
 			     gpointer data)
 {
 	char *contents, **lines;
@@ -124,7 +126,7 @@ totem_pl_parser_add_desktop (TotemPlParser *parser,
 	    && g_ascii_strcasecmp (type, "FSDevice") != 0) {
 		totem_pl_parser_add_one_file (parser, target, display_name);
 	} else {
-		if (totem_pl_parser_parse_internal (parser, target, NULL) != TOTEM_PL_PARSER_RESULT_SUCCESS)
+		if (totem_pl_parser_parse_internal (parser, target, NULL, parse_data) != TOTEM_PL_PARSER_RESULT_SUCCESS)
 			totem_pl_parser_add_one_file (parser, target, display_name);
 	}
 
diff --git a/plparse/totem-pl-parser-misc.h b/plparse/totem-pl-parser-misc.h
index e010c5a..b163695 100644
--- a/plparse/totem-pl-parser-misc.h
+++ b/plparse/totem-pl-parser-misc.h
@@ -27,6 +27,7 @@ G_BEGIN_DECLS
 
 #ifndef TOTEM_PL_PARSER_MINI
 #include "totem-pl-parser.h"
+#include "totem-pl-parser-private.h"
 #include <gio/gio.h>
 #else
 #include "totem-pl-parser-mini.h"
@@ -36,10 +37,12 @@ G_BEGIN_DECLS
 TotemPlParserResult totem_pl_parser_add_gvp (TotemPlParser *parser,
 					     GFile *file,
 					     GFile *base_file,
+					     TotemPlParseData *parse_data,
 					     gpointer data);
 TotemPlParserResult totem_pl_parser_add_desktop (TotemPlParser *parser,
 						 GFile *file,
 						 GFile *base_file,
+						 TotemPlParseData *parse_data,
 						 gpointer data);
 #endif /* !TOTEM_PL_PARSER_MINI */
 
diff --git a/plparse/totem-pl-parser-pla.c b/plparse/totem-pl-parser-pla.c
index 9c4d709..cb4f720 100644
--- a/plparse/totem-pl-parser-pla.c
+++ b/plparse/totem-pl-parser-pla.c
@@ -159,6 +159,7 @@ TotemPlParserResult
 totem_pl_parser_add_pla (TotemPlParser *parser,
 			 GFile *file,
 			 GFile *base_file,
+			 TotemPlParseData *parse_data,
 			 gpointer data)
 {
 	TotemPlParserResult retval = TOTEM_PL_PARSER_RESULT_UNHANDLED;
diff --git a/plparse/totem-pl-parser-pla.h b/plparse/totem-pl-parser-pla.h
index 00b75f3..0f416a4 100644
--- a/plparse/totem-pl-parser-pla.h
+++ b/plparse/totem-pl-parser-pla.h
@@ -27,6 +27,7 @@ G_BEGIN_DECLS
 
 #ifndef TOTEM_PL_PARSER_MINI
 #include "totem-pl-parser.h"
+#include "totem-pl-parser-private.h"
 #include <gio/gio.h>
 #endif /* !TOTEM_PL_PARSER_MINI */
 
@@ -41,6 +42,7 @@ gboolean totem_pl_parser_write_pla				(TotemPlParser *parser,
 TotemPlParserResult totem_pl_parser_add_pla			(TotemPlParser *parser,
 								 GFile *file,
 								 GFile *base_file,
+								 TotemPlParseData *parse_data,
 								 gpointer data);
 #endif /* !TOTEM_PL_PARSER_MINI */
 
diff --git a/plparse/totem-pl-parser-pls.c b/plparse/totem-pl-parser-pls.c
index 52c6ba7..1c8c5e1 100644
--- a/plparse/totem-pl-parser-pls.c
+++ b/plparse/totem-pl-parser-pls.c
@@ -147,7 +147,8 @@ TotemPlParserResult
 totem_pl_parser_add_pls_with_contents (TotemPlParser *parser,
 				       GFile *file,
 				       GFile *_base_file,
-				       const char *contents)
+				       const char *contents,
+				       TotemPlParseData *parse_data)
 {
 	TotemPlParserResult retval = TOTEM_PL_PARSER_RESULT_UNHANDLED;
 	GFile *base_file;
@@ -238,20 +239,20 @@ totem_pl_parser_add_pls_with_contents (TotemPlParser *parser,
 			continue;
 		}
 
-		fallback = parser->priv->fallback;
-		if (parser->priv->recurse)
-			parser->priv->fallback = FALSE;
+		fallback = parse_data->fallback;
+		if (parse_data->recurse)
+			parse_data->fallback = FALSE;
 
 		/* Get the length, if it's negative, that means that we have a stream
 		 * and should push the entry straight away */
 		if (length != NULL)
-			length_num = totem_pl_parser_parse_duration (length, parser->priv->debug);
+			length_num = totem_pl_parser_parse_duration (length, totem_pl_parser_is_debugging_enabled (parser));
 
 		if (strstr (file_str, "://") != NULL || file_str[0] == G_DIR_SEPARATOR) {
 			GFile *target;
 
 			target = g_file_new_for_commandline_arg (file_str);
-			if (length_num < 0 || totem_pl_parser_parse_internal (parser, target, NULL) != TOTEM_PL_PARSER_RESULT_SUCCESS) {
+			if (length_num < 0 || totem_pl_parser_parse_internal (parser, target, NULL, parse_data) != TOTEM_PL_PARSER_RESULT_SUCCESS) {
 				totem_pl_parser_add_uri (parser,
 							 TOTEM_PL_PARSER_FIELD_URI, file_str,
 							 TOTEM_PL_PARSER_FIELD_TITLE, title,
@@ -268,7 +269,7 @@ totem_pl_parser_add_pls_with_contents (TotemPlParser *parser,
 			target = g_file_get_child_for_display_name (base_file, utf8_filename, NULL);
 			g_free (utf8_filename);
 
-			if (length_num < 0 || totem_pl_parser_parse_internal (parser, target, base_file) != TOTEM_PL_PARSER_RESULT_SUCCESS) {
+			if (length_num < 0 || totem_pl_parser_parse_internal (parser, target, base_file, parse_data) != TOTEM_PL_PARSER_RESULT_SUCCESS) {
 				totem_pl_parser_add_uri (parser,
 							 TOTEM_PL_PARSER_FIELD_FILE, target,
 							 TOTEM_PL_PARSER_FIELD_TITLE, title,
@@ -280,7 +281,7 @@ totem_pl_parser_add_pls_with_contents (TotemPlParser *parser,
 			g_object_unref (target);
 		}
 
-		parser->priv->fallback = fallback;
+		parse_data->fallback = fallback;
 		g_free (file_str);
 		g_free (title);
 		g_free (genre);
@@ -303,6 +304,7 @@ TotemPlParserResult
 totem_pl_parser_add_pls (TotemPlParser *parser,
 			 GFile *file,
 			 GFile *base_file,
+			 TotemPlParseData *parse_data,
 			 gpointer data)
 {
 	TotemPlParserResult retval = TOTEM_PL_PARSER_RESULT_UNHANDLED;
@@ -317,7 +319,7 @@ totem_pl_parser_add_pls (TotemPlParser *parser,
 		return TOTEM_PL_PARSER_RESULT_SUCCESS;
 	}
 
-	retval = totem_pl_parser_add_pls_with_contents (parser, file, base_file, contents);
+	retval = totem_pl_parser_add_pls_with_contents (parser, file, base_file, contents, parse_data);
 	g_free (contents);
 
 	return retval;
diff --git a/plparse/totem-pl-parser-pls.h b/plparse/totem-pl-parser-pls.h
index 17bc230..e74b317 100644
--- a/plparse/totem-pl-parser-pls.h
+++ b/plparse/totem-pl-parser-pls.h
@@ -27,6 +27,7 @@ G_BEGIN_DECLS
 
 #ifndef TOTEM_PL_PARSER_MINI
 #include "totem-pl-parser.h"
+#include "totem-pl-parser-private.h"
 #include <gio/gio.h>
 #endif /* !TOTEM_PL_PARSER_MINI */
 
@@ -41,10 +42,12 @@ gboolean totem_pl_parser_write_pls				(TotemPlParser *parser,
 TotemPlParserResult totem_pl_parser_add_pls_with_contents	(TotemPlParser *parser,
 								 GFile *file,
 								 GFile *base_file,
-								 const char *contents);
+								 const char *contents,
+								 TotemPlParseData *parse_data);
 TotemPlParserResult totem_pl_parser_add_pls			(TotemPlParser *parser,
 								 GFile *file,
 								 GFile *base_file,
+								 TotemPlParseData *parse_data,
 								 gpointer data);
 #endif /* !TOTEM_PL_PARSER_MINI */
 
diff --git a/plparse/totem-pl-parser-podcast.c b/plparse/totem-pl-parser-podcast.c
index 2071155..e77252b 100644
--- a/plparse/totem-pl-parser-podcast.c
+++ b/plparse/totem-pl-parser-podcast.c
@@ -233,6 +233,7 @@ TotemPlParserResult
 totem_pl_parser_add_rss (TotemPlParser *parser,
 			 GFile *file,
 			 GFile *base_file,
+			 TotemPlParseData *parse_data,
 			 gpointer data)
 {
 #ifndef HAVE_CAMEL
@@ -285,6 +286,7 @@ TotemPlParserResult
 totem_pl_parser_add_itpc (TotemPlParser *parser,
 			  GFile *file,
 			  GFile *base_file,
+			  TotemPlParseData *parse_data,
 			  gpointer data)
 {
 #ifndef HAVE_CAMEL
@@ -303,7 +305,7 @@ totem_pl_parser_add_itpc (TotemPlParser *parser,
 	new_file = g_file_new_for_uri (new_uri);
 	g_free (new_uri);
 
-	ret = totem_pl_parser_add_rss (parser, new_file, base_file, data);
+	ret = totem_pl_parser_add_rss (parser, new_file, base_file, parse_data, data);
 
 	g_object_unref (new_file);
 
@@ -315,6 +317,7 @@ TotemPlParserResult
 totem_pl_parser_add_zune (TotemPlParser *parser,
 			  GFile *file,
 			  GFile *base_file,
+			  TotemPlParseData *parse_data,
 			  gpointer data)
 {
 #ifndef HAVE_CAMEL
@@ -341,7 +344,7 @@ totem_pl_parser_add_zune (TotemPlParser *parser,
 	new_file = g_file_new_for_uri (new_uri);
 	g_free (uri);
 
-	ret = totem_pl_parser_add_rss (parser, new_file, base_file, data);
+	ret = totem_pl_parser_add_rss (parser, new_file, base_file, parse_data, data);
 
 	g_object_unref (new_file);
 
@@ -483,6 +486,7 @@ TotemPlParserResult
 totem_pl_parser_add_atom (TotemPlParser *parser,
 			  GFile *file,
 			  GFile *base_file,
+			  TotemPlParseData *parse_data,
 			  gpointer data)
 {
 #ifndef HAVE_CAMEL
@@ -524,6 +528,7 @@ TotemPlParserResult
 totem_pl_parser_add_xml_feed (TotemPlParser *parser,
 			      GFile *file,
 			      GFile *base_file,
+			      TotemPlParseData *parse_data,
 			      gpointer data)
 {
 #ifndef HAVE_CAMEL
@@ -537,11 +542,11 @@ totem_pl_parser_add_xml_feed (TotemPlParser *parser,
 	len = strlen (data);
 
 	if (totem_pl_parser_is_rss (data, len) != FALSE)
-		return totem_pl_parser_add_rss (parser, file, base_file, data);
+		return totem_pl_parser_add_rss (parser, file, base_file, parse_data, data);
 	if (totem_pl_parser_is_atom (data, len) != FALSE)
-		return totem_pl_parser_add_atom (parser, file, base_file, data);
+		return totem_pl_parser_add_atom (parser, file, base_file, parse_data, data);
 	if (totem_pl_parser_is_opml (data, len) != FALSE)
-		return totem_pl_parser_add_opml (parser, file, base_file, data);
+		return totem_pl_parser_add_opml (parser, file, base_file, parse_data, data);
 
 	return TOTEM_PL_PARSER_RESULT_UNHANDLED;
 #endif /* !HAVE_CAMEL */
@@ -714,6 +719,7 @@ TotemPlParserResult
 totem_pl_parser_add_itms (TotemPlParser *parser,
 			  GFile *file,
 			  GFile *base_file,
+			  TotemPlParseData *parse_data,
 			  gpointer data)
 {
 #ifndef HAVE_CAMEL
@@ -773,7 +779,7 @@ totem_pl_parser_add_itms (TotemPlParser *parser,
 
 	DEBUG(feed_file, g_print ("Found feed URI: %s\n", uri));
 
-	ret = totem_pl_parser_add_rss (parser, feed_file, NULL, NULL);
+	ret = totem_pl_parser_add_rss (parser, feed_file, NULL, parse_data, NULL);
 	g_object_unref (feed_file);
 
 	return ret;
@@ -874,6 +880,7 @@ TotemPlParserResult
 totem_pl_parser_add_opml (TotemPlParser *parser,
 			  GFile *file,
 			  GFile *base_file,
+			  TotemPlParseData *parse_data,
 			  gpointer data)
 {
 #ifndef HAVE_CAMEL
diff --git a/plparse/totem-pl-parser-podcast.h b/plparse/totem-pl-parser-podcast.h
index 78f5ed5..ba3e592 100644
--- a/plparse/totem-pl-parser-podcast.h
+++ b/plparse/totem-pl-parser-podcast.h
@@ -26,6 +26,7 @@ G_BEGIN_DECLS
 
 #ifndef TOTEM_PL_PARSER_MINI
 #include "totem-pl-parser.h"
+#include "totem-pl-parser-private.h"
 #include <gio/gio.h>
 #else
 #include "totem-pl-parser-mini.h"
@@ -50,30 +51,37 @@ gboolean totem_pl_parser_is_itms_feed (GFile *file);
 TotemPlParserResult totem_pl_parser_add_xml_feed (TotemPlParser *parser,
 						  GFile *file,
 						  GFile *base_file,
+						  TotemPlParseData *parse_data,
 						  gpointer data);
 TotemPlParserResult totem_pl_parser_add_atom (TotemPlParser *parser,
 					      GFile *file,
 					      GFile *base_file,
+					      TotemPlParseData *parse_data,
 					      gpointer data);
 TotemPlParserResult totem_pl_parser_add_rss (TotemPlParser *parser,
 					     GFile *file,
 					     GFile *base_file,
+					     TotemPlParseData *parse_data,
 					     gpointer data);
 TotemPlParserResult totem_pl_parser_add_itpc (TotemPlParser *parser,
 					      GFile *file,
 					      GFile *base_file,
+					      TotemPlParseData *parse_data,
 					      gpointer data);
 TotemPlParserResult totem_pl_parser_add_zune (TotemPlParser *parser,
 					      GFile *file,
 					      GFile *base_file,
+					      TotemPlParseData *parse_data,
 					      gpointer data);
 TotemPlParserResult totem_pl_parser_add_itms (TotemPlParser *parser,
 					      GFile *file,
 					      GFile *base_file,
+					      TotemPlParseData *parse_data,
 					      gpointer data);
 TotemPlParserResult totem_pl_parser_add_opml (TotemPlParser *parser,
 					      GFile *file,
 					      GFile *base_file,
+					      TotemPlParseData *parse_data,
 					      gpointer data);
 
 #endif /* !TOTEM_PL_PARSER_MINI */
diff --git a/plparse/totem-pl-parser-private.h b/plparse/totem-pl-parser-private.h
index 422385b..9070bc4 100644
--- a/plparse/totem-pl-parser-private.h
+++ b/plparse/totem-pl-parser-private.h
@@ -56,7 +56,7 @@
 
 #ifndef TOTEM_PL_PARSER_MINI
 #define DEBUG(file, x) {					\
-	if (parser->priv->debug) {				\
+	if (totem_pl_parser_is_debugging_enabled (parser)) {	\
 		if (file != NULL) {				\
 			char *uri;				\
 								\
@@ -70,27 +70,23 @@
 	}							\
 }
 #else
-#define DEBUG(x) { if (parser->priv->debug) x; }
+#define DEBUG(x) { if (totem_pl_parser_is_debugging_enabled (parser)) x; }
 #endif
 
-struct TotemPlParserPrivate
-{
-	GList *ignore_schemes;
-	GList *ignore_mimetypes;
-
+typedef struct {
 	guint recurse_level;
 	guint fallback : 1;
 	guint recurse : 1;
-	guint debug : 1;
 	guint force : 1;
 	guint disable_unsafe : 1;
-};
+} TotemPlParseData;
 
 #ifndef TOTEM_PL_PARSER_MINI
 char *totem_pl_parser_read_ini_line_string	(char **lines, const char *key);
 int   totem_pl_parser_read_ini_line_int		(char **lines, const char *key);
 char *totem_pl_parser_read_ini_line_string_with_sep (char **lines, const char *key,
 						     const char *sep);
+gboolean totem_pl_parser_is_debugging_enabled	(TotemPlParser *parser);
 char *totem_pl_parser_base_uri			(GFile *file);
 void totem_pl_parser_playlist_end		(TotemPlParser *parser,
 						 const char *playlist_title);
@@ -114,7 +110,8 @@ char * totem_pl_parser_resolve_uri		(GFile *base_gfile,
 						 const char *relative_uri);
 TotemPlParserResult totem_pl_parser_parse_internal (TotemPlParser *parser,
 						    GFile *file,
-						    GFile *base_file);
+						    GFile *base_file,
+						    TotemPlParseData *parse_data);
 void totem_pl_parser_add_one_uri		(TotemPlParser *parser,
 						 const char *uri,
 						 const char *title);
diff --git a/plparse/totem-pl-parser-qt.c b/plparse/totem-pl-parser-qt.c
index e52ea51..4c22501 100644
--- a/plparse/totem-pl-parser-qt.c
+++ b/plparse/totem-pl-parser-qt.c
@@ -69,6 +69,7 @@ static TotemPlParserResult
 totem_pl_parser_add_quicktime_rtsptext (TotemPlParser *parser,
 					GFile *file,
 					GFile *base_file,
+					TotemPlParseData *parse_data,
 					gpointer data)
 {
 	char *contents = NULL;
@@ -114,7 +115,9 @@ totem_pl_parser_add_quicktime_rtsptext (TotemPlParser *parser,
 static TotemPlParserResult
 totem_pl_parser_add_quicktime_metalink (TotemPlParser *parser,
 					GFile *file,
-					GFile *base_file, gpointer data)
+					GFile *base_file,
+					TotemPlParseData *parse_data,
+					gpointer data)
 {
 	xml_node_t *doc, *node;
 	gsize size;
@@ -124,7 +127,7 @@ totem_pl_parser_add_quicktime_metalink (TotemPlParser *parser,
 
 	if (g_str_has_prefix (data, "RTSPtext") != FALSE
 			|| g_str_has_prefix (data, "rtsptext") != FALSE) {
-		return totem_pl_parser_add_quicktime_rtsptext (parser, file, base_file, data);
+		return totem_pl_parser_add_quicktime_rtsptext (parser, file, base_file, parse_data, data);
 	}
 	if (g_str_has_prefix (data, "SMILtext") != FALSE) {
 		char *contents;
@@ -201,12 +204,13 @@ TotemPlParserResult
 totem_pl_parser_add_quicktime (TotemPlParser *parser,
 			       GFile *file,
 			       GFile *base_file,
+			       TotemPlParseData *parse_data,
 			       gpointer data)
 {
 	if (data == NULL || totem_pl_parser_is_quicktime (data, strlen (data)) == NULL)
 		return TOTEM_PL_PARSER_RESULT_UNHANDLED;
 
-	return totem_pl_parser_add_quicktime_metalink (parser, file, base_file, data);
+	return totem_pl_parser_add_quicktime_metalink (parser, file, base_file, parse_data, data);
 }
 
 #endif /* !TOTEM_PL_PARSER_MINI */
diff --git a/plparse/totem-pl-parser-qt.h b/plparse/totem-pl-parser-qt.h
index 2be3293..930cf19 100644
--- a/plparse/totem-pl-parser-qt.h
+++ b/plparse/totem-pl-parser-qt.h
@@ -27,6 +27,7 @@ G_BEGIN_DECLS
 
 #ifndef TOTEM_PL_PARSER_MINI
 #include "totem-pl-parser.h"
+#include "totem-pl-parser-private.h"
 #include <gio/gio.h>
 #else
 #include "totem-pl-parser-mini.h"
@@ -38,6 +39,7 @@ const char * totem_pl_parser_is_quicktime (const char *data, gsize len);
 TotemPlParserResult totem_pl_parser_add_quicktime (TotemPlParser *parser,
 						   GFile *file,
 						   GFile *base_file,
+						   TotemPlParseData *parse_data,
 						   gpointer data);
 #endif /* !TOTEM_PL_PARSER_MINI */
 
diff --git a/plparse/totem-pl-parser-smil.c b/plparse/totem-pl-parser-smil.c
index e2992ee..790a2c2 100644
--- a/plparse/totem-pl-parser-smil.c
+++ b/plparse/totem-pl-parser-smil.c
@@ -172,7 +172,9 @@ totem_pl_parser_add_smil_with_doc (TotemPlParser *parser, GFile *file,
 TotemPlParserResult
 totem_pl_parser_add_smil (TotemPlParser *parser,
 			  GFile *file,
-			  GFile *base_file, gpointer data)
+			  GFile *base_file,
+			  TotemPlParseData *parse_data,
+			  gpointer data)
 {
 	char *contents;
 	gsize size;
diff --git a/plparse/totem-pl-parser-smil.h b/plparse/totem-pl-parser-smil.h
index 07ed194..1e9a6c4 100644
--- a/plparse/totem-pl-parser-smil.h
+++ b/plparse/totem-pl-parser-smil.h
@@ -27,6 +27,7 @@ G_BEGIN_DECLS
 
 #ifndef TOTEM_PL_PARSER_MINI
 #include "totem-pl-parser.h"
+#include "totem-pl-parser-private.h"
 #include <gio/gio.h>
 #else
 #include "totem-pl-parser-mini.h"
@@ -36,6 +37,7 @@ G_BEGIN_DECLS
 TotemPlParserResult totem_pl_parser_add_smil (TotemPlParser *parser,
 					      GFile *file,
 					      GFile *base_file,
+					      TotemPlParseData *parse_data,
 					      gpointer data);
 TotemPlParserResult totem_pl_parser_add_smil_with_data (TotemPlParser *parser,
 							GFile *file,
diff --git a/plparse/totem-pl-parser-wm.c b/plparse/totem-pl-parser-wm.c
index 94d48e6..bbce3bd 100644
--- a/plparse/totem-pl-parser-wm.c
+++ b/plparse/totem-pl-parser-wm.c
@@ -82,6 +82,7 @@ static TotemPlParserResult
 totem_pl_parser_add_asf_reference_parser (TotemPlParser *parser,
 					  GFile *file,
 					  GFile *base_file,
+					  TotemPlParseData *parse_data,
 					  gpointer data)
 {
 	char *contents, **lines, *ref;
@@ -97,7 +98,7 @@ totem_pl_parser_add_asf_reference_parser (TotemPlParser *parser,
 	ref = totem_pl_parser_read_ini_line_string (lines, "Ref1");
 	if (ref == NULL) {
 		g_strfreev (lines);
-		return totem_pl_parser_add_asx (parser, file, base_file, data);
+		return totem_pl_parser_add_asx (parser, file, base_file, parse_data, data);
 	}
 
 	/* change http to mmsh, thanks Microsoft */
@@ -119,6 +120,7 @@ static TotemPlParserResult
 totem_pl_parser_add_asf_parser (TotemPlParser *parser,
 				GFile *file,
 				GFile *base_file,
+				TotemPlParseData *parse_data,
 				gpointer data)
 {
 	TotemPlParserResult retval = TOTEM_PL_PARSER_RESULT_UNHANDLED;
@@ -130,7 +132,7 @@ totem_pl_parser_add_asf_parser (TotemPlParser *parser,
 		return TOTEM_PL_PARSER_RESULT_UNHANDLED;
 
 	if (g_str_has_prefix (data, "ASF ") == FALSE) {
-		return totem_pl_parser_add_asf_reference_parser (parser, file, base_file, data);
+		return totem_pl_parser_add_asf_reference_parser (parser, file, base_file, parse_data, data);
 	}
 
 	if (g_file_load_contents (file, NULL, &contents, &size, NULL, NULL) == FALSE)
@@ -155,7 +157,7 @@ totem_pl_parser_add_asf_parser (TotemPlParser *parser,
 }
 
 static gboolean
-parse_asx_entry (TotemPlParser *parser, GFile *base_file, xml_node_t *parent)
+parse_asx_entry (TotemPlParser *parser, GFile *base_file, xml_node_t *parent, TotemPlParseData *parse_data)
 {
 	xml_node_t *node;
 	TotemPlParserResult retval = TOTEM_PL_PARSER_RESULT_SUCCESS;
@@ -256,7 +258,7 @@ parse_asx_entry (TotemPlParser *parser, GFile *base_file, xml_node_t *parent)
 	g_free (resolved_uri);
 
 	/* .asx files can contain references to other .asx files */
-	retval = totem_pl_parser_parse_internal (parser, resolved, NULL);
+	retval = totem_pl_parser_parse_internal (parser, resolved, NULL, parse_data);
 	if (retval != TOTEM_PL_PARSER_RESULT_SUCCESS) {
 		totem_pl_parser_add_uri (parser,
 					 TOTEM_PL_PARSER_FIELD_FILE, resolved,
@@ -277,7 +279,7 @@ bail:
 }
 
 static gboolean
-parse_asx_entryref (TotemPlParser *parser, GFile *base_file, xml_node_t *node)
+parse_asx_entryref (TotemPlParser *parser, GFile *base_file, xml_node_t *node, TotemPlParseData *parse_data)
 {
 	TotemPlParserResult retval = TOTEM_PL_PARSER_RESULT_SUCCESS;
 	const char *uri;
@@ -294,7 +296,7 @@ parse_asx_entryref (TotemPlParser *parser, GFile *base_file, xml_node_t *node)
 	g_free (resolved_uri);
 
 	/* .asx files can contain references to other .asx files */
-	retval = totem_pl_parser_parse_internal (parser, resolved, NULL);
+	retval = totem_pl_parser_parse_internal (parser, resolved, NULL, parse_data);
 	if (retval != TOTEM_PL_PARSER_RESULT_SUCCESS) {
 		totem_pl_parser_add_uri (parser,
 					 TOTEM_PL_PARSER_FIELD_FILE, resolved,
@@ -308,7 +310,7 @@ parse_asx_entryref (TotemPlParser *parser, GFile *base_file, xml_node_t *node)
 
 //FIXME the retval is completely wrong
 static gboolean
-parse_asx_entries (TotemPlParser *parser, const char *uri, GFile *base_file, xml_node_t *parent)
+parse_asx_entries (TotemPlParser *parser, const char *uri, GFile *base_file, xml_node_t *parent, TotemPlParseData *parse_data)
 {
 	char *title = NULL;
 	GFile *new_base;
@@ -341,17 +343,17 @@ parse_asx_entries (TotemPlParser *parser, const char *uri, GFile *base_file, xml
 		}
 		if (g_ascii_strcasecmp (node->name, "entry") == 0) {
 			/* Whee! found an entry here, find the REF and TITLE */
-			if (parse_asx_entry (parser, new_base ? new_base : base_file, node) != FALSE)
+			if (parse_asx_entry (parser, new_base ? new_base : base_file, node, parse_data) != FALSE)
 				retval = TOTEM_PL_PARSER_RESULT_SUCCESS;
 		}
 		if (g_ascii_strcasecmp (node->name, "entryref") == 0) {
 			/* Found an entryref, extract the REF attribute */
-			if (parse_asx_entryref (parser, new_base ? new_base : base_file, node) != FALSE)
+			if (parse_asx_entryref (parser, new_base ? new_base : base_file, node, parse_data) != FALSE)
 				retval = TOTEM_PL_PARSER_RESULT_SUCCESS;
 		}
 		if (g_ascii_strcasecmp (node->name, "repeat") == 0) {
 			/* Repeat at the top-level */
-			if (parse_asx_entries (parser, uri, new_base ? new_base : base_file, node) != FALSE)
+			if (parse_asx_entries (parser, uri, new_base ? new_base : base_file, node, parse_data) != FALSE)
 				retval = TOTEM_PL_PARSER_RESULT_SUCCESS;
 		}
 	}
@@ -369,6 +371,7 @@ TotemPlParserResult
 totem_pl_parser_add_asx (TotemPlParser *parser,
 			 GFile *file,
 			 GFile *base_file,
+			 TotemPlParseData *parse_data,
 			 gpointer data)
 {
 	xml_node_t* doc;
@@ -377,7 +380,7 @@ totem_pl_parser_add_asx (TotemPlParser *parser,
 	TotemPlParserResult retval = TOTEM_PL_PARSER_RESULT_UNHANDLED;
 
 	if (data != NULL && totem_pl_parser_is_uri_list (data, strlen (data)) != FALSE) {
-		return totem_pl_parser_add_ram (parser, file, data);
+		return totem_pl_parser_add_ram (parser, file, parse_data, data);
 	}
 
 	if (g_file_load_contents (file, NULL, &contents, &size, NULL, NULL) == FALSE)
@@ -399,7 +402,7 @@ totem_pl_parser_add_asx (TotemPlParser *parser,
 
 	uri = g_file_get_uri (file);
 
-	if (parse_asx_entries (parser, uri, base_file, doc) != FALSE)
+	if (parse_asx_entries (parser, uri, base_file, doc, parse_data) != FALSE)
 		retval = TOTEM_PL_PARSER_RESULT_SUCCESS;
 
 	g_free (uri);
@@ -413,6 +416,7 @@ TotemPlParserResult
 totem_pl_parser_add_asf (TotemPlParser *parser,
 			 GFile *file,
 			 GFile *base_file,
+			 TotemPlParseData *parse_data,
 			 gpointer data)
 {
 	if (data == NULL) {
@@ -425,7 +429,7 @@ totem_pl_parser_add_asf (TotemPlParser *parser,
 		return TOTEM_PL_PARSER_RESULT_SUCCESS;
 	}
 
-	return totem_pl_parser_add_asf_parser (parser, file, base_file, data);
+	return totem_pl_parser_add_asf_parser (parser, file, base_file, parse_data, data);
 }
 
 #endif /* !TOTEM_PL_PARSER_MINI */
diff --git a/plparse/totem-pl-parser-wm.h b/plparse/totem-pl-parser-wm.h
index 658b7a9..5643d10 100644
--- a/plparse/totem-pl-parser-wm.h
+++ b/plparse/totem-pl-parser-wm.h
@@ -27,6 +27,7 @@ G_BEGIN_DECLS
 
 #ifndef TOTEM_PL_PARSER_MINI
 #include "totem-pl-parser.h"
+#include "totem-pl-parser-private.h"
 #include <gio/gio.h>
 #else
 #include "totem-pl-parser-mini.h"
@@ -39,10 +40,12 @@ const char * totem_pl_parser_is_asx (const char *data, gsize len);
 TotemPlParserResult totem_pl_parser_add_asf (TotemPlParser *parser,
 					     GFile *file,
 					     GFile *base_file,
+					     TotemPlParseData *parse_data,
 					     gpointer data);
 TotemPlParserResult totem_pl_parser_add_asx (TotemPlParser *parser,
 					     GFile *file,
 					     GFile *base_file,
+					     TotemPlParseData *parse_data,
 					     gpointer data);
 #endif /* !TOTEM_PL_PARSER_MINI */
 
diff --git a/plparse/totem-pl-parser-xspf.c b/plparse/totem-pl-parser-xspf.c
index 434b095..753e06e 100644
--- a/plparse/totem-pl-parser-xspf.c
+++ b/plparse/totem-pl-parser-xspf.c
@@ -294,6 +294,7 @@ TotemPlParserResult
 totem_pl_parser_add_xspf (TotemPlParser *parser,
 			  GFile *file,
 			  GFile *base_file,
+			  TotemPlParseData *parse_data,
 			  gpointer data)
 {
 	xmlDocPtr doc;
diff --git a/plparse/totem-pl-parser-xspf.h b/plparse/totem-pl-parser-xspf.h
index 85e4c5f..e1717f4 100644
--- a/plparse/totem-pl-parser-xspf.h
+++ b/plparse/totem-pl-parser-xspf.h
@@ -27,6 +27,7 @@ G_BEGIN_DECLS
 
 #ifndef TOTEM_PL_PARSER_MINI
 #include "totem-pl-parser.h"
+#include "totem-pl-parser-private.h"
 #include <gio/gio.h>
 #endif /* !TOTEM_PL_PARSER_MINI */
 
@@ -41,6 +42,7 @@ gboolean totem_pl_parser_write_xspf (TotemPlParser *parser,
 TotemPlParserResult totem_pl_parser_add_xspf (TotemPlParser *parser,
 					      GFile *file,
 					      GFile *base_file,
+					      TotemPlParseData *parse_data,
 					      gpointer data);
 #endif /* !TOTEM_PL_PARSER_MINI */
 
diff --git a/plparse/totem-pl-parser.c b/plparse/totem-pl-parser.c
index bbb5cf6..45924ff 100644
--- a/plparse/totem-pl-parser.c
+++ b/plparse/totem-pl-parser.c
@@ -1,4 +1,4 @@
-/* 
+/*
    Copyright (C) 2002, 2003, 2004, 2005, 2006 Bastien Nocera
    Copyright (C) 2003, 2004 Colin Walters <walters rhythmbox org>
 
@@ -139,7 +139,7 @@
 typedef const char * (*PlaylistIdenCallback) (const char *data, gsize len);
 
 #ifndef TOTEM_PL_PARSER_MINI
-typedef TotemPlParserResult (*PlaylistCallback) (TotemPlParser *parser, GFile *uri, GFile *base_file, gpointer data);
+typedef TotemPlParserResult (*PlaylistCallback) (TotemPlParser *parser, GFile *uri, GFile *base_file, TotemPlParseData *parse_data, gpointer data);
 #endif
 
 typedef struct {
@@ -226,6 +226,17 @@ static void totem_pl_parser_get_property (GObject *object,
 					  GValue *value,
 					  GParamSpec *pspec);
 
+struct TotemPlParserPrivate {
+	GList *ignore_schemes;
+	GList *ignore_mimetypes;
+	GMutex *ignore_mutex;
+
+	guint recurse : 1;
+	guint debug : 1;
+	guint force : 1;
+	guint disable_unsafe : 1;
+};
+
 enum {
 	PROP_NONE,
 	PROP_RECURSE,
@@ -255,6 +266,8 @@ static void totem_pl_parser_init       (TotemPlParser      *self);
 static void totem_pl_parser_class_init (TotemPlParserClass *klass);
 static gpointer totem_pl_parser_parent_class = NULL;
 
+#define TOTEM_PL_PARSER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TOTEM_TYPE_PL_PARSER, TotemPlParserPrivate))
+
 GType
 totem_pl_parser_get_type (void)
 {
@@ -272,10 +285,10 @@ totem_pl_parser_get_type (void)
 			0,
 			(GInstanceInitFunc) totem_pl_parser_init,
 		};
-		GType g_define_type_id = g_type_register_static (G_TYPE_OBJECT, "TotemPlParser", &g_define_type_info, 0); 
+		GType g_define_type_id = g_type_register_static (G_TYPE_OBJECT, "TotemPlParser", &g_define_type_info, 0);
 		g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
-	} 
-	return g_define_type_id__volatile; 
+	}
+	return g_define_type_id__volatile;
 }
 
 static void
@@ -285,6 +298,9 @@ totem_pl_parser_class_init (TotemPlParserClass *klass)
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
 	totem_pl_parser_parent_class = g_type_class_peek_parent (klass);
+	if (!g_thread_supported ())
+		g_thread_init (NULL);
+
 	g_type_class_add_private (klass, sizeof (TotemPlParserPrivate));
 
 	object_class->finalize = totem_pl_parser_finalize;
@@ -303,7 +319,7 @@ totem_pl_parser_class_init (TotemPlParserClass *klass)
 					 PROP_RECURSE,
 					 g_param_spec_boolean ("recurse",
 							       "recurse",
-							       "Whether or not to process URIs further", 
+							       "Whether or not to process URIs further",
 							       TRUE,
 							       G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
@@ -316,7 +332,7 @@ totem_pl_parser_class_init (TotemPlParserClass *klass)
 					 PROP_DEBUG,
 					 g_param_spec_boolean ("debug",
 							       "debug",
-							       "Whether or not to enable debugging output", 
+							       "Whether or not to enable debugging output",
 							       FALSE,
 							       G_PARAM_READWRITE));
 
@@ -330,7 +346,7 @@ totem_pl_parser_class_init (TotemPlParserClass *klass)
 					 PROP_FORCE,
 					 g_param_spec_boolean ("force",
 							       "force",
-							       "Whether or not to force parsing the file if the playlist looks unsupported", 
+							       "Whether or not to force parsing the file if the playlist looks unsupported",
 							       FALSE,
 							       G_PARAM_READWRITE));
 
@@ -345,7 +361,7 @@ totem_pl_parser_class_init (TotemPlParserClass *klass)
 					 PROP_DISABLE_UNSAFE,
 					 g_param_spec_boolean ("disable-unsafe",
 							       "disable-unsafe",
-							       "Whether or not to disable parsing of unsafe locations", 
+							       "Whether or not to disable parsing of unsafe locations",
 							       FALSE,
 							       G_PARAM_READWRITE));
 
@@ -625,6 +641,26 @@ totem_pl_parser_new (void)
 	return TOTEM_PL_PARSER (g_object_new (TOTEM_TYPE_PL_PARSER, NULL));
 }
 
+typedef struct {
+	TotemPlParser *parser;
+	char *playlist_uri;
+} PlaylistEndedSignalData;
+
+static gboolean
+emit_playlist_ended_signal (PlaylistEndedSignalData *data)
+{
+	g_signal_emit (data->parser,
+		       totem_pl_parser_table_signals[PLAYLIST_ENDED],
+		       0, data->playlist_uri);
+
+	/* Free the data */
+	g_object_unref (data->parser);
+	g_free (data->playlist_uri);
+	g_free (data);
+
+	return FALSE;
+}
+
 /**
  * totem_pl_parser_playlist_end:
  * @parser: a #TotemPlParser
@@ -636,9 +672,13 @@ totem_pl_parser_new (void)
 void
 totem_pl_parser_playlist_end (TotemPlParser *parser, const char *playlist_uri)
 {
-	g_signal_emit (G_OBJECT (parser),
-		       totem_pl_parser_table_signals[PLAYLIST_ENDED],
-		       0, playlist_uri);
+	PlaylistEndedSignalData *data;
+
+	data = g_new (PlaylistEndedSignalData, 1);
+	data->parser = g_object_ref (parser);
+	data->playlist_uri = g_strdup (playlist_uri);
+
+	g_idle_add ((GSourceFunc) emit_playlist_ended_signal, data);
 }
 
 static char *
@@ -704,6 +744,20 @@ my_g_file_info_get_mime_type_with_data (GFile *file, gpointer *data, TotemPlPars
 }
 
 /**
+ * totem_pl_parser_is_debugging_enabled:
+ * @parser: a #TotemPlParser
+ *
+ * Returns whether debugging is enabled. This is a private method, not exposed by the library.
+ *
+ * Return value: %TRUE if debugging is enabled, %FALSE otherwise
+ **/
+gboolean
+totem_pl_parser_is_debugging_enabled (TotemPlParser *parser)
+{
+	return parser->priv->debug;
+}
+
+/**
  * totem_pl_parser_base_uri:
  * @uri: a URI
  *
@@ -1209,25 +1263,49 @@ static void
 totem_pl_parser_init (TotemPlParser *parser)
 {
 	parser->priv = G_TYPE_INSTANCE_GET_PRIVATE (parser, TOTEM_TYPE_PL_PARSER, TotemPlParserPrivate);
+	parser->priv->ignore_mutex = g_mutex_new ();
 }
 
 static void
 totem_pl_parser_finalize (GObject *object)
 {
-	TotemPlParser *parser = TOTEM_PL_PARSER (object);
+	TotemPlParserPrivate *priv = TOTEM_PL_PARSER (object)->priv;
 
 	g_return_if_fail (object != NULL);
-	g_return_if_fail (parser->priv != NULL);
+	g_return_if_fail (priv != NULL);
 
-	g_list_foreach (parser->priv->ignore_schemes, (GFunc) g_free, NULL);
-	g_list_free (parser->priv->ignore_schemes);
+	g_list_foreach (priv->ignore_schemes, (GFunc) g_free, NULL);
+	g_list_free (priv->ignore_schemes);
 
-	g_list_foreach (parser->priv->ignore_mimetypes, (GFunc) g_free, NULL);
-	g_list_free (parser->priv->ignore_mimetypes);
+	g_list_foreach (priv->ignore_mimetypes, (GFunc) g_free, NULL);
+	g_list_free (priv->ignore_mimetypes);
+
+	g_mutex_free (priv->ignore_mutex);
 
 	G_OBJECT_CLASS (totem_pl_parser_parent_class)->finalize (object);
 }
 
+typedef struct {
+	TotemPlParser *parser;
+	guint signal_id;
+	char *uri;
+	GHashTable *metadata;
+} EntryParsedSignalData;
+
+static gboolean
+emit_entry_parsed_signal (EntryParsedSignalData *data)
+{
+	g_signal_emit (data->parser, data->signal_id, 0, data->uri, data->metadata);
+
+	/* Free the data */
+	g_object_unref (data->parser);
+	g_free (data->uri);
+	g_hash_table_unref (data->metadata);
+	g_free (data);
+
+	return FALSE;
+}
+
 static void
 totem_pl_parser_add_uri_valist (TotemPlParser *parser,
 				const gchar *first_property_name,
@@ -1340,15 +1418,21 @@ totem_pl_parser_add_uri_valist (TotemPlParser *parser,
 	}
 
 	if (g_hash_table_size (metadata) > 0 || uri != NULL) {
-		if (is_playlist == FALSE) {
-			g_signal_emit (G_OBJECT (parser),
-				       totem_pl_parser_table_signals[ENTRY_PARSED],
-				       0, uri, metadata);
-		} else {
-			g_signal_emit (G_OBJECT (parser),
-				       totem_pl_parser_table_signals[PLAYLIST_STARTED],
-				       0, uri, metadata);
-		}
+		EntryParsedSignalData *data;
+
+		/* Make sure to emit the signals asynchronously, as we could be in the main loop
+		 * *or* a worker thread at this point. */
+		data = g_new (EntryParsedSignalData, 1);
+		data->parser = g_object_ref (parser);
+		data->uri = g_strdup (uri);
+		data->metadata = g_hash_table_ref (metadata);
+
+		if (is_playlist == FALSE)
+			data->signal_id = totem_pl_parser_table_signals[ENTRY_PARSED];
+		else
+			data->signal_id = totem_pl_parser_table_signals[PLAYLIST_STARTED];
+
+		g_idle_add ((GSourceFunc) emit_entry_parsed_signal, data);
 	}
 
 	g_hash_table_unref (metadata);
@@ -1427,15 +1511,23 @@ totem_pl_parser_scheme_is_ignored (TotemPlParser *parser, GFile *uri)
 {
 	GList *l;
 
-	if (parser->priv->ignore_schemes == NULL)
+	g_mutex_lock (parser->priv->ignore_mutex);
+
+	if (parser->priv->ignore_schemes == NULL) {
+		g_mutex_unlock (parser->priv->ignore_mutex);
 		return FALSE;
+	}
 
 	for (l = parser->priv->ignore_schemes; l != NULL; l = l->next) {
 		const char *scheme = l->data;
-		if (g_file_has_uri_scheme (uri, scheme) != FALSE)
+		if (g_file_has_uri_scheme (uri, scheme) != FALSE) {
+			g_mutex_unlock (parser->priv->ignore_mutex);
 			return TRUE;
+		}
 	}
 
+	g_mutex_unlock (parser->priv->ignore_mutex);
+
 	return FALSE;
 }
 
@@ -1445,16 +1537,24 @@ totem_pl_parser_mimetype_is_ignored (TotemPlParser *parser,
 {
 	GList *l;
 
-	if (parser->priv->ignore_mimetypes == NULL)
+	g_mutex_lock (parser->priv->ignore_mutex);
+
+	if (parser->priv->ignore_mimetypes == NULL) {
+		g_mutex_unlock (parser->priv->ignore_mutex);
 		return FALSE;
+	}
 
 	for (l = parser->priv->ignore_mimetypes; l != NULL; l = l->next)
 	{
 		const char *item = l->data;
-		if (strcmp (mimetype, item) == 0)
+		if (strcmp (mimetype, item) == 0) {
+			g_mutex_unlock (parser->priv->ignore_mutex);
 			return TRUE;
+		}
 	}
 
+	g_mutex_unlock (parser->priv->ignore_mutex);
+
 	return FALSE;
 }
 
@@ -1610,7 +1710,8 @@ totem_pl_parser_ignore_from_mimetype (TotemPlParser *parser, const char *mimetyp
 TotemPlParserResult
 totem_pl_parser_parse_internal (TotemPlParser *parser,
 				GFile *file,
-				GFile *base_file)
+				GFile *base_file,
+				TotemPlParseData *parse_data)
 {
 	char *mimetype;
 	guint i;
@@ -1618,7 +1719,7 @@ totem_pl_parser_parse_internal (TotemPlParser *parser,
 	TotemPlParserResult ret = TOTEM_PL_PARSER_RESULT_UNHANDLED;
 	gboolean found = FALSE;
 
-	if (parser->priv->recurse_level > RECURSE_LEVEL_MAX)
+	if (parse_data->recurse_level > RECURSE_LEVEL_MAX)
 		return TOTEM_PL_PARSER_RESULT_ERROR;
 
 	if (g_file_has_uri_scheme (file, "mms") != FALSE
@@ -1637,23 +1738,23 @@ totem_pl_parser_parse_internal (TotemPlParser *parser,
 	    || g_file_has_uri_scheme (file, "feed") != FALSE
 	    || g_file_has_uri_scheme (file, "zcast") != FALSE) {
 		DEBUG(file, g_print ("URI '%s' is getting special cased for ITPC/FEED/ZCAST parsing\n", uri));
-		return totem_pl_parser_add_itpc (parser, file, base_file, NULL);
+		return totem_pl_parser_add_itpc (parser, file, base_file, parse_data, NULL);
 	}
 	if (g_file_has_uri_scheme (file, "zune") != FALSE) {
 		DEBUG(file, g_print ("URI '%s' is getting special cased for ZUNE parsing\n", uri));
-		return totem_pl_parser_add_zune (parser, file, base_file, NULL);
+		return totem_pl_parser_add_zune (parser, file, base_file, parse_data, NULL);
 	}
 	/* Try itms Podcast references, see itunes.py in PenguinTV */
 	if (totem_pl_parser_is_itms_feed (file) != FALSE) {
-	    	DEBUG(file, g_print ("URI '%s' is getting special cased for ITMS parsing\n", uri));
-	    	return totem_pl_parser_add_itms (parser, file, NULL, NULL);
+		DEBUG(file, g_print ("URI '%s' is getting special cased for ITMS parsing\n", uri));
+		return totem_pl_parser_add_itms (parser, file, NULL, parse_data, NULL);
 	}
 
-	if (!parser->priv->recurse && parser->priv->recurse_level > 0)
+	if (!parse_data->recurse && parse_data->recurse_level > 0)
 		return TOTEM_PL_PARSER_RESULT_UNHANDLED;
 
 	/* In force mode we want to get the data */
-	if (parser->priv->force != FALSE) {
+	if (parse_data->force != FALSE) {
 		mimetype = my_g_file_info_get_mime_type_with_data (file, &data, parser);
 	} else {
 		char *uri;
@@ -1700,7 +1801,7 @@ totem_pl_parser_parse_internal (TotemPlParser *parser,
 
 	/* If we're at the top-level of the parsing, try to get more
 	 * data from the playlist parser */
-	if (strcmp (mimetype, AUDIO_MPEG_TYPE) == 0 && parser->priv->recurse_level == 0 && data == NULL) {
+	if (strcmp (mimetype, AUDIO_MPEG_TYPE) == 0 && parse_data->recurse_level == 0 && data == NULL) {
 		char *tmp;
 		tmp = my_g_file_info_get_mime_type_with_data (file, &data, parser);
 		if (tmp != NULL) {
@@ -1716,13 +1817,13 @@ totem_pl_parser_parse_internal (TotemPlParser *parser,
 		return TOTEM_PL_PARSER_RESULT_IGNORED;
 	}
 
-	if (parser->priv->recurse || parser->priv->recurse_level == 0) {
-		parser->priv->recurse_level++;
+	if (parse_data->recurse || parse_data->recurse_level == 0) {
+		parse_data->recurse_level++;
 
 		for (i = 0; i < G_N_ELEMENTS(special_types); i++) {
 			if (strcmp (special_types[i].mimetype, mimetype) == 0) {
 				DEBUG(file, g_print ("URI '%s' is special type '%s'\n", uri, mimetype));
-				if (parser->priv->disable_unsafe != FALSE && special_types[i].unsafe != FALSE) {
+				if (parse_data->disable_unsafe != FALSE && special_types[i].unsafe != FALSE) {
 					DEBUG(file, g_print ("URI '%s' is unsafe so was ignored\n", uri));
 					g_free (mimetype);
 					g_free (data);
@@ -1734,7 +1835,7 @@ totem_pl_parser_parse_internal (TotemPlParser *parser,
 					base_file = g_object_ref (base_file);
 
 				DEBUG (file, g_print ("Using %s function for '%s'\n", special_types[i].mimetype, uri));
-				ret = (* special_types[i].func) (parser, file, base_file, data);
+				ret = (* special_types[i].func) (parser, file, base_file, parse_data, data);
 
 				if (base_file != NULL)
 					g_object_unref (base_file);
@@ -1762,7 +1863,7 @@ totem_pl_parser_parse_internal (TotemPlParser *parser,
 				else
 					base_file = g_object_ref (base_file);
 
-				ret = (* dual_types[i].func) (parser, file, base_file ? base_file : file, data);
+				ret = (* dual_types[i].func) (parser, file, base_file ? base_file : file, parse_data, data);
 
 				if (base_file != NULL)
 					g_object_unref (base_file);
@@ -1774,7 +1875,7 @@ totem_pl_parser_parse_internal (TotemPlParser *parser,
 
 		g_free (data);
 
-		parser->priv->recurse_level--;
+		parse_data->recurse_level--;
 	}
 
 	if (ret == TOTEM_PL_PARSER_RESULT_SUCCESS) {
@@ -1788,7 +1889,7 @@ totem_pl_parser_parse_internal (TotemPlParser *parser,
 	}
 	g_free (mimetype);
 
-	if (ret != TOTEM_PL_PARSER_RESULT_SUCCESS && parser->priv->fallback) {
+	if (ret != TOTEM_PL_PARSER_RESULT_SUCCESS && parse_data->fallback) {
 		totem_pl_parser_add_one_file (parser, file, NULL);
 		return TOTEM_PL_PARSER_RESULT_SUCCESS;
 	}
@@ -1796,6 +1897,81 @@ totem_pl_parser_parse_internal (TotemPlParser *parser,
 	return ret;
 }
 
+typedef struct {
+	char *uri;
+	char *base;
+	gboolean fallback;
+} ParseAsyncData;
+
+static void
+parse_async_data_free (ParseAsyncData *data)
+{
+	g_free (data->uri);
+	g_free (data->base);
+	g_slice_free (ParseAsyncData, data);
+}
+
+static void
+parse_thread (GSimpleAsyncResult *result, GObject *object, GCancellable *cancellable)
+{
+	TotemPlParserResult parse_result;
+	GError *error = NULL;
+	ParseAsyncData *data = g_simple_async_result_get_op_res_gpointer (result);
+
+	/* Check to see if it's been cancelled already */
+	if (g_cancellable_set_error_if_cancelled (cancellable, &error) == TRUE) {
+		g_simple_async_result_set_from_error (result, error);
+		g_simple_async_result_set_op_res_gpointer (result, GUINT_TO_POINTER (TOTEM_PL_PARSER_RESULT_CANCELLED), NULL);
+		g_error_free (error);
+		return;
+	}
+
+	/* Parse and return */
+	parse_result = totem_pl_parser_parse_with_base (TOTEM_PL_PARSER (object), data->uri, data->base, data->fallback);
+	g_simple_async_result_set_op_res_gpointer (result, GUINT_TO_POINTER (parse_result), NULL);
+}
+
+/**
+ * totem_pl_parser_parse_with_base_async:
+ * @parser: a #TotemPlParser
+ * @uri: the URI of the playlist to parse
+ * @base: the base path for relative filenames
+ * @fallback: %TRUE if the parser should add the playlist URI to the
+ * end of the playlist on parse failure
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when parsing is finished
+ * @user_data: data to pass to the @callback function
+ *
+ * Starts asynchronous parsing of a playlist given by the absolute URI @uri, using @base to resolve relative paths where appropriate.
+ * @self and @uri are both reffed/copied when this function is called, so can safely be freed after this function returns.
+ *
+ * For more details, see totem_pl_parser_parse_with_base(), which is the synchronous version of this function.
+ *
+ * When the operation is finished, @callback will be called. You can then call totem_pl_parser_parse_finish()
+ * to get the results of the operation.
+ **/
+void
+totem_pl_parser_parse_with_base_async (TotemPlParser *parser, const char *uri, const char *base, gboolean fallback,
+				       GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	GSimpleAsyncResult *result;
+	ParseAsyncData *data;
+
+	g_return_if_fail (TOTEM_IS_PL_PARSER (parser));
+	g_return_if_fail (uri != NULL);
+	g_return_if_fail (strstr (uri, "://") != NULL);
+
+	data = g_slice_new (ParseAsyncData);
+	data->uri = g_strdup (uri);
+	data->base = g_strdup (base);
+	data->fallback = fallback;
+
+	result = g_simple_async_result_new (G_OBJECT (parser), callback, user_data, totem_pl_parser_parse_with_base_async);
+	g_simple_async_result_set_op_res_gpointer (result, data, (GDestroyNotify) parse_async_data_free);
+	g_simple_async_result_run_in_thread (result, (GSimpleAsyncThreadFunc) parse_thread, G_PRIORITY_DEFAULT, cancellable);
+	g_object_unref (result);
+}
+
 /**
  * totem_pl_parser_parse_with_base:
  * @parser: a #TotemPlParser
@@ -1815,6 +1991,7 @@ totem_pl_parser_parse_with_base (TotemPlParser *parser, const char *uri,
 {
 	GFile *file, *base_file;
 	TotemPlParserResult retval;
+	TotemPlParseData data;
 
 	g_return_val_if_fail (TOTEM_IS_PL_PARSER (parser), TOTEM_PL_PARSER_RESULT_UNHANDLED);
 	g_return_val_if_fail (uri != NULL, TOTEM_PL_PARSER_RESULT_UNHANDLED);
@@ -1829,11 +2006,16 @@ totem_pl_parser_parse_with_base (TotemPlParser *parser, const char *uri,
 		return TOTEM_PL_PARSER_RESULT_UNHANDLED;
 	}
 
-	parser->priv->recurse_level = 0;
-	parser->priv->fallback = fallback != FALSE;
+	/* Use a struct to store copies of the options as set for this parse operation */
+	data.recurse_level = 0;
+	data.fallback = fallback;
+	data.recurse = parser->priv->recurse;
+	data.force = parser->priv->force;
+	data.disable_unsafe = parser->priv->disable_unsafe;
+
 	if (base != NULL)
 		base_file = g_file_new_for_uri (base);
-	retval = totem_pl_parser_parse_internal (parser, file, base_file);
+	retval = totem_pl_parser_parse_internal (parser, file, base_file, &data);
 
 	g_object_unref (file);
 	if (base_file != NULL)
@@ -1843,13 +2025,71 @@ totem_pl_parser_parse_with_base (TotemPlParser *parser, const char *uri,
 }
 
 /**
+ * totem_pl_parser_parse_async:
+ * @parser: a #TotemPlParser
+ * @uri: the URI of the playlist to parse
+ * @fallback: %TRUE if the parser should add the playlist URI to the
+ * end of the playlist on parse failure
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when parsing is finished
+ * @user_data: data to pass to the @callback function
+ *
+ * Starts asynchronous parsing of a playlist given by the absolute URI @uri. @self and @uri are both reffed/copied
+ * when this function is called, so can safely be freed after this function returns.
+ *
+ * For more details, see totem_pl_parser_parse(), which is the synchronous version of this function.
+ *
+ * When the operation is finished, @callback will be called. You can then call totem_pl_parser_parse_finish()
+ * to get the results of the operation.
+ **/
+void
+totem_pl_parser_parse_async (TotemPlParser *parser, const char *uri, gboolean fallback,
+			     GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	totem_pl_parser_parse_with_base_async (parser, uri, NULL, fallback, cancellable, callback, user_data);
+}
+
+/**
+ * totem_pl_parser_parse_finish:
+ * @parser: a #TotemPlParser
+ * @async_result: a #GAsyncResult
+ * @error: a #GError, or %NULL
+ *
+ * Finishes an asynchronous playlist parsing operation started with totem_pl_parser_parse_async()
+ * or totem_pl_parser_parse_with_base_async().
+ *
+ * If parsing of the playlist is cancelled part-way through, %TOTEM_PL_PARSER_RESULT_CANCELLED is returned when
+ * this function is called.
+ *
+ * Return value: a #TotemPlParserResult
+ **/
+TotemPlParserResult
+totem_pl_parser_parse_finish (TotemPlParser *parser, GAsyncResult *async_result, GError **error)
+{
+	GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (async_result);
+
+	g_return_val_if_fail (TOTEM_IS_PL_PARSER (parser), FALSE);
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (async_result), FALSE);
+
+	g_warn_if_fail (g_simple_async_result_get_source_tag (result) == totem_pl_parser_parse_with_base_async);
+
+	/* Propagate any errors which were caught and return the result; otherwise just return the result */
+	g_simple_async_result_propagate_error (result, error);
+	return GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (result));
+}
+
+/**
  * totem_pl_parser_parse:
  * @parser: a #TotemPlParser
  * @uri: the URI of the playlist to parse
  * @fallback: %TRUE if the parser should add the playlist URI to the
  * end of the playlist on parse failure
  *
- * Parses a playlist given by the absolute URI @uri.
+ * Parses a playlist given by the absolute URI @uri. This method is
+ * synchronous, and will block on (e.g.) network requests to slow
+ * servers. totem_pl_parser_parse_async() is recommended instead.
+ *
+ * Return values are as totem_pl_parser_parse_with_base().
  *
  * Return value: a #TotemPlParserResult
  **/
@@ -1876,11 +2116,15 @@ totem_pl_parser_add_ignored_scheme (TotemPlParser *parser,
 
 	g_return_if_fail (TOTEM_IS_PL_PARSER (parser));
 
+	g_mutex_lock (parser->priv->ignore_mutex);
+
 	s = g_strdup (scheme);
 	if (s[strlen (s) - 1] == ':')
 		s[strlen (s) - 1] = '\0';
 	parser->priv->ignore_schemes = g_list_prepend
 		(parser->priv->ignore_schemes, s);
+
+	g_mutex_unlock (parser->priv->ignore_mutex);
 }
 
 /**
@@ -1897,8 +2141,12 @@ totem_pl_parser_add_ignored_mimetype (TotemPlParser *parser,
 {
 	g_return_if_fail (TOTEM_IS_PL_PARSER (parser));
 
+	g_mutex_lock (parser->priv->ignore_mutex);
+
 	parser->priv->ignore_mimetypes = g_list_prepend
 		(parser->priv->ignore_mimetypes, g_strdup (mimetype));
+
+	g_mutex_unlock (parser->priv->ignore_mutex);
 }
 
 /**
@@ -2146,7 +2394,7 @@ totem_pl_parser_metadata_get_type (void)
 {
 	static volatile gsize g_define_type_id__volatile = 0;
 	if (g_once_init_enter (&g_define_type_id__volatile))
-	{ 
+	{
 		GType g_define_type_id = g_boxed_type_register_static (
 		    g_intern_static_string ("TotemPlParserMetadata"),
 		    (GBoxedCopyFunc) g_hash_table_ref,
diff --git a/plparse/totem-pl-parser.h b/plparse/totem-pl-parser.h
index a01d83c..1ebe32b 100644
--- a/plparse/totem-pl-parser.h
+++ b/plparse/totem-pl-parser.h
@@ -42,7 +42,9 @@ G_BEGIN_DECLS
  * @TOTEM_PL_PARSER_RESULT_UNHANDLED: The playlist could not be handled.
  * @TOTEM_PL_PARSER_RESULT_ERROR: There was an error parsing the playlist.
  * @TOTEM_PL_PARSER_RESULT_SUCCESS: The playlist was parsed successfully.
- * @TOTEM_PL_PARSER_RESULT_IGNORED: The playlist was ignored due to its scheme or MIME type (see totem_pl_parser_add_ignored_scheme() and totem_pl_parser_add_ignored_mimetype()).
+ * @TOTEM_PL_PARSER_RESULT_IGNORED: The playlist was ignored due to its scheme or MIME type (see totem_pl_parser_add_ignored_scheme()
+ * and totem_pl_parser_add_ignored_mimetype()).
+ * @TOTEM_PL_PARSER_RESULT_CANCELLED: Parsing of the playlist was cancelled part-way through.
  *
  * Gives the result of parsing a playlist.
  **/
@@ -50,7 +52,8 @@ typedef enum {
 	TOTEM_PL_PARSER_RESULT_UNHANDLED,
 	TOTEM_PL_PARSER_RESULT_ERROR,
 	TOTEM_PL_PARSER_RESULT_SUCCESS,
-	TOTEM_PL_PARSER_RESULT_IGNORED
+	TOTEM_PL_PARSER_RESULT_IGNORED,
+	TOTEM_PL_PARSER_RESULT_CANCELLED
 } TotemPlParserResult;
 
 typedef struct TotemPlParser	       TotemPlParser;
@@ -352,10 +355,24 @@ void       totem_pl_parser_add_ignored_mimetype (TotemPlParser *parser,
 
 TotemPlParserResult totem_pl_parser_parse (TotemPlParser *parser,
 					   const char *uri, gboolean fallback);
+void totem_pl_parser_parse_async (TotemPlParser *parser, const char *uri,
+				  gboolean fallback, GCancellable *cancellable,
+				  GAsyncReadyCallback callback,
+                                  gpointer user_data);
+TotemPlParserResult totem_pl_parser_parse_finish (TotemPlParser *parser,
+						  GAsyncResult *async_result,
+						  GError **error);
+
 TotemPlParserResult totem_pl_parser_parse_with_base (TotemPlParser *parser,
 						     const char *uri,
 						     const char *base,
 						     gboolean fallback);
+void totem_pl_parser_parse_with_base_async (TotemPlParser *parser,
+					    const char *uri, const char *base,
+					    gboolean fallback,
+					    GCancellable *cancellable,
+					    GAsyncReadyCallback callback,
+                    			    gpointer user_data);
 
 TotemPlParser *totem_pl_parser_new (void);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]