[rhythmbox/media-player-sync: 3/3] ipod: implement sync methods



commit 8cc15c26af34f1fbe77e4a2113b037f45112bb6f
Author: Jonathan Matthew <jonathan d14n org>
Date:   Sun Dec 27 20:54:48 2009 +1000

    ipod: implement sync methods
    
    Since the ipod plugin supports playlists, it implements the add_playlist
    and remove_playlists methods as well as get_entries and delete_entries.

 plugins/ipod/ipod-ui.xml                      |    2 +
 plugins/ipod/rb-ipod-db.c                     |   11 ++-
 plugins/ipod/rb-ipod-db.h                     |    1 +
 plugins/ipod/rb-ipod-source.c                 |  210 ++++++++++++++++++++++---
 plugins/ipod/rb-ipod-source.h                 |   13 +-
 plugins/ipod/rb-ipod-static-playlist-source.c |    7 +-
 6 files changed, 208 insertions(+), 36 deletions(-)
---
diff --git a/plugins/ipod/ipod-ui.xml b/plugins/ipod/ipod-ui.xml
index cdadb93..b9273de 100644
--- a/plugins/ipod/ipod-ui.xml
+++ b/plugins/ipod/ipod-ui.xml
@@ -1,6 +1,8 @@
 <ui>
   <popup name="iPodSourcePopup">
     <placeholder name="iPodSrcPopupRename" action="iPodSourceRename"/>
+    <menuitem name="iPodSrcPopupSync" action="MediaPlayerSourceSync"/>
+    <separator />
     <menuitem name="iPodSrcPopupPlaylistNew" action="iPodSourcePlaylistNew"/>
     <separator />
     <menuitem name="iPodSrcPopupEject" action="RemovableSourceEject"/>
diff --git a/plugins/ipod/rb-ipod-db.c b/plugins/ipod/rb-ipod-db.c
index 2eea1cb..6775dbf 100644
--- a/plugins/ipod/rb-ipod-db.c
+++ b/plugins/ipod/rb-ipod-db.c
@@ -873,7 +873,16 @@ rb_ipod_db_get_playlists (RbIpodDb *ipod_db)
 {
 	RbIpodDbPrivate *priv = IPOD_DB_GET_PRIVATE (ipod_db);
 
-	return priv->itdb->playlists;
+	return g_list_copy (priv->itdb->playlists);
+}
+
+Itdb_Playlist *
+rb_ipod_db_get_playlist_by_name (RbIpodDb *ipod_db,
+				 gchar *name)
+{
+	RbIpodDbPrivate *priv = IPOD_DB_GET_PRIVATE (ipod_db);
+
+	return itdb_playlist_by_name (priv->itdb, name);
 }
 
 GList *
diff --git a/plugins/ipod/rb-ipod-db.h b/plugins/ipod/rb-ipod-db.h
index 729056f..27d30a7 100644
--- a/plugins/ipod/rb-ipod-db.h
+++ b/plugins/ipod/rb-ipod-db.h
@@ -72,6 +72,7 @@ void rb_ipod_db_set_ipod_name (RbIpodDb *db, const char *name);
 const char *rb_ipod_db_get_ipod_name (RbIpodDb *db);
 
 GList *rb_ipod_db_get_playlists (RbIpodDb *ipod_db);
+Itdb_Playlist *rb_ipod_db_get_playlist_by_name (RbIpodDb *ipod_db, gchar *name);
 GList *rb_ipod_db_get_tracks (RbIpodDb *ipod_db);
 const char *rb_ipod_db_get_mount_path (RbIpodDb *ipod_db);
 Itdb_Device *rb_ipod_db_get_device (RbIpodDb *ipod_db);
diff --git a/plugins/ipod/rb-ipod-source.c b/plugins/ipod/rb-ipod-source.c
index ebd4cb0..617df71 100644
--- a/plugins/ipod/rb-ipod-source.c
+++ b/plugins/ipod/rb-ipod-source.c
@@ -49,6 +49,7 @@
 #include "rhythmdb.h"
 #include "rb-cut-and-paste-code.h"
 #include "rb-media-player-source.h"
+#include "rb-media-player-sync-settings.h"
 #include "rb-playlist-source.h"
 #include "rb-playlist-manager.h"
 #include "rb-podcast-manager.h"
