[rhythmbox] rhythmdb: convert RhythmDBEntryType into a GObject



commit 5e571406d4278c8bdda0f685d751d224f567413f
Author: Jonathan Matthew <jonathan d14n org>
Date:   Thu Apr 29 17:26:25 2010 +1000

    rhythmdb: convert RhythmDBEntryType into a GObject
    
    This makes it much easier to generate bindings for rhythmdb, and makes
    creating custom entry types a bit more sane too.  Now python entry types
    are created by subclassing rhythmdb.EntryType and overriding methods.
    In C code, entry types can be created either using the old method of setting
    function pointers or by subclassing.
    
    RHYTHMDB_ENTRY_TYPE_INVALID no longer exists.  NULL indicates the absence of
    an entry type.
    
    The 'type' entry property is now a GObject rather than a pointer, so
    rhythmdb_entry_get_pointer becomes rhythmdb_entry_get_object.
    
    Entry types still cannot be unregistered, so reference counting of entry types
    is not much of an issue.

 bindings/python/Makefile.am                        |   33 +-
 bindings/python/rb.defs                            |    6 +-
 bindings/python/rhythmdb.defs                      |  239 ++++++---
 bindings/python/rhythmdb.override                  |  475 +-----------------
 plugins/audiocd/rb-audiocd-source.c                |   36 +-
 plugins/audioscrobbler/rb-audioscrobbler.c         |    7 +-
 plugins/audioscrobbler/rb-lastfm-source.c          |   77 ++--
 plugins/coherence/upnp_coherence/MediaPlayer.py    |   12 +-
 plugins/coherence/upnp_coherence/__init__.py       |    7 +-
 plugins/daap/rb-daap-source.c                      |   67 ++--
 plugins/daap/rb-rhythmdb-dmap-db-adapter.c         |   12 +-
 plugins/daap/rb-rhythmdb-dmap-db-adapter.h         |    2 +-
 plugins/fmradio/rb-fm-radio-source.c               |   32 +-
 .../rb-generic-player-playlist-source.c            |    2 +-
 .../rb-generic-player-playlist-source.h            |    2 +-
 plugins/generic-player/rb-generic-player-plugin.c  |    4 +-
 plugins/generic-player/rb-generic-player-source.c  |  100 +++--
 plugins/generic-player/rb-nokia770-source.c        |   13 +-
 plugins/generic-player/rb-psp-source.c             |   16 +-
 plugins/ipod/rb-ipod-source.c                      |  119 +++---
 plugins/ipod/rb-ipod-static-playlist-source.c      |    2 +-
 plugins/ipod/rb-ipod-static-playlist-source.h      |    2 +-
 plugins/iradio/rb-iradio-source.c                  |   30 +-
 plugins/jamendo/jamendo/__init__.py                |   12 +-
 plugins/magnatune/magnatune/__init__.py            |   13 +-
 plugins/mtpdevice/rb-mtp-source.c                  |   20 +-
 podcast/Makefile.am                                |    3 +-
 podcast/rb-podcast-entry-types.c                   |  135 +++++
 podcast/rb-podcast-entry-types.h                   |   45 ++
 podcast/rb-podcast-manager.c                       |    7 +-
 podcast/rb-podcast-manager.h                       |    1 +
 rhythmdb/Makefile.am                               |    8 +-
 rhythmdb/rhythmdb-entry-type.c                     |  386 ++++++++++++++
 rhythmdb/rhythmdb-entry-type.h                     |  116 +++++
 rhythmdb/rhythmdb-entry.h                          |   44 ++
 rhythmdb/rhythmdb-import-job.c                     |   65 ++--
 rhythmdb/rhythmdb-import-job.h                     |    6 +-
 rhythmdb/rhythmdb-private.h                        |   13 +-
 rhythmdb/rhythmdb-query.c                          |   12 +-
 rhythmdb/rhythmdb-song-entry-types.c               |  148 ++++++
 rhythmdb/rhythmdb-tree.c                           |   67 ++--
 rhythmdb/rhythmdb.c                                |  536 +++++---------------
 rhythmdb/rhythmdb.h                                |  113 +----
 shell/rb-shell-clipboard.c                         |   22 +-
 shell/rb-shell.c                                   |   12 +-
 shell/rb-shell.h                                   |    4 +-
 shell/rb-track-transfer-batch.c                    |    2 +-
 sources/rb-auto-playlist-source.c                  |   12 +-
 sources/rb-browser-source.c                        |   10 +-
 sources/rb-import-errors-source.c                  |   46 +-
 sources/rb-import-errors-source.h                  |    6 +-
 sources/rb-library-source.c                        |   21 +-
 sources/rb-missing-files-source.c                  |    8 +-
 sources/rb-play-queue-source.c                     |    2 +-
 sources/rb-podcast-source.c                        |    7 +-
 sources/rb-removable-media-source.c                |   38 +-
 sources/rb-source.c                                |   37 +-
 sources/rb-static-playlist-source.c                |    9 +-
 sources/rb-static-playlist-source.h                |    2 +-
 sources/rb-streaming-source.c                      |    4 +-
 sources/sync/rb-sync-settings-ui.c                 |    1 +
 sources/sync/rb-sync-state.c                       |    3 +-
 tests/Makefile.am                                  |    2 +
 tests/bench-rhythmdb-load.c                        |    1 +
 tests/test-rhythmdb.c                              |    1 +
 tests/test-utils.c                                 |    6 +-
 widgets/rb-library-browser.c                       |   18 +-
 widgets/rb-library-browser.h                       |    2 +-
 widgets/rb-song-info.c                             |    3 +-
 69 files changed, 1780 insertions(+), 1544 deletions(-)
---
diff --git a/bindings/python/Makefile.am b/bindings/python/Makefile.am
index 5b64c64..280397f 100644
--- a/bindings/python/Makefile.am
+++ b/bindings/python/Makefile.am
@@ -37,7 +37,7 @@ rhythmdb.c: rhythmdb.defs rhythmdb.override
 		--register $(PYGTK_DEFSDIR)/gtk-types.defs \
 		--register $(GST_PYTHON_DEFSDIR)/gst-types.defs \
 		--override $*.override \
-		--prefix py$* $(<F) ) > $@ 
+		--prefix py$* $(<F) ) > $@
 
 rb.c: rb.defs rb.override
 	( cd $(srcdir) && $(PYGOBJECT_CODEGEN) \
@@ -46,20 +46,25 @@ rb.c: rb.defs rb.override
 		--register $(GST_PYTHON_DEFSDIR)/gst-types.defs \
 		--register rhythmdb.defs \
 		--override $*.override \
-		--prefix py$* $(<F) ) > $@ 
+		--prefix py$* $(<F) ) > $@
 
-BINDING_HEADERS_SRCDIR_IN = \
+RHYTHMDB_BINDING_HEADERS_SRCDIR_IN = \
+	rhythmdb/rhythmdb.h			\
+	rhythmdb/rhythmdb-entry.h		\
+	rhythmdb/rhythmdb-entry-type.h		\
+	rhythmdb/rhythmdb-property-model.h	\
+	rhythmdb/rhythmdb-query-model.h		\
+	rhythmdb/rhythmdb-query-results.h	\
+	rhythmdb/rhythmdb-import-job.h		\
+	$(NULL)
+
+RB_BINDING_HEADERS_SRCDIR_IN = \
 	backends/rb-player.h			\
 	backends/gstreamer/rb-player-gst.h	\
 	lib/rb-string-value-map.h		\
 	lib/rb-cut-and-paste-code.h		\
 	lib/rb-file-helpers.h			\
 	metadata/rb-metadata.h			\
-	rhythmdb/rhythmdb.h			\
-	rhythmdb/rhythmdb-property-model.h	\
-	rhythmdb/rhythmdb-query-model.h		\
-	rhythmdb/rhythmdb-query-results.h	\
-	rhythmdb/rhythmdb-import-job.h		\
 	shell/rb-plugin.h			\
 	shell/rb-removable-media-manager.h	\
 	shell/rb-shell.h			\
@@ -85,13 +90,17 @@ BINDING_HEADERS_SRCDIR_IN = \
 	widgets/rb-uri-dialog.h			\
 	$(NULL)
 
-BINDING_HEADERS_BUILDDIR_IN = 
+RB_BINDING_HEADERS_BUILDDIR_IN =
+RHYTHMDB_BINDING_HEADERS_BUILDDIR_IN =
 
-BINDING_HEADERS_SRCDIR		:= $(addprefix $(top_srcdir)/,$(BINDING_HEADERS_SRCDIR_IN))
-BINDING_HEADERS_BUILDDIR	:= $(addprefix $(top_builddir)/,$(BINDING_HEADERS_BUILDDIR_IN))
+RB_BINDING_HEADERS_SRCDIR		:= $(addprefix $(top_srcdir)/,$(RB_BINDING_HEADERS_SRCDIR_IN))
+RB_BINDING_HEADERS_BUILDDIR		:= $(addprefix $(top_builddir)/,$(RB_BINDING_HEADERS_BUILDDIR_IN))
+RHYTHMDB_BINDING_HEADERS_SRCDIR		:= $(addprefix $(top_srcdir)/,$(RHYTHMDB_BINDING_HEADERS_SRCDIR_IN))
+RHYTHMDB_BINDING_HEADERS_BUILDDIR	:= $(addprefix $(top_builddir)/,$(RHYTHMDB_BINDING_HEADERS_BUILDDIR_IN))
 
 regenerate-python-binding:
-	$(PYGOBJECT_H2DEF) $(sort $(BINDING_HEADERS_SRCDIR) $(BINDING_HEADERS_BUILDDIR)) > rhythmbox.defs.new
+	$(PYGOBJECT_H2DEF) -n RB -m rb $(sort $(RB_BINDING_HEADERS_SRCDIR) $(RB_BINDING_HEADERS_BUILDDIR)) > rb.defs.new
+	$(PYGOBJECT_H2DEF) -n RhythmDB -m rhythmdb $(sort $(RHYTHMDB_BINDING_HEADERS_SRCDIR) $(RHYTHMDB_BINDING_HEADERS_BUILDDIR)) > rhythmdb.defs.new
 
 BUILT_SOURCES = rhythmdb.c rb.c
 
diff --git a/bindings/python/rb.defs b/bindings/python/rb.defs
index de4c489..6bd7028 100644
--- a/bindings/python/rb.defs
+++ b/bindings/python/rb.defs
@@ -551,7 +551,7 @@
   (return-type "none")
   (parameters
     '("RBSource*" "source")
-    '("RhythmDBEntryType_*" "type")
+    '("RhythmDBEntryType*" "type")
   )
 )
 
@@ -576,7 +576,7 @@
   (c-name "rb_shell_get_source_by_entry_type")
   (return-type "RBSource*")
   (parameters
-    '("RhythmDBEntryType_*" "type")
+    '("RhythmDBEntryType*" "type")
   )
 )
 
@@ -2317,7 +2317,7 @@
     '("RBShell*" "shell")
     '("const-char*" "name")
     '("gboolean" "local")
-    '("RhythmDBEntryType_*" "entry_type")
+    '("RhythmDBEntryType*" "entry_type")
   )
 )
 
diff --git a/bindings/python/rhythmdb.defs b/bindings/python/rhythmdb.defs
index 27b5dfd..2368d3a 100644
--- a/bindings/python/rhythmdb.defs
+++ b/bindings/python/rhythmdb.defs
@@ -31,19 +31,11 @@
   )
 )
 
-(define-boxed EntryType
+(define-object EntryType
   (in-module "RhythmDB")
-  (c-name "RhythmDBEntryType_")
+  (parent "GObject")
+  (c-name "RhythmDBEntryType")
   (gtype-id "RHYTHMDB_TYPE_ENTRY_TYPE")
-  (fields
-    '("gpointer" "post_entry_create" (access readwrite))
-    '("gpointer" "pre_entry_destroy" (access readwrite))
-    '("gpointer" "get_playback_uri" (access readwrite))
-    '("gboolean" "save_to_disk" (access readwrite))
-    '("char*" "can_sync_metadata" (access readwrite))
-    '("char*" "sync_metadata" (access readwrite))
-    '("RhythmDBEntryCategory" "category" (access readwrite))
-  )
 )
 
 (define-boxed Query
@@ -249,12 +241,6 @@
   (return-type "GType")
 )
 
-(define-method get_entry_type
-  (of-object "RhythmDBEntry")
-  (c-name "rhythmdb_entry_get_entry_type")
-  (return-type "RhythmDBEntryType_*")
-)
-
 (define-method shutdown
   (of-object "RhythmDB")
   (c-name "rhythmdb_shutdown")
@@ -387,12 +373,6 @@
   )
 )
 
-(define-method get_playback_uri
-  (of-object "RhythmDBEntry")
-  (c-name "rhythmdb_entry_get_playback_uri")
-  (return-type "char*")
-)
-
 (define-function rhythmdb_get_type
   (c-name "rhythmdb_get_type")
   (return-type "GType")
@@ -404,21 +384,12 @@
   (return-type "none")
 )
 
-(define-method entry_is_editable
-  (of-object "RhythmDB")
-  (c-name "rhythmdb_entry_is_editable")
-  (return-type "gboolean")
-  (parameters
-    '("RhythmDBEntry*" "entry")
-  )
-)
-
 (define-method entry_new
   (of-object "RhythmDB")
   (c-name "rhythmdb_entry_new")
   (return-type "RhythmDBEntry*")
   (parameters
-    '("RhythmDBEntryType_*" "type")
+    '("RhythmDBEntryType*" "type")
     '("const-char*" "uri")
   )
 )
@@ -438,9 +409,9 @@
   (return-type "none")
   (parameters
     '("const-char*" "uri")
-    '("RhythmDBEntryType_*" "type")
-    '("RhythmDBEntryType_*" "ignore_type")
-    '("RhythmDBEntryType_*" "error_type")
+    '("RhythmDBEntryType*" "type")
+    '("RhythmDBEntryType*" "ignore_type")
+    '("RhythmDBEntryType*" "error_type")
   )
 )
 
@@ -469,7 +440,7 @@
   (c-name "rhythmdb_entry_delete_by_type")
   (return-type "none")
   (parameters
-    '("RhythmDBEntryType_*" "type")
+    '("RhythmDBEntryType*" "type")
   )
 )
 
@@ -521,7 +492,7 @@
   (c-name "rhythmdb_entry_foreach_by_type")
   (return-type "none")
   (parameters
-    '("RhythmDBEntryType" "entry_type")
+    '("RhythmDBEntryType*" "entry_type")
     '("GFunc" "func")
     '("gpointer" "data")
   )
@@ -532,7 +503,7 @@
   (c-name "rhythmdb_entry_count_by_type")
   (return-type "gint64")
   (parameters
-    '("RhythmDBEntryType" "entry_type")
+    '("RhythmDBEntryType*" "entry_type")
   )
 )
 
@@ -575,6 +546,17 @@
   )
 )
 
+(define-method entry_write_metadata_changes
+  (of-object "RhythmDB")
+  (c-name "rhythmdb_entry_write_metadata_changes")
+  (return-type "none")
+  (parameters
+    '("RhythmDBEntry*" "entry")
+    '("GSList*" "changes")
+    '("GError**" "error")
+  )
+)
+
 (define-method entry_foreach
   (of-object "RhythmDB")
   (c-name "rhythmdb_entry_foreach")
@@ -627,17 +609,17 @@
   )
 )
 
-;(define-method query_append_params
-;  (of-object "RhythmDB")
-;  (c-name "rhythmdb_query_append_params")
-;  (return-type "none")
-;  (parameters
-;    '("RhythmDBQuery" "query")
-;    '("RhythmDBQueryType" "type")
-;    '("RhythmDBPropType" "propid")
-;    '("GValue*" "value")
-;  )
-;)
+(define-method query_append_params
+  (of-object "RhythmDB")
+  (c-name "rhythmdb_query_append_params")
+  (return-type "none")
+  (parameters
+    '("RhythmDBQuery" "query")
+    '("RhythmDBQueryType" "type")
+    '("RhythmDBPropType" "propid")
+    '("GValue*" "value")
+  )
+)
 
 (define-method append_prop_multiple
   (of-object "RhythmDBQuery")
@@ -703,54 +685,24 @@
   )
 )
 
-(define-method entry_register_type
+(define-method register_entry_type
   (of-object "RhythmDB")
-  (c-name "rhythmdb_entry_register_type")
-  (return-type "RhythmDBEntryType_*")
+  (c-name "rhythmdb_register_entry_type")
+  (return-type "none")
   (parameters
-    '("const-char*" "name")
+    '("RhythmDBEntryType*" "entry_type")
   )
 )
 
 (define-method entry_type_get_by_name
   (of-object "RhythmDB")
   (c-name "rhythmdb_entry_type_get_by_name")
-  (return-type "RhythmDBEntryType_*")
+  (return-type "RhythmDBEntryType*")
   (parameters
     '("const-char*" "name")
   )
 )
 
-(define-function rhythmdb_entry_song_get_type
-  (c-name "rhythmdb_entry_song_get_type")
-  (return-type "RhythmDBEntryType_*")
-)
-
-(define-function rhythmdb_entry_iradio_get_type
-  (c-name "rhythmdb_entry_iradio_get_type")
-  (return-type "RhythmDBEntryType_*")
-)
-
-(define-function rhythmdb_entry_podcast_post_get_type
-  (c-name "rhythmdb_entry_podcast_post_get_type")
-  (return-type "RhythmDBEntryType_*")
-)
-
-(define-function rhythmdb_entry_podcast_feed_get_type
-  (c-name "rhythmdb_entry_podcast_feed_get_type")
-  (return-type "RhythmDBEntryType_*")
-)
-
-(define-function rhythmdb_entry_import_error_get_type
-  (c-name "rhythmdb_entry_import_error_get_type")
-  (return-type "RhythmDBEntryType_*")
-)
-
-(define-function rhythmdb_entry_ignore_get_type
-  (c-name "rhythmdb_entry_ignore_get_type")
-  (return-type "RhythmDBEntryType_*")
-)
-
 (define-method entry_request_extra_metadata
   (of-object "RhythmDB")
   (c-name "rhythmdb_entry_request_extra_metadata")
@@ -1235,3 +1187,120 @@
   (c-name "rhythmdb_import_job_get_imported")
   (return-type "int")
 )
+
+;; From rhythmdb-entry.h
+
+(define-function entry_get_type
+  (c-name "rhythmdb_entry_get_type")
+  (return-type "GType")
+)
+
+;; From rhythmdb-entry-type.h
+
+(define-function entry_category_get_type
+  (c-name "rhythmdb_entry_category_get_type")
+  (return-type "GType")
+)
+
+(define-function entry_type_get_type
+  (c-name "rhythmdb_entry_type_get_type")
+  (return-type "GType")
+)
+
+(define-method get_name
+  (of-object "RhythmDBEntryType")
+  (c-name "rhythmdb_entry_type_get_name")
+  (return-type "const-char*")
+)
+
+(define-method get_playback_uri
+  (of-object "RhythmDBEntry")
+  (c-name "rhythmdb_entry_get_playback_uri")
+  (return-type "char*")
+)
+
+(define-virtual get_playback_uri
+  (of-object "RhythmDBEntryType")
+  (return-type "char*")
+  (parameters
+    '("RhythmDBEntry*" "entry")
+  )
+)
+
+(define-method created
+  (of-object "RhythmDBEntry")
+  (c-name "rhythmdb_entry_created")
+  (return-type "none")
+)
+
+(define-virtual entry_created
+  (of-object "RhythmDBEntryType")
+  (return-type "none")
+  (parameters
+    '("RhythmDBEntry*" "entry")
+  )
+)
+
+(define-method pre_destroy
+  (of-object "RhythmDBEntry")
+  (c-name "rhythmdb_entry_pre_destroy")
+  (return-type "none")
+)
+
+(define-virtual destroy_entry
+  (of-object "RhythmDBEntryType")
+  (return-type "none")
+  (parameters
+    '("RhythmDBEntry*" "entry")
+  )
+)
+
+(define-method can_sync_metadata
+  (of-object "RhythmDBEntry")
+  (c-name "rhythmdb_entry_can_sync_metadata")
+  (return-type "gboolean")
+)
+
+(define-virtual can_sync_metadata
+  (of-object "RhythmDBEntryType")
+  (return-type "gboolean")
+  (parameters
+    '("RhythmDBEntry*" "entry")
+  )
+)
+
+(define-method sync_metadata
+  (of-object "RhythmDBEntry")
+  (c-name "rhythmdb_entry_sync_metadata")
+  (return-type "none")
+  (parameters
+    '("GSList*" "changes")
+    '("GError**" "error")
+  )
+)
+
+(define-virtual sync_metadata
+  (of-object "RhythmDBEntryType")
+  (return-type "none")
+  (parameters
+    '("RhythmDBEntry*" "entry")
+    '("GSList*" "changes")
+    '("GError**" "error")
+  )
+)
+
+
+(define-function get_song_entry_type
+  (c-name "rhythmdb_get_song_entry_type")
+  (return-type "RhythmDBEntryType*")
+)
+
+(define-function get_error_entry_type
+  (c-name "rhythmdb_get_error_entry_type")
+  (return-type "RhythmDBEntryType*")
+)
+
+(define-function get_ignore_entry_type
+  (c-name "rhythmdb_get_ignore_entry_type")
+  (return-type "RhythmDBEntryType*")
+)
diff --git a/bindings/python/rhythmdb.override b/bindings/python/rhythmdb.override
index c4c8130..b7510ab 100644
--- a/bindings/python/rhythmdb.override
+++ b/bindings/python/rhythmdb.override
@@ -44,12 +44,6 @@ py_return_boolean (gboolean val)
 		Py_RETURN_FALSE;
 }
 
-static void
-_py_decref (PyObject *o)
-{
-	Py_XDECREF (o);
-}
-
 typedef struct {
 	PyObject *func;
 	PyObject *data;
@@ -104,31 +98,6 @@ ignore
   rhythmdb_query_model_tree_path_to_entry
   rhythmdb_query_model_iter_to_entry
 %%
-override rhythmdb_entry_count_by_type kwargs
-static PyObject *
-_wrap_rhythmdb_entry_count_by_type(PyGObject *self, PyObject *args, PyObject *kwargs)
-{
-	static char *kwlist[] = { "entrytype", NULL };
-	PyObject *py_entrytype = NULL;
-	RhythmDBEntryType et;
-	gint64 ret;
-
-	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:RhythmDB.entry_count_by_type", kwlist, &py_entrytype))
-		return NULL;
-	if (pyg_boxed_check(py_entrytype, RHYTHMDB_TYPE_ENTRY_TYPE))
-		et = pyg_boxed_get(py_entrytype, RhythmDBEntryType_);
-	else {
-		char *s = g_strdup_printf ("entrytype should be a RhythmDBEntryType, is a %s", g_type_name (pyg_type_from_object ((PyObject*)py_entrytype)));
-		PyErr_SetString(PyExc_TypeError, s);
-		g_free (s);
-		return NULL;
-	}
-
-	ret = rhythmdb_entry_count_by_type(RHYTHMDB_RHYTHMDB(self->obj), et);
-
-	return PyLong_FromLongLong(ret);
-}
-%%
 override rhythmdb_entry_get kwargs
 static PyObject *
 _wrap_rhythmdb_entry_get(PyGObject *self, PyObject *args, PyObject *kwargs)
@@ -254,26 +223,19 @@ _wrap_rhythmdb_entry_foreach_by_type (PyGObject *self, PyObject *args, PyObject
 	static char *kwlist[] = {"entrytype", "func", "data", NULL};
 	PyRhythmDBEntryForeachData data = {NULL, NULL};
 	PyObject *py_entrytype;
-	RhythmDBEntryType et;
+	RhythmDBEntryType *etype;
 
 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|O:RhythmDB.entry_foreach_by_type",
 					 kwlist, &py_entrytype, &data.func, &data.data))
 		return NULL;
 
-	if (pyg_boxed_check(py_entrytype, RHYTHMDB_TYPE_ENTRY_TYPE)) {
-		et = pyg_boxed_get(py_entrytype, RhythmDBEntryType_);
-	} else {
-		char *s = g_strdup_printf ("self should be a RhythmDBEntryType, is a %s", g_type_name (pyg_type_from_object ((PyObject*)self)));
-		PyErr_SetString(PyExc_TypeError, s);
-		g_free (s);
-		return NULL;
-	}
+	etype = RHYTHMDB_ENTRY_TYPE (((PyGObject *)self)->obj);
 	if (!PyCallable_Check (data.func)) {
 		PyErr_SetString (PyExc_TypeError, "func must be callable");
 		return NULL;
 	}
 
-	rhythmdb_entry_foreach_by_type (RHYTHMDB (self->obj), et, (GFunc)_rhythmdb_entry_foreach_func, &data);
+	rhythmdb_entry_foreach_by_type (RHYTHMDB (self->obj), etype, (GFunc)_rhythmdb_entry_foreach_func, &data);
 
 	Py_RETURN_NONE;
 }
@@ -504,422 +466,6 @@ _wrap_rhythmdb_query_model_set_sort_order (PyGObject *self, PyObject *args, PyOb
 	Py_RETURN_NONE;
 }
 %%
