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