@@ -93,6 +94,10 @@ static gboolean rb_ipod_song_artwork_add_cb (RhythmDB *db,
 
 static guint64 impl_get_capacity (RBMediaPlayerSource *source);
 static guint64 impl_get_free_space (RBMediaPlayerSource *source);
+static void impl_get_entries (RBMediaPlayerSource *source, const char *category, GHashTable *map);
+static void impl_delete_entries (RBMediaPlayerSource *source, GList *entries, RBMediaPlayerSourceDeleteCallback callback, gpointer callback_data, GDestroyNotify destroy_data);
+static void impl_add_playlist (RBMediaPlayerSource *source, gchar *name, GList *entries);
+static void impl_remove_playlists (RBMediaPlayerSource *source);
 static void impl_show_properties (RBMediaPlayerSource *source, GtkWidget *info_box, GtkWidget *notebook);
 
 static void rb_ipod_source_set_property (GObject *object,
@@ -104,6 +109,7 @@ static void rb_ipod_source_get_property (GObject *object,
 					 GValue *value,
 					 GParamSpec *pspec);
 
+
 static RhythmDB *get_db_for_source (RBiPodSource *source);
 
 struct _PlayedEntry {
@@ -174,8 +180,12 @@ rb_ipod_source_class_init (RBiPodSourceClass *klass)
 	source_class->impl_get_ui_actions = impl_get_ui_actions;
 	source_class->impl_can_paste = (RBSourceFeatureFunc) rb_true_function;
 
+	mps_class->impl_get_entries = impl_get_entries;
 	mps_class->impl_get_capacity = impl_get_capacity;
 	mps_class->impl_get_free_space = impl_get_free_space;
+	mps_class->impl_delete_entries = impl_delete_entries;
+	mps_class->impl_add_playlist = impl_add_playlist;
+	mps_class->impl_remove_playlists = impl_remove_playlists;
 	mps_class->impl_show_properties = impl_show_properties;
 
 	rms_class->impl_should_paste = rb_removable_media_source_should_paste_no_duplicate;
@@ -286,12 +296,15 @@ rb_ipod_source_constructed (GObject *object)
 
 	rb_ipod_load_songs (source);
 
-        db = get_db_for_source (source);
-        g_signal_connect_object (db,
+	db = get_db_for_source (source);
+	g_signal_connect_object (db,
                                  "entry-extra-metadata-notify::rb:coverArt",
                                  G_CALLBACK (rb_ipod_song_artwork_add_cb),
-                                 RB_IPOD_SOURCE(source), 0);
+                                 source, 0);
+
         g_object_unref (db);
+
+        rb_media_player_source_load (RB_MEDIA_PLAYER_SOURCE (source));
 }
 
 static void
@@ -450,7 +463,7 @@ playlist_track_added (GtkTreeModel *model, GtkTreePath *path,
 	rb_ipod_db_add_to_playlist (priv->ipod_db, ipod_pl, track);
 }
 
-static void
+static RBIpodStaticPlaylistSource *
 add_rb_playlist (RBiPodSource *source, Itdb_Playlist *playlist)
 {
 	RBShell *shell;
@@ -506,6 +519,8 @@ add_rb_playlist (RBiPodSource *source, Itdb_Playlist *playlist)
 		priv->podcast_pl = playlist_source;
 	rb_shell_append_source (shell, RB_SOURCE (playlist_source), RB_SOURCE (source));
 	g_object_unref (shell);
+
+	return playlist_source;
 }
 
 static void
@@ -1039,6 +1054,7 @@ impl_get_ui_actions (RBSource *source)
 	GList *actions = NULL;
 
 	actions = g_list_prepend (actions, g_strdup ("RemovableSourceEject"));
+	actions = g_list_prepend (actions, g_strdup ("MediaPlayerSourceSync"));
 
 	return actions;
 }
@@ -1062,21 +1078,57 @@ impl_show_popup (RBSource *source)
 	return TRUE;
 }
 