-override-attr  RhythmDBEntryType_.sync_metadata
-
-static void
-_wrap_py_entry_type_sync_metadata (RhythmDB *db, RhythmDBEntry *entry,
-				   GError **error, PyObject *py_call)
-{
-	PyGILState_STATE __py_state;
-	__py_state = pyg_gil_state_ensure();
-
-	if (PyCallable_Check (py_call)) {
-		PyObject *ret, *args, *error;
-		PyObject *py_db, *py_entry;
-
-		py_db = pygobject_new (G_OBJECT (db));
-		py_entry = pyg_boxed_new (RHYTHMDB_TYPE_ENTRY, entry, FALSE, FALSE);
-		args = Py_BuildValue ("(OO)", py_db, py_entry);
-		ret = PyObject_Call (py_call, args, NULL);
-
-		Py_DECREF (py_db);
-		Py_DECREF (py_entry);
-		Py_DECREF (ret);
-
-		error = PyErr_Occurred ();
-		if (error != NULL) {
-			/* TODO: catch any exceptions, and set errors*/
-			/*PyErr_Clear ();*/
-		}
-	} else {
-		/* TODO: set error */
-	}
-
-	pyg_gil_state_release(__py_state);
-}
-
-static PyObject*
-_wrap_rhythmdb_entry_type__get_sync_metadata (PyGBoxed *self, void *closure)
-{
-	RhythmDBEntryType et;
-
-	if (pyg_boxed_check(self, RHYTHMDB_TYPE_ENTRY_TYPE))
-		et = pyg_boxed_get(self, RhythmDBEntryType_);
-	else {
-		char *s = g_strdup_printf ("self should be a RhythmDBEntryType, is a %s", g_type_name (pyg_type_from_object ((PyObject*)self)));
-		PyErr_SetString(PyExc_TypeError, s);
-		g_free (s);
-		return NULL;
-	}
-
-	if (et->sync_metadata == (RhythmDBEntrySyncFunc)rb_null_function) {
-		/* nothing */
-		Py_RETURN_NONE;
-	} else if (et->sync_metadata == (RhythmDBEntrySyncFunc)_wrap_py_entry_type_sync_metadata) {
-		/* it's python */
-		PyObject *value = (PyObject*)et->sync_metadata_data;
-
-		Py_INCREF (value);
-		return value;
-	} else {
-		/* FIXME: it's a non-python function */
-		return NULL;
-	}
-}
-
-static int
-_wrap_rhythmdb_entry_type__set_sync_metadata (PyGBoxed *self, PyObject *value, void *closure)
-{
-	RhythmDBEntryType et;
-
-	if (pyg_boxed_check(self, RHYTHMDB_TYPE_ENTRY_TYPE))
-		et = pyg_boxed_get(self, RhythmDBEntryType_);
-	else {
-		char *s = g_strdup_printf ("self should be a RhythmDBEntryType, is a %s", g_type_name (pyg_type_from_object ((PyObject*)self)));
-		PyErr_SetString(PyExc_TypeError, s);
-		g_free (s);
-		return -1;
-	}
-
-	if (et->sync_metadata_destroy)
-		et->sync_metadata_destroy (et->sync_metadata_data);
-
-	if (value == Py_None) {
-		et->sync_metadata = (RhythmDBEntrySyncFunc)rb_null_function;
-		et->sync_metadata_data = NULL;
-		et->sync_metadata_destroy = NULL;
-	} else if (PyCallable_Check (value)) {
-		/* method */
-		et->sync_metadata = (RhythmDBEntrySyncFunc)_wrap_py_entry_type_sync_metadata;
-		Py_INCREF (value);
-		et->sync_metadata_data = value;
-		et->sync_metadata_destroy = (GDestroyNotify)_py_decref;
-	} else {
-		PyErr_SetString(PyExc_TypeError, "value must be callable");
-		et->sync_metadata = NULL;
-		et->sync_metadata_data = NULL;
-		et->sync_metadata_destroy = NULL;
-		return -1;
-	}
-
-	return 0;
-}
-
-%%
-override-attr  RhythmDBEntryType_.save_to_disk
-
-static PyObject *
-_wrap_rhythmdb_entry_type__get_save_to_disk(PyGBoxed *self, void *closure)
-{
-    RhythmDBEntryType et;
-
-    if (pyg_boxed_check(self, RHYTHMDB_TYPE_ENTRY_TYPE))
-	    et = pyg_boxed_get(self, RhythmDBEntryType_);
-    else {
-	    char *s = g_strdup_printf ("self should be a RhythmDBEntryType, is a %s", g_type_name (pyg_type_from_object ((PyObject*)self)));
-	    PyErr_SetString(PyExc_TypeError, s);
-	    g_free (s);
-	    return NULL;
-    }
-
-    return py_return_boolean (et->save_to_disk);
-}
-
-static int
-_wrap_rhythmdb_entry_type__set_save_to_disk(PyGBoxed *self, PyObject *value)
-{
-	RhythmDBEntryType et;
-
-	if (pyg_boxed_check(self, RHYTHMDB_TYPE_ENTRY_TYPE)) {
-		et = pyg_boxed_get(self, RhythmDBEntryType_);
-	} else {
-		char *s = g_strdup_printf ("self should be a RhythmDBEntryType, is a %s", g_type_name (pyg_type_from_object ((PyObject*)self)));
-		PyErr_SetString(PyExc_TypeError, s);
-		g_free (s);
-		return -1;
-	}
-
-	if (value == Py_True) {
-	    et->save_to_disk = TRUE;
-	} else {
-	    et->save_to_disk = FALSE;
-	}
-	return 0;
-}
-
-%%
-override-attr  RhythmDBEntryType_.can_sync_metadata
-
-static gboolean
-_wrap_py_entry_type_can_sync_metadata (RhythmDB *db, RhythmDBEntry *entry,
-					  PyObject *py_call)
-{
-	gboolean retval;
-	PyGILState_STATE __py_state;
-
-	__py_state = pyg_gil_state_ensure();
-
-	if (PyCallable_Check (py_call)) {
-		PyObject *ret, *args;
-		PyObject *py_db, *py_entry;
-		int i;
-
-		py_db = pygobject_new (G_OBJECT (db));
-		py_entry = pyg_boxed_new (RHYTHMDB_TYPE_ENTRY, entry, FALSE, FALSE);
-		args = Py_BuildValue ("(OO)", py_db, py_entry);
-		ret = PyObject_Call (py_call, args, NULL);
-
-		Py_DECREF (py_db);
-		Py_DECREF (py_entry);
-
-		i = PyObject_IsTrue (ret);
-		Py_DECREF (ret);
-		if (i == 0) {
-			retval = FALSE;
-		} else if (i > 0) {
-			retval = TRUE;
-		} else {
-			/*TODO: emit error */
-			retval = FALSE;
-		}
-	} else {
-		/* TODO: emit error */
-		retval = FALSE;
-	}
-
-	pyg_gil_state_release(__py_state);
-	return retval;
-}
-
-static PyObject*
-_wrap_rhythmdb_entry_type__get_can_sync_metadata (PyGBoxed *self, void *closure)
-{
-	RhythmDBEntryType et;
-
-	if (pyg_boxed_check(self, RHYTHMDB_TYPE_ENTRY_TYPE))
-		et = pyg_boxed_get(self, RhythmDBEntryType_);
-	else {
-		char *s = g_strdup_printf ("self should be a RhythmDBEntryType, is a %s", g_type_name (pyg_type_from_object ((PyObject*)self)));
-		PyErr_SetString(PyExc_TypeError, s);
-		g_free (s);
-		return NULL;
-	}
-
-	if (et->can_sync_metadata == (RhythmDBEntryCanSyncFunc)rb_false_function) {
-		/* always false */
-		Py_RETURN_FALSE;
-	} else if (et->can_sync_metadata == (RhythmDBEntryCanSyncFunc)rb_true_function) {
-		/* always true */
-		Py_RETURN_TRUE;
-	} else if (et->can_sync_metadata == (RhythmDBEntryCanSyncFunc)rb_null_function) {
-		Py_RETURN_NONE;
-	} else if (et->can_sync_metadata == (RhythmDBEntryCanSyncFunc)_wrap_py_entry_type_can_sync_metadata) {
-		/* it's python */
-		PyObject *value = (PyObject*)et->can_sync_metadata_data;
-
-		Py_INCREF (value);
-		return value;
-	} else {
-		/* FIXME: it's a non-python function */
-		return NULL;
-	}
-}
-
-static int
-_wrap_rhythmdb_entry_type__set_can_sync_metadata (PyGBoxed *self, PyObject *value, void *closure)
-{
-	RhythmDBEntryType et;
-
-	if (pyg_boxed_check(self, RHYTHMDB_TYPE_ENTRY_TYPE))
-		et = pyg_boxed_get(self, RhythmDBEntryType_);
-	else {
-		char *s = g_strdup_printf ("self should be a RhythmDBEntryType, is a %s", g_type_name (pyg_type_from_object ((PyObject*)self)));
-		PyErr_SetString(PyExc_TypeError, s);
-		g_free (s);
-		return -1;
-	}
-
-	if (et->can_sync_metadata_destroy)
-		et->can_sync_metadata_destroy (et->can_sync_metadata_data);
-
-	if (value == Py_False) {
-		et->can_sync_metadata = (RhythmDBEntryCanSyncFunc)rb_false_function;
-		et->can_sync_metadata_data = NULL;
-		et->can_sync_metadata_destroy = NULL;
-	} else if (value == Py_True) {
-		et->can_sync_metadata = (RhythmDBEntryCanSyncFunc)rb_true_function;
-		et->can_sync_metadata_data = NULL;
-		et->can_sync_metadata_destroy = NULL;
-	} else if (value == Py_None) {
-		et->can_sync_metadata = (RhythmDBEntryCanSyncFunc)rb_null_function;
-		et->can_sync_metadata_data = NULL;
-		et->can_sync_metadata_destroy = NULL;
-	} else if (PyCallable_Check (value)) {
-		/* method */
-		et->can_sync_metadata = (RhythmDBEntryCanSyncFunc)_wrap_py_entry_type_can_sync_metadata;
-		Py_INCREF (value);
-		et->can_sync_metadata_data = value;
-		et->can_sync_metadata_destroy = (GDestroyNotify)_py_decref;
-	} else {
-		PyErr_SetString(PyExc_TypeError, "value must be callable");
-		et->can_sync_metadata = NULL;
-		et->can_sync_metadata_data = NULL;
-		et->can_sync_metadata_destroy = NULL;
-		return -1;
-	}
-
-	return 0;
-}
-%%
-override-attr  RhythmDBEntryType_.get_playback_uri
-
-static char*
-_wrap_py_entry_type_get_playback_uri (RhythmDBEntry *entry, PyObject *py_call)
-{
-	PyGILState_STATE __py_state;
-	__py_state = pyg_gil_state_ensure();
-
-	if (PyCallable_Check (py_call)) {
-		PyObject *py_ret, *args;
-		PyObject *py_entry;
-		char *ret;
-
-		py_entry = pyg_boxed_new (RHYTHMDB_TYPE_ENTRY, entry, FALSE, FALSE);
-		args = Py_BuildValue ("(O)", py_entry);
-		py_ret = PyObject_CallObject (py_call, args);
-
-		Py_DECREF (py_entry);
-
-		if (py_ret != Py_None) {
-			ret = g_strdup (PyString_AsString (py_ret));
-		} else {
-			ret = NULL;
-		}
-		Py_DECREF (py_ret);
-		pyg_gil_state_release(__py_state);
-		return ret;
-	} else {
-		/* TODO: emit error */
-		pyg_gil_state_release(__py_state);
-		return NULL;
-	}
-}
-
-static PyObject*
-_wrap_rhythmdb_entry_type__get_get_playback_uri (PyGBoxed *self, void *closure)
-{
-	RhythmDBEntryType et;
-	PyGILState_STATE __py_state;
-
-	__py_state = pyg_gil_state_ensure();
-
-	if (pyg_boxed_check(self, RHYTHMDB_TYPE_ENTRY_TYPE))
-		et = pyg_boxed_get(self, RhythmDBEntryType_);
-	else {
-		char *s = g_strdup_printf ("self should be a RhythmDBEntryType, is a %s", g_type_name (pyg_type_from_object ((PyObject*)self)));
-		PyErr_SetString(PyExc_TypeError, s);
-		g_free (s);
-		pyg_gil_state_release(__py_state);
-		return NULL;
-	}
-
-	if (et->get_playback_uri == (RhythmDBEntryStringFunc)rb_null_function) {
-		pyg_gil_state_release(__py_state);
-		Py_RETURN_NONE;
-	} else if (et->get_playback_uri == (RhythmDBEntryStringFunc)_wrap_py_entry_type_get_playback_uri) {
-		/* it's python */
-		PyObject *value = (PyObject*)et->get_playback_uri_data;
-
-		Py_INCREF (value);
-		pyg_gil_state_release(__py_state);
-		return value;
-	} else {
-		/* FIXME: it's a non-python function */
-		pyg_gil_state_release(__py_state);
-		return NULL;
-	}
-}
-
-static int
-_wrap_rhythmdb_entry_type__set_get_playback_uri (PyGBoxed *self, PyObject *value, void *closure)
-{
-	RhythmDBEntryType et;
-
-	if (pyg_boxed_check(self, RHYTHMDB_TYPE_ENTRY_TYPE))
-		et = pyg_boxed_get(self, RhythmDBEntryType_);
-	else {
-		char *s = g_strdup_printf ("self should be a RhythmDBEntryType, is a %s", g_type_name (pyg_type_from_object ((PyObject*)self)));
-		PyErr_SetString(PyExc_TypeError, s);
-		g_free (s);
-		return -1;
-	}
-
-	if (et->get_playback_uri_destroy)
-		et->get_playback_uri_destroy (et->get_playback_uri_data);
-
-	if (value == Py_None) {
-		et->get_playback_uri = (RhythmDBEntryStringFunc)rb_null_function;
-		et->get_playback_uri_data = NULL;
-		et->get_playback_uri_destroy = NULL;
-	} else if (PyCallable_Check (value)) {
-		/* method */
-		et->get_playback_uri = (RhythmDBEntryStringFunc)_wrap_py_entry_type_get_playback_uri;
-		Py_INCREF (value);
-		et->get_playback_uri_data = value;
-		et->get_playback_uri_destroy = (GDestroyNotify)_py_decref;
-	} else {
-		PyErr_SetString(PyExc_TypeError, "value must be callable");
-		et->get_playback_uri = NULL;
-		et->get_playback_uri_data = NULL;
-		et->get_playback_uri_destroy = NULL;
-		return -1;
-	}
-
-	return 0;
-}
-%%
-override-attr  RhythmDBEntryType_.category
-
-static PyObject *
-_wrap_rhythmdb_entry_type__get_category(PyGBoxed *self, void *closure)
-{
-    RhythmDBEntryType et;
-
-    if (pyg_boxed_check(self, RHYTHMDB_TYPE_ENTRY_TYPE))
-	    et = pyg_boxed_get(self, RhythmDBEntryType_);
-    else {
-	    char *s = g_strdup_printf ("self should be a RhythmDBEntryType, is a %s", g_type_name (pyg_type_from_object ((PyObject*)self)));
-	    PyErr_SetString(PyExc_TypeError, s);
-	    g_free (s);
-	    return NULL;
-    }
-    return pyg_enum_from_gtype(RHYTHMDB_TYPE_ENTRY_CATEGORY, et->category);
-}
-
-static int
-_wrap_rhythmdb_entry_type__set_category(PyGBoxed *self, PyObject *value)
-{
-	RhythmDBEntryType et;
-	int category;
-	int ret;
-
-	if (pyg_boxed_check(self, RHYTHMDB_TYPE_ENTRY_TYPE)) {
-		et = pyg_boxed_get(self, RhythmDBEntryType_);
-	} else {
-		char *s = g_strdup_printf ("self should be a RhythmDBEntryType, is a %s", g_type_name (pyg_type_from_object ((PyObject*)self)));
-		PyErr_SetString(PyExc_TypeError, s);
-		g_free (s);
-		return -1;
-	}
-
-	ret = pyg_enum_get_value (RHYTHMDB_TYPE_ENTRY_CATEGORY, value, &category);
-	if (ret == 0) {
-		et->category = category;
-	}
-	return ret;
-}
-
-%%
 override rhythmdb_entry_request_extra_metadata kwargs
 
 static PyObject *
@@ -1031,7 +577,6 @@ _wrap_rhythmdb_query_append (PyGObject *self, PyObject *args, PyObject *kwargs)
 		PyObject *criteria, *py_type, *obj;
 		RhythmDBQueryType type;
 		RhythmDBPropType propid = -1;
-		GType gtype;
 		GValue value = {0,};
 		int increment, remaining;
 		int index = 0;
