Пример #1
0
static gboolean
request_album_art_idle (RequestAlbumArtData *data)
{
	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (data->source);
	const char *album;

	/* pretty sure we don't need any extra locking here - we only touch the artwork
	 * request map on the main thread anyway.
	 */

	album = rhythmdb_entry_get_string (data->entry, RHYTHMDB_PROP_ALBUM);
	if (g_hash_table_lookup (priv->artwork_request_map, album) == NULL) {
		GValue *metadata;
		RhythmDB *db = get_db_for_source (data->source);

		rb_debug ("requesting cover art image for album %s", album);
		g_hash_table_insert (priv->artwork_request_map, (gpointer) album, GINT_TO_POINTER (1));
		metadata = rhythmdb_entry_request_extra_metadata (db, data->entry, "rb:coverArt");
		if (metadata) {
			artwork_notify_cb (db, data->entry, "rb:coverArt", metadata, data->source);
			g_value_unset (metadata);
			g_free (metadata);
		}
		g_object_unref (db);
	}

	g_object_unref (data->source);
	rhythmdb_entry_unref (data->entry);
	g_free (data);
	return FALSE;
}
Пример #2
0
static void
prepare_source (RBMtpSource *source, const char *stream_uri, GObject *src)
{
	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
	RhythmDBEntry *entry;
	RhythmDB *db;

	/* make sure this stream is for a file on our device */
	if (g_str_has_prefix (stream_uri, "xrbmtp://") == FALSE)
		return;

	db = get_db_for_source (source);
	entry = rhythmdb_entry_lookup_by_location (db, stream_uri);
	g_object_unref (db);
	if (entry == NULL)
		return;

	if (_rb_source_check_entry_type (RB_SOURCE (source), entry) == FALSE) {
		rhythmdb_entry_unref (entry);
		return;
	}

	rb_debug ("setting device-thread for stream %s", stream_uri);
	g_object_set (src, "device-thread", priv->device_thread, NULL);
	rhythmdb_entry_unref (entry);
}
Пример #3
0
static void
impl_delete_entries	(RBMediaPlayerSource *source,
			 GList *entries,
			 RBMediaPlayerSourceDeleteCallback callback,
			 gpointer user_data,
			 GDestroyNotify destroy_data)
{
	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
	RhythmDB *db;
	GList *i;
	TracksDeletedCallbackData *cb_data;

	cb_data = g_new0 (TracksDeletedCallbackData, 1);
	cb_data->source = g_object_ref (source);
	cb_data->callback_data = user_data;
	cb_data->callback = callback;
	cb_data->destroy_data = destroy_data;
	cb_data->check_folders = g_hash_table_new (g_direct_hash, g_direct_equal);

	db = get_db_for_source (RB_MTP_SOURCE (source));
	for (i = entries; i != NULL; i = i->next) {
		LIBMTP_track_t *track;
		const char *uri;
		const char *album_name;
		RhythmDBEntry *entry;

		entry = i->data;
		uri = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
		track = g_hash_table_lookup (priv->entry_map, entry);
		if (track == NULL) {
			rb_debug ("Couldn't find track on mtp-device! (%s)", uri);
			continue;
		}

		album_name = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM);
		if (g_strcmp0 (album_name, _("Unknown")) != 0) {
			rb_mtp_thread_remove_from_album (priv->device_thread, track, album_name);
		}
		rb_mtp_thread_delete_track (priv->device_thread, track);

		g_hash_table_insert (cb_data->check_folders,
				     GUINT_TO_POINTER (track->parent_id),
				     GINT_TO_POINTER (1));

		g_hash_table_remove (priv->entry_map, entry);
		rhythmdb_entry_delete (db, entry);
	}

	/* callback when all tracks have been deleted */
	rb_mtp_thread_queue_callback (priv->device_thread,
				      (RBMtpThreadCallback) delete_done_cb,
				      cb_data,
				      (GDestroyNotify) free_delete_data);

	rhythmdb_commit (db);
}
Пример #4
0
static void
reload_metadata_cmd (GtkAction *action, RBAudioCdSource *source)
{
	RhythmDB *db;

	g_return_if_fail (RB_IS_AUDIOCD_SOURCE (source));

	db = get_db_for_source (RB_AUDIOCD_SOURCE (source));
	rb_audiocd_load_metadata (RB_AUDIOCD_SOURCE (source), db);
	g_object_unref (db);
}
Пример #5
0
static void
mtp_tracklist_cb (LIBMTP_track_t *tracks, RBMtpSource *source)
{
	RhythmDB *db = NULL;
	LIBMTP_track_t *track;

	/* add tracks to database */
	db = get_db_for_source (source);
	for (track = tracks; track != NULL; track = track->next) {
		add_mtp_track_to_db (source, db, track);
	}
	g_object_unref (db);
}
static void
impl_delete (RBSource *source)
{
	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
	GList *sel;
	GList *tem;
	RBEntryView *tracks;
	RhythmDB *db;
	int ret;

	db = get_db_for_source (RB_MTP_SOURCE (source));

	tracks = rb_source_get_entry_view (source);
	sel = rb_entry_view_get_selected_entries (tracks);
	for (tem = sel; tem != NULL; tem = tem->next) {
		LIBMTP_track_t *track;
		RhythmDBEntry *entry;
		const char *uri;
		const char *album_name;

		entry = (RhythmDBEntry *)tem->data;
		uri = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
		track = g_hash_table_lookup (priv->entry_map, entry);
		if (track == NULL) {
			rb_debug ("Couldn't find track on mtp-device! (%s)", uri);
			continue;
		}

		ret = LIBMTP_Delete_Object (priv->device, track->item_id);
		if (ret != 0) {
			rb_debug ("Delete track %d failed", track->item_id);
			report_libmtp_errors (priv->device, TRUE);
			continue;
		}

		album_name = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM);
		if (strcmp (album_name, _("Unknown")) != 0) {
			remove_track_from_album (RB_MTP_SOURCE (source), album_name, track);
		}

		g_hash_table_remove (priv->entry_map, entry);
		rhythmdb_entry_delete (db, entry);
	}
	rhythmdb_commit (db);

	g_list_free (sel);
	g_list_free (tem);
}
Пример #7
0
static void
update_tracks (RBAudioCdSource *source, RhythmDBPropType property, GValue *value)
{
	RBAudioCdSourcePrivate *priv = AUDIOCD_SOURCE_GET_PRIVATE (source);
	RhythmDB *db;
	GList *i;

	db = get_db_for_source (source);

	for (i = priv->tracks; i != NULL; i = i->next) {
		rhythmdb_entry_set (db, i->data, property, value);
	}

	rhythmdb_commit (db);
	g_object_unref (db);
}
static gboolean
impl_track_added (RBRemovableMediaSource *isource,
		  RhythmDBEntry *entry,
		  const char *dest,
		  guint64 filesize,
		  const char *mimetype)
{
	RBMtpSource *source = RB_MTP_SOURCE (isource);
	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
	GFile *file;
	char *path;
	LIBMTP_track_t *track = NULL;

	file = g_file_new_for_uri (dest);
	path = g_file_get_path (file);
	track = transfer_track (source, priv->device, entry, path, filesize, mimetype);
	g_free (path);

	g_file_delete (file, NULL, NULL);

	if (track != NULL) {
		RhythmDB *db = get_db_for_source (source);

		if (priv->album_art_supported) {
			const char *album;

			album = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM);
			if (g_hash_table_lookup (priv->artwork_request_map, album) == NULL) {
				GValue *metadata;

				rb_debug ("requesting cover art image for album %s", album);
				g_hash_table_insert (priv->artwork_request_map, (gpointer) album, GINT_TO_POINTER (1));
				metadata = rhythmdb_entry_request_extra_metadata (db, entry, "rb:coverArt");
				if (metadata) {
					artwork_notify_cb (db, entry, "rb:coverArt", metadata, source);
					g_value_unset (metadata);
					g_free (metadata);
				}
			}
		}

		add_mtp_track_to_db (source, db, track);
		g_object_unref (db);
	}

	return FALSE;
}
Пример #9
0
static gpointer
rb_audiocd_load_songs (RBAudioCdSource *source)
{
	RBAudioCdSourcePrivate *priv = AUDIOCD_SOURCE_GET_PRIVATE (source);
	RhythmDB *db;
	GVolume *volume;

	g_object_get (source, "volume", &volume, NULL);
	priv->device_path = g_volume_get_identifier (volume,
						     G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
	g_object_unref (volume);

	db = get_db_for_source (source);

	rb_debug ("loading Audio CD from %s", priv->device_path);
	/* create a cdda gstreamer element, to get cd info from */
	priv->cdda = gst_element_make_from_uri (GST_URI_SRC, "cdda://", NULL);
	if (!priv->cdda) {
		gdk_threads_enter ();
		rb_error_dialog (NULL, _("Couldn't load Audio CD"),
					_("Rhythmbox could not get access to the CD device."));
		gdk_threads_leave ();
		goto error_out;
	}

	rb_debug ("cdda longname: %s", gst_element_factory_get_longname (gst_element_get_factory (priv->cdda)));
	g_object_set (G_OBJECT (priv->cdda), "device", priv->device_path, NULL);
	priv->pipeline = gst_pipeline_new ("pipeline");
	priv->fakesink = gst_element_factory_make ("fakesink", "fakesink");
	gst_bin_add_many (GST_BIN (priv->pipeline), priv->cdda, priv->fakesink, NULL);
	gst_element_link (priv->cdda, priv->fakesink);

	/* disable paranoia (if using cdparanoia) since we're only reading track information here.
	 * this reduces cdparanoia's cache size, so the process is much faster.
	 */
	if (g_object_class_find_property (G_OBJECT_GET_CLASS (source), "paranoia-mode"))
		g_object_set (source, "paranoia-mode", 0, NULL);

	if (rb_audiocd_scan_songs (source, db))
		rb_audiocd_load_metadata (source, db);

error_out:
	g_object_unref (db);
	g_object_unref (source);

	return NULL;
}
static GList *
impl_copy (RBSource *source)
{
	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (RB_MTP_SOURCE (source));
	RhythmDB *db;
	GList *selected_entries;
	GList *iter;
	GList *copy_entries;
	int ret = -1;
	LIBMTP_track_t *track = NULL;

	db = get_db_for_source (RB_MTP_SOURCE (source));

	copy_entries = NULL;
	selected_entries = rb_entry_view_get_selected_entries (rb_source_get_entry_view (source));
	for (iter = selected_entries; iter != NULL; iter = g_list_next (iter)) {
		RhythmDBEntry *entry;
		char *path;
		char *uri;

		entry = (RhythmDBEntry *)iter->data;
		track = g_hash_table_lookup (priv->entry_map, entry);

		if (track == NULL)
			continue;

		path = g_strdup_printf ("%s/%s", g_get_tmp_dir (), track->filename);
		uri = g_filename_to_uri (path, NULL, NULL);
		g_free (path);
		ret = rb_mtp_source_transfer_track_to_disk (priv->device, track, uri);

		if (ret == 0) {
			entry_set_string_prop (RHYTHMDB (db), entry, RHYTHMDB_PROP_LOCATION, uri);
			copy_entries = g_list_prepend (copy_entries, entry);
		}
		g_free (uri);
	}

	g_list_free (selected_entries);
	g_object_unref (G_OBJECT (db));

	return copy_entries;
}
Пример #11
0
static gboolean
impl_track_added (RBTransferTarget *target,
		  RhythmDBEntry *entry,
		  const char *dest,
		  guint64 filesize,
		  const char *media_type)
{
	LIBMTP_track_t *track = NULL;
	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (target);
	RhythmDB *db;

	track = g_hash_table_lookup (priv->track_transfer_map, dest);
	if (track == NULL) {
		rb_debug ("track-added called, but can't find a track for dest URI %s", dest);
		return FALSE;
	}
	g_hash_table_remove (priv->track_transfer_map, dest);

	if (strcmp (track->album, _("Unknown")) != 0) {
		rb_mtp_thread_add_to_album (priv->device_thread, track, track->album);

		if (priv->album_art_supported) {
			RBExtDBKey *key;

			/* need to do this in an idle handler? */
			key = rb_ext_db_key_create_lookup ("album", track->album);
			rb_ext_db_key_add_field (key, "artist", track->artist);
			rb_ext_db_request (priv->art_store,
					   key,
					   (RBExtDBRequestCallback) art_request_cb,
					   g_object_ref (target),
					   (GDestroyNotify) g_object_unref);
			rb_ext_db_key_free (key);
		}
	}

	db = get_db_for_source (RB_MTP_SOURCE (target));
	add_mtp_track_to_db (RB_MTP_SOURCE (target), db, track);
	g_object_unref (db);

	queue_free_space_update (RB_MTP_SOURCE (target));
	return FALSE;
}
Пример #12
0
static void
rb_mtp_source_dispose (GObject *object)
{
	RBMtpSource *source = RB_MTP_SOURCE (object);
	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
	RhythmDBEntryType *entry_type;
	RhythmDB *db;

	if (priv->device_thread != NULL) {
		g_object_unref (priv->device_thread);
		priv->device_thread = NULL;
	}

#if defined(HAVE_GUDEV)
	if (priv->remount_volume != NULL) {
		rb_debug ("remounting gvfs volume for mtp device");
		/* the callback will unref remount_volume */
		g_volume_mount (priv->remount_volume,
				G_MOUNT_MOUNT_NONE,
				NULL,
				NULL,
				remount_done_cb,
				NULL);
		priv->remount_volume = NULL;
	}
#endif
	if (priv->art_store != NULL) {
		g_object_unref (priv->art_store);
		priv->art_store = NULL;
	}

	db = get_db_for_source (source);

	g_object_get (G_OBJECT (source), "entry-type", &entry_type, NULL);
	rhythmdb_entry_delete_by_type (db, entry_type);
	g_object_unref (entry_type);

	rhythmdb_commit (db);
	g_object_unref (db);

	G_OBJECT_CLASS (rb_mtp_source_parent_class)->dispose (object);
}
Пример #13
0
static void
impl_delete_thyself (RBSource *source)
{
	RhythmDB *db;
	RhythmDBEntryType entry_type;

	rb_debug ("audio cd ejected");

	/* cancel the loading of metadata */
	rb_audiocd_load_metadata_cancel (RB_AUDIOCD_SOURCE (source));

	db = get_db_for_source (RB_AUDIOCD_SOURCE (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);

	rhythmdb_commit (db);
	g_object_unref (db);
}
Пример #14
0
static gboolean
impl_track_added (RBRemovableMediaSource *source,
		  RhythmDBEntry *entry,
		  const char *dest,
		  guint64 filesize,
		  const char *mimetype)
{
	LIBMTP_track_t *track = NULL;
	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
	RhythmDB *db;
	RhythmDBEntry *mtp_entry;

	track = g_hash_table_lookup (priv->track_transfer_map, dest);
	if (track == NULL) {
		rb_debug ("track-added called, but can't find a track for dest URI %s", dest);
		return FALSE;
	}
	g_hash_table_remove (priv->track_transfer_map, dest);

	db = get_db_for_source (RB_MTP_SOURCE (source));
	/* entry_map takes ownership of the track here */
	mtp_entry = add_mtp_track_to_db (RB_MTP_SOURCE (source), db, track);
	g_object_unref (db);

	if (strcmp (track->album, _("Unknown")) != 0) {
		rb_mtp_thread_add_to_album (priv->device_thread, track, track->album);
	}

	if (priv->album_art_supported) {
		RequestAlbumArtData *artdata;
		artdata = g_new0 (RequestAlbumArtData, 1);
		artdata->source = g_object_ref (source);
		artdata->entry = rhythmdb_entry_ref (mtp_entry);
		g_idle_add ((GSourceFunc) request_album_art_idle, artdata);
	}
	queue_free_space_update (RB_MTP_SOURCE (source));

	/* chain up to parent class for sync */
	RB_REMOVABLE_MEDIA_SOURCE_CLASS (rb_mtp_source_parent_class)->impl_track_added (source, entry, dest, filesize, mimetype);
	return FALSE;
}
static void
rb_mtp_source_dispose (GObject *object)
{
	RBMtpSource *source = RB_MTP_SOURCE (object);
	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
	RhythmDBEntryType entry_type;
	RhythmDB *db;

	db = get_db_for_source (source);

	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);

	rhythmdb_commit (db);
	g_object_unref (db);

	if (priv->load_songs_idle_id != 0) {
		g_source_remove (priv->load_songs_idle_id);
		priv->load_songs_idle_id = 0;
	}

	G_OBJECT_CLASS (rb_mtp_source_parent_class)->dispose (object);
}
Пример #16
0
static void
rb_mtp_source_constructed (GObject *object)
{
	RBMtpSource *source;
	RBMtpSourcePrivate *priv;
	RBEntryView *tracks;
	RBShell *shell;
	RBShellPlayer *shell_player;
	GObject *player_backend;
	GtkIconTheme *theme;
	GdkPixbuf *pixbuf;
#if defined(HAVE_GUDEV)
	GMount *mount;
#endif
	gint size;

	RB_CHAIN_GOBJECT_METHOD (rb_mtp_source_parent_class, constructed, object);
	source = RB_MTP_SOURCE (object);
	priv = MTP_SOURCE_GET_PRIVATE (source);

	/* try to open the device.  if gvfs has mounted it, unmount it first */
#if defined(HAVE_GUDEV)
	mount = find_mount_for_device (priv->udev_device);
	if (mount != NULL) {
		rb_debug ("device is already mounted, waiting until activated");
		g_mount_unmount_with_operation (mount,
						G_MOUNT_UNMOUNT_NONE,
						NULL,
						NULL,
						unmount_done_cb,
						g_object_ref (source));
		/* mount gets unreffed in callback */
	} else
#endif
	open_device (source);

	tracks = rb_source_get_entry_view (RB_SOURCE (source));
	rb_entry_view_append_column (tracks, RB_ENTRY_VIEW_COL_RATING, FALSE);
	rb_entry_view_append_column (tracks, RB_ENTRY_VIEW_COL_LAST_PLAYED, FALSE);

	/* the source element needs our cooperation */
	g_object_get (source, "shell", &shell, NULL);
	shell_player = RB_SHELL_PLAYER (rb_shell_get_player (shell));
	g_object_get (shell_player, "player", &player_backend, NULL);

	g_signal_connect_object (player_backend,
				 "prepare-source",
				 G_CALLBACK (prepare_player_source_cb),
				 source, 0);

	g_object_unref (player_backend);
	g_object_unref (shell);

	g_signal_connect_object (rb_encoder_factory_get (),
				 "prepare-source",
				 G_CALLBACK (prepare_encoder_source_cb),
				 source, 0);
	g_signal_connect_object (rb_encoder_factory_get (),
				 "prepare-sink",
				 G_CALLBACK (prepare_encoder_sink_cb),
				 source, 0);

	/* icon */
	theme = gtk_icon_theme_get_default ();
	gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR, &size, NULL);
	pixbuf = gtk_icon_theme_load_icon (theme, "multimedia-player", size, 0, NULL);

	rb_source_set_pixbuf (RB_SOURCE (source), pixbuf);
	g_object_unref (pixbuf);

	if (priv->album_art_supported) {
		RhythmDB *db;

		db = get_db_for_source (source);
		g_signal_connect_object (db, "entry-extra-metadata-notify::rb:coverArt",
					 G_CALLBACK (artwork_notify_cb), source, 0);
		g_object_unref (db);
	}
}
static gboolean
load_mtp_db_idle_cb (RBMtpSource* source)
{
	RhythmDB *db = NULL;
	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
	LIBMTP_track_t *tracks = NULL;
	LIBMTP_album_t *albums;
	gboolean device_forgets_albums = TRUE;

	db = get_db_for_source (source);

	g_assert (db != NULL);

	albums = LIBMTP_Get_Album_List (priv->device);
	report_libmtp_errors (priv->device, FALSE);
	if (albums != NULL) {
		LIBMTP_album_t *album;

		for (album = albums; album != NULL; album = album->next) {
			rb_debug ("album: %s, %d tracks", album->name, album->no_tracks);
			g_hash_table_insert (priv->album_map, album->name, album);
			if (album->no_tracks != 0) {
				device_forgets_albums = FALSE;
			}
		}

		if (device_forgets_albums) {
			rb_debug ("stupid mtp device detected.  will rebuild all albums.");
		}
	} else {
		rb_debug ("No albums");
		device_forgets_albums = FALSE;
	}

#ifdef HAVE_LIBMTP_030
	tracks = LIBMTP_Get_Tracklisting_With_Callback (priv->device, NULL, NULL);
#else
	tracks = LIBMTP_Get_Tracklisting (priv->device);
#endif
	report_libmtp_errors (priv->device, FALSE);
	if (tracks != NULL) {
		LIBMTP_track_t *track;
		for (track = tracks; track != NULL; track = track->next) {
			add_mtp_track_to_db (source, db, track);

			if (device_forgets_albums && track->album != NULL) {
				add_track_to_album (source, track->album, track);
			}
		}
	} else {
		rb_debug ("No tracks");
	}

	/* for stupid devices, remove any albums left with no tracks */
	if (device_forgets_albums) {
		GHashTableIter iter;
		gpointer value;
		LIBMTP_album_t *album;

		g_hash_table_iter_init (&iter, priv->album_map);
		while (g_hash_table_iter_next (&iter, NULL, &value)) {
			int ret;

			album = value;
			if (album->no_tracks == 0) {
				rb_debug ("pruning empty album \"%s\"", album->name); 
				ret = LIBMTP_Delete_Object (priv->device, album->album_id);
				if (ret != 0) {
					report_libmtp_errors (priv->device, FALSE);
				}
				g_hash_table_iter_remove (&iter);
			}
		}
	}


	g_object_unref (G_OBJECT (db));
	return FALSE;
}
Пример #18
0
static void
prepare_encoder_sink_cb (RBEncoderFactory *factory,
			 const char *stream_uri,
			 GObject *sink,
			 RBMtpSource *source)
{
	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
	RhythmDBEntry *entry;
	RhythmDB *db;
	LIBMTP_track_t *track;
	char **bits;
	char *extension;
	LIBMTP_filetype_t filetype;
	gulong track_id;
	GDate d;
	char **folder_path;

	/* make sure this stream is for a file on our device */
	if (g_str_has_prefix (stream_uri, "xrbmtp://") == FALSE)
		return;

	/* extract the entry ID, extension, and MTP filetype from the URI */
	bits = g_strsplit (stream_uri + strlen ("xrbmtp://"), "/", 3);
	track_id = strtoul (bits[0], NULL, 0);
	extension = g_strdup (bits[1]);
	filetype = strtoul (bits[2], NULL, 0);
	g_strfreev (bits);

	db = get_db_for_source (source);
	entry = rhythmdb_entry_lookup_by_id (db, track_id);
	g_object_unref (db);
	if (entry == NULL) {
		g_free (extension);
		return;
	}

	track = LIBMTP_new_track_t ();
	track->title = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_TITLE);
	track->album = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_ALBUM);
	track->artist = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_ARTIST);
	track->genre = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_GENRE);

	/* build up device filename */
	track->filename = g_strdup_printf ("%s - %s.%s",
					   rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST),
					   rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE),
					   extension);
	g_free (extension);

	/* construct folder path: artist/album */
	folder_path = g_new0 (char *, 3);
	folder_path[0] = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_ALBUM_ARTIST);
	if (folder_path[0] == NULL || folder_path[0][0] == '\0') {
		g_free (folder_path[0]);
		folder_path[0] = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_ARTIST);
	}
	folder_path[1] = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_ALBUM);

	/* ensure the filename is safe for FAT filesystems and doesn't contain slashes */
	sanitize_for_mtp (track->filename);
	sanitize_for_mtp (folder_path[0]);
	sanitize_for_mtp (folder_path[1]);

	if (rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DATE) > 0) {
		g_date_set_julian (&d, rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DATE));
		track->date = gdate_to_char (&d);
	}
	track->tracknumber = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TRACK_NUMBER);
	track->duration = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DURATION) * 1000;
	track->rating = rhythmdb_entry_get_double (entry, RHYTHMDB_PROP_RATING) * 20;
	track->usecount = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_PLAY_COUNT);

	track->filetype = filetype;

	g_object_set (sink,
		      "device-thread", priv->device_thread,
		      "folder-path", folder_path,
		      "mtp-track", track,
		      NULL);
	rhythmdb_entry_unref (entry);
	g_strfreev (folder_path);

	g_hash_table_insert (priv->track_transfer_map, g_strdup (stream_uri), track);
}
static GObject *
rb_mtp_source_constructor (GType type, guint n_construct_properties,
			   GObjectConstructParam *construct_properties)
{
	RBMtpSource *source;
	RBMtpSourcePrivate *priv;
	RBEntryView *tracks;
	GtkIconTheme *theme;
	GdkPixbuf *pixbuf;
	gint size;
	guint16 *types = NULL;
	guint16 num_types= 0;

	source = RB_MTP_SOURCE (G_OBJECT_CLASS (rb_mtp_source_parent_class)->
				constructor (type, n_construct_properties, construct_properties));

	tracks = rb_source_get_entry_view (RB_SOURCE (source));
	rb_entry_view_append_column (tracks, RB_ENTRY_VIEW_COL_RATING, FALSE);
	rb_entry_view_append_column (tracks, RB_ENTRY_VIEW_COL_LAST_PLAYED, FALSE);

	/* icon */
	theme = gtk_icon_theme_get_default ();
	gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR, &size, NULL);
	pixbuf = gtk_icon_theme_load_icon (theme, "multimedia-player", size, 0, NULL);

	rb_source_set_pixbuf (RB_SOURCE (source), pixbuf);
	g_object_unref (pixbuf);

	g_signal_connect (G_OBJECT (source), "notify::name",
			  (GCallback)rb_mtp_source_name_changed_cb, NULL);
	
	/* figure out supported file types */
	priv = MTP_SOURCE_GET_PRIVATE (source);
	if (LIBMTP_Get_Supported_Filetypes(priv->device, &types, &num_types) == 0) {
		int i;
		gboolean has_mp3 = FALSE;
		for (i = 0; i < num_types; i++) {
			const char *mediatype;

			if (i <= LIBMTP_FILETYPE_UNKNOWN) {
				priv->supported_types[types[i]] = 1;
			}

			/* this has to work with the remapping done in 
			 * rb-removable-media-source.c:impl_paste.
			 */
			switch (types[i]) {
			case LIBMTP_FILETYPE_WAV:
				mediatype = "audio/x-wav";
				break;
			case LIBMTP_FILETYPE_MP3:
				/* special handling for mp3: always put it at the front of the list
				 * if it's supported.
				 */
				has_mp3 = TRUE;
				mediatype = NULL;
				break;
			case LIBMTP_FILETYPE_WMA:
				mediatype = "audio/x-ms-wma";
				break;
			case LIBMTP_FILETYPE_OGG:
				mediatype = "application/ogg";
				break;
			case LIBMTP_FILETYPE_MP4:
			case LIBMTP_FILETYPE_M4A:
			case LIBMTP_FILETYPE_AAC:
				mediatype = "audio/aac";
				break;
			case LIBMTP_FILETYPE_WMV:
				mediatype = "audio/x-ms-wmv";
				break;
			case LIBMTP_FILETYPE_ASF:
				mediatype = "video/x-ms-asf";
				break;
			case LIBMTP_FILETYPE_FLAC:
				mediatype = "audio/flac";
				break;

			case LIBMTP_FILETYPE_JPEG:
				rb_debug ("JPEG (album art) supported");
				mediatype = NULL;
				priv->album_art_supported = TRUE;
				break;

			default:
				rb_debug ("unknown libmtp filetype %s supported", LIBMTP_Get_Filetype_Description (types[i]));
				mediatype = NULL;
				break;
			}

			if (mediatype != NULL) {
				rb_debug ("media type %s supported", mediatype);
				priv->mediatypes = g_list_prepend (priv->mediatypes,
								   g_strdup (mediatype));
			}
		}

		if (has_mp3) {
			rb_debug ("audio/mpeg supported");
			priv->mediatypes = g_list_prepend (priv->mediatypes, g_strdup ("audio/mpeg"));
		}
	} else {
		report_libmtp_errors (priv->device, FALSE);
	}
	
	if (priv->album_art_supported) {
		RhythmDB *db;

		db = get_db_for_source (source);
		g_signal_connect_object (db, "entry-extra-metadata-notify::rb:coverArt",
					 G_CALLBACK (artwork_notify_cb), source, 0);
		g_object_unref (db);
	}

	rb_mtp_source_load_tracks (source);

	return G_OBJECT (source);
}
Пример #20
0
static void
rb_audiocd_source_constructed (GObject *object)
{
	RBAudioCdSourcePrivate *priv;
	RBAudioCdSource *source;
	RBEntryView *entry_view;
	GtkCellRenderer *renderer;
	GtkTreeViewColumn *extract;
	GtkWidget *widget;
	GtkAction *action;
	RhythmDB *db;
	RBPlugin *plugin;
	RBShell *shell;
	char *ui_file;
	int toggle_width;

	RB_CHAIN_GOBJECT_METHOD (rb_audiocd_source_parent_class, constructed, object);
	source = RB_AUDIOCD_SOURCE (object);
	priv = AUDIOCD_SOURCE_GET_PRIVATE (source);

	g_object_set (G_OBJECT (source), "name", "Unknown Audio", NULL);

	g_object_get (source, "shell", &shell, NULL);
	priv->action_group = _rb_source_register_action_group (RB_SOURCE (source),
							       "AudioCdActions",
							       NULL, 0, NULL);
	_rb_action_group_add_source_actions (priv->action_group,
					     G_OBJECT (shell),
					     rb_audiocd_source_actions,
					     G_N_ELEMENTS (rb_audiocd_source_actions));
	g_object_unref (shell);

	action = gtk_action_group_get_action (priv->action_group,
					      "AudioCdCopyTracks");
	/* Translators: this is the toolbar button label
	   for Copy to Library action. */
	g_object_set (action, "short-label", _("Extract"), NULL);

#if !defined(HAVE_SJ_METADATA_GETTER)
	action = gtk_action_group_get_action (priv->action_group, "AudioCdSourceReloadMetadata");
	g_object_set (action, "visible", FALSE, NULL);
#endif


	/* we want audio cds to sort by track# by default */
	entry_view = rb_source_get_entry_view (RB_SOURCE (source));
	rb_entry_view_set_sorting_order (entry_view, "Track", GTK_SORT_ASCENDING);

	/* enable in-place editing for titles, artists, and genres */
	rb_entry_view_set_column_editable (entry_view, RB_ENTRY_VIEW_COL_TITLE, TRUE);
	rb_entry_view_set_column_editable (entry_view, RB_ENTRY_VIEW_COL_ARTIST, TRUE);
	rb_entry_view_set_column_editable (entry_view, RB_ENTRY_VIEW_COL_GENRE, TRUE);

	/* create the 'extract' column */
	renderer = gtk_cell_renderer_toggle_new ();
	extract = gtk_tree_view_column_new ();
	gtk_tree_view_column_pack_start (extract, renderer, FALSE);
	gtk_tree_view_column_set_cell_data_func (extract,
						 renderer,
						 (GtkTreeCellDataFunc) extract_cell_data_func,
						 source,
						 NULL);
	gtk_tree_view_column_set_clickable (extract, TRUE);
	widget = gtk_check_button_new ();
	g_object_set (widget, "active", TRUE, NULL);
	gtk_widget_show_all (widget);
	g_signal_connect_object (extract, "clicked", G_CALLBACK (extract_column_clicked_cb), source, 0);
	gtk_tree_view_column_set_widget (extract, widget);

	g_signal_connect_object (renderer, "toggled", G_CALLBACK (extract_toggled_cb), source, 0);

	/* set column width */
	gtk_cell_renderer_get_size (renderer, GTK_WIDGET (entry_view), NULL, NULL, NULL, &toggle_width, NULL);
	gtk_tree_view_column_set_sizing (extract, GTK_TREE_VIEW_COLUMN_FIXED);
	gtk_tree_view_column_set_fixed_width (extract, toggle_width + 5);

	rb_entry_view_insert_column_custom (entry_view, extract, "", "Extract", NULL, NULL, NULL, 1);
	gtk_widget_set_tooltip_text (gtk_tree_view_column_get_widget (extract),
	                             _("Select tracks to be extracted"));

	/* hide the 'album' column */
	gtk_tree_view_column_set_visible (rb_entry_view_get_column (entry_view, RB_ENTRY_VIEW_COL_ALBUM), FALSE);

	/* handle extra metadata requests for album artist and album artist sortname */
	db = get_db_for_source (source);
	g_signal_connect_object (G_OBJECT (db), "entry-extra-metadata-request::" RHYTHMDB_PROP_ALBUM_ARTIST,
				 G_CALLBACK (album_artist_metadata_request_cb), source, 0);
	g_signal_connect_object (G_OBJECT (db), "entry-extra-metadata-request::" RHYTHMDB_PROP_ALBUM_ARTIST_SORTNAME,
				 G_CALLBACK (album_artist_sortname_metadata_request_cb), source, 0);
	g_signal_connect_object (G_OBJECT (db), "entry-extra-metadata-gather",
				 G_CALLBACK (metadata_gather_cb), source, 0);
	g_object_unref (db);

	/* set up the album info widgets */
	g_object_get (source, "plugin", &plugin, NULL);
	ui_file = rb_plugin_find_file (plugin, "album-info.ui");
	g_object_unref (plugin);

	if (ui_file == NULL) {
		g_warning ("couldn't find album-info.ui");
	} else {
		RBAudioCdSourcePrivate *priv;
		GtkWidget *table;
		GtkBuilder *builder;
#if defined(HAVE_SJ_METADATA_GETTER) && GTK_CHECK_VERSION(2,17,6)
		GtkWidget *box;
		char *message;
#endif

		priv = AUDIOCD_SOURCE_GET_PRIVATE (source);

		builder = rb_builder_load (ui_file, NULL);
		g_free (ui_file);

		table = GTK_WIDGET (gtk_builder_get_object (builder, "album_info"));
		g_assert (table != NULL);

#if defined(HAVE_SJ_METADATA_GETTER) && GTK_CHECK_VERSION(2,17,6)
		/* Info bar for non-Musicbrainz data */
		priv->info_bar = gtk_info_bar_new_with_buttons (_("S_ubmit Album"), GTK_RESPONSE_OK,
								_("Hide"), GTK_RESPONSE_CANCEL,
								NULL);
		message = g_strdup_printf ("<b>%s</b>\n%s", _("Could not find this album on MusicBrainz."),
					   _("You can improve the MusicBrainz database by adding this album."));
		priv->info_bar_label = gtk_label_new (NULL);
		gtk_label_set_markup (GTK_LABEL (priv->info_bar_label), message);
		gtk_label_set_justify (GTK_LABEL (priv->info_bar_label), GTK_JUSTIFY_LEFT);
		g_free (message);
		box = gtk_info_bar_get_content_area (GTK_INFO_BAR (priv->info_bar));
		gtk_container_add (GTK_CONTAINER (box), priv->info_bar_label);
		gtk_widget_show_all (box);
		gtk_widget_set_no_show_all (priv->info_bar, TRUE);
		g_signal_connect (G_OBJECT (priv->info_bar), "response",
				  G_CALLBACK (info_bar_response_cb), source);
		gtk_table_attach_defaults (GTK_TABLE (table), priv->info_bar, 0, 2, 0, 1);
#endif

		priv->artist_entry = GTK_WIDGET (gtk_builder_get_object (builder, "artist_entry"));
		priv->artist_sort_entry = GTK_WIDGET (gtk_builder_get_object (builder, "artist_sort_entry"));
		priv->album_entry = GTK_WIDGET (gtk_builder_get_object (builder, "album_entry"));
		priv->year_entry = GTK_WIDGET (gtk_builder_get_object (builder, "year_entry"));
		priv->genre_entry = GTK_WIDGET (gtk_builder_get_object (builder, "genre_entry"));
		priv->disc_number_entry = GTK_WIDGET (gtk_builder_get_object (builder, "disc_number_entry"));

		g_signal_connect_object (priv->album_entry, "focus-out-event", G_CALLBACK (update_album_cb), source, 0);
		g_signal_connect_object (priv->genre_entry, "focus-out-event", G_CALLBACK (update_genre_cb), source, 0);
		g_signal_connect_object (priv->year_entry, "focus-out-event", G_CALLBACK (update_year_cb), source, 0);
		g_signal_connect_object (priv->disc_number_entry, "focus-out-event", G_CALLBACK (update_disc_number_cb), source, 0);

		gtk_box_pack_start (GTK_BOX (priv->box), table, FALSE, FALSE, 0);
		gtk_box_reorder_child (GTK_BOX (priv->box), table, 0);
		g_object_unref (builder);
	}

	g_object_ref (G_OBJECT (source));
	g_thread_create ((GThreadFunc)rb_audiocd_load_songs, source, FALSE, NULL);
}
Пример #21
0
gboolean
impl_receive_drag (RBDisplayPage *page, GtkSelectionData *data)
{
	GList *entries;
	RhythmDB *db;
	char *type;

	entries = NULL;
	type = gdk_atom_name (gtk_selection_data_get_data_type (data));
        db = get_db_for_source (RB_SOURCE (page));

	if (strcmp (type, "text/uri-list") == 0) {
		GList *list;
		GList *i;

		rb_debug ("parsing uri list");
		list = rb_uri_list_parse ((const char *) gtk_selection_data_get_data (data));

		for (i = list; i != NULL; i = g_list_next (i)) {
			char *uri;
			RhythmDBEntry *entry;

			if (i->data == NULL)
				continue;

			uri = i->data;
			entry = rhythmdb_entry_lookup_by_location (db, uri);

			if (entry == NULL) {
				/* add to the library */
				rb_debug ("received drop of unknown uri: %s", uri);
			} else {
				/* add to list of entries to copy */
				entries = g_list_prepend (entries, entry);
			}
			g_free (uri);
		}
		g_list_free (list);
	} else if (strcmp (type, "application/x-rhythmbox-entry") == 0) {
		char **list;
		char **i;

		rb_debug ("parsing entry ids");
		list = g_strsplit ((const char*) gtk_selection_data_get_data (data), "\n", -1);
		for (i = list; *i != NULL; i++) {
			RhythmDBEntry *entry;
			gulong id;

			id = atoi (*i);
			entry = rhythmdb_entry_lookup_by_id (db, id);
			if (entry != NULL)
				entries = g_list_prepend (entries, entry);
		}

		g_strfreev (list);
	} else {
		rb_debug ("received unknown drop type");
	}

	g_object_unref (db);
	g_free (type);

	if (entries) {
		entries = g_list_reverse (entries);
		if (rb_source_can_paste (RB_SOURCE (page))) {
			rb_source_paste (RB_SOURCE (page), entries);
		}
		g_list_free (entries);
	}

	return TRUE;
}
Пример #22
0
static void
metadata_cb (SjMetadataGetter *metadata,
	     GList *albums,
	     GError *error,
	     RBAudioCdSource *source)
{
	RBAudioCdSourcePrivate *priv = AUDIOCD_SOURCE_GET_PRIVATE (source);
	GList *cd_track = priv->tracks;
	RhythmDB *db;
	GValue true_value = {0,};
	AlbumDetails *album;

	g_assert (metadata == priv->metadata);

	if (error != NULL) {
		rb_debug ("Failed to load cd metadata: %s", error->message);
		/* TODO display error to user? */
		g_object_unref (metadata);
		priv->metadata = NULL;
		return;
	}
	if (albums == NULL) {
		rb_debug ("Musicbrainz didn't return any CD metadata, but didn't give an error");
		g_object_unref (metadata);
		priv->metadata = NULL;
		return;
	}
	if (cd_track == NULL) {
		/* empty cd? */
		rb_debug ("no tracks on the CD?");
		g_object_unref (metadata);
		priv->metadata = NULL;
		return;
	}

	db = get_db_for_source (source);

	g_value_init (&true_value, G_TYPE_BOOLEAN);
	g_value_set_boolean (&true_value, TRUE);

	g_free (priv->submit_url);
	priv->submit_url = NULL;

	/* if we have multiple results, ask the user to pick one */
	if (g_list_length (albums) > 1) {
		album = multiple_album_dialog (albums, source);
		if (album == NULL)
			album = (AlbumDetails *)albums->data;
	} else
		album = (AlbumDetails *)albums->data;

#if GTK_CHECK_VERSION(2,17,6)
	if (album->metadata_source != SOURCE_MUSICBRAINZ) {
		priv->submit_url = sj_metadata_getter_get_submit_url (metadata);
		if (priv->submit_url != NULL)
			gtk_widget_show (priv->info_bar);
	}
#endif

	if (album->metadata_source == SOURCE_FALLBACK) {
		rb_debug ("ignoring CD metadata from fallback source");
		g_object_unref (metadata);
		priv->metadata = NULL;
		g_object_unref (db);
		return;
	}

	if (album->artist != NULL) {
		gtk_entry_set_text (GTK_ENTRY (priv->artist_entry), album->artist);
	}
	if (album->artist_sortname != NULL) {
		gtk_entry_set_text (GTK_ENTRY (priv->artist_sort_entry), album->artist_sortname);
	}
	if (album->title != NULL) {
		gtk_entry_set_text (GTK_ENTRY (priv->album_entry), album->title);
	}
	if (album->release_date != NULL) {
		char *year;
		year = g_strdup_printf ("%d", g_date_get_year (album->release_date));
		gtk_entry_set_text (GTK_ENTRY (priv->year_entry), year);
		g_free (year);
	}
	if (album->disc_number != 0) {
		char *num;
		num = g_strdup_printf ("%d", album->disc_number);
		gtk_entry_set_text (GTK_ENTRY (priv->disc_number_entry), num);
		g_free (num);
	}
	if (album->genre != NULL) {
		gtk_entry_set_text (GTK_ENTRY (priv->genre_entry), album->genre);
	}

	g_object_set (G_OBJECT (source), "name", album->title, NULL);
	rb_debug ("musicbrainz_albumid: %s", album->album_id);
	rb_debug ("musicbrainz_albumartistid: %s", album->artist_id);
	rb_debug ("album artist: %s", album->artist);
	rb_debug ("disc number: %d", album->disc_number);
	rb_debug ("genre: %s", album->genre);

	while (album->tracks && cd_track) {
		TrackDetails *track = (TrackDetails*)album->tracks->data;
		RhythmDBEntry *entry = cd_track->data;
		GValue value = {0, };

		rb_debug ("storing metadata for %s - %s - %s", track->artist, album->title, track->title);

		rb_debug ("musicbrainz_trackid: %s", track->track_id);
		rb_debug ("musicbrainz_artistid: %s", track->artist_id);
		rb_debug ("artist sortname: %s", track->artist_sortname);

		/* record track info in entry*/
		entry_set_string_prop (db, entry, RHYTHMDB_PROP_TITLE, FALSE, track->title);
		entry_set_string_prop (db, entry, RHYTHMDB_PROP_ARTIST, FALSE, track->artist);
		entry_set_string_prop (db, entry, RHYTHMDB_PROP_ALBUM, FALSE, album->title);
		entry_set_string_prop (db, entry, RHYTHMDB_PROP_GENRE, FALSE, album->genre);
		entry_set_string_prop (db, entry, RHYTHMDB_PROP_MUSICBRAINZ_TRACKID, TRUE, track->track_id);
		entry_set_string_prop (db, entry, RHYTHMDB_PROP_MUSICBRAINZ_ARTISTID, TRUE, track->artist_id);
		entry_set_string_prop (db, entry, RHYTHMDB_PROP_MUSICBRAINZ_ALBUMID, TRUE, album->album_id);
		entry_set_string_prop (db, entry, RHYTHMDB_PROP_MUSICBRAINZ_ALBUMARTISTID, TRUE, album->artist_id);
		entry_set_string_prop (db, entry, RHYTHMDB_PROP_ARTIST_SORTNAME, TRUE, track->artist_sortname);

		g_value_init (&value, G_TYPE_ULONG);
		g_value_set_ulong (&value, track->duration);
		rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_DURATION, &value);
		g_value_unset (&value);

		if (album->disc_number != 0) {
			g_value_init (&value, G_TYPE_ULONG);
			g_value_set_ulong (&value, album->disc_number);
			rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_DISC_NUMBER, &value);
			g_value_unset (&value);
		}

		/*album->release_date (could potentially have multiple values)*/
		/* in current sj-structures.h, however, it does not */

		if (album->release_date) {
			GType type = rhythmdb_get_property_type (db, RHYTHMDB_PROP_DATE);
			g_value_init (&value, type);
			g_value_set_ulong (&value, g_date_get_julian (album->release_date));
			rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_DATE, &value);
			g_value_unset (&value);
		}

		rhythmdb_commit (db);

		album->tracks = g_list_next (album->tracks);
		cd_track = g_list_next (cd_track);
	}

	while (cd_track) {
		/* Musicbrainz doesn't report data tracks on multisession CDs.
		 * These aren't interesting to us anyway, so they should be hidden.
		 */
		RhythmDBEntry *entry = cd_track->data;
		rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_HIDDEN, &true_value);
		rhythmdb_commit (db);

		cd_track = g_list_next (cd_track);
	}

	/* And free the albums list, as it belongs to us, not
	 * the metadata getter */
	g_list_foreach (albums, (GFunc)album_details_free, NULL);
	g_list_free (albums);

	g_object_unref (metadata);
	priv->metadata = NULL;

	g_object_unref (db);
}