-void
-rb_ipod_source_trash_entries (RBiPodSource *source, GList *entries)
+typedef struct {
+	RBMediaPlayerSource *source;
+	RBMediaPlayerSourceDeleteCallback callback;
+	gpointer callback_data;
+	GDestroyNotify destroy_data;
+	GList *files;
+} DeleteFileData;
+
+static gboolean
+delete_done_cb (DeleteFileData *data)
+{
+	if (data->callback) {
+		data->callback (data->source, data->callback_data);
+	}
+	if (data->destroy_data) {
+		data->destroy_data (data->callback_data);
+	}
+	g_object_unref (data->source);
+	rb_list_deep_free (data->files);
+	return FALSE;
+}
+
+static gpointer
+delete_thread (DeleteFileData *data)
+{
+	GList *i;
+	rb_debug ("deleting %d files", g_list_length (data->files));
+	for (i = data->files; i != NULL; i = i->next) {
+		g_unlink ((const char *)i->data);
+	}
+	rb_debug ("done deleting %d files", g_list_length (data->files));
+	g_idle_add ((GSourceFunc) delete_done_cb, data);
+	return NULL;
+}
+
+static void
+impl_delete_entries (RBMediaPlayerSource *source, GList *entries, RBMediaPlayerSourceDeleteCallback callback, gpointer cb_data, GDestroyNotify destroy_data)
 {
 	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
-	RhythmDB *db;
-	GList *tem;
+	RhythmDB *db = get_db_for_source ((RBiPodSource *)source);
+	GList *i;
+	GList *filenames = NULL;
+	DeleteFileData *data = g_new0 (DeleteFileData, 1);
 
-	db = get_db_for_source (source);
-	for (tem = entries; tem != NULL; tem = tem->next) {
-		RhythmDBEntry *entry;
-		const gchar *uri;
-		gchar *file;
+	for (i = entries; i != NULL; i = i->next) {
+		const char *uri;
+		char *filename;
 		Itdb_Track *track;
+		RhythmDBEntry *entry;
 
-		entry = (RhythmDBEntry *)tem->data;
+		entry = i->data;
 		uri = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
 		track = g_hash_table_lookup (priv->entry_map, entry);
 		if (track == NULL) {
@@ -1086,15 +1138,24 @@ rb_ipod_source_trash_entries (RBiPodSource *source, GList *entries)
 
 		rb_ipod_db_remove_track (priv->ipod_db, track);
 		g_hash_table_remove (priv->entry_map, entry);
-		file = g_filename_from_uri (uri, NULL, NULL);
-		if (file != NULL)
-			g_unlink (file);
-		g_free (file);
+		filename = g_filename_from_uri (uri, NULL, NULL);
+
+		if (filename != NULL) {
+			filenames = g_list_prepend (filenames, filename);
+		}
 		rhythmdb_entry_delete (db, entry);
 	}
 
 	rhythmdb_commit (db);
 	g_object_unref (db);
+
+	data->source = g_object_ref (source);
+	data->callback = callback;
+	data->callback_data = cb_data;
+	data->destroy_data = destroy_data;
+	data->files = filenames;
+
+	g_thread_create ((GThreadFunc) delete_thread, data, FALSE, NULL);
 }
 
 static void
@@ -1105,10 +1166,53 @@ impl_move_to_trash (RBSource *source)
 
 	songs = rb_source_get_entry_view (source);
 	sel = rb_entry_view_get_selected_entries (songs);
-	rb_ipod_source_trash_entries (RB_IPOD_SOURCE (source), sel);
+	impl_delete_entries (RB_MEDIA_PLAYER_SOURCE (source), sel, NULL, NULL, NULL);
+	rb_list_destroy_free (sel, (GDestroyNotify) rhythmdb_entry_unref);
+}
 
-	g_list_foreach (sel, (GFunc) rhythmdb_entry_unref, NULL);
-	g_list_free (sel);
+static void
+impl_add_playlist (RBMediaPlayerSource *source,
+		   char *name,
+		   GList *entries)	/* GList of RhythmDBEntry * on the device to go into the playlist */
+{
+	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
+	RBIpodStaticPlaylistSource *playlist_source;
+	Itdb_Playlist *ipod_playlist;
+	GList *iter;
+
+	ipod_playlist = itdb_playlist_new (name, FALSE);
+	rb_ipod_db_add_playlist (priv->ipod_db, ipod_playlist);
+	playlist_source = add_rb_playlist (RB_IPOD_SOURCE (source), ipod_playlist);
+
+	for (iter = entries; iter != NULL; iter = iter->next) {
+		rb_static_playlist_source_add_entry (RB_STATIC_PLAYLIST_SOURCE (playlist_source), iter->data, -1);
+	}
+}
+
+static void
+impl_remove_playlists (RBMediaPlayerSource *source)
+{
+	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
+	GList *playlists;
+	GList *p;
+
+	playlists = rb_ipod_db_get_playlists (priv->ipod_db);
+
+	for (p = playlists; p != NULL; p = p->next) {
+		Itdb_Playlist *playlist = (Itdb_Playlist *)p->data;
+		/* XXX might need to exclude more playlists here.. */
+		if (!itdb_playlist_is_mpl (playlist) && !playlist->is_spl) {
+
+			/* destroy the playlist source */
+			RBSource *rb_playlist = RB_SOURCE (playlist->userdata);
+			rb_source_delete_thyself (rb_playlist);
+
+			/* remove playlist from ipod */
+			rb_ipod_db_remove_playlist (priv->ipod_db, playlist);
+		}
+	}
+
+	g_list_free (playlists);
 }
 
 static char *
@@ -1275,6 +1379,25 @@ request_artwork (RBiPodSource *isource,
 	}
 }
 