@@ -1104,17 +649,9 @@ _wrap_rhythmdb_query_append (PyGObject *self, PyObject *args, PyObject *kwargs)
 				obj = PySequence_GetItem (criteria, index+2);
 				g_value_init (&value, rhythmdb_get_property_type (RHYTHMDB_RHYTHMDB(self->obj), propid));
 				if (propid == RHYTHMDB_PROP_TYPE) {
-					RhythmDBEntryType et;
-					if (pyg_boxed_check(obj, RHYTHMDB_TYPE_ENTRY_TYPE)) {
-						et = pyg_boxed_get(obj, RhythmDBEntryType_);
-					} else {
-						char *s = g_strdup_printf ("self should be a RhythmDBEntryType, is a %s",
-									   g_type_name (pyg_type_from_object (obj)));
-						PyErr_SetString(PyExc_TypeError, s);
-						g_free (s);
-						return NULL;
-					}
-					g_value_set_pointer (&value, et);
+					RhythmDBEntryType *etype;
+					etype = RHYTHMDB_ENTRY_TYPE (((PyGObject *)obj)->obj);
+					g_value_set_object (&value, etype);
 				} else {
 					if (pyg_value_from_pyobject  (&value, obj) < 0) {
 						Py_XDECREF (obj);
diff --git a/plugins/audiocd/rb-audiocd-source.c b/plugins/audiocd/rb-audiocd-source.c
index ea3c41b..066804e 100644
--- a/plugins/audiocd/rb-audiocd-source.c
+++ b/plugins/audiocd/rb-audiocd-source.c
@@ -170,7 +170,6 @@ get_db_for_source (RBAudioCdSource *source)
 	return db;
 }
 
-
 static void
 rb_audiocd_source_class_init (RBAudioCdSourceClass *klass)
 {
@@ -425,25 +424,28 @@ rb_audiocd_source_new (RBPlugin *plugin,
 		       GVolume *volume)
 {
 	GObject *source;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	RhythmDB *db;
 	char *name;
 	char *path;
 
-	g_object_get (shell, "db", &db, NULL);
-
 	path = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
 	name = g_strdup_printf ("audiocd: %s", path);
-	entry_type = rhythmdb_entry_register_type (db, name);
-	g_free (name);
 	g_free (path);
-	g_object_unref (db);
 
-	entry_type->category = RHYTHMDB_ENTRY_NORMAL;
-	entry_type->can_sync_metadata = (RhythmDBEntryCanSyncFunc)rb_true_function;
-	/* TODO save the metadata somewhere */
-	entry_type->sync_metadata = (RhythmDBEntrySyncFunc)rb_null_function;
-	entry_type->entry_type_data_size = sizeof(RBAudioCDEntryData);
+	g_object_get (shell, "db", &db, NULL);
+	entry_type = g_object_new (RHYTHMDB_TYPE_ENTRY_TYPE,
+				   "db", db,
+				   "name", name,
+				   "save-to-disk", FALSE,
+				   "category", RHYTHMDB_ENTRY_NORMAL,
+				   "type-data-size", sizeof(RBAudioCDEntryData),
+				   NULL);
+	entry_type->can_sync_metadata = (RhythmDBEntryTypeBooleanFunc) rb_true_function;
+	entry_type->sync_metadata = (RhythmDBEntryTypeSyncFunc) rb_null_function;
+	rhythmdb_register_entry_type (db, entry_type);
+	g_object_unref (db);
+	g_free (name);
 
 	source = g_object_new (RB_TYPE_AUDIOCD_SOURCE,
 			       "entry-type", entry_type,
@@ -535,15 +537,15 @@ rb_audiocd_create_track_entry (RBAudioCdSource *source,
 	guint64 duration;
 	GValue value = {0, };
 	gchar *str;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	RBAudioCDEntryData *extra_data;
 
 	audio_path = g_strdup_printf ("cdda://%d#%s", track_number, priv->device_path);
 
-	g_object_get (G_OBJECT (source), "entry-type", &entry_type, NULL);
+	g_object_get (source, "entry-type", &entry_type, NULL);
 	rb_debug ("Audio CD - create entry for track %d from %s", track_number, audio_path);
 	entry = rhythmdb_entry_new (db, entry_type, audio_path);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 	if (entry == NULL) {
 		g_free (audio_path);
 		return NULL;
@@ -1055,7 +1057,7 @@ static void
 impl_delete_thyself (RBSource *source)
 {
 	RhythmDB *db;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 
 	rb_debug ("audio cd ejected");
 
@@ -1066,7 +1068,7 @@ impl_delete_thyself (RBSource *source)
 
 	g_object_get (source, "entry-type", &entry_type, NULL);
 	rhythmdb_entry_delete_by_type (db, entry_type);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 
 	rhythmdb_commit (db);
 	g_object_unref (db);
diff --git a/plugins/audioscrobbler/rb-audioscrobbler.c b/plugins/audioscrobbler/rb-audioscrobbler.c
index cd3e2c7..2615a7f 100644
--- a/plugins/audioscrobbler/rb-audioscrobbler.c
+++ b/plugins/audioscrobbler/rb-audioscrobbler.c
@@ -58,6 +58,7 @@
 #include "rb-cut-and-paste-code.h"
 #include "rb-plugin.h"
 #include "rb-util.h"
+#include "rb-podcast-entry-types.h"
 
 #include "rb-audioscrobbler-entry.h"
 
@@ -440,13 +441,15 @@ rb_audioscrobbler_is_queueable (RhythmDBEntry *entry)
 	const char *title;
 	const char *artist;
 	gulong duration;
-	RhythmDBEntryType type;
+	RhythmDBEntryType *type;
+	RhythmDBEntryCategory category;
 
 	/* First, check if the entry is appropriate for sending to 
 	 * audioscrobbler
 	 */
 	type = rhythmdb_entry_get_entry_type (entry);
-	if (type->category != RHYTHMDB_ENTRY_NORMAL) {
+	g_object_get (type, "category", &category, NULL);
+	if (category != RHYTHMDB_ENTRY_NORMAL) {
 		rb_debug ("entry %s is not queueable: category not NORMAL", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION));
 		return FALSE;
 	}
diff --git a/plugins/audioscrobbler/rb-lastfm-source.c b/plugins/audioscrobbler/rb-lastfm-source.c
index 492c7ca..a71845a 100644
--- a/plugins/audioscrobbler/rb-lastfm-source.c
+++ b/plugins/audioscrobbler/rb-lastfm-source.c
@@ -119,7 +119,6 @@ static void queue_get_playlist_and_skip (RBLastfmSource *source, RhythmDBEntry *
 static void queue_love_track (RBLastfmSource *source);
 static void queue_ban_track (RBLastfmSource *source);
 
-
 static void rb_lastfm_source_class_init (RBLastfmSourceClass *klass);
 static void rb_lastfm_source_init (RBLastfmSource *source);
 static void rb_lastfm_source_constructed (GObject *object);
@@ -207,7 +206,6 @@ typedef struct
 	char *download_url;
 } RBLastfmTrackEntryData;
 
-
 struct RBLastfmSourcePrivate
 {
 	GtkWidget *main_box;
@@ -224,8 +222,8 @@ struct RBLastfmSourcePrivate
 	RBEntryView *tracks;
 
 	RBShellPlayer *shell_player;
-	RhythmDBEntryType station_entry_type;
-	RhythmDBEntryType track_entry_type;
+	RhythmDBEntryType *station_entry_type;
+	RhythmDBEntryType *track_entry_type;
 	char *session_id;
 	RhythmDBEntry *current_station;
 	RBPlayOrder *play_order;
@@ -328,18 +326,18 @@ rb_lastfm_source_class_init (RBLastfmSourceClass *klass)
 
 	g_object_class_install_property (object_class,
 					 PROP_ENTRY_TYPE,
-					 g_param_spec_boxed ("entry-type",
-							     "Entry type",
-							     "Entry type for last.fm tracks",
-							     RHYTHMDB_TYPE_ENTRY_TYPE,
-							     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+					 g_param_spec_object ("entry-type",
+							      "Entry type",
+							      "Entry type for last.fm tracks",
+							      RHYTHMDB_TYPE_ENTRY_TYPE,
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 	g_object_class_install_property (object_class,
 					 PROP_STATION_ENTRY_TYPE,
-					 g_param_spec_boxed ("station-entry-type",
-							     "Entry type",
-							     "Entry type for last.fm stations",
-							     RHYTHMDB_TYPE_ENTRY_TYPE,
-							     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+					 g_param_spec_object ("station-entry-type",
+							      "Entry type",
+							      "Entry type for last.fm stations",
+							      RHYTHMDB_TYPE_ENTRY_TYPE,
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 	g_object_class_override_property (object_class,
 					  PROP_PLAY_ORDER,
 					  "play-order");
@@ -617,10 +615,10 @@ rb_lastfm_source_set_property (GObject *object,
 
 	switch (prop_id) {
 	case PROP_ENTRY_TYPE:
-		source->priv->track_entry_type = g_value_get_boxed (value);
+		source->priv->track_entry_type = g_value_get_object (value);
 		break;
 	case PROP_STATION_ENTRY_TYPE:
-		source->priv->station_entry_type = g_value_get_boxed (value);
+		source->priv->station_entry_type = g_value_get_object (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -638,10 +636,10 @@ rb_lastfm_source_get_property (GObject *object,
 
 	switch (prop_id) {
 	case PROP_ENTRY_TYPE:
-		g_value_set_boxed (value, source->priv->track_entry_type);
+		g_value_set_object (value, source->priv->track_entry_type);
 		break;
 	case PROP_STATION_ENTRY_TYPE:
-		g_value_set_boxed (value, source->priv->station_entry_type);
+		g_value_set_object (value, source->priv->station_entry_type);
 		break;
 	case PROP_PLAY_ORDER:
 		g_value_set_object (value, source->priv->play_order);
@@ -652,10 +650,8 @@ rb_lastfm_source_get_property (GObject *object,
 	}
 }
 
-/* entry data stuff */
-
 static void
-destroy_track_data (RhythmDBEntry *entry, gpointer meh)
+destroy_track_data (RhythmDBEntryType *etype, RhythmDBEntry *entry)
 {
 	RBLastfmTrackEntryData *data;
 
@@ -671,31 +667,38 @@ rb_lastfm_source_new (RBPlugin *plugin,
 		      RBShell  *shell)
 {
 	RBSource *source;
-	RhythmDBEntryType station_entry_type;
-	RhythmDBEntryType track_entry_type;
+	RhythmDBEntryType *station_entry_type;
+	RhythmDBEntryType *track_entry_type;
 	RhythmDB *db;
 
 	g_object_get (G_OBJECT (shell), "db", &db, NULL);
 
 	/* register entry types if they're not already registered */
 	station_entry_type = rhythmdb_entry_type_get_by_name (db, "lastfm-station");
-	if (station_entry_type == RHYTHMDB_ENTRY_TYPE_INVALID) {
-		station_entry_type = rhythmdb_entry_register_type (db, "lastfm-station");
-		station_entry_type->save_to_disk = TRUE;
-		station_entry_type->can_sync_metadata = (RhythmDBEntryCanSyncFunc) rb_true_function;
-		station_entry_type->sync_metadata = (RhythmDBEntrySyncFunc) rb_null_function;
-		station_entry_type->get_playback_uri = (RhythmDBEntryStringFunc) rb_null_function;	/* can't play stations, exactly */
-		station_entry_type->category = RHYTHMDB_ENTRY_CONTAINER;
+	if (station_entry_type == NULL) {
+		station_entry_type = g_object_new (RHYTHMDB_TYPE_ENTRY_TYPE,
+						   "db", db,
+						   "name", "lastfm-station",
+						   "save-to-disk", TRUE,
+						   "category", RHYTHMDB_ENTRY_CONTAINER,
+						   NULL);
+		station_entry_type->can_sync_metadata = (RhythmDBEntryTypeBooleanFunc) rb_true_function;
+		station_entry_type->sync_metadata = (RhythmDBEntryTypeSyncFunc) rb_null_function;
+		station_entry_type->get_playback_uri = (RhythmDBEntryTypeStringFunc) rb_null_function;
+		rhythmdb_register_entry_type (db, station_entry_type);
 	}
 
 	track_entry_type = rhythmdb_entry_type_get_by_name (db, "lastfm-track");
-	if (track_entry_type == RHYTHMDB_ENTRY_TYPE_INVALID) {
-		track_entry_type = rhythmdb_entry_register_type (db, "lastfm-track");
-		track_entry_type->save_to_disk = FALSE;
-		track_entry_type->category = RHYTHMDB_ENTRY_NORMAL;
-
-		track_entry_type->entry_type_data_size = sizeof (RBLastfmTrackEntryData);
-		track_entry_type->pre_entry_destroy = destroy_track_data;
+	if (track_entry_type == NULL) {
+		track_entry_type = g_object_new (RHYTHMDB_TYPE_ENTRY_TYPE,
+						 "db", db,
+						 "name", "lastfm-track",
+						 "save-to-disk", FALSE,
+						 "category", RHYTHMDB_ENTRY_NORMAL,
+						 "type-data-size", sizeof (RBLastfmTrackEntryData),
+						 NULL);
+		track_entry_type->destroy_entry = destroy_track_data;
+		rhythmdb_register_entry_type (db, track_entry_type);
 	}
 
 	source = RB_SOURCE (g_object_new (RB_TYPE_LASTFM_SOURCE,
diff --git a/plugins/coherence/upnp_coherence/MediaPlayer.py b/plugins/coherence/upnp_coherence/MediaPlayer.py
index d90b5f4..8be6226 100644
--- a/plugins/coherence/upnp_coherence/MediaPlayer.py
+++ b/plugins/coherence/upnp_coherence/MediaPlayer.py
@@ -50,6 +50,9 @@ class RhythmboxPlayer(log.Loggable):
         self.player = self.shell.get_player()
         louie.send('Coherence.UPnP.Backend.init_completed', None, backend=self)
 
+	self.entry_type = rhythmdb.EntryType(name='CoherencePlayer')
+	self.shell.props.db.register_entry_type(self.entry_type)
+
         self.playing = False
         self.state = None
         self.duration = None
@@ -263,12 +266,10 @@ class RhythmboxPlayer(log.Loggable):
                 self.info("check for entry %r %r %r", self.entry,item.server_uuid,uri)
                 if self.entry == None:
                     if item.server_uuid is not None:
-                        entry_type = self.shell.props.db.entry_register_type("CoherenceUpnp:" + item.server_uuid)
-                        self.entry = self.shell.props.db.entry_new(entry_type, uri)
+                        self.entry = self.shell.props.db.entry_new(self.entry_type, uri)
                         self.info("create new entry %r", self.entry)
                     else:
-                        entry_type = self.shell.props.db.entry_register_type("CoherencePlayer")
-                        self.entry = self.shell.props.db.entry_new(entry_type, uri)
+                        self.entry = self.shell.props.db.entry_new(self.entry_type, uri)
                         self.info("load and check for entry %r", self.entry)
 
                 duration = None
@@ -315,8 +316,7 @@ class RhythmboxPlayer(log.Loggable):
             else:
                 #self.shell.load_uri(uri,play=False)
                 #self.entry = self.shell.props.db.entry_lookup_by_location(uri)
-                entry_type = self.shell.props.db.entry_register_type("CoherencePlayer")
-                self.entry = self.shell.props.db.entry_new(entry_type, uri)
+                self.entry = self.shell.props.db.entry_new(self.entry_type, uri)
 
 
         self.playing = False
diff --git a/plugins/coherence/upnp_coherence/__init__.py b/plugins/coherence/upnp_coherence/__init__.py
index caf2b46..1bb0097 100644
--- a/plugins/coherence/upnp_coherence/__init__.py
+++ b/plugins/coherence/upnp_coherence/__init__.py
@@ -73,6 +73,9 @@ class CoherencePlugin(rb.Plugin, log.Loggable):
         print "coherence UPnP plugin activated"
         self.shell = shell
         self.sources = {}
+	if self.entry_type is None:
+            self.entry_type = rhythmdb.EntryType(name='CoherenceUpnp')
+            shell.props.db.register_entry_type(self.entry_type)
 
         # Set up our icon
         the_icon = None
@@ -249,13 +252,11 @@ class CoherencePlugin(rb.Plugin, log.Loggable):
 
         db = self.shell.props.db
         group = rb.rb_source_group_get_by_name("shared")
-        entry_type = db.entry_register_type("CoherenceUpnp:%s" %
-                 client.device.get_id()[5:])
 
         from UpnpSource import UpnpSource
         source = gobject.new (UpnpSource,
                     shell=self.shell,
-                    entry_type=entry_type,
+                    entry_type=self.entry_type,
                     source_group=group,
                     plugin=self,
                     client=client,
diff --git a/plugins/daap/rb-daap-source.c b/plugins/daap/rb-daap-source.c
index 6a07369..6cde517 100644
--- a/plugins/daap/rb-daap-source.c
+++ b/plugins/daap/rb-daap-source.c
@@ -75,7 +75,6 @@ static gboolean rb_daap_source_show_popup (RBSource *source);
 static char * rb_daap_source_get_browser_key (RBSource *source);
 static char * rb_daap_source_get_paned_key (RBBrowserSource *source);
 static void rb_daap_source_get_status (RBSource *source, char **text, char **progress_text, float *progress);
-static char * rb_daap_source_get_playback_uri (RhythmDBEntry *entry, gpointer data);
 
 #define CONF_STATE_SORTING CONF_PREFIX "/state/daap/sorting"
 #define CONF_STATE_PANED_POSITION CONF_PREFIX "/state/daap/paned_position"
@@ -113,6 +112,19 @@ enum {
 
 G_DEFINE_TYPE (RBDAAPSource, rb_daap_source, RB_TYPE_BROWSER_SOURCE)
 
+static char *
+rb_daap_entry_type_get_playback_uri (RhythmDBEntryType *etype, RhythmDBEntry *entry)
+{
+	const char *location;
+
+	location = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MOUNTPOINT);
+	if (location == NULL) {
+		location = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
+	}
+
+	return g_strdup (location);
+}
+
 static void
 rb_daap_source_dispose (GObject *object)
 {
@@ -276,19 +288,24 @@ rb_daap_source_new (RBShell *shell,
 		    gboolean password_protected)
 {
 	RBSource *source;
-	RhythmDBEntryType type;
+	RhythmDBEntryType *entry_type;
 	GdkPixbuf *icon;
 	RhythmDB *db;
 	char *entry_type_name;
 
 	g_object_get (shell, "db", &db, NULL);
 	entry_type_name = g_strdup_printf ("daap:%s:%s:%s", service_name, name, host);
-	type = rhythmdb_entry_register_type (db, entry_type_name);
-	g_free (entry_type_name);
-	type->save_to_disk = FALSE;
-	type->category = RHYTHMDB_ENTRY_NORMAL;
-	type->get_playback_uri = (RhythmDBEntryStringFunc) rb_daap_source_get_playback_uri;
+
+	entry_type = g_object_new (RHYTHMDB_TYPE_ENTRY_TYPE,
+				   "db", db,
+				   "name", entry_type_name,
+				   "save-to-disk", FALSE,
+				   "category", RHYTHMDB_ENTRY_NORMAL,
+				   NULL);
+	entry_type->get_playback_uri = rb_daap_entry_type_get_playback_uri;
+	rhythmdb_register_entry_type (db, entry_type);
 	g_object_unref (db);
+	g_free (entry_type_name);
 
 	icon = rb_daap_plugin_get_icon (RB_DAAP_PLUGIN (plugin), password_protected, FALSE);
 	source = RB_SOURCE (g_object_new (RB_TYPE_DAAP_SOURCE,
@@ -296,7 +313,7 @@ rb_daap_source_new (RBShell *shell,
 					  "name", name,
 					  "host", host,
 					  "port", port,
-					  "entry-type", type,
+					  "entry-type", entry_type,
 					  "icon", icon,
 					  "shell", shell,
 					  "visibility", TRUE,
@@ -311,7 +328,7 @@ rb_daap_source_new (RBShell *shell,
 	}
 
 	rb_shell_register_entry_type_for_source (shell, source,
-						 type);
+						 entry_type);
 
 	return source;
 }
@@ -544,7 +561,7 @@ rb_daap_source_connection_cb (DMAPConnection   *connection,
 	RBShell *shell = NULL;
 	GSList *playlists;
 	GSList *l;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 
 	rb_debug ("Connection callback result: %s", result ? "success" : "failure");
 	daap_source->priv->tried_password = FALSE;
@@ -585,7 +602,7 @@ rb_daap_source_connection_cb (DMAPConnection   *connection,
 	}
 
 	g_object_unref (shell);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 }
 
 static void
@@ -597,7 +614,7 @@ rb_daap_source_activate (RBSource *source)
 	RhythmDB *rdb = NULL;
 	DMAPDb *db = NULL;
 	char *name = NULL;
-	RhythmDBEntryType type;
+	RhythmDBEntryType *entry_type;
 
 	if (daap_source->priv->connection != NULL) {
 		return;
@@ -606,10 +623,10 @@ rb_daap_source_activate (RBSource *source)
 	g_object_get (daap_source,
 		      "shell", &shell,
 		      "name", &name,
-		      "entry-type", &type,
+		      "entry-type", &entry_type,
 		      NULL);
 	g_object_get (shell, "db", &rdb, NULL);
-	db = DMAP_DB (rb_rhythmdb_dmap_db_adapter_new (rdb, type));
+	db = DMAP_DB (rb_rhythmdb_dmap_db_adapter_new (rdb, entry_type));
 
 	factory = DMAP_RECORD_FACTORY (rb_daap_record_factory_new ());
 
@@ -619,7 +636,7 @@ rb_daap_source_activate (RBSource *source)
 								daap_source->priv->password_protected,
 								db,
 								factory);
-        g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, type);
+	g_object_unref (entry_type);
 	g_object_add_weak_pointer (G_OBJECT (daap_source->priv->connection), (gpointer *)&daap_source->priv->connection);
 
 	g_free (name);
@@ -666,7 +683,7 @@ rb_daap_source_disconnect (RBDAAPSource *daap_source)
 	GSList *l;
 	RBShell *shell;
 	RhythmDB *db;
-	RhythmDBEntryType type;
+	RhythmDBEntryType *entry_type;
 
 	if (daap_source->priv->connection == NULL
 	 || daap_source->priv->disconnecting == TRUE) {
@@ -677,12 +694,12 @@ rb_daap_source_disconnect (RBDAAPSource *daap_source)
 
 	daap_source->priv->disconnecting = TRUE;
 
-	g_object_get (daap_source, "shell", &shell, "entry-type", &type, NULL);
+	g_object_get (daap_source, "shell", &shell, "entry-type", &entry_type, NULL);
 	g_object_get (shell, "db", &db, NULL);
 	g_object_unref (shell);
 
-	rhythmdb_entry_delete_by_type (db, type);
-        g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, type);
+	rhythmdb_entry_delete_by_type (db, entry_type);
+        g_object_unref (entry_type);
 	rhythmdb_commit (db);
 
 	g_object_unref (db);
@@ -780,15 +797,3 @@ rb_daap_source_get_status (RBSource *source,
 	RB_SOURCE_CLASS (rb_daap_source_parent_class)->impl_get_status (source, text, progress_text, progress);
 }
 
-static char *
-rb_daap_source_get_playback_uri (RhythmDBEntry *entry, gpointer data)
-{
-	const char *location;
-
-	location = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MOUNTPOINT);
-	if (location == NULL) {
-		location = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
-	}
-
-	return g_strdup (location);
-}
diff --git a/plugins/daap/rb-rhythmdb-dmap-db-adapter.c b/plugins/daap/rb-rhythmdb-dmap-db-adapter.c
index b4370ce..abd0087 100644
--- a/plugins/daap/rb-rhythmdb-dmap-db-adapter.c
+++ b/plugins/daap/rb-rhythmdb-dmap-db-adapter.c
@@ -36,7 +36,7 @@
 
 struct RBRhythmDBDMAPDbAdapterPrivate {
 	RhythmDB *db;
-	RhythmDBEntryType type;
+	RhythmDBEntryType *entry_type;
 };
 
 typedef struct ForeachAdapterData {
@@ -90,7 +90,7 @@ rb_rhythmdb_dmap_db_adapter_foreach	(const DMAPDb *db,
 	foreach_adapter_data->func = func;
 
 	rhythmdb_entry_foreach_by_type (RB_RHYTHMDB_DMAP_DB_ADAPTER (db)->priv->db,
-					RB_RHYTHMDB_DMAP_DB_ADAPTER (db)->priv->type,
+					RB_RHYTHMDB_DMAP_DB_ADAPTER (db)->priv->entry_type,
 				       (GFunc) foreach_adapter,
 				        foreach_adapter_data);
 
@@ -103,7 +103,7 @@ rb_rhythmdb_dmap_db_adapter_count (const DMAPDb *db)
 	g_assert (RB_RHYTHMDB_DMAP_DB_ADAPTER (db)->priv->db != NULL);
 	return rhythmdb_entry_count_by_type (
 			RB_RHYTHMDB_DMAP_DB_ADAPTER (db)->priv->db,
-			RB_RHYTHMDB_DMAP_DB_ADAPTER (db)->priv->type);
+			RB_RHYTHMDB_DMAP_DB_ADAPTER (db)->priv->entry_type);
 }
 
 static void
@@ -163,7 +163,7 @@ rb_rhythmdb_dmap_db_adapter_add (DMAPDb *db, DMAPRecord *record)
                      "daap.songgenre", &genre,
 		      NULL);
 
-	entry = rhythmdb_entry_new (priv->db, priv->type, uri);
+	entry = rhythmdb_entry_new (priv->db, priv->entry_type, uri);
 
 	if (entry == NULL) {
 		g_warning ("cannot create entry for daap track %s", uri);
@@ -261,7 +261,7 @@ G_DEFINE_TYPE_WITH_CODE (RBRhythmDBDMAPDbAdapter, rb_rhythmdb_dmap_db_adapter, G
 			 G_IMPLEMENT_INTERFACE (TYPE_DMAP_DB, rb_rhythmdb_dmap_db_adapter_interface_init))
 
 RBRhythmDBDMAPDbAdapter *
-rb_rhythmdb_dmap_db_adapter_new (RhythmDB *rdb, RhythmDBEntryType type)
+rb_rhythmdb_dmap_db_adapter_new (RhythmDB *rdb, RhythmDBEntryType *entry_type)
 {
 	RBRhythmDBDMAPDbAdapter *db;
 
@@ -269,7 +269,7 @@ rb_rhythmdb_dmap_db_adapter_new (RhythmDB *rdb, RhythmDBEntryType type)
 					       NULL));
 
 	db->priv->db = rdb;
-	db->priv->type = type;
+	db->priv->entry_type = entry_type;
 
 	return db;
 }
diff --git a/plugins/daap/rb-rhythmdb-dmap-db-adapter.h b/plugins/daap/rb-rhythmdb-dmap-db-adapter.h
index 536718d..32782ef 100644
--- a/plugins/daap/rb-rhythmdb-dmap-db-adapter.h
+++ b/plugins/daap/rb-rhythmdb-dmap-db-adapter.h
@@ -53,7 +53,7 @@ typedef struct {
 	GObjectClass parent;
 } RBRhythmDBDMAPDbAdapterClass;
 
-RBRhythmDBDMAPDbAdapter *rb_rhythmdb_dmap_db_adapter_new (RhythmDB *db, RhythmDBEntryType type);
+RBRhythmDBDMAPDbAdapter *rb_rhythmdb_dmap_db_adapter_new (RhythmDB *db, RhythmDBEntryType *entry_type);
 GType rb_rhythmdb_dmap_db_adapter_get_type (void);
 
 #endif /* _RB_RHYTHMDB_DMAP_DB_ADAPTER */
diff --git a/plugins/fmradio/rb-fm-radio-source.c b/plugins/fmradio/rb-fm-radio-source.c
index deea780..5f488a6 100644
--- a/plugins/fmradio/rb-fm-radio-source.c
+++ b/plugins/fmradio/rb-fm-radio-source.c
@@ -47,7 +47,6 @@ static void     rb_fm_radio_source_class_init  (RBFMRadioSourceClass *class);
 static void     rb_fm_radio_source_init        (RBFMRadioSource *self);
 static void	rb_fm_radio_source_constructed (GObject *object);
 static void     rb_fm_radio_source_dispose     (GObject *object);
-static char    *rb_fm_radio_source_get_playback_uri (RhythmDBEntry *entry, gpointer data);
 static void     rb_fm_radio_source_do_query    (RBFMRadioSource *self);
 static void     rb_fm_radio_source_songs_view_sort_order_changed (
 						RBEntryView *view,
@@ -72,7 +71,7 @@ static RBEntryView *impl_get_entry_view (RBSource *source);
 struct _RBFMRadioSourcePrivate {
 	RhythmDB *db;
 	RBShellPlayer *player;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	RhythmDBEntry *playing_entry;
 
 	RBEntryView *stations;
@@ -176,23 +175,34 @@ rb_fm_radio_source_constructed (GObject *object)
 				 self, 0);
 }
 
+static char *
+rb_fm_radio_source_get_playback_uri (RhythmDBEntryType *etype, RhythmDBEntry *entry)
+{
+	return g_strdup("xrbsilence:///");
+}
+
 RBSource *
 rb_fm_radio_source_new (RBShell *shell, RBRadioTuner *tuner)
 {
 	RBFMRadioSource *self;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	RhythmDB *db;
 
 	g_object_get (shell, "db", &db, NULL);
 
 	entry_type = rhythmdb_entry_type_get_by_name (db, "fmradio-station");
-	if (entry_type == RHYTHMDB_ENTRY_TYPE_INVALID) {
-		entry_type = rhythmdb_entry_register_type (db, "fmradio-station");
-		entry_type->save_to_disk = TRUE;
-		entry_type->can_sync_metadata = (RhythmDBEntryCanSyncFunc) rb_true_function;
-		entry_type->sync_metadata = (RhythmDBEntrySyncFunc) rb_null_function;
+	if (entry_type == NULL) {
+		entry_type = g_object_new (RHYTHMDB_TYPE_ENTRY_TYPE,
+					   "db", db,
+					   "name", "fmradio-station",
+					   "save-to-disk", TRUE,
+					   NULL);
+		entry_type->can_sync_metadata = (RhythmDBEntryTypeBooleanFunc) rb_true_function;
+		entry_type->sync_metadata = (RhythmDBEntryTypeSyncFunc) rb_null_function;
 		entry_type->get_playback_uri = rb_fm_radio_source_get_playback_uri;
+		rhythmdb_register_entry_type (db, entry_type);
 	}
+
 	self = g_object_new (RB_TYPE_FM_RADIO_SOURCE,
 			     "name", _("FM Radio"),
 			     "shell", shell,
@@ -205,12 +215,6 @@ rb_fm_radio_source_new (RBShell *shell, RBRadioTuner *tuner)
 	return RB_SOURCE (self);
 }
 
-static char *
-rb_fm_radio_source_get_playback_uri (RhythmDBEntry *entry, gpointer data)
-{
-	return g_strdup("xrbsilence:///");
-}
-
 static void
 rb_fm_radio_source_dispose (GObject *object)
 {
diff --git a/plugins/generic-player/rb-generic-player-playlist-source.c b/plugins/generic-player/rb-generic-player-playlist-source.c
index 7be15f7..db48688 100644
--- a/plugins/generic-player/rb-generic-player-playlist-source.c
+++ b/plugins/generic-player/rb-generic-player-playlist-source.c
@@ -429,7 +429,7 @@ rb_generic_player_playlist_source_new (RBShell *shell,
 				       RBGenericPlayerSource *player_source,
 				       const char *playlist_file,
 				       const char *device_root,
-				       RhythmDBEntryType entry_type)
+				       RhythmDBEntryType *entry_type)
 {
 	RBSource *source;
 	source = RB_SOURCE (g_object_new (RB_TYPE_GENERIC_PLAYER_PLAYLIST_SOURCE,
diff --git a/plugins/generic-player/rb-generic-player-playlist-source.h b/plugins/generic-player/rb-generic-player-playlist-source.h
index 5af30b5..e65d6d2 100644
--- a/plugins/generic-player/rb-generic-player-playlist-source.h
+++ b/plugins/generic-player/rb-generic-player-playlist-source.h
@@ -57,7 +57,7 @@ RBSource *	rb_generic_player_playlist_source_new (RBShell *shell,
 						       RBGenericPlayerSource *source,
 						       const char *playlist_file,
 						       const char *device_root,
-						       RhythmDBEntryType entry_type);
+						       RhythmDBEntryType *entry_type);
 void		rb_generic_player_playlist_delete_from_player (RBGenericPlayerPlaylistSource *source);
 
 G_END_DECLS
diff --git a/plugins/generic-player/rb-generic-player-plugin.c b/plugins/generic-player/rb-generic-player-plugin.c
index aea9118..acae670 100644
--- a/plugins/generic-player/rb-generic-player-plugin.c
+++ b/plugins/generic-player/rb-generic-player-plugin.c
@@ -149,7 +149,7 @@ rb_generic_player_plugin_new_playlist (GtkAction *action, RBSource *source)
 	RBShell *shell;
 	RBSourceList *sourcelist;
 	RBSource *playlist;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 
 	g_return_if_fail (RB_IS_GENERIC_PLAYER_SOURCE (source));
 	g_object_get (source,
@@ -158,7 +158,7 @@ rb_generic_player_plugin_new_playlist (GtkAction *action, RBSource *source)
 		      NULL);
 
 	playlist = rb_generic_player_playlist_source_new (shell, RB_GENERIC_PLAYER_SOURCE (source), NULL, NULL, entry_type);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 
 	rb_generic_player_source_add_playlist (RB_GENERIC_PLAYER_SOURCE (source),
 					       shell,
diff --git a/plugins/generic-player/rb-generic-player-source.c b/plugins/generic-player/rb-generic-player-source.c
index b845308..90dfb83 100644
--- a/plugins/generic-player/rb-generic-player-source.c
+++ b/plugins/generic-player/rb-generic-player-source.c
@@ -121,8 +121,8 @@ typedef struct
 	char *mount_path;
 
 	/* entry types */
-	RhythmDBEntryType ignore_type;
-	RhythmDBEntryType error_type;
+	RhythmDBEntryType *ignore_type;
+	RhythmDBEntryType *error_type;
 
 	/* information derived from volume */
 	gboolean read_only;
@@ -175,18 +175,18 @@ rb_generic_player_source_class_init (RBGenericPlayerSourceClass *klass)
 
 	g_object_class_install_property (object_class,
 					 PROP_ERROR_ENTRY_TYPE,
-					 g_param_spec_boxed ("error-entry-type",
-							     "Error entry type",
-							     "Entry type to use for import error entries added by this source",
-							     RHYTHMDB_TYPE_ENTRY_TYPE,
-							     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+					 g_param_spec_object ("error-entry-type",
+							      "Error entry type",
+							      "Entry type to use for import error entries added by this source",
+							      RHYTHMDB_TYPE_ENTRY_TYPE,
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 	g_object_class_install_property (object_class,
 					 PROP_IGNORE_ENTRY_TYPE,
-					 g_param_spec_boxed ("ignore-entry-type",
-							     "Ignore entry type",
-							     "Entry type to use for ignore entries added by this source",
-							     RHYTHMDB_TYPE_ENTRY_TYPE,
-							     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+					 g_param_spec_object ("ignore-entry-type",
+							      "Ignore entry type",
+							      "Entry type to use for ignore entries added by this source",
+							      RHYTHMDB_TYPE_ENTRY_TYPE,
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 	g_object_class_install_property (object_class,
 					 PROP_DEVICE_INFO,
 					 g_param_spec_object ("device-info",
@@ -211,7 +211,7 @@ impl_constructed (GObject *object)
 {
 	RBGenericPlayerSource *source;
 	RBGenericPlayerSourcePrivate *priv;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	GMount *mount;
 	char **playlist_formats;
 	char *mount_name;
@@ -260,10 +260,10 @@ impl_constructed (GObject *object)
 
 	g_object_get (priv->device_info, "playlist-formats", &playlist_formats, NULL);
 	if (playlist_formats != NULL && g_strv_length (playlist_formats) > 0) {
-		entry_type->has_playlists = TRUE;
+		g_object_set (entry_type, "has-playlists", TRUE, NULL);
 	}
 	g_strfreev (playlist_formats);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 
         rb_media_player_source_load (RB_MEDIA_PLAYER_SOURCE (source));
 	load_songs (source);
@@ -276,10 +276,10 @@ impl_set_property (GObject *object, guint prop_id, const GValue *value, GParamSp
 
 	switch (prop_id) {
 	case PROP_IGNORE_ENTRY_TYPE:
-		priv->ignore_type = g_value_get_boxed (value);
+		priv->ignore_type = g_value_get_object (value);
 		break;
 	case PROP_ERROR_ENTRY_TYPE:
-		priv->error_type = g_value_get_boxed (value);
+		priv->error_type = g_value_get_object (value);
 		break;
 	case PROP_DEVICE_INFO:
 		priv->device_info = g_value_dup_object (value);
@@ -297,10 +297,10 @@ impl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *ps
 
 	switch (prop_id) {
 	case PROP_IGNORE_ENTRY_TYPE:
-		g_value_set_boxed (value, priv->ignore_type);
+		g_value_set_object (value, priv->ignore_type);
 		break;
 	case PROP_ERROR_ENTRY_TYPE:
-		g_value_set_boxed (value, priv->error_type);
+		g_value_set_object (value, priv->error_type);
 		break;
 	case PROP_DEVICE_INFO:
 		g_value_set_object (value, priv->device_info);
@@ -322,15 +322,15 @@ impl_dispose (GObject *object)
 	}
 
 	if (priv->db != NULL) {
-		if (priv->ignore_type != RHYTHMDB_ENTRY_TYPE_INVALID) {
+		if (priv->ignore_type != NULL) {
 			rhythmdb_entry_delete_by_type (priv->db, priv->ignore_type);
-			g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, priv->ignore_type);
-			priv->ignore_type = RHYTHMDB_ENTRY_TYPE_INVALID;
+			g_object_unref (priv->ignore_type);
+			priv->ignore_type = NULL;
 		}
-		if (priv->error_type != RHYTHMDB_ENTRY_TYPE_INVALID) {
+		if (priv->error_type != NULL) {
 			rhythmdb_entry_delete_by_type (priv->db, priv->error_type);
-			g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, priv->error_type);
-			priv->error_type = RHYTHMDB_ENTRY_TYPE_INVALID;
+			g_object_unref (priv->error_type);
+			priv->error_type = NULL;
 		}
 
 		g_object_unref (priv->db);
@@ -364,9 +364,9 @@ RBRemovableMediaSource *
 rb_generic_player_source_new (RBPlugin *plugin, RBShell *shell, GMount *mount, MPIDDevice *device_info)
 {
 	RBGenericPlayerSource *source;
-	RhythmDBEntryType entry_type;
-	RhythmDBEntryType error_type;
-	RhythmDBEntryType ignore_type;
+	RhythmDBEntryType *entry_type;
+	RhythmDBEntryType *error_type;
+	RhythmDBEntryType *ignore_type;
 	RhythmDB *db;
 	GVolume *volume;
 	char *name;
@@ -378,15 +378,33 @@ rb_generic_player_source_new (RBPlugin *plugin, RBShell *shell, GMount *mount, M
 	path = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
 
 	name = g_strdup_printf ("generic audio player: %s", path);
-	entry_type = rhythmdb_entry_register_type (db, name);
+	entry_type = g_object_new (RHYTHMDB_TYPE_ENTRY_TYPE,
+				   "db", db,
+				   "name", name,
+				   "save-to-disk", FALSE,
+				   "category", RHYTHMDB_ENTRY_NORMAL,
+				   NULL);
+	rhythmdb_register_entry_type (db, entry_type);
 	g_free (name);
 
 	name = g_strdup_printf ("generic audio player (ignore): %s", path);
-	ignore_type = rhythmdb_entry_register_type (db, name);
+	ignore_type = g_object_new (RHYTHMDB_TYPE_ENTRY_TYPE,
+				    "db", db,
+				    "name", name,
+				    "save-to-disk", FALSE,
+				    "category", RHYTHMDB_ENTRY_VIRTUAL,
+				    NULL);
+	rhythmdb_register_entry_type (db, ignore_type);
 	g_free (name);
 
 	name = g_strdup_printf ("generic audio player (errors): %s", path);
-	error_type = rhythmdb_entry_register_type (db, name);
+	error_type = g_object_new (RHYTHMDB_TYPE_ENTRY_TYPE,
+				   "db", db,
+				   "name", name,
+				   "save-to-disk", FALSE,
+				   "category", RHYTHMDB_ENTRY_VIRTUAL,
+				   NULL);
+	rhythmdb_register_entry_type (db, error_type);
 	g_free (name);
 
 	g_object_unref (db);
@@ -468,14 +486,12 @@ static void
 load_songs (RBGenericPlayerSource *source)
 {
 	RBGenericPlayerSourcePrivate *priv = GET_PRIVATE (source);
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	char **audio_folders;
 	char *mount_path;
 
 	mount_path = rb_generic_player_source_get_mount_path (source);
-	g_object_get (source,
-		      "entry-type", &entry_type,
-		      NULL);
+	g_object_get (source, "entry-type", &entry_type, NULL);
 
 	/* if we have a set of folders on the device containing audio files,
 	 * load only those folders, otherwise add the whole volume.
@@ -503,7 +519,7 @@ load_songs (RBGenericPlayerSource *source)
 
 	rhythmdb_import_job_start (priv->import_job);
 
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 	g_free (mount_path);
 }
 
@@ -678,7 +694,7 @@ load_playlist_file (RBGenericPlayerSource *source,
 		    const char *playlist_path,
 		    const char *rel_path)
 {
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	RBGenericPlayerPlaylistSource *playlist;
 	RBShell *shell;
 	char *mount_path;
@@ -701,7 +717,7 @@ load_playlist_file (RBGenericPlayerSource *source,
 		rb_generic_player_source_add_playlist (source, shell, RB_SOURCE (playlist));
 	}
 
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 	g_object_unref (shell);
 	g_free (mount_path);
 }
@@ -714,7 +730,7 @@ visit_playlist_dirs (GFile *file,
 	char *basename;
 	char *uri;
 	RhythmDBEntry *entry;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	RBGenericPlayerSourcePrivate *priv = GET_PRIVATE (source);
 
 	if (dir) {
@@ -734,7 +750,7 @@ visit_playlist_dirs (GFile *file,
 
 		g_object_get (source, "entry-type", &entry_type, NULL);
 		is_song = (rhythmdb_entry_get_entry_type (entry) == entry_type);
-		g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+		g_object_unref (entry_type);
 
 		if (is_song) {
 			rb_debug ("%s was loaded as a song",
@@ -1333,7 +1349,7 @@ static void
 impl_add_playlist (RBMediaPlayerSource *source, char *name, GList *entries)
 {
 	RBSource *playlist;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	RBShell *shell;
 	GList *i;
 
@@ -1343,7 +1359,7 @@ impl_add_playlist (RBMediaPlayerSource *source, char *name, GList *entries)
 		      NULL);
 
 	playlist = rb_generic_player_playlist_source_new (shell, RB_GENERIC_PLAYER_SOURCE (source), NULL, NULL, entry_type);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 
 	rb_generic_player_source_add_playlist (RB_GENERIC_PLAYER_SOURCE (source),
 					       shell,
diff --git a/plugins/generic-player/rb-nokia770-source.c b/plugins/generic-player/rb-nokia770-source.c
index 5e5e95e..b0a3198 100644
--- a/plugins/generic-player/rb-nokia770-source.c
+++ b/plugins/generic-player/rb-nokia770-source.c
@@ -81,7 +81,7 @@ RBRemovableMediaSource *
 rb_nokia770_source_new (RBPlugin *plugin, RBShell *shell, GMount *mount, MPIDDevice *device_info)
 {
 	RBNokia770Source *source;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	RhythmDB *db;
 	GVolume *volume;
 	char *name;
@@ -94,7 +94,14 @@ rb_nokia770_source_new (RBPlugin *plugin, RBShell *shell, GMount *mount, MPIDDev
 	g_object_get (G_OBJECT (shell), "db", &db, NULL);
 	path = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
 	name = g_strdup_printf ("nokia770: %s", path);
-	entry_type = rhythmdb_entry_register_type (db, name);
+
+	entry_type = g_object_new (RHYTHMDB_TYPE_ENTRY_TYPE,
+				   "db", db,
+				   "name", name,
+				   "category", RHYTHMDB_ENTRY_NORMAL,
+				   "save-to-disk", FALSE,
+				   NULL);
+	rhythmdb_register_entry_type (db, entry_type);
 	g_object_unref (db);
 	g_free (name);
 	g_free (path);
@@ -103,8 +110,6 @@ rb_nokia770_source_new (RBPlugin *plugin, RBShell *shell, GMount *mount, MPIDDev
 	source = RB_NOKIA770_SOURCE (g_object_new (RB_TYPE_NOKIA770_SOURCE,
 						   "plugin", plugin,
 						   "entry-type", entry_type,
-						   "ignore-entry-type", RHYTHMDB_ENTRY_TYPE_INVALID,
-						   "error-entry-type", RHYTHMDB_ENTRY_TYPE_INVALID,
 						   "mount", mount,
 						   "shell", shell,
 						   "source-group", RB_SOURCE_GROUP_DEVICES,
diff --git a/plugins/generic-player/rb-psp-source.c b/plugins/generic-player/rb-psp-source.c
index cb3dff5..1cdb6c0 100644
--- a/plugins/generic-player/rb-psp-source.c
+++ b/plugins/generic-player/rb-psp-source.c
@@ -79,7 +79,7 @@ RBRemovableMediaSource *
 rb_psp_source_new (RBPlugin *plugin, RBShell *shell, GMount *mount, MPIDDevice *device_info)
 {
 	RBPspSource *source;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	RhythmDB *db;
 	char *name;
 	char *path;
@@ -92,7 +92,13 @@ rb_psp_source_new (RBPlugin *plugin, RBShell *shell, GMount *mount, MPIDDevice *
 	g_object_get (G_OBJECT (shell), "db", &db, NULL);
 	path = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
 	name = g_strdup_printf ("psp: %s", path);
-	entry_type = rhythmdb_entry_register_type (db, name);
+	entry_type = g_object_new (RHYTHMDB_TYPE_ENTRY_TYPE,
+				   "db", db,
+				   "name", name,
+				   "save-to-disk", FALSE,
+				   "category", RHYTHMDB_ENTRY_NORMAL,
+				   NULL);
+	rhythmdb_register_entry_type (db, entry_type);
 	g_object_unref (db);
 	g_free (name);
 	g_free (path);
@@ -101,8 +107,6 @@ rb_psp_source_new (RBPlugin *plugin, RBShell *shell, GMount *mount, MPIDDevice *
 	source = RB_PSP_SOURCE (g_object_new (RB_TYPE_PSP_SOURCE,
 					  "plugin", plugin,
 					  "entry-type", entry_type,
-					  "ignore-entry-type", RHYTHMDB_ENTRY_TYPE_INVALID,
-					  "error-entry-type", RHYTHMDB_ENTRY_TYPE_INVALID,
 					  "mount", mount,
 					  "shell", shell,
 					  "source-group", RB_SOURCE_GROUP_DEVICES,
@@ -195,7 +199,7 @@ visit_playlist_dirs (RBPspSource *source,
 {
 	RBShell *shell;
 	RhythmDB *db;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	char *playlist_path;
 	char *playlist_name;
 	RBSource *playlist;
@@ -218,7 +222,7 @@ visit_playlist_dirs (RBPspSource *source,
 				      RHYTHMDB_QUERY_PROP_PREFIX, RHYTHMDB_PROP_LOCATION, playlist_path,
 				      RHYTHMDB_QUERY_END);
 	g_free (playlist_path);
-        g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+        g_object_unref (entry_type);
 
 	playlist_name = g_file_get_basename (file);
 	playlist = rb_auto_playlist_source_new (shell, playlist_name, FALSE);
diff --git a/plugins/ipod/rb-ipod-source.c b/plugins/ipod/rb-ipod-source.c
index 2f8b018..ae372dd 100644
--- a/plugins/ipod/rb-ipod-source.c
+++ b/plugins/ipod/rb-ipod-source.c
@@ -53,6 +53,7 @@
 #include "rb-playlist-source.h"
 #include "rb-playlist-manager.h"
 #include "rb-podcast-manager.h"
+#include "rb-podcast-entry-types.h"
 
 #define CONF_STATE_PANED_POSITION CONF_PREFIX "/state/ipod/paned_position"
 #define CONF_STATE_SHOW_BROWSER   CONF_PREFIX "/state/ipod/show_browser"
@@ -278,7 +279,7 @@ rb_ipod_source_name_changed_cb (RBiPodSource *source, GParamSpec *spec,
 
 static void
 rb_ipod_source_init (RBiPodSource *source)
-{	
+{
 }
 
 static void
@@ -358,7 +359,7 @@ rb_ipod_source_new (RBPlugin *plugin,
 		    MPIDDevice *device_info)
 {
 	RBiPodSource *source;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	RhythmDB *db;
 	GVolume *volume;
 	char *name;
@@ -369,12 +370,16 @@ rb_ipod_source_new (RBPlugin *plugin,
 	if (path == NULL)
 		path = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UUID);
 	g_object_unref (volume);
-	
+
 	g_object_get (shell, "db", &db, NULL);
 	name = g_strdup_printf ("ipod: %s", path);
-	entry_type =  rhythmdb_entry_register_type (db, name);
-	entry_type->save_to_disk = FALSE;
-	entry_type->category = RHYTHMDB_ENTRY_NORMAL;
+	entry_type = g_object_new (RHYTHMDB_TYPE_ENTRY_TYPE,
+				   "db", db,
+				   "name", name,
+				   "save-to-disk", FALSE,
+				   "category", RHYTHMDB_ENTRY_NORMAL,
+				   NULL);
+	rhythmdb_register_entry_type (db, entry_type);
 	g_object_unref (db);
 	g_free (name);
 	g_free (path);
@@ -389,7 +394,7 @@ rb_ipod_source_new (RBPlugin *plugin,
 					       NULL));
 
 	rb_shell_register_entry_type_for_source (shell, RB_SOURCE (source), entry_type);
-        g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+        g_object_unref (entry_type);
 
 	return RB_MEDIA_PLAYER_SOURCE (source);
 }
@@ -472,7 +477,7 @@ add_rb_playlist (RBiPodSource *source, Itdb_Playlist *playlist)
 	RBIpodStaticPlaylistSource *playlist_source;
 	GList *it;
 	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	RhythmDBQueryModel *model;
 
 	g_object_get (source,
@@ -485,7 +490,7 @@ add_rb_playlist (RBiPodSource *source, Itdb_Playlist *playlist)
                                                               priv->ipod_db,
                                                               playlist,
                                                               entry_type);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 
 	for (it = playlist->members; it != NULL; it = it->next) {
 		Itdb_Track *song;
@@ -585,7 +590,7 @@ create_ipod_song_from_entry (RhythmDBEntry *entry, guint64 filesize, const char
 	track->app_rating = track->rating;
 	track->playcount = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_PLAY_COUNT);
 
-	if (rhythmdb_entry_get_pointer (entry, RHYTHMDB_PROP_TYPE) == RHYTHMDB_ENTRY_TYPE_PODCAST_POST) {
+	if (rhythmdb_entry_get_entry_type (entry) == RHYTHMDB_ENTRY_TYPE_PODCAST_POST) {
 		track->mediatype = MEDIATYPE_PODCAST;
 		track->time_released = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_POST_TIME);
 	} else {
@@ -621,19 +626,17 @@ static void
 add_ipod_song_to_db (RBiPodSource *source, RhythmDB *db, Itdb_Track *song)
 {
 	RhythmDBEntry *entry;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
 	char *pc_path;
 	const char *mount_path;
 
 	/* Set URI */
-	g_object_get (source, "entry-type", &entry_type,
-		      NULL);
+	g_object_get (source, "entry-type", &entry_type, NULL);
 	mount_path = rb_ipod_db_get_mount_path (priv->ipod_db);
 	pc_path = ipod_path_to_uri (mount_path, song->ipod_path);
-	entry = rhythmdb_entry_new (RHYTHMDB (db), entry_type,
-				    pc_path);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	entry = rhythmdb_entry_new (RHYTHMDB (db), entry_type, pc_path);
+	g_object_unref (entry_type);
 
 	if (entry == NULL) {
 		rb_debug ("cannot create entry %s", pc_path);
@@ -853,7 +856,7 @@ remove_playcount_file (RBiPodSource *source)
         char *playcounts_file;
         int result;
 	const char *mountpoint;
-	
+
 	mountpoint = rb_ipod_db_get_mount_path (priv->ipod_db);
         itunesdb_dir = itdb_get_itunes_dir (mountpoint);
         playcounts_file = itdb_get_path (itunesdb_dir, "Play Counts");
@@ -918,24 +921,20 @@ rb_ipod_source_entry_changed_cb (RhythmDB *db,
 	int i;
 
 	/* Ignore entries which are not iPod entries */
-	RhythmDBEntryType entry_type;
-	RhythmDBEntryType ipod_entry_type;
+	RhythmDBEntryType *entry_type;
+	RhythmDBEntryType *ipod_entry_type;
 	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
 
-	entry_type = rhythmdb_entry_get_pointer (entry, RHYTHMDB_PROP_TYPE);
-	g_object_get (G_OBJECT (source),
-		      "entry-type", &ipod_entry_type,
-		      NULL);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, ipod_entry_type);
-	/* ipod_entry_type can no longer be dereferenced, but its value 
-	 * hasn't been changed, so this comparison is valid
-	 */
+	entry_type = rhythmdb_entry_get_entry_type (entry);
+	g_object_get (source, "entry-type", &ipod_entry_type, NULL);
 	if (entry_type != ipod_entry_type) {
-		return; 
+		g_object_unref (ipod_entry_type);
+		return;
 	}
+	g_object_unref (ipod_entry_type);
 
 	/* If an interesting property was changed, update it on the iPod */
-	/* If the iPod database is being saved in a separate thread, this 
+	/* If the iPod database is being saved in a separate thread, this
 	 * might not be 100% thread-safe, but at worst we'll modify a field
 	 * at the time it's being saved which will get a wrong value, but
 	 * that's the worst that can happen and that's pretty theoretical,
@@ -953,7 +952,7 @@ rb_ipod_source_entry_changed_cb (RhythmDB *db,
 			old_rating = g_value_get_double (&change->old);
 			new_rating = g_value_get_double (&change->new);
 			if (old_rating != new_rating) {
-				track = g_hash_table_lookup (priv->entry_map, 
+				track = g_hash_table_lookup (priv->entry_map,
 							     entry);
 				track->rating = new_rating * ITDB_RATING_STEP;
 				track->app_rating = track->rating;
@@ -972,7 +971,7 @@ rb_ipod_source_entry_changed_cb (RhythmDB *db,
 			old_playcount = g_value_get_ulong (&change->old);
 			new_playcount = g_value_get_ulong (&change->new);
 			if (old_playcount != new_playcount) {
-				track = g_hash_table_lookup (priv->entry_map, 
+				track = g_hash_table_lookup (priv->entry_map,
 							     entry);
 				track->playcount = new_playcount;
 				rb_debug ("playcount changed, saving db");
@@ -990,7 +989,7 @@ rb_ipod_source_entry_changed_cb (RhythmDB *db,
 			old_lastplay = g_value_get_ulong (&change->old);
 			new_lastplay = g_value_get_ulong (&change->new);
 			if (old_lastplay != new_lastplay) {
-				track = g_hash_table_lookup (priv->entry_map, 
+				track = g_hash_table_lookup (priv->entry_map,
 							     entry);
 				track->time_played = new_lastplay;
 				rb_debug ("last play time changed, saving db");
@@ -998,7 +997,7 @@ rb_ipod_source_entry_changed_cb (RhythmDB *db,
 			} else {
 				rb_debug ("last play time didn't change");
 			}
-			break;			
+			break;
 		}
 		default:
 			rb_debug ("Ignoring property %d", change->prop);
@@ -1028,7 +1027,7 @@ load_ipod_db_idle_cb (RBiPodSource *source)
 	load_ipod_playlists (source);
 	send_offline_plays_notification (source);
 
-	g_signal_connect_object(G_OBJECT(db), "entry-changed", 
+	g_signal_connect_object(G_OBJECT(db), "entry-changed",
 				G_CALLBACK (rb_ipod_source_entry_changed_cb),
 				source, 0);
 
@@ -1251,7 +1250,7 @@ impl_build_dest_uri (RBRemovableMediaSource *source,
 
 	uri = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
 	mount_path = rb_ipod_db_get_mount_path (priv->ipod_db);
-	dest = ipod_get_filename_for_uri (mount_path,  uri, 
+	dest = ipod_get_filename_for_uri (mount_path,  uri,
 					  mimetype, extension);
 	if (dest != NULL) {
 		char *dest_uri;
@@ -1277,7 +1276,7 @@ artwork_notify_cb (RhythmDB *db,
 
 	g_return_if_fail (G_VALUE_HOLDS (metadata, GDK_TYPE_PIXBUF));
 	pixbuf = GDK_PIXBUF (g_value_get_object (metadata));
-		
+
 	song = g_hash_table_lookup (priv->artwork_request_map, entry);
 	if (song == NULL)
 		return;
@@ -1293,29 +1292,29 @@ rb_add_artwork_whole_album_cb (GtkTreeModel *query_model,
 			       RBiPodSongArtworkAddData *artwork_data)
 {
 	RhythmDBEntry *entry;
-	Itdb_Track *song;	
-	
+	Itdb_Track *song;
+
 	entry = rhythmdb_query_model_iter_to_entry (RHYTHMDB_QUERY_MODEL (query_model), iter);
 
 	song = g_hash_table_lookup (artwork_data->priv->entry_map, entry);
 	rhythmdb_entry_unref (entry);
 	g_return_val_if_fail (song != NULL, FALSE);
 
-	if (song->has_artwork == 0x01) {		   
-		return FALSE;				
+	if (song->has_artwork == 0x01) {
+		return FALSE;
 	}
-	
+
 	rb_ipod_db_set_thumbnail (artwork_data->priv->ipod_db, song, artwork_data->pixbuf);
-	
-	return FALSE;	
-}			     
 
-static gboolean 
+	return FALSE;
+}
+
+static gboolean
 rb_ipod_song_artwork_add_cb (RhythmDB *db,
 			     RhythmDBEntry *entry,
 			     const gchar *property_name,
 			     const GValue *metadata,
-			     RBiPodSource *isource)			     
+			     RBiPodSource *isource)
 {
 	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (isource);
 	Itdb_Device *device;
@@ -1323,7 +1322,7 @@ rb_ipod_song_artwork_add_cb (RhythmDB *db,
 	GdkPixbuf *pixbuf;
 	GtkTreeModel *query_model;
 	RBiPodSongArtworkAddData artwork_data;
-        RhythmDBEntryType entry_type;
+        RhythmDBEntryType *entry_type;
 
 	if (metadata == NULL) {
 		return FALSE;
@@ -1333,7 +1332,7 @@ rb_ipod_song_artwork_add_cb (RhythmDB *db,
 		return FALSE;
 	}
 
-	song = g_hash_table_lookup (priv->entry_map, entry);		
+	song = g_hash_table_lookup (priv->entry_map, entry);
         if (song == NULL) {
                 return FALSE;
         }
@@ -1347,12 +1346,12 @@ rb_ipod_song_artwork_add_cb (RhythmDB *db,
 		return FALSE;
 	}
 
-        g_object_get (G_OBJECT (isource), "entry-type", &entry_type, NULL);
- 
+        g_object_get (isource, "entry-type", &entry_type, NULL);
+
 	pixbuf = GDK_PIXBUF (g_value_get_object (metadata));
-	
+
 	query_model = GTK_TREE_MODEL (rhythmdb_query_model_new_empty (db));
-	
+
 	rhythmdb_do_full_query (db, RHYTHMDB_QUERY_RESULTS (query_model),
                                 RHYTHMDB_QUERY_PROP_EQUALS,
                                 RHYTHMDB_PROP_TYPE, entry_type,
@@ -1361,18 +1360,18 @@ rb_ipod_song_artwork_add_cb (RhythmDB *db,
 				RHYTHMDB_QUERY_PROP_EQUALS,
 				RHYTHMDB_PROP_ALBUM, song->album,
 				RHYTHMDB_QUERY_END);
-				
+
 	artwork_data.priv = priv;
 	artwork_data.pixbuf = pixbuf;
-				
+
 	gtk_tree_model_foreach (query_model,
 				(GtkTreeModelForeachFunc) rb_add_artwork_whole_album_cb,
 				&artwork_data);
-        g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);	
+        g_object_unref (entry_type);
 	g_object_unref(query_model);
 	return FALSE;
 }
-												
+
 static void
 request_artwork (RBiPodSource *isource,
 		 RhythmDBEntry *entry,
@@ -1475,7 +1474,7 @@ impl_track_added (RBRemovableMediaSource *source,
 		if (song->mediatype == MEDIATYPE_PODCAST) {
 			add_to_podcasts (isource, song);
 		}
-		device = rb_ipod_db_get_device (priv->ipod_db);		
+		device = rb_ipod_db_get_device (priv->ipod_db);
 		if (device && itdb_device_supports_artwork (device)) {
 			request_artwork (isource, entry, db, song);
 		}
@@ -1835,9 +1834,9 @@ rb_ipod_source_remove_playlist (RBiPodSource *ipod_source,
 static gboolean
 ipod_name_changed_cb (GtkWidget     *widget,
  		      GdkEventFocus *event,
- 		      gpointer       user_data) 
+		      gpointer       user_data)
 {
-	g_object_set (RB_SOURCE (user_data), "name", 
+	g_object_set (RB_SOURCE (user_data), "name",
 		      gtk_entry_get_text (GTK_ENTRY (widget)),
 		      NULL);
 	return FALSE;
@@ -1885,7 +1884,7 @@ impl_show_properties (RBMediaPlayerSource *source, GtkWidget *info_box, GtkWidge
  		rb_debug ("Couldn't load ipod-info.ui");
  		return;
  	}
-	
+
 	ipod_dev = rb_ipod_db_get_device (priv->ipod_db);
 
 	/* basic tab stuff */
diff --git a/plugins/ipod/rb-ipod-static-playlist-source.c b/plugins/ipod/rb-ipod-static-playlist-source.c
index 1419d66..36d40a9 100644
--- a/plugins/ipod/rb-ipod-static-playlist-source.c
+++ b/plugins/ipod/rb-ipod-static-playlist-source.c
@@ -158,7 +158,7 @@ rb_ipod_static_playlist_source_new (RBShell *shell,
 				    RBiPodSource *ipod_source,
 				    RbIpodDb *ipod_db,
 				    Itdb_Playlist *playlist,
-				    RhythmDBEntryType entry_type)
+				    RhythmDBEntryType *entry_type)
 {
 	RBIpodStaticPlaylistSource *source;
 
diff --git a/plugins/ipod/rb-ipod-static-playlist-source.h b/plugins/ipod/rb-ipod-static-playlist-source.h
index bfd45ac..16f2ff3 100644
--- a/plugins/ipod/rb-ipod-static-playlist-source.h
+++ b/plugins/ipod/rb-ipod-static-playlist-source.h
@@ -52,7 +52,7 @@ RBIpodStaticPlaylistSource *	rb_ipod_static_playlist_source_new (RBShell *shell,
 								    RBiPodSource *source,
 								    RbIpodDb *ipod_db,
 								    Itdb_Playlist *playlist,
-								    RhythmDBEntryType entry_type);
+								    RhythmDBEntryType *entry_type);
 
 Itdb_Playlist* rb_ipod_static_playlist_source_get_itdb_playlist (RBIpodStaticPlaylistSource *playlist);
 RBiPodSource* rb_ipod_static_playlist_source_get_ipod_source (RBIpodStaticPlaylistSource *playlist);
diff --git a/plugins/iradio/rb-iradio-source.c b/plugins/iradio/rb-iradio-source.c
index 1817b17..d25501f 100644
--- a/plugins/iradio/rb-iradio-source.c
+++ b/plugins/iradio/rb-iradio-source.c
@@ -426,18 +426,22 @@ RBSource *
 rb_iradio_source_new (RBShell *shell, RBPlugin *plugin)
 {
 	RBSource *source;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	RhythmDB *db;
 
 	g_object_get (shell, "db", &db, NULL);
 
 	entry_type = rhythmdb_entry_type_get_by_name (db, "iradio");
-	if (entry_type == RHYTHMDB_ENTRY_TYPE_INVALID) {
-		entry_type = rhythmdb_entry_register_type (db, "iradio");
-		entry_type->save_to_disk = TRUE;
-		entry_type->category = RHYTHMDB_ENTRY_STREAM;
-		entry_type->can_sync_metadata = (RhythmDBEntryCanSyncFunc) rb_true_function;
-		entry_type->sync_metadata = (RhythmDBEntrySyncFunc) rb_null_function;
+	if (entry_type == NULL) {
+		entry_type = g_object_new (RHYTHMDB_TYPE_ENTRY_TYPE,
+					   "db", db,
+					   "name", "iradio",
+					   "save-to-disk", TRUE,
+					   "category", RHYTHMDB_ENTRY_STREAM,
+					   NULL);
+		entry_type->can_sync_metadata = (RhythmDBEntryTypeBooleanFunc) rb_true_function;
+		entry_type->sync_metadata = (RhythmDBEntryTypeSyncFunc) rb_null_function;
+		rhythmdb_register_entry_type (db, entry_type);
 	}
 	g_object_unref (db);
 
@@ -484,7 +488,7 @@ rb_iradio_source_add_station (RBIRadioSource *source,
 	char *real_uri = NULL;
 	char *fixed_title;
 	char *fixed_genre = NULL;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 
 	real_uri = guess_uri_scheme (uri);
 	if (real_uri)
@@ -499,7 +503,7 @@ rb_iradio_source_add_station (RBIRadioSource *source,
 
 	g_object_get (source, "entry-type", &entry_type, NULL);
 	entry = rhythmdb_entry_new (source->priv->db, entry_type, uri);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 	if (entry == NULL) {
 		g_free (real_uri);
 		return;
@@ -762,7 +766,7 @@ rb_iradio_source_do_query (RBIRadioSource *source)
 	RhythmDBQueryModel *station_query_model = NULL;
 	RhythmDBPropertyModel *genre_model;
 	GPtrArray *query;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 
 	/* don't update the selection while we're rebuilding the query */
 	source->priv->setting_new_query = TRUE;
@@ -777,7 +781,7 @@ rb_iradio_source_do_query (RBIRadioSource *source)
 				      RHYTHMDB_PROP_TYPE,
 				      entry_type,
 				      RHYTHMDB_QUERY_END);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 
 	if (source->priv->search_query != NULL) {
 		rhythmdb_query_append (source->priv->db,
@@ -1007,13 +1011,13 @@ rb_iradio_source_cmd_new_station (GtkAction *action,
 static gboolean
 check_entry_type (RBIRadioSource *source, RhythmDBEntry *entry)
 {
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	gboolean matches = FALSE;
 
 	g_object_get (source, "entry-type", &entry_type, NULL);
 	if (entry != NULL && rhythmdb_entry_get_entry_type (entry) == entry_type)
 		matches = TRUE;
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 
 	return matches;
 }
diff --git a/plugins/jamendo/jamendo/__init__.py b/plugins/jamendo/jamendo/__init__.py
index eea0f75..e7ecb14 100644
--- a/plugins/jamendo/jamendo/__init__.py
+++ b/plugins/jamendo/jamendo/__init__.py
@@ -52,6 +52,12 @@ popup_ui = """
 </ui>
 """
 
+class JamendoEntryType(rhythmdb.EntryType):
+	def __init__(self):
+		rhythmdb.EntryType.__init__(self, name='jamendo')
+
+	def can_sync_metadata(self, entry):
+		return True
 
 class Jamendo(rb.Plugin):
 	#
@@ -64,10 +70,8 @@ class Jamendo(rb.Plugin):
 	def activate(self, shell):
 		self.db = shell.get_property("db")
 
-		self.entry_type = self.db.entry_register_type("JamendoEntryType")
-		# allow changes which don't do anything
-		self.entry_type.can_sync_metadata = True
-		self.entry_type.sync_metadata = None
+		self.entry_type = JamendoEntryType()
+		self.db.register_entry_type(self.entry_type)
 
 		theme = gtk.icon_theme_get_default()
 		rb.append_plugin_source_path(theme, "/icons/")
diff --git a/plugins/magnatune/magnatune/__init__.py b/plugins/magnatune/magnatune/__init__.py
index bb9e47f..6f50ebc 100644
--- a/plugins/magnatune/magnatune/__init__.py
+++ b/plugins/magnatune/magnatune/__init__.py
@@ -57,6 +57,13 @@ popup_ui = """
 </ui>
 """
 
+class MagnatuneEntryType(rhythmdb.EntryType):
+	def __init__(self):
+		rhythmdb.EntryType.__init__(self, name='magnatune')
+
+	def can_sync_metadata(self, entry):
+		return True
+
 class Magnatune(rb.Plugin):
 	client = gconf.client_get_default()
 
@@ -82,10 +89,8 @@ class Magnatune(rb.Plugin):
 		self.shell = shell # so the source can update the progress bar
 		self.db = shell.get_property("db")
 
-		self.entry_type = self.db.entry_register_type("MagnatuneEntryType")
-		# allow changes which don't do anything
-		self.entry_type.can_sync_metadata = True
-		self.entry_type.sync_metadata = None
+		self.entry_type = MagnatuneEntryType()
+		self.db.register_entry_type(self.entry_type)
 
 		theme = gtk.icon_theme_get_default()
 		rb.append_plugin_source_path(theme, "/icons")
diff --git a/plugins/mtpdevice/rb-mtp-source.c b/plugins/mtpdevice/rb-mtp-source.c
index 1f1b66f..2ce4dac 100644
--- a/plugins/mtpdevice/rb-mtp-source.c
+++ b/plugins/mtpdevice/rb-mtp-source.c
@@ -486,7 +486,7 @@ rb_mtp_source_dispose (GObject *object)
 {
 	RBMtpSource *source = RB_MTP_SOURCE (object);
 	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	RhythmDB *db;
 
 	if (priv->device_thread != NULL) {
@@ -512,7 +512,7 @@ rb_mtp_source_dispose (GObject *object)
 
 	g_object_get (G_OBJECT (source), "entry-type", &entry_type, NULL);
 	rhythmdb_entry_delete_by_type (db, entry_type);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 
 	rhythmdb_commit (db);
 	g_object_unref (db);
@@ -567,17 +567,19 @@ rb_mtp_source_new (RBShell *shell,
 		   LIBMTP_raw_device_t *device)
 {
 	RBMtpSource *source = NULL;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	RhythmDB *db = NULL;
 	char *name = NULL;
 
 	g_object_get (shell, "db", &db, NULL);
 	name = g_strdup_printf ("MTP-%u-%d", device->bus_location, device->devnum);
 
-	entry_type = rhythmdb_entry_register_type (db, name);
-	entry_type->save_to_disk = FALSE;
-	entry_type->category = RHYTHMDB_ENTRY_NORMAL;
-
+	entry_type = g_object_new (RHYTHMDB_TYPE_ENTRY_TYPE,
+				   "db", db,
+				   "name", name,
+				   "save-to-disk", FALSE,
+				   "category", RHYTHMDB_ENTRY_NORMAL,
+				   NULL);
 	g_free (name);
 	g_object_unref (db);
 
@@ -652,7 +654,7 @@ add_mtp_track_to_db (RBMtpSource *source,
 		     LIBMTP_track_t *track)
 {
 	RhythmDBEntry *entry = NULL;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
 	char *name = NULL;
 
@@ -669,7 +671,7 @@ add_mtp_track_to_db (RBMtpSource *source,
 	name = g_strdup_printf ("xrbmtp://%i/%s", track->item_id, track->filename);
 	entry = rhythmdb_entry_new (RHYTHMDB (db), entry_type, name);
 	g_free (name);
-        g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+        g_object_unref (entry_type);
 
 	if (entry == NULL) {
 		rb_debug ("cannot create entry %i", track->item_id);
diff --git a/podcast/Makefile.am b/podcast/Makefile.am
index cab390f..0e9578a 100644
--- a/podcast/Makefile.am
+++ b/podcast/Makefile.am
@@ -17,7 +17,8 @@ librbpodcast_la_SOURCES =				\
 	rb-podcast-properties-dialog.c			\
 	rb-podcast-properties-dialog.h			\
 	rb-podcast-parse.c				\
-	rb-podcast-manager.c
+	rb-podcast-manager.c				\
+	rb-podcast-entry-types.c
 
 noinst_PROGRAMS = test-podcast-parse
 test_podcast_parse_SOURCES =				\
diff --git a/podcast/rb-podcast-entry-types.c b/podcast/rb-podcast-entry-types.c
new file mode 100644
index 0000000..0bd5409
--- /dev/null
+++ b/podcast/rb-podcast-entry-types.c
@@ -0,0 +1,135 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ *  Copyright (C) 2010  Jonathan Matthew  <jonathan d14n org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#include "config.h"
+
+#include "rb-podcast-entry-types.h"
+#include "rhythmdb-private.h"		/* for RhythmDBPodcastFields, which should move in here somehow */
+#include "rhythmdb.h"
+#include "rb-util.h"
+
+static RhythmDBEntryType *podcast_post_entry_type = NULL;
+static RhythmDBEntryType *podcast_feed_entry_type = NULL;
+
+static char *
+podcast_get_playback_uri (RhythmDBEntryType *entry_type, RhythmDBEntry *entry)
+{
+	if (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MOUNTPOINT) != NULL) {
+		return rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_LOCATION);
+	}
+	return NULL;
+}
+
+static void
+podcast_post_create (RhythmDBEntryType *entry_type, RhythmDBEntry *entry)
+{
+	RhythmDBPodcastFields *podcast = RHYTHMDB_ENTRY_GET_TYPE_DATA (entry, RhythmDBPodcastFields);
+	RBRefString *empty = rb_refstring_new ("");
+	podcast->description = rb_refstring_ref (empty);
+	podcast->subtitle = rb_refstring_ref (empty);
+	podcast->summary = rb_refstring_ref (empty);
+	podcast->lang = rb_refstring_ref (empty);
+	podcast->copyright = rb_refstring_ref (empty);
+	podcast->image = rb_refstring_ref (empty);
+	rb_refstring_unref (empty);
+}
+
+static void
+podcast_data_destroy (RhythmDBEntryType *entry_type, RhythmDBEntry *entry)
+{
+	RhythmDBPodcastFields *podcast = RHYTHMDB_ENTRY_GET_TYPE_DATA (entry, RhythmDBPodcastFields);
+	rb_refstring_unref (podcast->description);
+	rb_refstring_unref (podcast->subtitle);
+	rb_refstring_unref (podcast->summary);
+	rb_refstring_unref (podcast->lang);
+	rb_refstring_unref (podcast->copyright);
+	rb_refstring_unref (podcast->image);
+}
+
+/**
+ * rb_podcast_get_post_entry_type:
+ *
+ * Returns the #RhythmDBEntryType for podcast posts
+ *
+ * Return value: (transfer none): the entry type for podcast posts
+ */
+RhythmDBEntryType *
+rb_podcast_get_post_entry_type (void)
+{
+	return podcast_post_entry_type;
+}
+
+/**
+ * rhythmdb_get_ignore_entry_type:
+ *
+ * Returns the #RhythmDBEntryType for ignored files
+ *
+ * Return value: (transfer none): the entry type for ignored files
+ */
+RhythmDBEntryType *
+rb_podcast_get_feed_entry_type (void)
+{
+	return podcast_feed_entry_type;
+}
+
+
+
+void
+rb_podcast_register_entry_types (RhythmDB *db)
+{
+	g_assert (podcast_post_entry_type == NULL);
+	g_assert (podcast_feed_entry_type == NULL);
+
+	podcast_post_entry_type = g_object_new (RHYTHMDB_TYPE_ENTRY_TYPE,
+						"db", db,
+						"name", "podcast-post",
+						"save-to-disk", TRUE,
+						"category", RHYTHMDB_ENTRY_NORMAL,
+						"type-data-size", sizeof (RhythmDBPodcastFields),
+						NULL);
+	podcast_post_entry_type->entry_created = podcast_post_create;
+	podcast_post_entry_type->destroy_entry = podcast_data_destroy;
+	podcast_post_entry_type->get_playback_uri = podcast_get_playback_uri;
+	podcast_post_entry_type->can_sync_metadata = (RhythmDBEntryTypeBooleanFunc) rb_true_function;
+	podcast_post_entry_type->sync_metadata = (RhythmDBEntryTypeSyncFunc) rb_null_function;
+	rhythmdb_register_entry_type (db, podcast_post_entry_type);
+
+	podcast_feed_entry_type = g_object_new (RHYTHMDB_TYPE_ENTRY_TYPE,
+						"db", db,
+						"name", "podcast-feed",
+						"save-to-disk", TRUE,
+						"category", RHYTHMDB_ENTRY_CONTAINER,
+						"type-data-size", sizeof (RhythmDBPodcastFields),
+						NULL);
+	podcast_feed_entry_type->entry_created = podcast_post_create;
+	podcast_feed_entry_type->destroy_entry = podcast_data_destroy;
+	podcast_feed_entry_type->get_playback_uri = (RhythmDBEntryTypeStringFunc) rb_null_function;
+	podcast_feed_entry_type->can_sync_metadata = (RhythmDBEntryTypeBooleanFunc) rb_true_function;
+	podcast_feed_entry_type->sync_metadata = (RhythmDBEntryTypeSyncFunc) rb_null_function;
+	rhythmdb_register_entry_type (db, podcast_feed_entry_type);
+}
diff --git a/podcast/rb-podcast-entry-types.h b/podcast/rb-podcast-entry-types.h
new file mode 100644
index 0000000..86d1b7d
--- /dev/null
+++ b/podcast/rb-podcast-entry-types.h
@@ -0,0 +1,45 @@
+/*
+ *  Copyright (C) 2010 Jonathan Matthew  <jonathan d14n org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#ifndef RB_PODCAST_ENTRY_TYPES_H
+#define RB_PODCAST_ENTRY_TYPES_H
+
+#include <rhythmdb/rhythmdb-entry-type.h>
+#include <rhythmdb/rhythmdb.h>
+
+G_BEGIN_DECLS
+
+RhythmDBEntryType *rb_podcast_get_post_entry_type  (void);
+RhythmDBEntryType *rb_podcast_get_feed_entry_type  (void);
+#define RHYTHMDB_ENTRY_TYPE_PODCAST_POST (rb_podcast_get_post_entry_type ())
+#define RHYTHMDB_ENTRY_TYPE_PODCAST_FEED (rb_podcast_get_feed_entry_type ())
+
+void			rb_podcast_register_entry_types		(RhythmDB *db);
+
+G_END_DECLS
+
+#endif /* RB_PODCAST_ENTRY_TYPES_H */
diff --git a/podcast/rb-podcast-manager.c b/podcast/rb-podcast-manager.c
index 9bb92da..a972490 100644
--- a/podcast/rb-podcast-manager.c
+++ b/podcast/rb-podcast-manager.c
@@ -40,6 +40,7 @@
 #include "rb-preferences.h"
 #include "eel-gconf-extensions.h"
 #include "rb-podcast-manager.h"
+#include "rb-podcast-entry-types.h"
 #include "rb-file-helpers.h"
 #include "rb-debug.h"
 #include "rb-marshal.h"
@@ -486,7 +487,7 @@ rb_podcast_manager_entry_downloaded (RhythmDBEntry *entry)
 {
 	gulong status;
 	const gchar *file_name;
-	RhythmDBEntryType type = rhythmdb_entry_get_entry_type (entry);
+	RhythmDBEntryType *type = rhythmdb_entry_get_entry_type (entry);
 
 	g_assert (type == RHYTHMDB_ENTRY_TYPE_PODCAST_POST);
 
@@ -1344,7 +1345,7 @@ rb_podcast_manager_save_metadata (RBPodcastManager *pd, RhythmDBEntry *entry)
 static void
 rb_podcast_manager_db_entry_added_cb (RBPodcastManager *pd, RhythmDBEntry *entry)
 {
-	RhythmDBEntryType type = rhythmdb_entry_get_entry_type (entry);
+	RhythmDBEntryType *type = rhythmdb_entry_get_entry_type (entry);
 
 	if (type != RHYTHMDB_ENTRY_TYPE_PODCAST_POST)
 		return;
@@ -1706,7 +1707,7 @@ rb_podcast_manager_delete_download (RBPodcastManager *pd, RhythmDBEntry *entry)
 	const char *file_name;
 	GFile *file;
 	GError *error = NULL;
-	RhythmDBEntryType type = rhythmdb_entry_get_entry_type (entry);
+	RhythmDBEntryType *type = rhythmdb_entry_get_entry_type (entry);
 
 	/* make sure it's a podcast post */
 	g_assert (type == RHYTHMDB_ENTRY_TYPE_PODCAST_POST);
diff --git a/podcast/rb-podcast-manager.h b/podcast/rb-podcast-manager.h
index 22695b3..deaa18b 100644
--- a/podcast/rb-podcast-manager.h
+++ b/podcast/rb-podcast-manager.h
@@ -91,6 +91,7 @@ RhythmDBEntry *         rb_podcast_manager_add_post  	  	(RhythmDB *db,
 
 gboolean		rb_podcast_manager_entry_downloaded	(RhythmDBEntry *entry);
 
+
 G_END_DECLS
 
 #endif /* RB_PODCAST_MANAGER_H */
diff --git a/rhythmdb/Makefile.am b/rhythmdb/Makefile.am
index 18acbe2..99af5e5 100644
--- a/rhythmdb/Makefile.am
+++ b/rhythmdb/Makefile.am
@@ -10,6 +10,7 @@ INCLUDES = 						\
 	-I$(top_srcdir)/lib 				\
 	-I$(top_srcdir)/widgets				\
 	-I$(top_srcdir)/metadata			\
+	-I$(top_srcdir)/podcast				\
 	-I$(top_builddir)/lib                           \
 	$(RHYTHMBOX_CFLAGS)				\
 	$(NO_STRICT_ALIASING_CFLAGS)
@@ -21,7 +22,8 @@ rhythmdbinclude_HEADERS =				\
 	rhythmdb-property-model.h			\
 	rhythmdb-query-model.h				\
 	rhythmdb-query-results.h			\
-	rhythmdb-import-job.h
+	rhythmdb-import-job.h				\
+	rhythmdb-entry-type.h
 
 librhythmdb_la_SOURCES =				\
 	$(rhythmdbinclude_HEADERS)			\
@@ -33,7 +35,9 @@ librhythmdb_la_SOURCES =				\
 	rhythmdb-property-model.c			\
 	rhythmdb-query-model.c				\
 	rhythmdb-query-results.c			\
-	rhythmdb-import-job.c
+	rhythmdb-import-job.c				\
+	rhythmdb-entry-type.c				\
+	rhythmdb-song-entry-types.c
 
 
 if USE_TREEDB
diff --git a/rhythmdb/rhythmdb-entry-type.c b/rhythmdb/rhythmdb-entry-type.c
new file mode 100644
index 0000000..4973bd8
--- /dev/null
+++ b/rhythmdb/rhythmdb-entry-type.c
@@ -0,0 +1,386 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ *  Copyright (C) 2010  Jonathan Matthew  <jonathan d14n org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#include "config.h"
+
+#include "rhythmdb-entry-type.h"
+#include "rhythmdb-private.h"
+
+enum
+{
+	PROP_0,
+	PROP_DB,
+	PROP_NAME,
+	PROP_SAVE_TO_DISK,
+	PROP_TYPE_DATA_SIZE,
+	PROP_CATEGORY,
+	PROP_HAS_PLAYLISTS		/* temporary */
+};
+
+static void rhythmdb_entry_type_class_init (RhythmDBEntryTypeClass *klass);
+static void rhythmdb_entry_type_init (RhythmDBEntryType *etype);
+
+struct _RhythmDBEntryTypePrivate
+{
+	RhythmDB *db;
+
+	char *name;
+	gboolean save_to_disk;
+	guint entry_type_data_size;
+	RhythmDBEntryCategory category;
+	gboolean has_playlists;
+};
+
+G_DEFINE_TYPE (RhythmDBEntryType, rhythmdb_entry_type, G_TYPE_OBJECT)
+
+/**
+ * SECTION:rhythmdb-entry-type
+ * @short_description: Database entry type base class
+ *
+ * This is the base class for database entry type classes, which provide
+ * some aspects of the behaviour of database entry types.  There are different
+ * entry types for songs, radio streams, podcast feeds and episodes, and so on.
+ */
+
+/**
+ * rhythmdb_entry_type_get_name:
+ * @etype: a #RhythmDBEntryType
+ *
+ * Returns the name of the entry type
+ *
+ * Return value: entry type name
+ */
+const char *
+rhythmdb_entry_type_get_name (RhythmDBEntryType *etype)
+{
+	return etype->priv->name;
+}
+
+/**
+ * rhythmdb_entry_get_playback_uri:
+ * @entry: a #RhythmDBEntry
+ *
+ * Returns an allocated string containing the playback URI for @entry,
+ * or NULL if the entry cannot be played.
+ *
+ * Return value: playback URI or NULL
+ */
+char *
+rhythmdb_entry_get_playback_uri (RhythmDBEntry *entry)
+{
+	RhythmDBEntryType *etype = rhythmdb_entry_get_entry_type (entry);
+	RhythmDBEntryTypeClass *klass = RHYTHMDB_ENTRY_TYPE_GET_CLASS (etype);
+
+	if (etype->get_playback_uri) {
+		return (etype->get_playback_uri) (etype, entry);
+	} else if (klass->get_playback_uri) {
+		return (klass->get_playback_uri) (etype, entry);
+	} else {
+		return rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_LOCATION);
+	}
+}
+
+/**
+ * rhythmdb_entry_created:
+ * @entry: a newly created #RhythmDBEntry
+ *
+ * Calls the entry type's post-creation method for @entry.
+ */
+void
+rhythmdb_entry_created (RhythmDBEntry *entry)
+{
+	RhythmDBEntryType *etype;
+	RhythmDBEntryTypeClass *klass;
+
+	etype = rhythmdb_entry_get_entry_type (entry);
+	klass = RHYTHMDB_ENTRY_TYPE_GET_CLASS (etype);
+
+	if (etype->entry_created) {
+		etype->entry_created (etype, entry);
+	} else if (klass->entry_created) {
+		klass->entry_created (etype, entry);
+	}
+}
+
+/**
+ * rhythmdb_entry_pre_destroy:
+ * @entry: a #RhythmDBEntry
+ *
+ * Calls the entry type's pre-deletion method for @entry.
+ */
+void
+rhythmdb_entry_pre_destroy (RhythmDBEntry *entry)
+{
+	RhythmDBEntryType *etype = rhythmdb_entry_get_entry_type (entry);
+	RhythmDBEntryTypeClass *klass = RHYTHMDB_ENTRY_TYPE_GET_CLASS (etype);
+	if (etype->destroy_entry) {
+		etype->destroy_entry (etype, entry);
+	} else if (klass->destroy_entry) {
+		klass->destroy_entry (etype, entry);
+	}
+}
+
+/**
+ * rhythmdb_entry_can_sync_metadata:
+ * @entry: a #RhythmDBEntry
+ *
+ * Calls the entry type's method to check if it can sync metadata for @entry.
+ * Usually this is only true for entries backed by files, where tag-writing is
+ * enabled, and the appropriate tag-writing facilities are available.
+ *
+ * Return value: %TRUE if the entry can be synced
+ */
+gboolean
+rhythmdb_entry_can_sync_metadata (RhythmDBEntry *entry)
+{
+	RhythmDBEntryType *etype = rhythmdb_entry_get_entry_type (entry);
+	RhythmDBEntryTypeClass *klass = RHYTHMDB_ENTRY_TYPE_GET_CLASS (etype);
+	if (etype->can_sync_metadata) {
+		return etype->can_sync_metadata (etype, entry);
+	} else if (klass->can_sync_metadata) {
+		return klass->can_sync_metadata (etype, entry);
+	} else {
+		return FALSE;
+	}
+}
+
+/**
+ * rhythmdb_entry_sync_metadata:
+ * @entry: a #RhythmDBEntry
+ * @changes: a list of #RhythmDBEntryChange structures
+ * @error: returns error information
+ *
+ * Calls the entry type's method to sync metadata changes for @entry.
+ */
+void
+rhythmdb_entry_sync_metadata (RhythmDBEntry *entry, GSList *changes, GError **error)
+{
+	RhythmDBEntryType *etype = rhythmdb_entry_get_entry_type (entry);
+	RhythmDBEntryTypeClass *klass = RHYTHMDB_ENTRY_TYPE_GET_CLASS (etype);
+	if (etype->sync_metadata) {
+		etype->sync_metadata (etype, entry, changes, error);
+	} else if (klass->sync_metadata) {
+		klass->sync_metadata (etype, entry, changes, error);
+	} else {
+		/* default implementation? */
+	}
+}
+
+static void
+rhythmdb_entry_type_init (RhythmDBEntryType *etype)
+{
+	etype->priv = G_TYPE_INSTANCE_GET_PRIVATE (etype,
+						   RHYTHMDB_TYPE_ENTRY_TYPE,
+						   RhythmDBEntryTypePrivate);
+}
+
+static void
+impl_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+	RhythmDBEntryType *etype = RHYTHMDB_ENTRY_TYPE (object);
+
+	switch (prop_id) {
+	case PROP_DB:
+		etype->priv->db = g_value_get_object (value);
+		break;
+	case PROP_NAME:
+		etype->priv->name = g_value_dup_string (value);
+		break;
+	case PROP_SAVE_TO_DISK:
+		etype->priv->save_to_disk = g_value_get_boolean (value);
+		break;
+	case PROP_TYPE_DATA_SIZE:
+		etype->priv->entry_type_data_size = g_value_get_uint (value);
+		break;
+	case PROP_CATEGORY:
+		etype->priv->category = g_value_get_enum (value);
+		break;
+	case PROP_HAS_PLAYLISTS:
+		etype->priv->has_playlists = g_value_get_boolean (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+impl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+	RhythmDBEntryType *etype = RHYTHMDB_ENTRY_TYPE (object);
+
+	switch (prop_id) {
+	case PROP_DB:
+		g_value_set_object (value, etype->priv->db);
+		break;
+	case PROP_NAME:
+		g_value_set_string (value, etype->priv->name);
+		break;
+	case PROP_SAVE_TO_DISK:
+		g_value_set_boolean (value, etype->priv->save_to_disk);
+		break;
+	case PROP_TYPE_DATA_SIZE:
+		g_value_set_uint (value, etype->priv->entry_type_data_size);
+		break;
+	case PROP_CATEGORY:
+		g_value_set_enum (value, etype->priv->category);
+		break;
+	case PROP_HAS_PLAYLISTS:
+		g_value_set_boolean (value, etype->priv->has_playlists);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+impl_finalize (GObject *object)
+{
+	RhythmDBEntryType *etype = RHYTHMDB_ENTRY_TYPE (object);
+
+	g_free (etype->priv->name);
+
+	G_OBJECT_CLASS (rhythmdb_entry_type_parent_class)->finalize (object);
+}
+
+static void
+rhythmdb_entry_type_class_init (RhythmDBEntryTypeClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->set_property = impl_set_property;
+	object_class->get_property = impl_get_property;
+	object_class->finalize = impl_finalize;
+
+	/**
+	 * RhythmDBEntryTYpe:db
+	 *
+	 * The #RhythmDB instance.
+	 */
+	g_object_class_install_property (object_class,
+					 PROP_DB,
+					 g_param_spec_object ("db",
+							      "RhythmDB",
+							      "RhythmDB instance",
+							      RHYTHMDB_TYPE,
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	/**
+	 * RhythmDBEntryType:name
+	 *
+	 * Entry type name.  This must be unique.
+	 */
+	g_object_class_install_property (object_class,
+					 PROP_NAME,
+					 g_param_spec_string ("name",
+							      "name",
+							      "entry type name",
+							      NULL,
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	/**
+	 * RhythmDBEntryType:save-to-disk
+	 *
+	 * If %TRUE, entries of this type should be written to the
+	 * on-disk database.
+	 */
+	g_object_class_install_property (object_class,
+					 PROP_SAVE_TO_DISK,
+					 g_param_spec_boolean ("save-to-disk",
+							       "save to disk",
+							       "whether to save this type of entry to disk",
+							       FALSE,
+							       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+	/**
+	 * RhythmDBEntryType:type-data-size
+	 *
+	 * The size of the type-specific data structure to allocate for each
+	 * entry of this type.
+	 */
+	g_object_class_install_property (object_class,
+					 PROP_TYPE_DATA_SIZE,
+					 g_param_spec_uint ("type-data-size",
+							    "type data size",
+							    "size of entry type specific data",
+							    0, G_MAXUINT, 0,
+							    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+	/**
+	 * RhythmDBEntryType:category
+	 *
+	 * The #RhythmDBEntryCategory that this entry type fits into.
+	 */
+	g_object_class_install_property (object_class,
+					 PROP_CATEGORY,
+					 g_param_spec_enum ("category",
+							    "category",
+							    "RhythmDBEntryCategory for the entry type",
+							    RHYTHMDB_TYPE_ENTRY_CATEGORY,
+							    RHYTHMDB_ENTRY_NORMAL,
+							    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+	/**
+	 * RhythmDBEntryType:has-playlists
+	 *
+	 * If %TRUE, entries of this type can be added to playlists.
+	 */
+	g_object_class_install_property (object_class,
+					 PROP_HAS_PLAYLISTS,
+					 g_param_spec_boolean ("has-playlists",
+							       "has playlists",
+							       "whether this type of entry has playlists",
+							       FALSE,
+							       G_PARAM_READWRITE));
+
+	g_type_class_add_private (klass, sizeof (RhythmDBEntryTypePrivate));
+}
+
+
+
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+GType
+rhythmdb_entry_category_get_type (void)
+{
+	static GType etype = 0;
+
+	if (etype == 0)
+	{
+		static const GEnumValue values[] =
+		{
+			ENUM_ENTRY (RHYTHMDB_ENTRY_NORMAL, "normal"),
+			ENUM_ENTRY (RHYTHMDB_ENTRY_STREAM, "stream"),
+			ENUM_ENTRY (RHYTHMDB_ENTRY_CONTAINER, "container"),
+			ENUM_ENTRY (RHYTHMDB_ENTRY_VIRTUAL, "virtual"),
+			{ 0, 0, 0 }
+		};
+
+		etype = g_enum_register_static ("RhythmDBEntryCategory", values);
+	}
+
+	return etype;
+}
diff --git a/rhythmdb/rhythmdb-entry-type.h b/rhythmdb/rhythmdb-entry-type.h
new file mode 100644
index 0000000..c725301
--- /dev/null
+++ b/rhythmdb/rhythmdb-entry-type.h
@@ -0,0 +1,116 @@
+/*
+ *  Copyright (C) 2010 Jonathan Matthew  <jonathan d14n org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#ifndef RHYTHMDB_ENTRY_TYPE_H
+#define RHYTHMDB_ENTRY_TYPE_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <rhythmdb/rhythmdb-entry.h>
+
+G_BEGIN_DECLS
+
+/* entry type category */
+
+GType rhythmdb_entry_category_get_type (void);
+#define RHYTHMDB_TYPE_ENTRY_CATEGORY (rhythmdb_entry_category_get_type ())
+typedef enum {
+	RHYTHMDB_ENTRY_NORMAL,		/* anything that doesn't match the other categories */
+	RHYTHMDB_ENTRY_STREAM,		/* endless streams (eg shoutcast) */
+	RHYTHMDB_ENTRY_CONTAINER,	/* things that point to other entries (eg podcast feeds) */
+	RHYTHMDB_ENTRY_VIRTUAL		/* import errors, ignored files */
+} RhythmDBEntryCategory;
+
+/* entry type */
+
+typedef struct _RhythmDBEntryType RhythmDBEntryType;
+typedef struct _RhythmDBEntryTypeClass RhythmDBEntryTypeClass;
+typedef struct _RhythmDBEntryTypePrivate RhythmDBEntryTypePrivate;
+
+#define RHYTHMDB_TYPE_ENTRY_TYPE      (rhythmdb_entry_type_get_type ())
+#define RHYTHMDB_ENTRY_TYPE(o)        (G_TYPE_CHECK_INSTANCE_CAST ((o), RHYTHMDB_TYPE_ENTRY_TYPE, RhythmDBEntryType))
+#define RHYTHMDB_ENTRY_TYPE_CLASS(k)  (G_TYPE_CHECK_CLASS_CAST((k), RHYTHMDB_TYPE_ENTRY_TYPE, RhythmDBEntryTypeClass))
+#define RHYTHMDB_IS_ENTRY_TYPE(o)     (G_TYPE_CHECK_INSTANCE_TYPE ((o), RHYTHMDB_TYPE_ENTRY_TYPE))
+#define RHYTHMDB_IS_ENTRY_TYPE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), RHYTHMDB_TYPE_ENTRY_TYPE))
+#define RHYTHMDB_ENTRY_TYPE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RHYTHMDB_TYPE_ENTRY_TYPE, RhythmDBEntryTypeClass))
+
+typedef char *(*RhythmDBEntryTypeStringFunc) (RhythmDBEntryType *entry_type, RhythmDBEntry *entry);
+typedef gboolean (*RhythmDBEntryTypeBooleanFunc) (RhythmDBEntryType *entry_type, RhythmDBEntry *entry);
+typedef void (*RhythmDBEntryTypeSyncFunc) (RhythmDBEntryType *entry_type, RhythmDBEntry *entry, GSList *changes, GError **error);
+
+struct _RhythmDBEntryType {
+	GObject parent;
+
+	/* function pointers for C users */
+	void		(*entry_created) (RhythmDBEntryType *etype, RhythmDBEntry *entry);
+	void		(*destroy_entry) (RhythmDBEntryType *etype, RhythmDBEntry *entry);
+
+	char *		(*get_playback_uri) (RhythmDBEntryType *etype, RhythmDBEntry *entry);
+
+	gboolean	(*can_sync_metadata) (RhythmDBEntryType *etype, RhythmDBEntry *entry);
+	void		(*sync_metadata) (RhythmDBEntryType *etype, RhythmDBEntry *entry, GSList *changes, GError **error);
+
+	RhythmDBEntryTypePrivate *priv;
+};
+
+struct _RhythmDBEntryTypeClass {
+	GObjectClass parent_class;
+
+	/* methods */
+	void		(*entry_created) (RhythmDBEntryType *etype, RhythmDBEntry *entry);
+	void		(*destroy_entry) (RhythmDBEntryType *etype, RhythmDBEntry *entry);
+
+	char *		(*get_playback_uri) (RhythmDBEntryType *etype, RhythmDBEntry *entry);
+
+	gboolean	(*can_sync_metadata) (RhythmDBEntryType *etype, RhythmDBEntry *entry);
+	void		(*sync_metadata) (RhythmDBEntryType *etype, RhythmDBEntry *entry, GSList *changes, GError **error);
+};
+
+GType		rhythmdb_entry_type_get_type (void);
+
+const char *	rhythmdb_entry_type_get_name (RhythmDBEntryType *etype);
+
+char *		rhythmdb_entry_get_playback_uri (RhythmDBEntry *entry);
+void 		rhythmdb_entry_created (RhythmDBEntry *entry);
+void 		rhythmdb_entry_pre_destroy (RhythmDBEntry *entry);
+gboolean 	rhythmdb_entry_can_sync_metadata (RhythmDBEntry *entry);
+void 		rhythmdb_entry_sync_metadata (RhythmDBEntry *entry, GSList *changes, GError **error);
+
+/* predefined entry types -- these mostly need to die */
+
+#define RHYTHMDB_ENTRY_TYPE_SONG (rhythmdb_get_song_entry_type ())
+#define RHYTHMDB_ENTRY_TYPE_IMPORT_ERROR (rhythmdb_get_error_entry_type ())
+#define RHYTHMDB_ENTRY_TYPE_IGNORE (rhythmdb_get_ignore_entry_type ())
+
+RhythmDBEntryType *rhythmdb_get_song_entry_type          (void);
+RhythmDBEntryType *rhythmdb_get_error_entry_type	 (void);
+RhythmDBEntryType *rhythmdb_get_ignore_entry_type        (void);
+
+G_END_DECLS
+
+#endif
diff --git a/rhythmdb/rhythmdb-entry.h b/rhythmdb/rhythmdb-entry.h
new file mode 100644
index 0000000..c24a4e0
--- /dev/null
+++ b/rhythmdb/rhythmdb-entry.h
@@ -0,0 +1,44 @@
+/*
+ *  Copyright (C) 2010 Jonathan Matthew  <jonathan d14n org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#ifndef RHYTHMDB_ENTRY_H
+#define RHYTHMDB_ENTRY_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+struct RhythmDBEntry_;
+typedef struct RhythmDBEntry_ RhythmDBEntry;
+GType rhythmdb_entry_get_type (void);
+
+#define RHYTHMDB_TYPE_ENTRY      (rhythmdb_entry_get_type ())
+#define RHYTHMDB_ENTRY(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RHYTHMDB_TYPE_ENTRY, RhythmDBEntry))
+
+G_END_DECLS
+
+#endif /* RHYTHMDB_ENTRY_H */
diff --git a/rhythmdb/rhythmdb-import-job.c b/rhythmdb/rhythmdb-import-job.c
index 3f31175..97bca26 100644
--- a/rhythmdb/rhythmdb-import-job.c
+++ b/rhythmdb/rhythmdb-import-job.c
@@ -29,6 +29,7 @@
 #include "config.h"
 
 #include "rhythmdb-import-job.h"
+#include "rhythmdb-entry-type.h"
 #include "rb-util.h"
 #include "rb-file-helpers.h"
 #include "rb-marshal.h"
@@ -64,9 +65,9 @@ struct _RhythmDBImportJobPrivate
 	int		imported;
 	GHashTable	*outstanding;
 	RhythmDB	*db;
-	RhythmDBEntryType entry_type;
-	RhythmDBEntryType ignore_type;
-	RhythmDBEntryType error_type;
+	RhythmDBEntryType *entry_type;
+	RhythmDBEntryType *ignore_type;
+	RhythmDBEntryType *error_type;
 	GStaticMutex    lock;
 	GSList		*uri_list;
 	gboolean	started;
@@ -98,9 +99,9 @@ G_DEFINE_TYPE (RhythmDBImportJob, rhythmdb_import_job, G_TYPE_OBJECT)
  * @db: the #RhythmDB object
  * @entry_type: the #RhythmDBEntryType to use for normal entries
  * @ignore_type: the #RhythmDBEntryType to use for ignored files
- *   (or RHYTHMDB_ENTRY_TYPE_INVALID to not create ignore entries)
+ *   (or NULL to not create ignore entries)
  * @error_type: the #RhythmDBEntryType to use for import error
- *   entries (or RHYTHMDB_ENTRY_TYPE_INVALID for none)
+ *   entries (or NULL for none)
  *
  * Creates a new import job with the specified entry types.
  * Before starting the job, the caller must add one or more
@@ -110,9 +111,9 @@ G_DEFINE_TYPE (RhythmDBImportJob, rhythmdb_import_job, G_TYPE_OBJECT)
  */
 RhythmDBImportJob *
 rhythmdb_import_job_new (RhythmDB *db,
-			 RhythmDBEntryType entry_type,
-			 RhythmDBEntryType ignore_type,
-			 RhythmDBEntryType error_type)
+			 RhythmDBEntryType *entry_type,
+			 RhythmDBEntryType *ignore_type,
+			 RhythmDBEntryType *error_type)
 {
 	GObject *obj;
 
@@ -491,13 +492,13 @@ impl_set_property (GObject *object,
 					 job, 0);
 		break;
 	case PROP_ENTRY_TYPE:
-		job->priv->entry_type = g_value_get_boxed (value);
+		job->priv->entry_type = g_value_get_object (value);
 		break;
 	case PROP_IGNORE_TYPE:
-		job->priv->ignore_type = g_value_get_boxed (value);
+		job->priv->ignore_type = g_value_get_object (value);
 		break;
 	case PROP_ERROR_TYPE:
-		job->priv->error_type = g_value_get_boxed (value);
+		job->priv->error_type = g_value_get_object (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -518,13 +519,13 @@ impl_get_property (GObject *object,
 		g_value_set_object (value, job->priv->db);
 		break;
 	case PROP_ENTRY_TYPE:
-		g_value_set_boxed (value, job->priv->entry_type);
+		g_value_set_object (value, job->priv->entry_type);
 		break;
 	case PROP_IGNORE_TYPE:
-		g_value_set_boxed (value, job->priv->ignore_type);
+		g_value_set_object (value, job->priv->ignore_type);
 		break;
 	case PROP_ERROR_TYPE:
-		g_value_set_boxed (value, job->priv->error_type);
+		g_value_set_object (value, job->priv->error_type);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -556,10 +557,6 @@ impl_finalize (GObject *object)
 	
 	g_hash_table_destroy (job->priv->outstanding);
 
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, job->priv->entry_type);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, job->priv->ignore_type);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, job->priv->error_type);
-	
 	rb_slist_deep_free (job->priv->uri_list);
 
 	g_static_mutex_free (&job->priv->lock);
@@ -580,32 +577,32 @@ rhythmdb_import_job_class_init (RhythmDBImportJobClass *klass)
 	g_object_class_install_property (object_class,
 					 PROP_DB,
 					 g_param_spec_object ("db",
-						 	      "db",
+							      "db",
 							      "RhythmDB object",
 							      RHYTHMDB_TYPE,
 							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_object_class_install_property (object_class,
 					 PROP_ENTRY_TYPE,
-					 g_param_spec_boxed ("entry-type",
-						 	     "Entry type",
-							     "Entry type to use for entries added by this job",
-							     RHYTHMDB_TYPE_ENTRY_TYPE,
-							     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+					 g_param_spec_object ("entry-type",
+							      "Entry type",
+							      "Entry type to use for entries added by this job",
+							      RHYTHMDB_TYPE_ENTRY_TYPE,
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 	g_object_class_install_property (object_class,
 					 PROP_IGNORE_TYPE,
-					 g_param_spec_boxed ("ignore-type",
-						 	     "Ignored entry type",
-							     "Entry type to use for ignored entries added by this job",
-							     RHYTHMDB_TYPE_ENTRY_TYPE,
-							     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+					 g_param_spec_object ("ignore-type",
+							      "Ignored entry type",
+							      "Entry type to use for ignored entries added by this job",
+							      RHYTHMDB_TYPE_ENTRY_TYPE,
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 	g_object_class_install_property (object_class,
 					 PROP_ERROR_TYPE,
-					 g_param_spec_boxed ("error-type",
-						 	     "Error entry type",
-							     "Entry type to use for import error entries added by this job",
-							     RHYTHMDB_TYPE_ENTRY_TYPE,
-							     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+					 g_param_spec_object ("error-type",
+							      "Error entry type",
+							      "Entry type to use for import error entries added by this job",
+							      RHYTHMDB_TYPE_ENTRY_TYPE,
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	/**
 	 * RhythmDBImportJob::entry-added:
diff --git a/rhythmdb/rhythmdb-import-job.h b/rhythmdb/rhythmdb-import-job.h
index 5b84b7a..a72ec96 100644
--- a/rhythmdb/rhythmdb-import-job.h
+++ b/rhythmdb/rhythmdb-import-job.h
@@ -67,9 +67,9 @@ struct _RhythmDBImportJobClass
 GType		rhythmdb_import_job_get_type		(void);
 
 RhythmDBImportJob *rhythmdb_import_job_new		(RhythmDB *db,
-							 RhythmDBEntryType entry_type,
-							 RhythmDBEntryType ignore_type,
-							 RhythmDBEntryType error_type);
+							 RhythmDBEntryType *entry_type,
+							 RhythmDBEntryType *ignore_type,
+							 RhythmDBEntryType *error_type);
 void		rhythmdb_import_job_add_uri		(RhythmDBImportJob *job, const char *uri);
 void		rhythmdb_import_job_start		(RhythmDBImportJob *job);
 void		rhythmdb_import_job_cancel		(RhythmDBImportJob *job);
diff --git a/rhythmdb/rhythmdb-private.h b/rhythmdb/rhythmdb-private.h
index 14b5f4b..07a6973 100644
--- a/rhythmdb/rhythmdb-private.h
+++ b/rhythmdb/rhythmdb-private.h
@@ -34,7 +34,7 @@
 
 G_BEGIN_DECLS
 
-RhythmDBEntry * rhythmdb_entry_allocate		(RhythmDB *db, RhythmDBEntryType type);
+RhythmDBEntry * rhythmdb_entry_allocate		(RhythmDB *db, RhythmDBEntryType *type);
 void		rhythmdb_entry_insert		(RhythmDB *db, RhythmDBEntry *entry);
 
 typedef struct {
@@ -69,7 +69,7 @@ struct RhythmDBEntry_ {
 	guint flags;
 	volatile gint refcount;
 	void *data;
-	RhythmDBEntryType type;
+	RhythmDBEntryType *type;
 	guint id;
 
 	/* metadata */
@@ -201,9 +201,9 @@ typedef struct
 	} type;
 	RBRefString *uri;
 	RBRefString *real_uri; /* Target of a symlink, if any */
-	RhythmDBEntryType entry_type;
-	RhythmDBEntryType ignore_type;
-	RhythmDBEntryType error_type;
+	RhythmDBEntryType *entry_type;
+	RhythmDBEntryType *ignore_type;
+	RhythmDBEntryType *error_type;
 
 	GError *error;
 	RhythmDB *db;
@@ -242,6 +242,9 @@ void rhythmdb_monitor_uri_path (RhythmDB *db, const char *uri, GError **error);
 GPtrArray *rhythmdb_query_parse_valist (RhythmDB *db, va_list args);
 void       rhythmdb_read_encoded_property (RhythmDB *db, const char *data, RhythmDBPropType propid, GValue *val);
 
+/* from rhythmdb-song-entry-types.c */
+void       rhythmdb_register_song_entry_types (RhythmDB *db);
+
 G_END_DECLS
 
 #endif /* __RHYTHMDB_PRIVATE_H */
diff --git a/rhythmdb/rhythmdb-query.c b/rhythmdb/rhythmdb-query.c
index 487b223..719ea95 100644
--- a/rhythmdb/rhythmdb-query.c
+++ b/rhythmdb/rhythmdb-query.c
@@ -360,8 +360,8 @@ prop_gvalue_to_string (RhythmDB *db,
 	switch (propid) {
 	case RHYTHMDB_PROP_TYPE:
 		{
-			RhythmDBEntryType type = g_value_get_pointer (val);
-			return g_strdup (type->name);
+			RhythmDBEntryType *type = g_value_get_object (val);
+			return g_strdup (rhythmdb_entry_type_get_name (type));
 		}
 		break;
 	default:
@@ -458,12 +458,12 @@ rhythmdb_read_encoded_property (RhythmDB *db,
 			g_value_set_double (val, d);
 		}
 		break;
-	case G_TYPE_POINTER:
+	case G_TYPE_OBJECT:			/* hm, really? */
 		if (propid == RHYTHMDB_PROP_TYPE) {
-			RhythmDBEntryType entry_type;
+			RhythmDBEntryType *entry_type;
 			entry_type = rhythmdb_entry_type_get_by_name (db, content);
-			if (entry_type != RHYTHMDB_ENTRY_TYPE_INVALID) {
-				g_value_set_pointer (val, entry_type);
+			if (entry_type != NULL) {
+				g_value_set_object (val, entry_type);
 				break;
 			} else {
 				g_warning ("Unexpected entry type");
diff --git a/rhythmdb/rhythmdb-song-entry-types.c b/rhythmdb/rhythmdb-song-entry-types.c
new file mode 100644
index 0000000..8bdeada
--- /dev/null
+++ b/rhythmdb/rhythmdb-song-entry-types.c
@@ -0,0 +1,148 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ *  Copyright (C) 2010  Jonathan Matthew  <jonathan d14n org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The Rhythmbox authors hereby grant permission for non-GPL compatible
+ *  GStreamer plugins to be used and distributed together with GStreamer
+ *  and Rhythmbox. This permission is above and beyond the permissions granted
+ *  by the GPL license by which Rhythmbox is covered. If you modify this code
+ *  you may extend this exception to your version of the code, but you are not
+ *  obligated to do so. If you do not wish to do so, delete this exception
+ *  statement from your version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
+ *
+ */
+
+#include "config.h"
+
+#include "rhythmdb-entry-type.h"
+#include "rhythmdb-private.h"
+#include "rb-util.h"
+
+static RhythmDBEntryType *song_entry_type = NULL;
+static RhythmDBEntryType *error_entry_type = NULL;
+static RhythmDBEntryType *ignore_entry_type = NULL;
+
+static void
+song_sync_metadata (RhythmDBEntryType *entry_type,
+		    RhythmDBEntry *entry,
+		    GSList *changes,
+		    GError **error)
+{
+	RhythmDB *db;
+
+	g_object_get (entry_type, "db", &db, NULL);
+	rhythmdb_entry_write_metadata_changes (db, entry, changes, error);
+	g_object_unref (db);
+}
+
+
+static gboolean
+song_can_sync_metadata (RhythmDBEntryType *entry_type,
+			RhythmDBEntry *entry)
+{
+	const char *mimetype;
+	gboolean can_sync;
+	RhythmDB *db;
+
+	g_object_get (entry_type, "db", &db, NULL);
+
+	mimetype = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MIMETYPE);
+	can_sync = rb_metadata_can_save (db->priv->metadata, mimetype);
+
+	g_object_unref (db);
+	return can_sync;
+}
+
+/**
+ * rhythmdb_get_song_entry_type:
+ *
+ * Returns the #RhythmDBEntryType for normal songs.
+ *
+ * Return value: (transfer none): the entry type for normal songs
+ */
+RhythmDBEntryType *
+rhythmdb_get_song_entry_type (void)
+{
+	return song_entry_type;
+}
+
+/**
+ * rhythmdb_get_ignore_entry_type:
+ *
+ * Returns the #RhythmDBEntryType for ignored files
+ *
+ * Return value: (transfer none): the entry type for ignored files
+ */
+RhythmDBEntryType *
+rhythmdb_get_ignore_entry_type (void)
+{
+	return ignore_entry_type;
+}
+
+/**
+ * rhythmdb_get_error_entry_type:
+ *
+ * Returns the #RhythmDBEntryType for import errors
+ *
+ * Return value: (transfer none): the entry type for import errors
+ */
+RhythmDBEntryType *
+rhythmdb_get_error_entry_type (void)
+{
+	return error_entry_type;
+}
+
+
+
+void
+rhythmdb_register_song_entry_types (RhythmDB *db)
+{
+	g_assert (song_entry_type == NULL);
+	g_assert (error_entry_type == NULL);
+	g_assert (ignore_entry_type == NULL);
+
+	song_entry_type = g_object_new (RHYTHMDB_TYPE_ENTRY_TYPE,
+					"db", db,
+					"name", "song",
+					"save-to-disk", TRUE,
+					"has-playlists", TRUE,
+					NULL);
+	song_entry_type->can_sync_metadata = song_can_sync_metadata;
+	song_entry_type->sync_metadata = song_sync_metadata;
+
+	ignore_entry_type = g_object_new (RHYTHMDB_TYPE_ENTRY_TYPE,
+					  "db", db,
+					  "name", "ignore",
+					  "save-to-disk", TRUE,
+					  "category", RHYTHMDB_ENTRY_VIRTUAL,
+					  NULL);
+	ignore_entry_type->get_playback_uri = (RhythmDBEntryTypeStringFunc) rb_null_function;
+
+	error_entry_type = g_object_new (RHYTHMDB_TYPE_ENTRY_TYPE,
+					 "db", db,
+					 "name", "import-error",
+					 "category", RHYTHMDB_ENTRY_VIRTUAL,
+					 NULL);
+	error_entry_type->get_playback_uri = (RhythmDBEntryTypeStringFunc) rb_null_function;
+	error_entry_type->can_sync_metadata = (RhythmDBEntryTypeBooleanFunc) rb_true_function;
+	error_entry_type->sync_metadata = (RhythmDBEntryTypeSyncFunc) rb_null_function;
+
+
+	rhythmdb_register_entry_type (db, song_entry_type);
+	rhythmdb_register_entry_type (db, error_entry_type);
+	rhythmdb_register_entry_type (db, ignore_entry_type);
+}
diff --git a/rhythmdb/rhythmdb-tree.c b/rhythmdb/rhythmdb-tree.c
index 92c8889..fb1ad99 100644
--- a/rhythmdb/rhythmdb-tree.c
+++ b/rhythmdb/rhythmdb-tree.c
@@ -54,6 +54,7 @@
 #include "rb-debug.h"
 #include "rb-util.h"
 #include "rb-file-helpers.h"
+#include "rb-podcast-entry-types.h"
 
 typedef struct RhythmDBTreeProperty
 {
@@ -78,14 +79,14 @@ static gboolean rhythmdb_tree_entry_set (RhythmDB *db, RhythmDBEntry *entry,
 					 guint propid, const GValue *value);
 
 static void rhythmdb_tree_entry_delete (RhythmDB *db, RhythmDBEntry *entry);
-static void rhythmdb_tree_entry_delete_by_type (RhythmDB *adb, RhythmDBEntryType type);
+static void rhythmdb_tree_entry_delete_by_type (RhythmDB *adb, RhythmDBEntryType *type);
 
 static RhythmDBEntry * rhythmdb_tree_entry_lookup_by_location (RhythmDB *db, RBRefString *uri);
 static RhythmDBEntry * rhythmdb_tree_entry_lookup_by_id (RhythmDB *db, gint id);
 static void rhythmdb_tree_entry_foreach (RhythmDB *adb, GFunc func, gpointer user_data);
 static gint64 rhythmdb_tree_entry_count (RhythmDB *adb);
-static void rhythmdb_tree_entry_foreach_by_type (RhythmDB *adb, RhythmDBEntryType type, GFunc func, gpointer user_data);
-static gint64 rhythmdb_tree_entry_count_by_type (RhythmDB *adb, RhythmDBEntryType type);
+static void rhythmdb_tree_entry_foreach_by_type (RhythmDB *adb, RhythmDBEntryType *type, GFunc func, gpointer user_data);
+static gint64 rhythmdb_tree_entry_count_by_type (RhythmDB *adb, RhythmDBEntryType *type);
 static gboolean rhythmdb_tree_entry_keyword_add (RhythmDB *adb, RhythmDBEntry *entry, RBRefString *keyword);
 static gboolean rhythmdb_tree_entry_keyword_remove (RhythmDB *adb, RhythmDBEntry *entry, RBRefString *keyword);
 static gboolean rhythmdb_tree_entry_keyword_has (RhythmDB *adb, RhythmDBEntry *entry, RBRefString *keyword);
@@ -96,8 +97,7 @@ static void rhythmdb_tree_do_full_query (RhythmDB *db, GPtrArray *query,
 static gboolean rhythmdb_tree_evaluate_query (RhythmDB *adb, GPtrArray *query,
 				       RhythmDBEntry *aentry);
 static void rhythmdb_tree_entry_type_registered (RhythmDB *db,
-						 const char *name,
-						 RhythmDBEntryType type);
+						 RhythmDBEntryType *type);
 
 typedef void (*RBTreeEntryItFunc)(RhythmDBTree *db,
 				  RhythmDBEntry *entry,
@@ -107,7 +107,7 @@ typedef void (*RBTreePropertyItFunc)(RhythmDBTree *db,
 				     RhythmDBTreeProperty *property,
 				     gpointer data);
 static void rhythmdb_hash_tree_foreach (RhythmDB *adb,
-					RhythmDBEntryType type,
+					RhythmDBEntryType *type,
 					RBTreeEntryItFunc entry_func,
 					RBTreePropertyItFunc album_func,
 					RBTreePropertyItFunc artist_func,
@@ -123,7 +123,7 @@ static RhythmDBTreeProperty *get_or_create_album (RhythmDBTree *db, RhythmDBTree
 						  RBRefString *name);
 static RhythmDBTreeProperty *get_or_create_artist (RhythmDBTree *db, RhythmDBTreeProperty *genre,
 						   RBRefString *name);
-static RhythmDBTreeProperty *get_or_create_genre (RhythmDBTree *db, RhythmDBEntryType type,
+static RhythmDBTreeProperty *get_or_create_genre (RhythmDBTree *db, RhythmDBEntryType *type,
 							 RBRefString *name);
 
 static void remove_entry_from_album (RhythmDBTree *db, RhythmDBEntry *entry);
@@ -427,7 +427,7 @@ rhythmdb_tree_parser_start_element (struct RhythmDBTreeLoadContext *ctx,
 	case RHYTHMDB_TREE_PARSER_STATE_RHYTHMDB:
 	{
 		if (!strcmp (name, "entry")) {
-			RhythmDBEntryType type = RHYTHMDB_ENTRY_TYPE_INVALID;
+			RhythmDBEntryType *type = NULL;
 			const char *typename = NULL;
 			for (; *attrs; attrs +=2) {
 				if (!strcmp (*attrs, "type")) {
@@ -438,7 +438,7 @@ rhythmdb_tree_parser_start_element (struct RhythmDBTreeLoadContext *ctx,
 			}
 
 			g_assert (typename);
-			if (type != RHYTHMDB_ENTRY_TYPE_INVALID) {
+			if (type != NULL) {
 				ctx->state = RHYTHMDB_TREE_PARSER_STATE_ENTRY;
 				ctx->entry = rhythmdb_entry_allocate (RHYTHMDB (ctx->db), type);
 				ctx->entry->flags |= RHYTHMDB_ENTRY_TREE_LOADING;
@@ -517,6 +517,7 @@ rhythmdb_tree_parser_end_element (struct RhythmDBTreeLoadContext *ctx,
 			rb_debug ("pre-Date entry found, causing re-read");
 			ctx->entry->mtime = 0;
 		}
+#if 0
 		if (ctx->entry->type == RHYTHMDB_ENTRY_TYPE_PODCAST_FEED) {
 			RhythmDBPodcastFields *podcast = RHYTHMDB_ENTRY_GET_TYPE_DATA (ctx->entry, RhythmDBPodcastFields);
 			/* Handle upgrades from 0.9.2.
@@ -541,6 +542,7 @@ rhythmdb_tree_parser_end_element (struct RhythmDBTreeLoadContext *ctx,
 				ctx->entry->mountpoint = tmp;
 			}
 		}
+#endif
 		if (ctx->entry->type == RHYTHMDB_ENTRY_TYPE_SONG) {
 			/* Since we now care about mountpoints for all local entries, not just
 			 * those on things that actually get mounted and unmounted, we need to
@@ -576,6 +578,7 @@ rhythmdb_tree_parser_end_element (struct RhythmDBTreeLoadContext *ctx,
 					rhythmdb_commit (RHYTHMDB (ctx->db));
 					ctx->batch_count = 0;
 				}
+#if 0
 			} else if (ctx->entry->type == RHYTHMDB_ENTRY_TYPE_PODCAST_POST &&
 				   entry->type == RHYTHMDB_ENTRY_TYPE_SONG) {
 				rb_debug ("found song entry with duplicate location for Podcast post %s. merging metadata",
@@ -599,6 +602,7 @@ rhythmdb_tree_parser_end_element (struct RhythmDBTreeLoadContext *ctx,
 					rhythmdb_commit (RHYTHMDB (ctx->db));
 					ctx->batch_count = 0;
 				}
+#endif
 			} else {
 				rb_debug ("found entry with duplicate location %s. merging metadata",
 					  rb_refstring_get (ctx->entry->location));
@@ -971,7 +975,7 @@ save_entry (RhythmDBTree *db,
 		podcast = RHYTHMDB_ENTRY_GET_TYPE_DATA (entry, RhythmDBPodcastFields);
 
 	RHYTHMDB_FWRITE_STATICSTR ("  <entry type=\"", ctx->handle, ctx->error);
-	encoded	= xmlEncodeEntitiesReentrant (NULL, BAD_CAST entry->type->name);
+	encoded	= xmlEncodeEntitiesReentrant (NULL, BAD_CAST rhythmdb_entry_type_get_name (entry->type));
 	RHYTHMDB_FWRITE (encoded, 1, xmlStrlen (encoded), ctx->handle, ctx->error);
 	g_free (encoded);
 
@@ -1173,10 +1177,12 @@ save_entry (RhythmDBTree *db,
 
 static void
 save_entry_type (const char *name,
-		 RhythmDBEntryType entry_type,
+		 RhythmDBEntryType *entry_type,
 		 struct RhythmDBTreeSaveContext *ctx)
 {
-	if (entry_type->save_to_disk == FALSE)
+	gboolean save_to_disk = FALSE;
+	g_object_get (entry_type, "save-to-disk", &save_to_disk, NULL);
+	if (save_to_disk == FALSE)
 		return;
 
 	rb_debug ("saving entries of type %s", name);
@@ -1381,7 +1387,7 @@ rhythmdb_tree_property_new (RhythmDBTree *db)
 
 static GHashTable *
 get_genres_hash_for_type (RhythmDBTree *db,
-			  RhythmDBEntryType type)
+			  RhythmDBEntryType *type)
 {
 	GHashTable *table;
 
@@ -1433,7 +1439,7 @@ genres_hash_foreach (RhythmDBTree *db, RBHFunc func, gpointer data)
 /* must be called with the genres lock held */
 static RhythmDBTreeProperty *
 get_or_create_genre (RhythmDBTree *db,
-		     RhythmDBEntryType type,
+		     RhythmDBEntryType *type,
 		     RBRefString *name)
 {
 	RhythmDBTreeProperty *genre;
@@ -1557,7 +1563,7 @@ rhythmdb_tree_entry_set (RhythmDB *adb,
 			 const GValue *value)
 {
 	RhythmDBTree *db = RHYTHMDB_TREE (adb);
-	RhythmDBEntryType type;
+	RhythmDBEntryType *type;
 
 	type = entry->type;
 
@@ -1700,7 +1706,7 @@ rhythmdb_tree_entry_delete (RhythmDB *adb,
 
 typedef struct {
 	RhythmDB *db;
-	RhythmDBEntryType type;
+	RhythmDBEntryType *type;
 } RbEntryRemovalCtxt;
 
 /* must be called with the entries and genres locks held */
@@ -1731,7 +1737,7 @@ remove_one_song (gpointer key,
 
 static void
 rhythmdb_tree_entry_delete_by_type (RhythmDB *adb,
-				    RhythmDBEntryType type)
+				    RhythmDBEntryType *type)
 {
 	RhythmDBTree *db = RHYTHMDB_TREE (adb);
 	RbEntryRemovalCtxt ctxt;
@@ -1819,9 +1825,9 @@ rhythmdb_tree_evaluate_query (RhythmDB *adb,
 				    g_value_get_double (data->val)) \
 					return FALSE; \
 				break; \
-                        case G_TYPE_POINTER: \
-                                if (rhythmdb_entry_get_pointer (entry, data->propid) OP \
-                                    g_value_get_pointer (data->val)) \
+                        case G_TYPE_OBJECT: \
+                                if ((gpointer)rhythmdb_entry_get_object (entry, data->propid) OP \
+                                    g_value_get_object (data->val)) \
                                         return FALSE; \
                                 break; \
 			default: \
@@ -2214,12 +2220,12 @@ conjunctive_query (RhythmDBTree *db,
 	g_mutex_lock (db->priv->genres_lock);
 	if (type_query_idx >= 0) {
 		GHashTable *genres;
-		RhythmDBEntryType etype;
+		RhythmDBEntryType *etype;
 		RhythmDBQueryData *qdata = g_ptr_array_index (query, type_query_idx);
 
 		g_ptr_array_remove_index_fast (query, type_query_idx);
 
-		etype = g_value_get_pointer (qdata->val);
+		etype = g_value_get_object (qdata->val);
 		genres = get_genres_hash_for_type (db, etype);
 		if (genres != NULL) {
 			conjunctive_query_genre (db, genres, traversal_data);
@@ -2440,7 +2446,7 @@ _foreach_by_type_cb (RhythmDB *db, RhythmDBEntry *entry, ForeachTypeData *data)
 
 static void
 rhythmdb_tree_entry_foreach_by_type (RhythmDB *db,
-				     RhythmDBEntryType type,
+				     RhythmDBEntryType *type,
 				     GFunc foreach_func,
 				     gpointer data)
 {
@@ -2459,7 +2465,7 @@ count_entries (RhythmDB *db, RhythmDBTreeProperty *album, gint64 *count)
 
 static gint64
 rhythmdb_tree_entry_count_by_type (RhythmDB *db,
-				   RhythmDBEntryType type)
+				   RhythmDBEntryType *type)
 {
 	gint64 count = 0;
 	rhythmdb_hash_tree_foreach (db, type,
@@ -2681,7 +2687,7 @@ hash_tree_genres_foreach (gpointer key,
 
 static void
 rhythmdb_hash_tree_foreach (RhythmDB *adb,
-			    RhythmDBEntryType type,
+			    RhythmDBEntryType *type,
 			    RBTreeEntryItFunc entry_func,
 			    RBTreePropertyItFunc album_func,
 			    RBTreePropertyItFunc artist_func,
@@ -2714,22 +2720,23 @@ rhythmdb_hash_tree_foreach (RhythmDB *adb,
 
 static void
 rhythmdb_tree_entry_type_registered (RhythmDB *db,
-				     const char *name,
-				     RhythmDBEntryType entry_type)
+				     RhythmDBEntryType *entry_type)
 {
 	GList *entries = NULL;
 	GList *e;
 	gint count = 0;
 	RhythmDBTree *rdb;
+	char *name;
 	RBRefString *rs_name;
 
-	if (name == NULL)
-		return;
-
 	rdb = RHYTHMDB_TREE (db);
 	g_mutex_lock (RHYTHMDB_TREE(rdb)->priv->entries_lock);
 
+	/* ugh, this sucks, maybe store the name as a refstring in the object? */
+	g_object_get (entry_type, "name", &name, NULL);
 	rs_name = rb_refstring_find (name);
+	g_free (name);
+
 	if (rs_name)
 		entries = g_hash_table_lookup (rdb->priv->unknown_entry_types, rs_name);
 	if (entries == NULL) {
diff --git a/rhythmdb/rhythmdb.c b/rhythmdb/rhythmdb.c
index c974499..29cec30 100644
--- a/rhythmdb/rhythmdb.c
+++ b/rhythmdb/rhythmdb.c
@@ -69,6 +69,7 @@
 #include "rb-dialog.h"
 #include "rb-string-value-map.h"
 #include "rb-async-queue-watch.h"
+#include "rb-podcast-entry-types.h"
 
 #define PROP_ENTRY(p,t,n) { RHYTHMDB_PROP_ ## p, "RHYTHMDB_PROP_" #p "", t, n }
 
@@ -80,7 +81,7 @@ typedef struct _RhythmDBPropertyDef {
 } RhythmDBPropertyDef;
 
 static const RhythmDBPropertyDef rhythmdb_properties[] = {
-	PROP_ENTRY(TYPE, G_TYPE_POINTER, "type"),
+	PROP_ENTRY(TYPE, G_TYPE_OBJECT, "type"),
 	PROP_ENTRY(ENTRY_ID, G_TYPE_ULONG, "entry-id"),
 	PROP_ENTRY(TITLE, G_TYPE_STRING, "title"),
 	PROP_ENTRY(GENRE, G_TYPE_STRING, "genre"),
@@ -218,9 +219,9 @@ typedef struct
 typedef struct
 {
 	RhythmDB *db;
-	RhythmDBEntryType type;
-	RhythmDBEntryType ignore_type;
-	RhythmDBEntryType error_type;
+	RhythmDBEntryType *type;
+	RhythmDBEntryType *ignore_type;
+	RhythmDBEntryType *error_type;
 } RhythmDBAddThreadData;
 
 typedef struct
@@ -235,9 +236,9 @@ typedef struct
 	RBRefString *uri;
 	union {
 		struct {
-			RhythmDBEntryType entry_type;
-			RhythmDBEntryType ignore_type;
-			RhythmDBEntryType error_type;
+			RhythmDBEntryType *entry_type;
+			RhythmDBEntryType *ignore_type;
+			RhythmDBEntryType *error_type;
 		} types;
 		GSList *changes;
 	} data;
@@ -274,7 +275,6 @@ static void library_location_changed_cb (GConfClient *client,
 static void rhythmdb_sync_library_location (RhythmDB *db);
 static void rhythmdb_entry_sync_mirrored (RhythmDBEntry *entry,
 					  guint propid);
-static void rhythmdb_register_core_entry_types (RhythmDB *db);
 static gboolean rhythmdb_entry_extra_metadata_accumulator (GSignalInvocationHint *ihint,
 							   GValue *return_accu,
 							   const GValue *handler_return,
@@ -288,9 +288,9 @@ static void rhythmdb_event_free (RhythmDB *db, RhythmDBEvent *event);
 static void rhythmdb_add_to_stat_list (RhythmDB *db,
 				       const char *uri,
 				       RhythmDBEntry *entry,
-				       RhythmDBEntryType type,
-				       RhythmDBEntryType ignore_type,
-				       RhythmDBEntryType error_type);
+				       RhythmDBEntryType *type,
+				       RhythmDBEntryType *ignore_type,
+				       RhythmDBEntryType *error_type);
 static void free_entry_changes (GSList *entry_changes);
 
 enum
@@ -723,10 +723,12 @@ rhythmdb_init (RhythmDB *db)
 		g_hash_table_insert (db->priv->propname_map, (gpointer) name, GINT_TO_POINTER (i));
 	}
 
-	db->priv->entry_type_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+	db->priv->entry_type_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
 	db->priv->entry_type_map_mutex = g_mutex_new ();
 	db->priv->entry_type_mutex = g_mutex_new ();
-	rhythmdb_register_core_entry_types (db);
+
+	rhythmdb_register_song_entry_types (db);
+	rb_podcast_register_entry_types (db);
 
  	db->priv->stat_mutex = g_mutex_new ();
 
@@ -1440,7 +1442,7 @@ process_added_entries_cb (RhythmDBEntry *entry,
 		g_mutex_lock (db->priv->stat_mutex);
 		if (db->priv->action_thread_running == FALSE) {
 			rhythmdb_add_to_stat_list (db, uri, entry,
-						   RHYTHMDB_ENTRY_TYPE_INVALID,
+						   RHYTHMDB_ENTRY_TYPE_SONG,
 						   RHYTHMDB_ENTRY_TYPE_IGNORE,
 						   RHYTHMDB_ENTRY_TYPE_IMPORT_ERROR);
 		}
@@ -1521,7 +1523,7 @@ sync_entry_changed (RhythmDBEntry *entry,
 		if (metadata_field_from_prop (change->prop, &field)) {
 			RhythmDBAction *action;
 
-			if (!rhythmdb_entry_is_editable (db, entry)) {
+			if (!rhythmdb_entry_can_sync_metadata (entry)) {
 				g_warning ("trying to sync properties of non-editable file");
 				break;
 			}
@@ -1644,13 +1646,15 @@ rhythmdb_error_quark (void)
  */
 RhythmDBEntry *
 rhythmdb_entry_allocate (RhythmDB *db,
-			 RhythmDBEntryType type)
+			 RhythmDBEntryType *type)
 {
 	RhythmDBEntry *ret;
+	guint type_data_size = 0;
 	gsize size = sizeof (RhythmDBEntry);
 
-	if (type->entry_type_data_size) {
-		size = ALIGN_STRUCT (sizeof (RhythmDBEntry)) + type->entry_type_data_size;
+	g_object_get (type, "type-data-size", &type_data_size, NULL);
+	if (type_data_size > 0) {
+		size = ALIGN_STRUCT (sizeof (RhythmDBEntry)) + type_data_size;
 	}
 	ret = g_malloc0 (size);
 	ret->id = (guint) g_atomic_int_exchange_and_add (&db->priv->next_entry_id, 1);
@@ -1678,8 +1682,7 @@ rhythmdb_entry_allocate (RhythmDB *db,
 	/* The refcount is initially 0, we want to set it to 1 */
 	ret->refcount = 1;
 
-	if (type->post_entry_create)
-		(type->post_entry_create)(ret, type->post_entry_create_data);
+	rhythmdb_entry_created (ret);
 
 	return ret;
 }
@@ -1701,9 +1704,13 @@ rhythmdb_entry_get_type_data (RhythmDBEntry *entry,
 			      guint expected_size)
 {
 	g_return_val_if_fail (entry != NULL, NULL);
+	int type_data_size = 0;
+	gsize offset;
+
+	g_object_get (entry->type, "type-data-size", &type_data_size, NULL);
 
-	g_assert (expected_size == entry->type->entry_type_data_size);
-	gsize offset = ALIGN_STRUCT (sizeof (RhythmDBEntry));
+	g_assert (expected_size == type_data_size);
+	offset = ALIGN_STRUCT (sizeof (RhythmDBEntry));
 
 	return (gpointer) (((guint8 *)entry) + offset);
 }
@@ -1752,7 +1759,7 @@ rhythmdb_entry_insert (RhythmDB *db,
  */
 RhythmDBEntry *
 rhythmdb_entry_new (RhythmDB *db,
-		    RhythmDBEntryType type,
+		    RhythmDBEntryType *type,
 		    const char *uri)
 {
 	RhythmDBEntry *ret;
@@ -1788,7 +1795,7 @@ rhythmdb_entry_new (RhythmDB *db,
  */
 RhythmDBEntry *
 rhythmdb_entry_example_new (RhythmDB *db,
-			    RhythmDBEntryType type,
+			    RhythmDBEntryType *type,
 			    const char *uri)
 {
 	RhythmDBEntry *ret;
@@ -1846,12 +1853,7 @@ rhythmdb_entry_ref (RhythmDBEntry *entry)
 static void
 rhythmdb_entry_finalize (RhythmDBEntry *entry)
 {
-	RhythmDBEntryType type;
-
-	type = rhythmdb_entry_get_entry_type (entry);
-
-	if (type->pre_entry_destroy)
-		(type->pre_entry_destroy)(entry, type->pre_entry_destroy_data);
+	rhythmdb_entry_pre_destroy (entry);
 
 	rb_refstring_unref (entry->location);
 	rb_refstring_unref (entry->playback_error);
@@ -1892,30 +1894,6 @@ rhythmdb_entry_unref (RhythmDBEntry *entry)
 	}
 }
 
-/**
- * rhythmdb_entry_is_editable:
- * @db: a #RhythmDB.
- * @entry: a #RhythmDBEntry.
- *
- * This determines whether any changes to the entries metadata can be saved.
- * Usually this is only true for entries backed by files, where tag-writing is
- * enabled, and the appropriate tag-writing facilities are available.
- *
- * Returns: whether the entry's metadata can be changed.
- */
-gboolean
-rhythmdb_entry_is_editable (RhythmDB *db,
-			    RhythmDBEntry *entry)
-{
-	RhythmDBEntryType entry_type;
-
-	g_return_val_if_fail (RHYTHMDB_IS (db), FALSE);
-	g_return_val_if_fail (entry != NULL, FALSE);
-
-	entry_type = rhythmdb_entry_get_entry_type (entry);
-	return entry_type->can_sync_metadata (db, entry, entry_type->can_sync_metadata_data);
-}
-
 static void
 set_metadata_string_with_default (RhythmDB *db,
 				  RBMetaData *metadata,
@@ -2195,7 +2173,7 @@ rhythmdb_process_stat_event (RhythmDB *db,
 			guint64 new_size;
 
 			/* update the existing entry, as long as the entry type matches */
-			if ((event->entry_type != RHYTHMDB_ENTRY_TYPE_INVALID) && (entry->type != event->entry_type))
+			if ((event->entry_type != NULL) && (entry->type != event->entry_type))
 				g_warning ("attempt to use same location in multiple entry types");
 
 			if (entry->type == event->ignore_type)
@@ -2282,23 +2260,23 @@ typedef struct
 static void
 rhythmdb_add_import_error_entry (RhythmDB *db,
 				 RhythmDBEvent *event,
-				 RhythmDBEntryType error_entry_type)
+				 RhythmDBEntryType *error_entry_type)
 {
 	RhythmDBEntry *entry;
 	GValue value = {0,};
 
-	if (error_entry_type == RHYTHMDB_ENTRY_TYPE_INVALID) {
+	if (error_entry_type == NULL) {
 		/* we don't have an error entry type, so we can't add an import error */
 		return;
 	}
 	rb_debug ("adding import error type %s for %s: %s",
-		  error_entry_type->name,
+		  rhythmdb_entry_type_get_name (error_entry_type),
 		  rb_refstring_get (event->real_uri),
 		  event->error ? event->error->message : "<no error>");
 
 	entry = rhythmdb_entry_lookup_by_location_refstring (db, event->real_uri);
 	if (entry) {
-		RhythmDBEntryType entry_type = rhythmdb_entry_get_entry_type (entry);
+		RhythmDBEntryType *entry_type = rhythmdb_entry_get_entry_type (entry);
 		if (entry_type != event->error_type &&
 		    entry_type != event->ignore_type) {
 			/* FIXME we've successfully read this file before.. so what should we do? */
@@ -2414,7 +2392,7 @@ rhythmdb_process_metadata_load (RhythmDB *db, RhythmDBEvent *event)
 	GValue value = {0,};
 	GTimeVal time;
 
-	if (event->entry_type == RHYTHMDB_ENTRY_TYPE_INVALID)
+	if (event->entry_type == NULL)
 		event->entry_type = RHYTHMDB_ENTRY_TYPE_SONG;
 
 	if (event->metadata != NULL) {
@@ -2467,7 +2445,7 @@ rhythmdb_process_metadata_load (RhythmDB *db, RhythmDBEvent *event)
 	entry = rhythmdb_entry_lookup_by_location_refstring (db, event->real_uri);
 
 	if (entry != NULL) {
-		RhythmDBEntryType etype;
+		RhythmDBEntryType *etype;
 		etype = rhythmdb_entry_get_entry_type (entry);
 		if (etype == event->error_type || etype == event->ignore_type) {
 			/* switching from IGNORE/ERROR to SONG, recreate the entry */
@@ -2505,7 +2483,7 @@ rhythmdb_process_metadata_load (RhythmDB *db, RhythmDBEvent *event)
 		g_value_unset (&value);
 	}
 
-	if ((event->entry_type != RHYTHMDB_ENTRY_TYPE_INVALID) && (entry->type != event->entry_type)) {
+	if ((event->entry_type != NULL) && (entry->type != event->entry_type)) {
 		g_warning ("attempt to use same location in multiple entry types");
 		return TRUE;
 	}
@@ -2890,8 +2868,8 @@ rhythmdb_entry_get (RhythmDB *db,
 	case G_TYPE_DOUBLE:
 		g_value_set_double (val, rhythmdb_entry_get_double (entry, propid));
 		break;
-	case G_TYPE_POINTER:
-		g_value_set_pointer (val, rhythmdb_entry_get_pointer (entry, propid));
+	case G_TYPE_OBJECT:
+		g_value_set_object (val, rhythmdb_entry_get_object (entry, propid));
 		break;
 	default:
 		g_assert_not_reached ();
@@ -2965,7 +2943,7 @@ action_thread_main (RhythmDB *db)
 			{
 				GError *error = NULL;
 				RhythmDBEntry *entry;
-				RhythmDBEntryType entry_type;
+				RhythmDBEntryType *entry_type;
 
 				if (db->priv->dry_run) {
 					rb_debug ("dry run is enabled, not syncing metadata");
@@ -2977,7 +2955,7 @@ action_thread_main (RhythmDB *db)
 					break;
 
 				entry_type = rhythmdb_entry_get_entry_type (entry);
-				entry_type->sync_metadata (db, entry, action->data.changes, &error, entry_type->sync_metadata_data);
+				rhythmdb_entry_sync_metadata (entry, action->data.changes, &error);
 
 				if (error != NULL) {
 					RhythmDBSaveErrorData *data;
@@ -3031,7 +3009,7 @@ rhythmdb_add_uri (RhythmDB *db,
 {
 	rhythmdb_add_uri_with_types (db,
 				     uri,
-				     RHYTHMDB_ENTRY_TYPE_INVALID,
+				     RHYTHMDB_ENTRY_TYPE_SONG,
 				     RHYTHMDB_ENTRY_TYPE_IGNORE,
 				     RHYTHMDB_ENTRY_TYPE_IMPORT_ERROR);
 }
@@ -3040,9 +3018,9 @@ static void
 rhythmdb_add_to_stat_list (RhythmDB *db,
 			   const char *uri,
 			   RhythmDBEntry *entry,
-			   RhythmDBEntryType type,
-			   RhythmDBEntryType ignore_type,
-			   RhythmDBEntryType error_type)
+			   RhythmDBEntryType *type,
+			   RhythmDBEntryType *ignore_type,
+			   RhythmDBEntryType *error_type)
 {
 	RhythmDBEvent *result;
 
@@ -3079,9 +3057,9 @@ rhythmdb_add_to_stat_list (RhythmDB *db,
 void
 rhythmdb_add_uri_with_types (RhythmDB *db,
 			     const char *uri,
-			     RhythmDBEntryType type,
-			     RhythmDBEntryType ignore_type,
-			     RhythmDBEntryType error_type)
+			     RhythmDBEntryType *type,
+			     RhythmDBEntryType *ignore_type,
+			     RhythmDBEntryType *error_type)
 {
 	rb_debug ("queueing stat for \"%s\"", uri);
 	g_assert (uri && *uri);
@@ -3834,7 +3812,7 @@ rhythmdb_entry_move_to_trash (RhythmDB *db,
  */
 void
 rhythmdb_entry_delete_by_type (RhythmDB *db,
-			       RhythmDBEntryType type)
+			       RhythmDBEntryType *type)
 {
 	RhythmDBClass *klass = RHYTHMDB_GET_CLASS (db);
 
@@ -4019,7 +3997,7 @@ rhythmdb_entry_count (RhythmDB *db)
  */
 void
 rhythmdb_entry_foreach_by_type (RhythmDB *db,
-				RhythmDBEntryType entry_type,
+				RhythmDBEntryType *entry_type,
 				GFunc func,
 				gpointer data)
 {
@@ -4039,7 +4017,7 @@ rhythmdb_entry_foreach_by_type (RhythmDB *db,
  */
 gint64
 rhythmdb_entry_count_by_type (RhythmDB *db,
-			      RhythmDBEntryType entry_type)
+			      RhythmDBEntryType *entry_type)
 {
 	RhythmDBClass *klass = RHYTHMDB_GET_CLASS (db);
 
@@ -4294,28 +4272,6 @@ rhythmdb_query_type_get_type (void)
 }
 
 GType
-rhythmdb_entry_category_get_type (void)
-{
-	static GType etype = 0;
-
-	if (etype == 0)
-	{
-		static const GEnumValue values[] =
-		{
-			ENUM_ENTRY (RHYTHMDB_ENTRY_NORMAL, "normal"),
-			ENUM_ENTRY (RHYTHMDB_ENTRY_STREAM, "stream"),
-			ENUM_ENTRY (RHYTHMDB_ENTRY_CONTAINER, "container"),
-			ENUM_ENTRY (RHYTHMDB_ENTRY_VIRTUAL, "virtual"),
-			{ 0, 0, 0 }
-		};
-
-		etype = g_enum_register_static ("RhythmDBEntryCategory", values);
-	}
-
-	return etype;
-}
-
-GType
 rhythmdb_prop_type_get_type (void)
 {
 	static GType etype = 0;
@@ -4649,116 +4605,28 @@ rhythmdb_compute_status_normal (gint n_songs,
 	return ret;
 }
 
-static void
-default_sync_metadata (RhythmDB *db,
-		       RhythmDBEntry *entry,
-		       GSList *changes,
-		       GError **error,
-		       gpointer data)
-{
-	const char *uri;
-	GError *local_error = NULL;
-	GSList *t;
-
-	uri = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
-	rb_metadata_reset (db->priv->metadata);
-
-	for (t = changes; t; t = t->next) {
-		RBMetaDataField field;
-		GValue val = {0,};
-		RhythmDBEntryChange *change = (RhythmDBEntryChange *)t->data;
-
-		if (metadata_field_from_prop (change->prop, &field) == FALSE) {
-			continue;
-		}
-
-		g_value_init (&val, rhythmdb_properties[change->prop].prop_type);
-		rhythmdb_entry_get (db, entry, change->prop, &val);
-		rb_metadata_set (db->priv->metadata, field, &val);
-		g_value_unset (&val);
-	}
-
-	rb_metadata_save (db->priv->metadata, uri, &local_error);
-	if (local_error != NULL) {
-		RhythmDBAction *load_action;
-
-		/* reload the metadata, to revert the db changes */
-		rb_debug ("error saving metadata for %s: %s; reloading metadata to revert",
-			  rb_refstring_get (entry->location),
-			  local_error->message);
-		load_action = g_slice_new0 (RhythmDBAction);
-		load_action->type = RHYTHMDB_ACTION_LOAD;
-		load_action->uri = rb_refstring_ref (entry->location);
-		load_action->data.types.entry_type = RHYTHMDB_ENTRY_TYPE_INVALID;
-		load_action->data.types.error_type = RHYTHMDB_ENTRY_TYPE_INVALID;
-		load_action->data.types.ignore_type = RHYTHMDB_ENTRY_TYPE_INVALID;
-		g_async_queue_push (db->priv->action_queue, load_action);
-
-		g_propagate_error (error, local_error);
-	}
-}
-
 /**
- * rhythmdb_entry_register_type:
- * @db: a #RhythmDB
- * @name: optional name for the entry type
- *
- * Registers a new #RhythmDBEntryType. This should be called to create a new
- * entry type for non-permanent sources.
+ * rhythmdb_register_entry_type:
+ * @db: the #RhythmDB
+ * @etype: the new entry type to register
  *
- * Returns: the new #RhythmDBEntryType.
+ * Registers a new entry type.  An entry type must be registered before
+ * any entries can be created for it.
  */
-RhythmDBEntryType
-rhythmdb_entry_register_type (RhythmDB *db,
-			      const char *name)
+void
+rhythmdb_register_entry_type (RhythmDB *db, RhythmDBEntryType *etype)
 {
-	RhythmDBEntryType type;
 	RhythmDBClass *klass = RHYTHMDB_GET_CLASS (db);
+	char *name = NULL;
 
+	g_object_get (etype, "name", &name, NULL);
 	g_assert (name != NULL);
-
-	type = g_new0 (RhythmDBEntryType_, 1);
-	type->can_sync_metadata = (RhythmDBEntryCanSyncFunc)rb_false_function;
-	type->sync_metadata = default_sync_metadata;
-	type->name = g_strdup (name);
-
 	g_mutex_lock (db->priv->entry_type_map_mutex);
-	g_hash_table_insert (db->priv->entry_type_map, g_strdup (type->name), type);
+	g_hash_table_insert (db->priv->entry_type_map, name, g_object_ref (etype));
 	g_mutex_unlock (db->priv->entry_type_map_mutex);
 
 	if (klass->impl_entry_type_registered)
-		klass->impl_entry_type_registered (db, name, type);
-
-	return type;
-}
-
-static void
-rhythmdb_entry_register_type_alias (RhythmDB *db,
-				    RhythmDBEntryType type,
-				    const char *name)
-{
-	char *dn = g_strdup (name);
-
-	g_mutex_lock (db->priv->entry_type_map_mutex);
-	g_hash_table_insert (db->priv->entry_type_map, dn, type);
-	g_mutex_unlock (db->priv->entry_type_map_mutex);
-}
-
-typedef struct {
-	GHFunc func;
-	gpointer data;
-} RhythmDBEntryTypeForeachData;
-
-static void
-rhythmdb_entry_type_foreach_cb (const char *name,
-				RhythmDBEntryType entry_type,
-				RhythmDBEntryTypeForeachData *data)
-{
-	/* skip aliases */
-	if (strcmp (entry_type->name, name))
-		return;
-
-	data->func ((gpointer) name, entry_type, data->data);
+		klass->impl_entry_type_registered (db, etype);
 }
 
 /**
@@ -4774,15 +4642,8 @@ rhythmdb_entry_type_foreach (RhythmDB *db,
 			     GHFunc func,
 			     gpointer data)
 {
-	RhythmDBEntryTypeForeachData d;
-
-	d.func = func;
-	d.data = data;
-
 	g_mutex_lock (db->priv->entry_type_mutex);
-	g_hash_table_foreach (db->priv->entry_type_map,
-			      (GHFunc) rhythmdb_entry_type_foreach_cb,
-			      &d);
+	g_hash_table_foreach (db->priv->entry_type_map, func, data);
 	g_mutex_unlock (db->priv->entry_type_mutex);
 }
 
@@ -4791,13 +4652,12 @@ rhythmdb_entry_type_foreach (RhythmDB *db,
  * @db: a #RhythmDB
  * @name: name of the type to look for
  *
- * Locates a #RhythmDBEntryType by name. Returns
- * RHYTHMDB_ENTRY_TYPE_INVALID if no entry type
- * is registered with the specified name.
+ * Locates a #RhythmDBEntryType by name. Returns NULL if no entry
+ * type is registered with the specified name.
  *
  * Returns: the #RhythmDBEntryType
  */
-RhythmDBEntryType
+RhythmDBEntryType *
 rhythmdb_entry_type_get_by_name (RhythmDB *db,
 				 const char *name)
 {
@@ -4809,142 +4669,7 @@ rhythmdb_entry_type_get_by_name (RhythmDB *db,
 	}
 	g_mutex_unlock (db->priv->entry_type_map_mutex);
 
-	if (t)
-		return (RhythmDBEntryType) t;
-
-	return RHYTHMDB_ENTRY_TYPE_INVALID;
-}
-
-static gboolean
-song_can_sync_metadata (RhythmDB *db,
-			RhythmDBEntry *entry,
-			gpointer data)
-{
-	const char *mimetype;
-
-	mimetype = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MIMETYPE);
-	return rb_metadata_can_save (db->priv->metadata, mimetype);
-}
-
-static char *
-podcast_get_playback_uri (RhythmDBEntry *entry,
-			  gpointer data)
-{
-	if (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MOUNTPOINT) != NULL) {
-		return rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_LOCATION);
-	}
-	return NULL;
-}
-
-static void
-podcast_post_create (RhythmDBEntry *entry,
-		     gpointer something)
-{
-	RhythmDBPodcastFields *podcast = RHYTHMDB_ENTRY_GET_TYPE_DATA (entry, RhythmDBPodcastFields);
-	RBRefString *empty = rb_refstring_new ("");
-	podcast->description = rb_refstring_ref (empty);
-	podcast->subtitle = rb_refstring_ref (empty);
-	podcast->summary = rb_refstring_ref (empty);
-	podcast->lang = rb_refstring_ref (empty);
-	podcast->copyright = rb_refstring_ref (empty);
-	podcast->image = rb_refstring_ref (empty);
-	rb_refstring_unref (empty);
-}
-
-static void
-podcast_data_destroy (RhythmDBEntry *entry,
-		      gpointer something)
-{
-	RhythmDBPodcastFields *podcast = RHYTHMDB_ENTRY_GET_TYPE_DATA (entry, RhythmDBPodcastFields);
-	rb_refstring_unref (podcast->description);
-	rb_refstring_unref (podcast->subtitle);
-	rb_refstring_unref (podcast->summary);
-	rb_refstring_unref (podcast->lang);
-	rb_refstring_unref (podcast->copyright);
-	rb_refstring_unref (podcast->image);
-}
-
-static RhythmDBEntryType song_type = RHYTHMDB_ENTRY_TYPE_INVALID;
-static RhythmDBEntryType ignore_type = RHYTHMDB_ENTRY_TYPE_INVALID;
-static RhythmDBEntryType import_error_type = RHYTHMDB_ENTRY_TYPE_INVALID;
-
-/* to be evicted */
-static RhythmDBEntryType podcast_post_type = RHYTHMDB_ENTRY_TYPE_INVALID;
-static RhythmDBEntryType podcast_feed_type = RHYTHMDB_ENTRY_TYPE_INVALID;
-
-static void
-rhythmdb_register_core_entry_types (RhythmDB *db)
-{
-	/* regular songs */
-	song_type = rhythmdb_entry_register_type (db, "song");
-	rhythmdb_entry_register_type_alias (db, song_type, "0");
-	song_type->save_to_disk = TRUE;
-	song_type->has_playlists = TRUE;
-	song_type->category = RHYTHMDB_ENTRY_NORMAL;
-	song_type->can_sync_metadata = song_can_sync_metadata;
-
-	/* import errors */
-	import_error_type = rhythmdb_entry_register_type (db, "import-error");
-	import_error_type->get_playback_uri = (RhythmDBEntryStringFunc)rb_null_function;
-	import_error_type->category = RHYTHMDB_ENTRY_VIRTUAL;
-
-	/* ignored files */
-	ignore_type = rhythmdb_entry_register_type (db, "ignore");
-	ignore_type->save_to_disk = TRUE;
-	ignore_type->category = RHYTHMDB_ENTRY_VIRTUAL;
-	ignore_type->can_sync_metadata = (RhythmDBEntryCanSyncFunc) rb_true_function;
-	ignore_type->sync_metadata = (RhythmDBEntrySyncFunc) rb_null_function;
-
-	/* podcast posts */
-	podcast_post_type = rhythmdb_entry_register_type (db, "podcast-post");
-	podcast_post_type->entry_type_data_size = sizeof (RhythmDBPodcastFields);
-	podcast_post_type->save_to_disk = TRUE;
-	podcast_post_type->category = RHYTHMDB_ENTRY_NORMAL;
-	podcast_post_type->post_entry_create = (RhythmDBEntryActionFunc) podcast_post_create;
-	podcast_post_type->pre_entry_destroy = (RhythmDBEntryActionFunc) podcast_data_destroy;
-	podcast_post_type->get_playback_uri = podcast_get_playback_uri;
-	podcast_post_type->can_sync_metadata = (RhythmDBEntryCanSyncFunc) rb_true_function;
-	podcast_post_type->sync_metadata = (RhythmDBEntrySyncFunc) rb_null_function;
-
-	/* podcast feeds */
-	podcast_feed_type = rhythmdb_entry_register_type (db, "podcast-feed");
-	podcast_feed_type->entry_type_data_size = sizeof (RhythmDBPodcastFields);
-	podcast_feed_type->save_to_disk = TRUE;
-	podcast_feed_type->category = RHYTHMDB_ENTRY_VIRTUAL;
-	podcast_post_type->post_entry_create = (RhythmDBEntryActionFunc) podcast_post_create;
-	podcast_feed_type->pre_entry_destroy = (RhythmDBEntryActionFunc) podcast_data_destroy;
-	podcast_feed_type->can_sync_metadata = (RhythmDBEntryCanSyncFunc) rb_true_function;
-	podcast_feed_type->sync_metadata = (RhythmDBEntrySyncFunc) rb_null_function;
-}
-
-RhythmDBEntryType
-rhythmdb_entry_song_get_type (void)
-{
-	return song_type;
-}
-
-RhythmDBEntryType
-rhythmdb_entry_ignore_get_type (void)
-{
-	return ignore_type;
-}
-
-RhythmDBEntryType
-rhythmdb_entry_import_error_get_type (void)
-{
-	return import_error_type;
-}
-
-RhythmDBEntryType 
-rhythmdb_entry_podcast_post_get_type (void) 
-{
-	return podcast_post_type;
-}
-
-RhythmDBEntryType
-rhythmdb_entry_podcast_feed_get_type (void)
-{
-	return podcast_feed_type;
+	return (RhythmDBEntryType *) t;
 }
 
 static void
@@ -5335,32 +5060,32 @@ rhythmdb_entry_get_uint64 (RhythmDBEntry *entry,
  *
  * Return value: the #RhythmDBEntryType for @entry
  */
-RhythmDBEntryType
+RhythmDBEntryType *
 rhythmdb_entry_get_entry_type (RhythmDBEntry *entry)
 {
-	g_return_val_if_fail (entry != NULL, RHYTHMDB_ENTRY_TYPE_INVALID);
+	g_return_val_if_fail (entry != NULL, NULL);
 
 	return entry->type;
 }
 
 /**
- * rhythmdb_entry_get_pointer:
+ * rhythmdb_entry_get_object:
  * @entry: a #RhythmDBEntry
  * @propid: the property to return
  *
- * Returns the value of a pointer property of @entry.
+ * Returns the value of an object property of @entry.
  *
  * Return value: property value
  */
-gpointer
-rhythmdb_entry_get_pointer (RhythmDBEntry *entry,
-			    RhythmDBPropType propid)
+GObject *
+rhythmdb_entry_get_object (RhythmDBEntry *entry,
+			   RhythmDBPropType propid)
 {
 	g_return_val_if_fail (entry != NULL, NULL);
 
 	switch (propid) {
 	case RHYTHMDB_PROP_TYPE:
-		return entry->type;
+		return G_OBJECT (entry->type);
 	default:
 		g_assert_not_reached ();
 		return NULL;
@@ -5473,31 +5198,6 @@ rhythmdb_entry_get_double (RhythmDBEntry *entry,
 	}
 }
 
-/**
- * rhythmdb_entry_get_playback_uri:
- * @entry: a #RhythmDBEntry
- *
- * Returns the playback URI for @entry.
- *
- * FIXME: establish guidelines for deciding when to use this and
- * when to use RHYTHMDB_PROP_LOCATION..
- *
- * Return value: the playback URI for @entry, must be freed by caller
- */
-char *
-rhythmdb_entry_get_playback_uri (RhythmDBEntry *entry)
-{
-	RhythmDBEntryType type;
-
-	g_return_val_if_fail (entry != NULL, NULL);
-
-	type = rhythmdb_entry_get_entry_type (entry);
-	if (type->get_playback_uri)
-		return (type->get_playback_uri) (entry, type->get_playback_uri_data);
-	else
-		return rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_LOCATION);
-}
-
 
 /**
  * rhythmdb_entry_keyword_add:
@@ -5590,6 +5290,63 @@ rhythmdb_entry_keywords_get	(RhythmDB *db,
 }
 
 /**
+ * rhythmdb_entry_write_metadata_changes:
+ * @db: the #RhythmDB
+ * @entry: the #RhythmDBEntry to update
+ * @changes: a list of changes to write
+ * @error: returns error information
+ *
+ * This can be called from a #RhythmDBEntryType sync_metadata function
+ * when the appropriate action is to write the metadata changes
+ * to the file at the entry's location.
+ */
+void
+rhythmdb_entry_write_metadata_changes (RhythmDB *db,
+				       RhythmDBEntry *entry,
+				       GSList *changes,
+				       GError **error)
+{
+	const char *uri;
+	GError *local_error = NULL;
+	GSList *t;
+
+	uri = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
+	rb_metadata_reset (db->priv->metadata);
+
+	for (t = changes; t; t = t->next) {
+		RBMetaDataField field;
+		GValue val = {0,};
+		RhythmDBEntryChange *change = (RhythmDBEntryChange *)t->data;
+
+		if (metadata_field_from_prop (change->prop, &field) == FALSE) {
+			continue;
+		}
+
+		g_value_init (&val, rhythmdb_get_property_type (db, change->prop));
+		rhythmdb_entry_get (db, entry, change->prop, &val);
+		rb_metadata_set (db->priv->metadata, field, &val);
+		g_value_unset (&val);
+	}
+
+	rb_metadata_save (db->priv->metadata, uri, &local_error);
+	if (local_error != NULL) {
+		RhythmDBAction *load_action;
+
+		/* reload the metadata, to revert the db changes */
+		rb_debug ("error saving metadata for %s: %s; reloading metadata to revert",
+			  rb_refstring_get (entry->location),
+			  local_error->message);
+		load_action = g_slice_new0 (RhythmDBAction);
+		load_action->type = RHYTHMDB_ACTION_LOAD;
+		load_action->uri = rb_refstring_ref (entry->location);
+		/* XXX entry types? */
+		g_async_queue_push (db->priv->action_queue, load_action);
+
+		g_propagate_error (error, local_error);
+	}
+}
+
+/**
  * rhythmdb_get_property_type:
  * @db: the #RhythmDB
  * @property_id: a property ID (#RhythmDBPropType)
@@ -5651,29 +5408,6 @@ rhythmdb_entry_change_get_type (void)
 }
 
 /**
- * rhythmdb_entry_type_get_type:
- *
- * Returns the #GType for #RhythmDBEntryType.  #RhythmDBEntryType is stored as a boxed
- * value, where copying the value just copies the pointer, and freeing it does nothing.
- * Entry types cannot be destroyed, so they are not reference counted.
- *
- * Return value: entry type value type
- */
-GType
-rhythmdb_entry_type_get_type (void)
-{
-	static GType type = 0;
-
-	if (G_UNLIKELY (type == 0)) {
-		type = g_boxed_type_register_static ("RhythmDBEntryType",
-						     (GBoxedCopyFunc)rb_copy_function,
-						     (GBoxedFreeFunc)rb_null_function);
-	}
-
-	return type;
-}
-
-/**
  * rhythmdb_entry_is_lossless:
  * @entry: a #RhythmDBEntry
  *
diff --git a/rhythmdb/rhythmdb.h b/rhythmdb/rhythmdb.h
index 82eb000..9a82f39 100644
--- a/rhythmdb/rhythmdb.h
+++ b/rhythmdb/rhythmdb.h
@@ -36,6 +36,8 @@
 
 #include <rhythmdb/rb-refstring.h>
 #include <lib/rb-string-value-map.h>
+#include <rhythmdb/rhythmdb-entry.h>
+#include <rhythmdb/rhythmdb-entry-type.h>
 #include <rhythmdb/rhythmdb-query-results.h>
 
 G_BEGIN_DECLS
@@ -50,62 +52,6 @@ typedef struct _RhythmDBClass RhythmDBClass;
 #define RHYTHMDB_IS_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), RHYTHMDB_TYPE))
 #define RHYTHMDB_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RHYTHMDB_TYPE, RhythmDBClass))
 
-struct RhythmDBEntry_;
-typedef struct RhythmDBEntry_ RhythmDBEntry;
-GType rhythmdb_entry_get_type (void);
-
-#define RHYTHMDB_TYPE_ENTRY      (rhythmdb_entry_get_type ())
-#define RHYTHMDB_ENTRY(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RHYTHMDB_TYPE_ENTRY, RhythmDBEntry))
-
-typedef void (*RhythmDBEntryActionFunc) (RhythmDBEntry *entry, gpointer data);
-typedef char* (*RhythmDBEntryStringFunc) (RhythmDBEntry *entry, gpointer data);
-typedef gboolean (*RhythmDBEntryCanSyncFunc) (RhythmDB *db, RhythmDBEntry *entry, gpointer data);
-typedef void (*RhythmDBEntrySyncFunc) (RhythmDB *db, RhythmDBEntry *entry, GSList *changes, GError **error, gpointer data);
-
-GType rhythmdb_entry_category_get_type (void);
-#define RHYTHMDB_TYPE_ENTRY_CATEGORY (rhythmdb_entry_category_get_type ())
-typedef enum {
-	RHYTHMDB_ENTRY_NORMAL,		/* anything that doesn't match the other categories */
-	RHYTHMDB_ENTRY_STREAM,		/* endless streams (eg shoutcast, last.fm) */
-	RHYTHMDB_ENTRY_CONTAINER,	/* things that point to other entries (eg podcast feeds) */
-	RHYTHMDB_ENTRY_VIRTUAL		/* import errors, ignored files */
-} RhythmDBEntryCategory;
-
-typedef struct {
-	char 				*name;
-
-	guint				entry_type_data_size;
-	gboolean			save_to_disk;
-	gboolean			has_playlists;
-	RhythmDBEntryCategory		category;
-
-	/* virtual functions here */
-	RhythmDBEntryActionFunc		post_entry_create;
-	gpointer			post_entry_create_data;
-	GDestroyNotify			post_entry_create_destroy;
-
-	RhythmDBEntryActionFunc		pre_entry_destroy;
-	gpointer			pre_entry_destroy_data;
-	GDestroyNotify			pre_entry_destroy_destroy;
-
-	RhythmDBEntryStringFunc		get_playback_uri;
-	gpointer			get_playback_uri_data;
-	GDestroyNotify			get_playback_uri_destroy;
-
-	RhythmDBEntryCanSyncFunc	can_sync_metadata;
-	gpointer			can_sync_metadata_data;
-	GDestroyNotify			can_sync_metadata_destroy;
-
-	RhythmDBEntrySyncFunc		sync_metadata;
-	gpointer			sync_metadata_data;
-	GDestroyNotify			sync_metadata_destroy;
-} RhythmDBEntryType_;
-typedef RhythmDBEntryType_ *RhythmDBEntryType;
-
-GType rhythmdb_entry_type_get_type (void);
-#define RHYTHMDB_TYPE_ENTRY_TYPE	(rhythmdb_entry_type_get_type ())
-#define RHYTHMDB_ENTRY_TYPE(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), RHYTHMDB_TYPE_ENTRY_TYPE, RhythmDBEntryType_))
-#define RHYTHMDB_IS_ENTRY_TYPE(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), RHYTHMDB_TYPE_ENTRY_TYPE))
 
 typedef GPtrArray RhythmDBQuery;
 GType rhythmdb_query_get_type (void);
@@ -113,13 +59,6 @@ GType rhythmdb_query_get_type (void);
 #define RHYTHMDB_QUERY(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), RHYTHMDB_TYPE_QUERY, RhythmDBQuery))
 #define RHYTHMDB_IS_QUERY(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), RHYTHMDB_TYPE_QUERY))
 
-#define RHYTHMDB_ENTRY_TYPE_SONG (rhythmdb_entry_song_get_type ())
-#define RHYTHMDB_ENTRY_TYPE_PODCAST_POST (rhythmdb_entry_podcast_post_get_type ())
-#define RHYTHMDB_ENTRY_TYPE_PODCAST_FEED (rhythmdb_entry_podcast_feed_get_type ())
-#define RHYTHMDB_ENTRY_TYPE_IMPORT_ERROR (rhythmdb_entry_import_error_get_type ())
-#define RHYTHMDB_ENTRY_TYPE_IGNORE (rhythmdb_entry_ignore_get_type ())
-#define RHYTHMDB_ENTRY_TYPE_INVALID (GINT_TO_POINTER (-1))
-
 typedef enum
 {
 	RHYTHMDB_QUERY_END,
@@ -275,9 +214,9 @@ gboolean rhythmdb_entry_get_boolean	(RhythmDBEntry *entry, RhythmDBPropType prop
 guint64 rhythmdb_entry_get_uint64	(RhythmDBEntry *entry, RhythmDBPropType propid);
 gulong rhythmdb_entry_get_ulong		(RhythmDBEntry *entry, RhythmDBPropType propid);
 double rhythmdb_entry_get_double	(RhythmDBEntry *entry, RhythmDBPropType propid);
-gpointer rhythmdb_entry_get_pointer     (RhythmDBEntry *entry, RhythmDBPropType propid);
+GObject *rhythmdb_entry_get_object     (RhythmDBEntry *entry, RhythmDBPropType propid);
 
-RhythmDBEntryType rhythmdb_entry_get_entry_type (RhythmDBEntry *entry);
+RhythmDBEntryType *rhythmdb_entry_get_entry_type (RhythmDBEntry *entry);
 
 typedef enum
 {
@@ -331,7 +270,7 @@ struct _RhythmDBClass
 
 	void		(*impl_entry_delete)	(RhythmDB *db, RhythmDBEntry *entry);
 
-	void            (*impl_entry_delete_by_type) (RhythmDB *db, RhythmDBEntryType type);
+	void            (*impl_entry_delete_by_type) (RhythmDB *db, RhythmDBEntryType *type);
 
 	RhythmDBEntry *	(*impl_lookup_by_location)(RhythmDB *db, RBRefString *uri);
 
@@ -343,17 +282,16 @@ struct _RhythmDBClass
 
 	gint64		(*impl_entry_count)	(RhythmDB *db);
 
-	void		(*impl_entry_foreach_by_type) (RhythmDB *db, RhythmDBEntryType type, GFunc func, gpointer data);
+	void		(*impl_entry_foreach_by_type) (RhythmDB *db, RhythmDBEntryType *type, GFunc func, gpointer data);
 
-	gint64		(*impl_entry_count_by_type) (RhythmDB *db, RhythmDBEntryType type);
+	gint64		(*impl_entry_count_by_type) (RhythmDB *db, RhythmDBEntryType *type);
 
 	void		(*impl_do_full_query)	(RhythmDB *db, RhythmDBQuery *query,
 						 RhythmDBQueryResults *results,
 						 gboolean *cancel);
 
 	void		(*impl_entry_type_registered) (RhythmDB *db,
-						       const char *name,
-						       RhythmDBEntryType type);
+						       RhythmDBEntryType *type);
 
 	gboolean	(*impl_entry_keyword_add)	(RhythmDB *db,
 							 RhythmDBEntry *entry,
@@ -383,17 +321,15 @@ void		rhythmdb_start_action_thread	(RhythmDB *db);
 
 void		rhythmdb_commit		(RhythmDB *db);
 
-gboolean	rhythmdb_entry_is_editable (RhythmDB *db, RhythmDBEntry *entry);
+RhythmDBEntry *	rhythmdb_entry_new	(RhythmDB *db, RhythmDBEntryType *type, const char *uri);
+RhythmDBEntry *	rhythmdb_entry_example_new	(RhythmDB *db, RhythmDBEntryType *type, const char *uri);
 
-RhythmDBEntry *	rhythmdb_entry_new	(RhythmDB *db, RhythmDBEntryType type, const char *uri);
-RhythmDBEntry *	rhythmdb_entry_example_new	(RhythmDB *db, RhythmDBEntryType type, const char *uri);
-
-void		rhythmdb_add_uri	(RhythmDB *db, const char *uri);
+void		rhythmdb_add_uri	(RhythmDB *db, const char *uri);		/* <-- die */
 void		rhythmdb_add_uri_with_types (RhythmDB *db,
 					     const char *uri,
-					     RhythmDBEntryType type,
-					     RhythmDBEntryType ignore_type,
-					     RhythmDBEntryType error_type);
+					     RhythmDBEntryType *type,
+					     RhythmDBEntryType *ignore_type,
+					     RhythmDBEntryType *error_type);
 
 void		rhythmdb_entry_get	(RhythmDB *db, RhythmDBEntry *entry, RhythmDBPropType propid, GValue *val);
 void		rhythmdb_entry_set	(RhythmDB *db, RhythmDBEntry *entry,
@@ -408,7 +344,7 @@ gpointer	rhythmdb_entry_get_type_data (RhythmDBEntry *entry, guint expected_size
 
 void		rhythmdb_entry_delete	(RhythmDB *db, RhythmDBEntry *entry);
 void            rhythmdb_entry_delete_by_type (RhythmDB *db,
-					       RhythmDBEntryType type);
+					       RhythmDBEntryType *type);
 void		rhythmdb_entry_move_to_trash (RhythmDB *db,
 					      RhythmDBEntry *entry);
 
@@ -427,11 +363,11 @@ void		rhythmdb_entry_foreach		(RhythmDB *db,
 gint64		rhythmdb_entry_count		(RhythmDB *db);
 
 void		rhythmdb_entry_foreach_by_type  (RhythmDB *db,
-						 RhythmDBEntryType entry_type,
+						 RhythmDBEntryType *entry_type,
 						 GFunc func,
 						 gpointer data);
 gint64		rhythmdb_entry_count_by_type	(RhythmDB *db,
-						 RhythmDBEntryType entry_type);
+						 RhythmDBEntryType *entry_type);
 
 gboolean	rhythmdb_entry_keyword_add	(RhythmDB *db,
 						 RhythmDBEntry *entry,
@@ -445,6 +381,11 @@ gboolean	rhythmdb_entry_keyword_has	(RhythmDB *db,
 GList* /*<RBRefString>*/ rhythmdb_entry_keywords_get	(RhythmDB *db,
 							 RhythmDBEntry *entry);
 
+void		rhythmdb_entry_write_metadata_changes (RhythmDB *db,
+						 RhythmDBEntry *entry,
+						 GSList *changes,
+						 GError **error);
+
 /*
  * Returns a freshly allocated GtkTreeModel which represents the query.
  * The extended arguments alternate between RhythmDBQueryType args
@@ -512,14 +453,8 @@ char *		rhythmdb_compute_status_normal		(gint n_songs, glong duration,
 							 const char *singular,
 							 const char *plural);
 
-RhythmDBEntryType rhythmdb_entry_register_type          (RhythmDB *db, const char *name);
-RhythmDBEntryType rhythmdb_entry_type_get_by_name       (RhythmDB *db, const char *name);
-
-RhythmDBEntryType rhythmdb_entry_song_get_type          (void);
-RhythmDBEntryType rhythmdb_entry_podcast_post_get_type  (void);
-RhythmDBEntryType rhythmdb_entry_podcast_feed_get_type  (void);
-RhythmDBEntryType rhythmdb_entry_import_error_get_type	(void);
-RhythmDBEntryType rhythmdb_entry_ignore_get_type        (void);
+void		rhythmdb_register_entry_type		(RhythmDB *db, RhythmDBEntryType *entry_type);
+RhythmDBEntryType *rhythmdb_entry_type_get_by_name      (RhythmDB *db, const char *name);
 
 GType rhythmdb_get_property_type (RhythmDB *db, guint property_id);
 
diff --git a/shell/rb-shell-clipboard.c b/shell/rb-shell-clipboard.c
index 7f0bab5..a298ed4 100644
--- a/shell/rb-shell-clipboard.c
+++ b/shell/rb-shell-clipboard.c
@@ -580,7 +580,7 @@ rb_shell_clipboard_sync (RBShellClipboard *clipboard)
 	gboolean can_select_all = FALSE;
 	gboolean can_show_properties = FALSE;
 	GtkAction *action;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 
 	if (clipboard->priv->source) {
 		view = rb_source_get_entry_view (clipboard->priv->source);
@@ -654,9 +654,11 @@ rb_shell_clipboard_sync (RBShellClipboard *clipboard)
 	action = gtk_action_group_get_action (clipboard->priv->actiongroup, "EditPlaylistAdd");
 	if (clipboard->priv->source != NULL) {
 		g_object_get (clipboard->priv->source, "entry-type", &entry_type, NULL);
-		if (entry_type != RHYTHMDB_ENTRY_TYPE_INVALID) {
-			gtk_action_set_sensitive (action, entry_type->has_playlists);
-			g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+		if (entry_type != NULL) {
+			gboolean has_playlists;
+			g_object_get (entry_type, "has-playlists", &has_playlists, NULL);
+			gtk_action_set_sensitive (action, has_playlists);
+			g_object_unref (entry_type);
 		} else {
 			gtk_action_set_sensitive (action, FALSE);
 		}
@@ -949,8 +951,8 @@ add_playlist_to_menu (GtkTreeModel *model,
 		      GtkTreeIter *iter,
 		      RBShellClipboard *clipboard)
 {
-	RhythmDBEntryType entry_type;
-	RhythmDBEntryType source_entry_type;
+	RhythmDBEntryType *entry_type;
+	RhythmDBEntryType *source_entry_type;
 	RBSource *source = NULL;
 	char *action_name;
 	GtkAction *action;
@@ -976,8 +978,8 @@ add_playlist_to_menu (GtkTreeModel *model,
 	g_object_get (source, "entry-type", &source_entry_type, NULL);
 	if (source_entry_type != entry_type) {
 		g_object_unref (source);
-		g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, source_entry_type);
-		g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+		g_object_unref (entry_type);
+		g_object_unref (source_entry_type);
 		return FALSE;
 	}
 
@@ -1014,8 +1016,8 @@ add_playlist_to_menu (GtkTreeModel *model,
 				       GTK_UI_MANAGER_AUTO, FALSE);
 	}
 
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, source_entry_type);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (source_entry_type);
+	g_object_unref (entry_type);
 	g_free (action_name);
 	g_object_unref (source);
 
diff --git a/shell/rb-shell.c b/shell/rb-shell.c
index e9e463e..27c308c 100644
--- a/shell/rb-shell.c
+++ b/shell/rb-shell.c
@@ -1937,7 +1937,7 @@ rb_shell_db_entry_added_cb (RhythmDB *db,
  */
 RBSource *
 rb_shell_get_source_by_entry_type (RBShell *shell,
-				   RhythmDBEntryType type)
+				   RhythmDBEntryType *type)
 {
 	return g_hash_table_lookup (shell->priv->sources_hash, type);
 }
@@ -1956,7 +1956,7 @@ rb_shell_get_source_by_entry_type (RBShell *shell,
 void
 rb_shell_register_entry_type_for_source (RBShell *shell,
 					 RBSource *source,
-					 RhythmDBEntryType type)
+					 RhythmDBEntryType *type)
 {
 	if (shell->priv->sources_hash == NULL) {
 		shell->priv->sources_hash = g_hash_table_new (g_direct_hash,
@@ -2027,7 +2027,7 @@ static void
 rb_shell_source_deleted_cb (RBSource *source,
 			    RBShell *shell)
 {
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 
 	rb_debug ("source deleted");
 
@@ -2036,7 +2036,7 @@ rb_shell_source_deleted_cb (RBSource *source,
 	if (rb_shell_get_source_by_entry_type (shell, entry_type) == source) {
 		g_hash_table_remove (shell->priv->sources_hash, entry_type);
 	}
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 
 
 	if (source == rb_shell_player_get_playing_source (shell->priv->player_shell) ||
@@ -2084,7 +2084,7 @@ rb_shell_playing_from_queue_cb (RBShellPlayer *player,
 	} else {
 		RBSource *source;
 		RhythmDBEntry *entry;
-		RhythmDBEntryType entry_type;
+		RhythmDBEntryType *entry_type;
 
 		/* if playing from the queue, show the playing entry as playing in the
 		 * registered source for its type, so it makes sense when 'jump to current'
@@ -2949,7 +2949,7 @@ rb_shell_jump_to_entry_with_source (RBShell *shell,
 	if ((source == RB_SOURCE (shell->priv->queue_source) &&
 	     shell->priv->queue_as_sidebar) ||
 	     source == NULL) {
-		RhythmDBEntryType entry_type;
+		RhythmDBEntryType *entry_type;
 		entry_type = rhythmdb_entry_get_entry_type (entry);
 		source = rb_shell_get_source_by_entry_type (shell, entry_type);
 	}
diff --git a/shell/rb-shell.h b/shell/rb-shell.h
index 60caa03..b1c7065 100644
--- a/shell/rb-shell.h
+++ b/shell/rb-shell.h
@@ -155,9 +155,9 @@ gboolean	rb_shell_do_notify (RBShell *shell,
 
 void            rb_shell_register_entry_type_for_source (RBShell *shell,
 							 RBSource *source,
-							 RhythmDBEntryType type);
+							 RhythmDBEntryType *type);
 RBSource * rb_shell_get_source_by_entry_type (RBShell *shell,
-					      RhythmDBEntryType type);
+					      RhythmDBEntryType *type);
 
 gboolean        rb_shell_get_party_mode (RBShell *shell);
 
diff --git a/shell/rb-track-transfer-batch.c b/shell/rb-track-transfer-batch.c
index 8d94e54..05020d0 100644
--- a/shell/rb-track-transfer-batch.c
+++ b/shell/rb-track-transfer-batch.c
@@ -253,7 +253,7 @@ _rb_track_transfer_batch_start (RBTrackTransferBatch *batch, GObject *queue)
 		}
 
 		if (batch->priv->source == NULL) {
-			RhythmDBEntryType entry_type;
+			RhythmDBEntryType *entry_type;
 			RBSource *entry_origin;
 
 			entry_type = rhythmdb_entry_get_entry_type (entry);
diff --git a/sources/rb-auto-playlist-source.c b/sources/rb-auto-playlist-source.c
index 0b6558e..fc237c5 100644
--- a/sources/rb-auto-playlist-source.c
+++ b/sources/rb-auto-playlist-source.c
@@ -248,7 +248,7 @@ rb_auto_playlist_source_constructed (GObject *object)
 	RBAutoPlaylistSource *source;
 	RBAutoPlaylistSourcePrivate *priv;
 	RBShell *shell;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 
 	RB_CHAIN_GOBJECT_METHOD (rb_auto_playlist_source_parent_class, constructed, object);
 
@@ -260,7 +260,7 @@ rb_auto_playlist_source_constructed (GObject *object)
 	g_object_get (RB_PLAYLIST_SOURCE (source), "entry-type", &entry_type, NULL);
 	priv->browser = rb_library_browser_new (rb_playlist_source_get_db (RB_PLAYLIST_SOURCE (source)),
 						entry_type);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 	gtk_paned_pack1 (GTK_PANED (priv->paned), GTK_WIDGET (priv->browser), TRUE, FALSE);
 	g_signal_connect_object (G_OBJECT (priv->browser), "notify::output-model",
 				 G_CALLBACK (rb_auto_playlist_source_browser_changed_cb),
@@ -610,12 +610,12 @@ impl_receive_drag (RBSource *asource, GtkSelectionData *data)
 	g_strfreev (names);
 
 	if (subquery != NULL) {
-		RhythmDBEntryType qtype;
+		RhythmDBEntryType *qtype;
 		GPtrArray *query;
 
 		g_object_get (source, "entry-type", &qtype, NULL);
-		if (qtype == RHYTHMDB_ENTRY_TYPE_INVALID)
-			qtype = RHYTHMDB_ENTRY_TYPE_SONG;
+		if (qtype == NULL)
+			qtype = g_object_ref (RHYTHMDB_ENTRY_TYPE_SONG);
 
 		query = rhythmdb_query_parse (db,
 					      RHYTHMDB_QUERY_PROP_EQUALS,
@@ -630,7 +630,7 @@ impl_receive_drag (RBSource *asource, GtkSelectionData *data)
 
 		rhythmdb_query_free (subquery);
 		rhythmdb_query_free (query);
-                g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, qtype);
+		g_object_unref (qtype);
 	}
 
 	g_object_unref (db);
diff --git a/sources/rb-browser-source.c b/sources/rb-browser-source.c
index 9007612..b0cbf86 100644
--- a/sources/rb-browser-source.c
+++ b/sources/rb-browser-source.c
@@ -342,7 +342,7 @@ rb_browser_source_constructed (GObject *object)
 	GObject *shell_player;
 	char *browser_key;
 	char *paned_key;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 
 	RB_CHAIN_GOBJECT_METHOD (rb_browser_source_parent_class, constructed, object);
 
@@ -481,7 +481,7 @@ rb_browser_source_constructed (GObject *object)
 	source->priv->cached_all_query = rhythmdb_query_model_new_empty (source->priv->db);
 	rb_browser_source_populate (source);
 
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 }
 
 static void
@@ -570,7 +570,7 @@ rb_browser_source_populate (RBBrowserSource *source)
 				      RHYTHMDB_QUERY_RESULTS (source->priv->cached_all_query),
 				      RHYTHMDB_QUERY_PROP_EQUALS, RHYTHMDB_PROP_TYPE, entry_type,
 				      RHYTHMDB_QUERY_END);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 }
 
 static void
@@ -884,7 +884,7 @@ rb_browser_source_do_query (RBBrowserSource *source, gboolean subset)
 {
 	RhythmDBQueryModel *query_model;
 	GPtrArray *query;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 
 	/* use the cached 'all' query to optimise the no-search case */
 	if (source->priv->search_query == NULL) {
@@ -902,7 +902,7 @@ rb_browser_source_do_query (RBBrowserSource *source, gboolean subset)
 				      RHYTHMDB_QUERY_SUBQUERY,
 				      source->priv->search_query,
 				      RHYTHMDB_QUERY_END);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 
 	if (subset) {
 		/* if we're appending text to an existing search string, the results will be a subset
diff --git a/sources/rb-import-errors-source.c b/sources/rb-import-errors-source.c
index 3c0d60e..bcebd71 100644
--- a/sources/rb-import-errors-source.c
+++ b/sources/rb-import-errors-source.c
@@ -75,8 +75,8 @@ struct _RBImportErrorsSourcePrivate
 	RhythmDBQueryModel *missing_plugin_model;
 	GtkWidget *infobar;
 
-	RhythmDBEntryType normal_entry_type;
-	RhythmDBEntryType ignore_entry_type;
+	RhythmDBEntryType *normal_entry_type;
+	RhythmDBEntryType *ignore_entry_type;
 };
 
 G_DEFINE_TYPE (RBImportErrorsSource, rb_import_errors_source, RB_TYPE_SOURCE);
@@ -134,18 +134,18 @@ rb_import_errors_source_class_init (RBImportErrorsSourceClass *klass)
 
 	g_object_class_install_property (object_class,
 					 PROP_NORMAL_ENTRY_TYPE,
-					 g_param_spec_boxed ("normal-entry-type",
-							     "Normal entry type",
-							     "Entry type for successfully imported entries of this type",
-							     RHYTHMDB_TYPE_ENTRY_TYPE,
-							     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+					 g_param_spec_object ("normal-entry-type",
+							      "Normal entry type",
+							      "Entry type for successfully imported entries of this type",
+							      RHYTHMDB_TYPE_ENTRY_TYPE,
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 	g_object_class_install_property (object_class,
 					 PROP_IGNORE_ENTRY_TYPE,
-					 g_param_spec_boxed ("ignore-entry-type",
-							     "Ignore entry type",
-							     "Entry type for entries of this type to be ignored",
-							     RHYTHMDB_TYPE_ENTRY_TYPE,
-							     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+					 g_param_spec_object ("ignore-entry-type",
+							      "Ignore entry type",
+							      "Entry type for entries of this type to be ignored",
+							      RHYTHMDB_TYPE_ENTRY_TYPE,
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_type_class_add_private (klass, sizeof (RBImportErrorsSourcePrivate));
 }
@@ -177,7 +177,7 @@ rb_import_errors_source_constructed (GObject *object)
 	RBShell *shell;
 	GPtrArray *query;
 	RhythmDBQueryModel *model;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	GtkWidget *box;
 	GtkWidget *label;
 
@@ -247,7 +247,7 @@ rb_import_errors_source_constructed (GObject *object)
 	gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (source->priv->infobar))),
 			   label);
 
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 
 	box = gtk_vbox_new (FALSE, 6);
 	gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (source->priv->view), TRUE, TRUE, 0);
@@ -274,10 +274,10 @@ impl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *ps
 	RBImportErrorsSource *source = RB_IMPORT_ERRORS_SOURCE (object);
 	switch (prop_id) {
 	case PROP_NORMAL_ENTRY_TYPE:
-		g_value_set_boxed (value, source->priv->normal_entry_type);
+		g_value_set_object (value, source->priv->normal_entry_type);
 		break;
 	case PROP_IGNORE_ENTRY_TYPE:
-		g_value_set_boxed (value, source->priv->ignore_entry_type);
+		g_value_set_object (value, source->priv->ignore_entry_type);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -291,10 +291,10 @@ impl_set_property (GObject *object, guint prop_id, const GValue *value, GParamSp
 	RBImportErrorsSource *source = RB_IMPORT_ERRORS_SOURCE (object);
 	switch (prop_id) {
 	case PROP_NORMAL_ENTRY_TYPE:
-		source->priv->normal_entry_type = g_value_get_boxed (value);
+		source->priv->normal_entry_type = g_value_get_object (value);
 		break;
 	case PROP_IGNORE_ENTRY_TYPE:
-		source->priv->ignore_entry_type = g_value_get_boxed (value);
+		source->priv->ignore_entry_type = g_value_get_object (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -340,9 +340,9 @@ impl_get_entry_view (RBSource *asource)
  */
 RBSource *
 rb_import_errors_source_new (RBShell *shell,
-			     RhythmDBEntryType entry_type,
-			     RhythmDBEntryType normal_entry_type,
-			     RhythmDBEntryType ignore_entry_type)
+			     RhythmDBEntryType *entry_type,
+			     RhythmDBEntryType *normal_entry_type,
+			     RhythmDBEntryType *ignore_entry_type)
 {
 	RBSource *source;
 
@@ -423,7 +423,7 @@ static void
 missing_plugins_retry_cb (gpointer instance, gboolean installed, RBImportErrorsSource *source)
 {
 	GtkTreeIter iter;
-	RhythmDBEntryType error_entry_type;
+	RhythmDBEntryType *error_entry_type;
 
 	gtk_info_bar_set_response_sensitive (GTK_INFO_BAR (source->priv->infobar),
 					     GTK_RESPONSE_OK,
@@ -447,7 +447,7 @@ missing_plugins_retry_cb (gpointer instance, gboolean installed, RBImportErrorsS
 					     error_entry_type);
 	} while (gtk_tree_model_iter_next (GTK_TREE_MODEL (source->priv->missing_plugin_model), &iter));
 
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, error_entry_type);
+	g_object_unref (error_entry_type);
 }
 
 static void
diff --git a/sources/rb-import-errors-source.h b/sources/rb-import-errors-source.h
index 24546a9..60e6df8 100644
--- a/sources/rb-import-errors-source.h
+++ b/sources/rb-import-errors-source.h
@@ -60,9 +60,9 @@ struct _RBImportErrorsSourceClass
 GType		rb_import_errors_source_get_type		(void);
 
 RBSource *      rb_import_errors_source_new			(RBShell *shell,
-								 RhythmDBEntryType entry_type,
-								 RhythmDBEntryType normal_entry_type,
-								 RhythmDBEntryType ignore_entry_type);
+								 RhythmDBEntryType *entry_type,
+								 RhythmDBEntryType *normal_entry_type,
+								 RhythmDBEntryType *ignore_entry_type);
 
 G_END_DECLS
 
diff --git a/sources/rb-library-source.c b/sources/rb-library-source.c
index 6871b10..7abcdf6 100644
--- a/sources/rb-library-source.c
+++ b/sources/rb-library-source.c
@@ -393,9 +393,6 @@ rb_library_source_new (RBShell *shell)
 	RBSource *source;
 	GdkPixbuf *icon;
 	gint size;
-	RhythmDBEntryType entry_type;
-
-	entry_type = RHYTHMDB_ENTRY_TYPE_SONG;
 
 	gtk_icon_size_lookup (RB_SOURCE_ICON_SIZE, &size, NULL);
 	icon = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
@@ -404,7 +401,7 @@ rb_library_source_new (RBShell *shell)
 					 0, NULL);
 	source = RB_SOURCE (g_object_new (RB_TYPE_LIBRARY_SOURCE,
 					  "name", _("Music"),
-					  "entry-type", entry_type,
+					  "entry-type", RHYTHMDB_ENTRY_TYPE_SONG,
 					  "source-group", RB_SOURCE_GROUP_LIBRARY,
 					  "sorting-key", CONF_STATE_LIBRARY_SORTING,
 					  "shell", shell,
@@ -415,7 +412,7 @@ rb_library_source_new (RBShell *shell)
 		g_object_unref (icon);
 	}
 
-	rb_shell_register_entry_type_for_source (shell, source, entry_type);
+	rb_shell_register_entry_type_for_source (shell, source, RHYTHMDB_ENTRY_TYPE_SONG);
 
 	return source;
 }
@@ -1008,7 +1005,7 @@ layout_example_label_update (RBLibrarySource *source)
 	char *format;
 	char *tmp;
 	GMAudioProfile *profile;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	RhythmDBEntry *sample_entry;
 
   	profile = gm_audio_profile_choose_get_active (source->priv->preferred_format_menu);
@@ -1029,7 +1026,7 @@ layout_example_label_update (RBLibrarySource *source)
 
 	g_object_get (source, "entry-type", &entry_type, NULL);
 	sample_entry = rhythmdb_entry_example_new (source->priv->db, entry_type, NULL);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 
 	file_value = filepath_parse_pattern (source->priv->db, file_pattern, sample_entry);
 	path_value = filepath_parse_pattern (source->priv->db, path_pattern, sample_entry);
@@ -1287,7 +1284,7 @@ impl_paste (RBSource *asource, GList *entries)
 	GList *l;
 	GSList *sl;
 	RBShell *shell;
-	RhythmDBEntryType source_entry_type;
+	RhythmDBEntryType *source_entry_type;
 	RBTrackTransferBatch *batch;
 	gboolean start_batch = FALSE;
 
@@ -1311,7 +1308,7 @@ impl_paste (RBSource *asource, GList *entries)
 
 	for (l = entries; l != NULL; l = g_list_next (l)) {
 		RhythmDBEntry *entry = (RhythmDBEntry *)l->data;
-		RhythmDBEntryType entry_type;
+		RhythmDBEntryType *entry_type;
 		RBSource *source_source;
 
 		rb_debug ("pasting entry %s", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION));
@@ -1332,7 +1329,7 @@ impl_paste (RBSource *asource, GList *entries)
 		rb_track_transfer_batch_add (batch, entry);
 		start_batch = TRUE;
 	}
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, source_entry_type);
+	g_object_unref (source_entry_type);
 
 	if (start_batch) {
 		rb_track_transfer_queue_start_batch (xferq, batch);
@@ -1448,7 +1445,7 @@ rb_library_source_add_child_source (const char *path, RBLibrarySource *library_s
 	RBShell *shell;
 	char *name;
 	GdkPixbuf *icon;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	char *sort_column;
 	int sort_order;
 	GFile *file;
@@ -1485,7 +1482,7 @@ rb_library_source_add_child_source (const char *path, RBLibrarySource *library_s
 	rb_shell_append_source (shell, source, RB_SOURCE (library_source));
 	library_source->priv->child_sources = g_list_prepend (library_source->priv->child_sources, source);
 
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 	g_object_unref (shell);
 	g_free (name);
 }
diff --git a/sources/rb-missing-files-source.c b/sources/rb-missing-files-source.c
index 4db4ae6..896223c 100644
--- a/sources/rb-missing-files-source.c
+++ b/sources/rb-missing-files-source.c
@@ -145,7 +145,7 @@ rb_missing_files_source_constructed (GObject *object)
 	RBShell *shell;
 	GPtrArray *query;
 	RhythmDBQueryModel *model;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 
 	RB_CHAIN_GOBJECT_METHOD (rb_missing_files_source_parent_class, constructed, object);
 	source = RB_MISSING_FILES_SOURCE (object);
@@ -167,7 +167,7 @@ rb_missing_files_source_constructed (GObject *object)
 				      	RHYTHMDB_PROP_HIDDEN,
 					TRUE,
 				      RHYTHMDB_QUERY_END);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 
 	model = rhythmdb_query_model_new (source->priv->db, query,
 					  NULL, NULL, NULL, FALSE);
@@ -274,7 +274,7 @@ rb_missing_files_source_new (RBShell *shell,
 			     RBLibrarySource *library)
 {
 	RBSource *source;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 
 	g_object_get (library, "entry-type", &entry_type, NULL);
 	source = RB_SOURCE (g_object_new (RB_TYPE_MISSING_FILES_SOURCE,
@@ -285,7 +285,7 @@ rb_missing_files_source_new (RBShell *shell,
 					  "hidden-when-empty", TRUE,
 					  "source-group", RB_SOURCE_GROUP_LIBRARY,
 					  NULL));
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 	return source;
 }
 
diff --git a/sources/rb-play-queue-source.c b/sources/rb-play-queue-source.c
index 7c57cfd..e3c15a8 100644
--- a/sources/rb-play-queue-source.c
+++ b/sources/rb-play-queue-source.c
@@ -317,7 +317,7 @@ rb_play_queue_source_new (RBShell *shell)
 					"name", _("Play Queue"),
 					"shell", shell,
 					"is-local", TRUE,
-					"entry-type", RHYTHMDB_ENTRY_TYPE_INVALID,
+					"entry-type", NULL,
 					"source-group", RB_SOURCE_GROUP_LIBRARY,
 					NULL));
 }
diff --git a/sources/rb-podcast-source.c b/sources/rb-podcast-source.c
index 0b5f7c5..55c96d3 100644
--- a/sources/rb-podcast-source.c
+++ b/sources/rb-podcast-source.c
@@ -47,6 +47,7 @@
 #include <gtk/gtk.h>
 
 #include "rb-podcast-source.h"
+#include "rb-podcast-entry-types.h"
 
 #include "rhythmdb.h"
 #include "rhythmdb-query-model.h"
@@ -1127,7 +1128,7 @@ static GPtrArray *
 construct_query_from_selection (RBPodcastSource *source)
 {
 	GPtrArray *query;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 
 	g_object_get (source, "entry-type", &entry_type, NULL);
 
@@ -1136,7 +1137,7 @@ construct_query_from_selection (RBPodcastSource *source)
 				      RHYTHMDB_PROP_TYPE,
 				      entry_type,
 				      RHYTHMDB_QUERY_END);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 
 	if (source->priv->search_query) {
 		rhythmdb_query_append (source->priv->db,
@@ -2078,7 +2079,7 @@ rb_podcast_source_entry_changed_cb (RhythmDB *db,
 				    GValueArray *changes,
 				    RBPodcastSource *source)
 {
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	gboolean feed_changed;
 	int i;
 
diff --git a/sources/rb-removable-media-source.c b/sources/rb-removable-media-source.c
index e162f07..54f6d64 100644
--- a/sources/rb-removable-media-source.c
+++ b/sources/rb-removable-media-source.c
@@ -326,16 +326,16 @@ impl_delete_thyself (RBSource *source)
 {
 	RhythmDB *db;
 	RBShell *shell;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 
 	g_object_get (source, "shell", &shell, NULL);
 	g_object_get (shell, "db", &db, NULL);
 	g_object_unref (shell);
 
 	g_object_get (source, "entry-type", &entry_type, NULL);
-	rb_debug ("deleting all entries of type '%s'", entry_type->name);
+	rb_debug ("deleting all entries of type '%s'", rhythmdb_entry_type_get_name (entry_type));
 	rhythmdb_entry_delete_by_type (db, entry_type);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 
 	rhythmdb_commit (db);
 	g_object_unref (db);
@@ -393,7 +393,7 @@ impl_paste (RBSource *bsource, GList *entries)
 	RBShell *shell;
 	GList *mime_types;
 	GList *l;
-	RhythmDBEntryType our_entry_type;
+	RhythmDBEntryType *our_entry_type;
 	RBTrackTransferBatch *batch;
 	gboolean start_batch = FALSE;
 
@@ -413,7 +413,7 @@ impl_paste (RBSource *bsource, GList *entries)
 
 	for (l = entries; l != NULL; l = l->next) {
 		RhythmDBEntry *entry;
-		RhythmDBEntryType entry_type;
+		RhythmDBEntryType *entry_type;
 		const char *location;
 
 		entry = (RhythmDBEntry *)l->data;
@@ -431,12 +431,8 @@ impl_paste (RBSource *bsource, GList *entries)
 		} else {
 			rb_debug ("can't copy entry %s from the device to itself", location);
 		}
-
-		if (entry_type) {
-			g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
-		}
 	}
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, our_entry_type);
+	g_object_unref (our_entry_type);
 
 	if (start_batch) {
 		rb_track_transfer_queue_start_batch (xferq, batch);
@@ -733,7 +729,7 @@ gboolean
 rb_removable_media_source_should_paste_no_duplicate (RBRemovableMediaSource *source,
 						     RhythmDBEntry *entry)
 {
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	RhythmDB *db;
 	RBShell *shell;
 	const char *title;
@@ -773,8 +769,8 @@ rb_removable_media_source_should_paste_no_duplicate (RBRemovableMediaSource *sou
 
 	no_match = (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (query_model),
 						 &iter));
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
-	g_object_unref(query_model);
+	g_object_unref (entry_type);
+	g_object_unref (query_model);
 	g_object_unref (db);
 	if (no_match == FALSE) {
 		rb_debug ("not adding %lu - %s - %s - %s to removable device since it's already present", track_number, title, album, artist);
@@ -785,10 +781,12 @@ rb_removable_media_source_should_paste_no_duplicate (RBRemovableMediaSource *sou
 static gboolean
 impl_should_paste (RBRemovableMediaSource *source, RhythmDBEntry *entry)
 {
-	RhythmDBEntryType entry_type = rhythmdb_entry_get_entry_type (entry);
-	gboolean should_paste = (entry_type->category == RHYTHMDB_ENTRY_NORMAL);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
-	return should_paste;
+	RhythmDBEntryCategory cat;
+	RhythmDBEntryType *entry_type = rhythmdb_entry_get_entry_type (entry);
+
+	g_object_get (entry_type, "category", &cat, NULL);
+
+	return (cat == RHYTHMDB_ENTRY_NORMAL);
 }
 
 /**
@@ -842,7 +840,7 @@ rb_removable_media_source_track_added (RBRemovableMediaSource *source,
 		add_to_db = klass->impl_track_added (source, entry, uri, filesize, mimetype);
 
 	if (add_to_db) {
-		RhythmDBEntryType entry_type;
+		RhythmDBEntryType *entry_type;
 		RhythmDB *db;
 		RBShell *shell;
 
@@ -851,8 +849,8 @@ rb_removable_media_source_track_added (RBRemovableMediaSource *source,
 		g_object_unref (shell);
 
 		g_object_get (source, "entry-type", &entry_type, NULL);
-		rhythmdb_add_uri_with_types (db, uri, entry_type, RHYTHMDB_ENTRY_TYPE_INVALID, RHYTHMDB_ENTRY_TYPE_INVALID);
-		g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+		rhythmdb_add_uri_with_types (db, uri, entry_type, NULL, NULL);
+		g_object_unref (entry_type);
 
 		g_object_unref (db);
 	}
diff --git a/sources/rb-source.c b/sources/rb-source.c
index 66170be..04004e4 100644
--- a/sources/rb-source.c
+++ b/sources/rb-source.c
@@ -119,7 +119,7 @@ struct _RBSourcePrivate
 	guint hidden_when_empty : 1;
 	guint update_visibility_id;
 	guint update_status_id;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	RBSourceGroup *source_group;
 	RBPlugin *plugin;
 	RBSourceSearchType search_type;
@@ -289,7 +289,7 @@ rb_source_class_init (RBSourceClass *klass)
 	g_object_class_install_property (object_class,
 					 PROP_QUERY_MODEL,
 					 g_param_spec_object ("query-model",
-						 	      "RhythmDBQueryModel",
+							      "RhythmDBQueryModel",
 							      "RhythmDBQueryModel object",
 							      RHYTHMDB_TYPE_QUERY_MODEL,
 							      G_PARAM_READWRITE));
@@ -312,11 +312,11 @@ rb_source_class_init (RBSourceClass *klass)
 	 */
 	g_object_class_install_property (object_class,
 					 PROP_ENTRY_TYPE,
-					 g_param_spec_boxed ("entry-type",
-							     "Entry type",
-							     "Type of the entries which should be displayed by this source",
-							     RHYTHMDB_TYPE_ENTRY_TYPE,
-							     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+					 g_param_spec_object ("entry-type",
+							      "Entry type",
+							      "Type of the entries which should be displayed by this source",
+							      RHYTHMDB_TYPE_ENTRY_TYPE,
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 	/**
 	 * RBSource:plugin:
 	 *
@@ -325,7 +325,7 @@ rb_source_class_init (RBSourceClass *klass)
 	g_object_class_install_property (object_class,
 					 PROP_PLUGIN,
 					 g_param_spec_object ("plugin",
-						 	      "RBPlugin",
+							      "RBPlugin",
 							      "RBPlugin instance for the plugin that created the source",
 							      RB_TYPE_PLUGIN,
 							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
@@ -339,7 +339,7 @@ rb_source_class_init (RBSourceClass *klass)
 	g_object_class_install_property (object_class,
 					 PROP_BASE_QUERY_MODEL,
 					 g_param_spec_object ("base-query-model",
-						 	      "RhythmDBQueryModel",
+							      "RhythmDBQueryModel",
 							      "RhythmDBQueryModel object (unfiltered)",
 							      RHYTHMDB_TYPE_QUERY_MODEL,
 							      G_PARAM_READABLE));
@@ -351,7 +351,7 @@ rb_source_class_init (RBSourceClass *klass)
 	g_object_class_install_property (object_class,
 					 PROP_PLAY_ORDER,
 					 g_param_spec_object ("play-order",
-						 	      "play order",
+							      "play order",
 							      "optional play order specific to the source",
 							      RB_TYPE_PLAY_ORDER,
 							      G_PARAM_READABLE));
@@ -365,7 +365,7 @@ rb_source_class_init (RBSourceClass *klass)
 	g_object_class_install_property (object_class,
 					 PROP_SEARCH_TYPE,
 					 g_param_spec_enum ("search-type",
-						 	    "search-type",
+							    "search-type",
 							    "search type",
 							    RB_TYPE_SOURCE_SEARCH_TYPE,
 							    RB_SOURCE_SEARCH_NONE,
@@ -636,7 +636,7 @@ rb_source_set_property (GObject *object,
 		priv->source_group = g_value_get_boxed (value);
 		break;
 	case PROP_ENTRY_TYPE:
-		priv->entry_type = g_value_get_boxed (value);
+		priv->entry_type = g_value_get_object (value);
 		break;
 	case PROP_PLUGIN:
 		priv->plugin = g_value_get_object (value);
@@ -688,7 +688,7 @@ rb_source_get_property (GObject *object,
 		g_value_set_boxed (value, priv->source_group);
 		break;
 	case PROP_ENTRY_TYPE:
-		g_value_set_boxed (value, priv->entry_type);
+		g_value_set_object (value, priv->entry_type);
 		break;
 	case PROP_PLUGIN:
 		g_value_set_object (value, priv->plugin);
@@ -1923,15 +1923,16 @@ _rb_action_group_add_source_actions (GtkActionGroup *group,
 gboolean
 _rb_source_check_entry_type (RBSource *source, RhythmDBEntry *entry)
 {
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	gboolean ret = TRUE;
 
 	g_object_get (source, "entry-type", &entry_type, NULL);
-	if (entry_type != RHYTHMDB_ENTRY_TYPE_INVALID &&
-	    rhythmdb_entry_get_entry_type (entry) != entry_type) {
-		ret = FALSE;
+	if (entry_type != NULL) {
+		if (rhythmdb_entry_get_entry_type (entry) != entry_type) {
+			ret = FALSE;
+		}
+		g_object_unref (entry_type);
 	}
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
 	return ret;
 }
 
diff --git a/sources/rb-static-playlist-source.c b/sources/rb-static-playlist-source.c
index 347b4dd..21ff166 100644
--- a/sources/rb-static-playlist-source.c
+++ b/sources/rb-static-playlist-source.c
@@ -278,7 +278,7 @@ rb_static_playlist_source_constructed (GObject *object)
 	RBPlaylistSource *psource;
 	RBEntryView *songs;
 	RBShell *shell;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 
 	RB_CHAIN_GOBJECT_METHOD (rb_static_playlist_source_parent_class, constructed, object);
 
@@ -320,7 +320,10 @@ rb_static_playlist_source_constructed (GObject *object)
 	g_object_get (source, "entry-type", &entry_type, NULL);
 	priv->browser = rb_library_browser_new (rb_playlist_source_get_db (RB_PLAYLIST_SOURCE (source)),
 						entry_type);
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	if (entry_type != NULL) {
+		g_object_unref (entry_type);
+	}
+
 	gtk_paned_pack1 (GTK_PANED (priv->paned), GTK_WIDGET (priv->browser), TRUE, FALSE);
 	g_signal_connect_object (priv->browser, "notify::output-model",
 				 G_CALLBACK (rb_static_playlist_source_browser_changed_cb),
@@ -364,7 +367,7 @@ rb_static_playlist_source_constructed (GObject *object)
  * Return value: new playlist.
  */
 RBSource *
-rb_static_playlist_source_new (RBShell *shell, const char *name, const char *sorting_name, gboolean local, RhythmDBEntryType entry_type)
+rb_static_playlist_source_new (RBShell *shell, const char *name, const char *sorting_name, gboolean local, RhythmDBEntryType *entry_type)
 {
 	if (name == NULL)
 		name = "";
diff --git a/sources/rb-static-playlist-source.h b/sources/rb-static-playlist-source.h
index 2a4c34e..dc8ee49 100644
--- a/sources/rb-static-playlist-source.h
+++ b/sources/rb-static-playlist-source.h
@@ -64,7 +64,7 @@ RBSource *	rb_static_playlist_source_new		(RBShell *shell,
 							 const char *name,
 							 const char *sorting_name,
 							 gboolean local,
-							 RhythmDBEntryType entry_type);
+							 RhythmDBEntryType *entry_type);
 
 RBSource *	rb_static_playlist_source_new_from_xml	(RBShell *shell,
 							 xmlNodePtr node);
diff --git a/sources/rb-streaming-source.c b/sources/rb-streaming-source.c
index 5e13e33..4bbee36 100644
--- a/sources/rb-streaming-source.c
+++ b/sources/rb-streaming-source.c
@@ -241,13 +241,13 @@ buffering_cb (GObject *backend, gpointer whatever, guint progress, RBStreamingSo
 static gboolean
 check_entry_type (RBStreamingSource *source, RhythmDBEntry *entry)
 {
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	gboolean matches = FALSE;
 
 	g_object_get (source, "entry-type", &entry_type, NULL);
 	if (entry != NULL && rhythmdb_entry_get_entry_type (entry) == entry_type)
 		matches = TRUE;
-	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	g_object_unref (entry_type);
 
 	return matches;
 }
diff --git a/sources/sync/rb-sync-settings-ui.c b/sources/sync/rb-sync-settings-ui.c
index e7406d6..3167c47 100644
--- a/sources/sync/rb-sync-settings-ui.c
+++ b/sources/sync/rb-sync-settings-ui.c
@@ -34,6 +34,7 @@
 #include "rb-debug.h"
 #include "rb-util.h"
 #include "rb-playlist-manager.h"
+#include "rb-podcast-entry-types.h"
 
 struct _RBSyncSettingsUIPrivate
 {
diff --git a/sources/sync/rb-sync-state.c b/sources/sync/rb-sync-state.c
index 6009d9f..38c11e1 100644
--- a/sources/sync/rb-sync-state.c
+++ b/sources/sync/rb-sync-state.c
@@ -33,6 +33,7 @@
 
 #include "rhythmdb-query-model.h"
 #include "rb-podcast-manager.h"
+#include "rb-podcast-entry-types.h"
 #include "rb-playlist-manager.h"
 #include "rb-shell.h"
 
@@ -188,7 +189,7 @@ hash_table_insert_from_tree_model_cb (GtkTreeModel *query_model,
 
 static void
 itinerary_insert_all_of_type (RhythmDB *db,
-			      RhythmDBEntryType entry_type,
+			      RhythmDBEntryType *entry_type,
 			      GHashTable *target)
 {
 	GtkTreeModel *query_model;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index e10abc8..67a226b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -7,6 +7,7 @@ LDADD = \
 	$(top_builddir)/rhythmdb/librhythmdb.la 		\
 	$(top_builddir)/metadata/librbmetadata.la		\
 	$(top_builddir)/widgets/librbwidgets.la			\
+	$(top_builddir)/podcast/librbpodcast.la			\
 	$(top_builddir)/lib/librb.la				\
 	$(RHYTHMBOX_LIBS)
 
@@ -54,6 +55,7 @@ INCLUDES = 							\
 	-I$(top_srcdir)/metadata				\
 	-I$(top_srcdir)/widgets					\
 	-I$(top_srcdir)/rhythmdb				\
+	-I$(top_srcdir)/podcast					\
 	-I$(top_srcdir)/plugins/audioscrobbler			\
 	-D_XOPEN_SOURCE -D_BSD_SOURCE
 
diff --git a/tests/bench-rhythmdb-load.c b/tests/bench-rhythmdb-load.c
index bf278c2..be1f5f9 100644
--- a/tests/bench-rhythmdb-load.c
+++ b/tests/bench-rhythmdb-load.c
@@ -38,6 +38,7 @@
 
 #include "rhythmdb.h"
 #include "rhythmdb-tree.h"
+#include "rb-podcast-entry-types.h"
 
 /* test utils */
 gboolean waiting, signaled;
diff --git a/tests/test-rhythmdb.c b/tests/test-rhythmdb.c
index ee17212..b353819 100644
--- a/tests/test-rhythmdb.c
+++ b/tests/test-rhythmdb.c
@@ -41,6 +41,7 @@
 #include "rhythmdb.h"
 #include "rhythmdb-tree.h"
 #include "rhythmdb-query-model.h"
+#include "rb-podcast-entry-types.h"
 
 static void
 set_true (RhythmDBEntry *entry, gboolean *b)
diff --git a/tests/test-utils.c b/tests/test-utils.c
index 5970960..a8b648f 100644
--- a/tests/test-utils.c
+++ b/tests/test-utils.c
@@ -133,7 +133,7 @@ gboolean waiting_db, finalised_db;
 void
 test_rhythmdb_setup (void)
 {
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 
 	init_once (TRUE);
 
@@ -143,8 +143,8 @@ test_rhythmdb_setup (void)
 
 	/* allow SONGs to be synced to for the tests */
 	entry_type = RHYTHMDB_ENTRY_TYPE_SONG;
-	entry_type->can_sync_metadata = (RhythmDBEntryCanSyncFunc)rb_true_function;
-	entry_type->sync_metadata = (RhythmDBEntrySyncFunc)rb_null_function;
+	entry_type->can_sync_metadata = (RhythmDBEntryTypeBooleanFunc)rb_true_function;
+	entry_type->sync_metadata = (RhythmDBEntryTypeSyncFunc)rb_null_function;
 }
 
 void
diff --git a/widgets/rb-library-browser.c b/widgets/rb-library-browser.c
index 68c02fe..7979bb3 100644
--- a/widgets/rb-library-browser.c
+++ b/widgets/rb-library-browser.c
@@ -109,7 +109,7 @@ struct _RBLibraryBrowserRebuildData
 typedef struct
 {
 	RhythmDB *db;
-	RhythmDBEntryType entry_type;
+	RhythmDBEntryType *entry_type;
 	RhythmDBQueryModel *input_model;
 	RhythmDBQueryModel *output_model;
 
@@ -207,11 +207,11 @@ rb_library_browser_class_init (RBLibraryBrowserClass *klass)
 	 */
 	g_object_class_install_property (object_class,
 					 PROP_ENTRY_TYPE,
-					 g_param_spec_boxed ("entry-type",
-						 	     "Entry type",
-							     "Type of entry to display in this browser",
-							     RHYTHMDB_TYPE_ENTRY_TYPE,
-							     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+					 g_param_spec_object ("entry-type",
+							      "Entry type",
+							      "Type of entry to display in this browser",
+							      RHYTHMDB_TYPE_ENTRY_TYPE,
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_type_class_add_private (klass, sizeof (RBLibraryBrowserPrivate));
 }
@@ -335,7 +335,7 @@ rb_library_browser_set_property (GObject *object,
 		}
 		break;
 	case PROP_ENTRY_TYPE:
-		priv->entry_type = g_value_get_boxed (value);
+		priv->entry_type = g_value_get_object (value);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -362,7 +362,7 @@ rb_library_browser_get_property (GObject *object,
 		g_value_set_object (value, priv->output_model);
 		break;
 	case PROP_ENTRY_TYPE:
-		g_value_set_boxed (value, priv->entry_type);
+		g_value_set_object (value, priv->entry_type);
 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -381,7 +381,7 @@ rb_library_browser_get_property (GObject *object,
  */
 RBLibraryBrowser *
 rb_library_browser_new (RhythmDB *db,
-			RhythmDBEntryType entry_type)
+			RhythmDBEntryType *entry_type)
 {
 	RBLibraryBrowser *widget;
 
diff --git a/widgets/rb-library-browser.h b/widgets/rb-library-browser.h
index 362adf3..75160bc 100644
--- a/widgets/rb-library-browser.h
+++ b/widgets/rb-library-browser.h
@@ -58,7 +58,7 @@ struct _RBLibraryBrowserClass
 
 GType			rb_library_browser_get_type (void);
 RBLibraryBrowser *	rb_library_browser_new      (RhythmDB *db,
-						     RhythmDBEntryType entry_type);
+						     RhythmDBEntryType *entry_type);
 
 void 			rb_library_browser_set_model (RBLibraryBrowser *widget,
 						      RhythmDBQueryModel *model,
diff --git a/widgets/rb-song-info.c b/widgets/rb-song-info.c
index 13cdff1..2c670cd 100644
--- a/widgets/rb-song-info.c
+++ b/widgets/rb-song-info.c
@@ -468,8 +468,7 @@ rb_song_info_constructed (GObject *object)
 	g_return_if_fail (selected_entries != NULL);
 
 	for (tem = selected_entries; tem; tem = tem->next) {
-		if (!rhythmdb_entry_is_editable (song_info->priv->db,
-						 selected_entries->data)) {
+		if (!rhythmdb_entry_can_sync_metadata (selected_entries->data)) {
 			editable = FALSE;
 			break;
 		}



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