+Itdb_Playlist *
+rb_ipod_source_get_playlist (RBiPodSource *source,
+			     gchar *name)
+{
+	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
+	Itdb_Playlist *ipod_playlist;
+
+	ipod_playlist = rb_ipod_db_get_playlist_by_name (priv->ipod_db, name);
+
+	/* Playlist doesn't exist on the iPod, create it */
+	if (ipod_playlist == NULL) {
+		ipod_playlist = itdb_playlist_new (name, FALSE);
+		rb_ipod_db_add_playlist (priv->ipod_db, ipod_playlist);
+		add_rb_playlist (source, ipod_playlist);
+	}
+
+	return ipod_playlist;
+}
+
 static void
 add_to_podcasts (RBiPodSource *source, Itdb_Track *song)
 {
@@ -1341,6 +1464,10 @@ impl_track_added (RBRemovableMediaSource *source,
 	}
 
 	g_object_unref (db);
+
+	/* chain up to parent class for sync */
+	RB_REMOVABLE_MEDIA_SOURCE_CLASS (rb_ipod_source_parent_class)->impl_track_added (source, entry, dest, filesize, mimetype);
+
 	return FALSE;
 }
 
@@ -1603,6 +1730,7 @@ static void
 impl_delete_thyself (RBSource *source)
 {
 	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
+	RhythmDB *db;
 	GList *p;
 
         if (priv->ipod_db == NULL) {
@@ -1610,6 +1738,12 @@ impl_delete_thyself (RBSource *source)
             return;
         }
 
+	db = get_db_for_source (RB_IPOD_SOURCE (source));
+	g_signal_handlers_disconnect_by_func (db,
+					      G_CALLBACK (rb_ipod_song_artwork_add_cb),
+					      RB_IPOD_SOURCE (source));
+	g_object_unref (db);
+
 	for (p = rb_ipod_db_get_playlists (priv->ipod_db);
 	     p != NULL;
 	     p = p->next) {
@@ -1650,8 +1784,7 @@ impl_get_mime_types (RBRemovableMediaSource *source)
 	return ret;
 }
 
-
-void
+Itdb_Playlist *
 rb_ipod_source_new_playlist (RBiPodSource *source)
 {
 	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
@@ -1659,12 +1792,13 @@ rb_ipod_source_new_playlist (RBiPodSource *source)
 
 	if (priv->ipod_db == NULL) {
 		rb_debug ("can't create new ipod playlist with no ipod db");
-		return;
+		return NULL;
 	}
 
 	ipod_playlist = itdb_playlist_new (_("New playlist"), FALSE);
 	rb_ipod_db_add_playlist (priv->ipod_db, ipod_playlist);
 	add_rb_playlist (source, ipod_playlist);
+	return ipod_playlist;
 }
 
 void
@@ -1817,3 +1951,31 @@ impl_get_free_space (RBMediaPlayerSource *source)
 	return rb_ipod_helpers_get_free_space (get_mount_point (RB_IPOD_SOURCE (source)));
 }
 
+static void
+impl_get_entries (RBMediaPlayerSource *source, const char *category, GHashTable *map)
+{
+	RBiPodSourcePrivate *priv = IPOD_SOURCE_GET_PRIVATE (source);
+	GHashTableIter iter;
+	gpointer key, value;
+	Itdb_Mediatype media_type;
+
+	/* map the sync category to an itdb media type */
+	if (g_str_equal (category, SYNC_CATEGORY_MUSIC)) {
+		media_type = ITDB_MEDIATYPE_AUDIO;
+	} else if (g_str_equal (category, SYNC_CATEGORY_PODCAST)) {
+		media_type = ITDB_MEDIATYPE_PODCAST;
+	} else {
+		g_warning ("unsupported ipod sync category %s", category);
+		return;
+	}
+
+	/* extract all entries matching the media type for the sync category */
+	g_hash_table_iter_init (&iter, priv->entry_map);
+	while (g_hash_table_iter_next (&iter, &key, &value)) {
+		Itdb_Track *track = value;
+		if (track->mediatype == media_type) {
+			RhythmDBEntry *entry = key;
+			_rb_media_player_source_add_to_map (map, entry);
+		}
+	}
+}
diff --git a/plugins/ipod/rb-ipod-source.h b/plugins/ipod/rb-ipod-source.h
index f93ac4b..7d8bff4 100644
--- a/plugins/ipod/rb-ipod-source.h
+++ b/plugins/ipod/rb-ipod-source.h
@@ -33,6 +33,7 @@
 #include "rhythmdb.h"
 #include "rb-plugin.h"
 #include "mediaplayerid.h"
+#include "rb-ipod-db.h"
 
 G_BEGIN_DECLS
 
@@ -53,21 +54,19 @@ typedef struct
 	RBMediaPlayerSourceClass parent;
 } RBiPodSourceClass;
 
-RBMediaPlayerSource    *rb_ipod_source_new		(RBPlugin *plugin,
+RBMediaPlayerSource	*rb_ipod_source_new		(RBPlugin *plugin,
 							 RBShell *shell,
-                                                         GMount *mount,
+							 GMount *mount,
 							 MPIDDevice *device_info);
 GType			rb_ipod_source_get_type		(void);
 GType                   rb_ipod_source_register_type    (GTypeModule *module);
 
-void			rb_ipod_source_new_playlist	(RBiPodSource *source);
+Itdb_Playlist *		rb_ipod_source_new_playlist	(RBiPodSource *source);
 void			rb_ipod_source_remove_playlist	(RBiPodSource *ipod_source,
 							 RBSource *source);
 
-void			rb_ipod_source_show_properties	(RBiPodSource *source);
-
-void			rb_ipod_source_trash_entries	(RBiPodSource *source,
-							 GList *entries);
+Itdb_Playlist *		rb_ipod_source_get_playlist	(RBiPodSource *source,
+							 gchar *name);
 
 G_END_DECLS
 
diff --git a/plugins/ipod/rb-ipod-static-playlist-source.c b/plugins/ipod/rb-ipod-static-playlist-source.c
index c5cb7c1..7e265d8 100644
--- a/plugins/ipod/rb-ipod-static-playlist-source.c
+++ b/plugins/ipod/rb-ipod-static-playlist-source.c
@@ -31,6 +31,7 @@
 #include "rhythmdb.h"
 
 #include "rb-ipod-static-playlist-source.h"
+#include "rb-media-player-source.h"
 #include "rb-ipod-source.h"
 
 static void rb_ipod_static_playlist_source_constructed (GObject *object);
@@ -274,9 +275,7 @@ impl_move_to_trash (RBSource *source)
 
 	songs = rb_source_get_entry_view (source);
 	sel = rb_entry_view_get_selected_entries (songs);
-	rb_ipod_source_trash_entries (priv->ipod_source, sel);
-
-	g_list_foreach (sel, (GFunc) rhythmdb_entry_unref, NULL);
-	g_list_free (sel);
+	rb_media_player_source_delete_entries (RB_MEDIA_PLAYER_SOURCE (priv->ipod_source), sel, NULL, NULL, NULL);
+	rb_list_destroy_free (sel, (GDestroyNotify)rhythmdb_entry_unref);
 }
 



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