AudioscrobblerEntry * rb_audioscrobbler_entry_create (RhythmDBEntry *rb_entry) { AudioscrobblerEntry *as_entry = g_new0 (AudioscrobblerEntry, 1); as_entry->title = rhythmdb_entry_dup_string (rb_entry, RHYTHMDB_PROP_TITLE); as_entry->track = rhythmdb_entry_get_ulong (rb_entry, RHYTHMDB_PROP_TRACK_NUMBER); as_entry->artist = rhythmdb_entry_dup_string (rb_entry, RHYTHMDB_PROP_ARTIST); as_entry->album = rhythmdb_entry_dup_string (rb_entry, RHYTHMDB_PROP_ALBUM); if (strcmp (as_entry->album, _("Unknown")) == 0) { g_free (as_entry->album); as_entry->album = g_strdup (""); } as_entry->length = rhythmdb_entry_get_ulong (rb_entry, RHYTHMDB_PROP_DURATION); as_entry->mbid = rhythmdb_entry_dup_string (rb_entry, RHYTHMDB_PROP_MUSICBRAINZ_TRACKID); if (strcmp (as_entry->mbid, _("Unknown")) == 0) { g_free (as_entry->mbid); as_entry->mbid = g_strdup (""); } /* * TODO: identify the source type. we just use 'P' for everything for now. * should use 'R' for iradio, 'P' for everything else except last.fm. * for last.fm, we need to extract the recommendation key from the db entry's * extra data (see RBLastfmTrackEntryData in rb-lastfm-source.c) and include * that in the source info here. */ as_entry->source = g_strdup ("P"); return as_entry; }
static LIBMTP_track_t * transfer_track (RBMtpSource *source, LIBMTP_mtpdevice_t *device, RhythmDBEntry *entry, const char *filename, guint64 filesize, const char *mimetype) { LIBMTP_track_t *trackmeta = LIBMTP_new_track_t (); GDate d; int ret; trackmeta->title = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_TITLE); trackmeta->album = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_ALBUM); trackmeta->artist = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_ARTIST); trackmeta->genre = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_GENRE); trackmeta->filename = g_path_get_basename (filename); if (rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DATE) > 0) { /* Entries without a date returns 0, g_date_set_julian don't accept that */ g_date_set_julian (&d, rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DATE)); trackmeta->date = gdate_to_char (&d); } trackmeta->tracknumber = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TRACK_NUMBER); trackmeta->duration = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DURATION) * 1000; trackmeta->rating = rhythmdb_entry_get_double (entry, RHYTHMDB_PROP_RATING) * 20; trackmeta->usecount = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_PLAY_COUNT); trackmeta->filesize = filesize; if (mimetype == NULL) { mimetype = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MIMETYPE); } trackmeta->filetype = mimetype_to_filetype (source, mimetype); rb_debug ("using libmtp filetype %d (%s) for source media type %s", trackmeta->filetype, LIBMTP_Get_Filetype_Description (trackmeta->filetype), mimetype); #ifdef HAVE_LIBMTP_030 ret = LIBMTP_Send_Track_From_File (device, filename, trackmeta, NULL, NULL); #else ret = LIBMTP_Send_Track_From_File (device, filename, trackmeta, NULL, NULL, 0); #endif rb_debug ("LIBMTP_Send_Track_From_File (%s) returned %d", filename, ret); if (ret != 0) { report_libmtp_errors (device, TRUE); LIBMTP_destroy_track_t (trackmeta); return NULL; } if (strcmp (trackmeta->album, _("Unknown")) != 0) { add_track_to_album (source, trackmeta->album, trackmeta); } return trackmeta; }
static void podcast_post_date_cell_data_func (GtkTreeViewColumn *column, GtkCellRenderer *renderer, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) { RhythmDBEntry *entry; gulong value; char *str; gtk_tree_model_get (tree_model, iter, 0, &entry, -1); value = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_POST_TIME); if (value == 0) { str = g_strdup (_("Unknown")); } else { str = rb_utf_friendly_time (value); } g_object_set (G_OBJECT (renderer), "text", str, NULL); g_free (str); rhythmdb_entry_unref (entry); }
static gboolean check_entry_grace_period (RhythmDB *db, RhythmDBEntry *entry) { GTimeVal time; gulong last_seen; gulong grace_period; GError *error; error = NULL; grace_period = g_settings_get_int (db->priv->settings, "grace-period"); if (error != NULL) { g_error_free (error); return FALSE; } /* This is a bit silly, but I prefer to make sure we won't * overflow in the following calculations */ if ((grace_period <= 0) || (grace_period > 20000)) { return FALSE; } /* Convert from days to seconds */ grace_period = grace_period * 60 * 60 * 24; g_get_current_time (&time); last_seen = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_LAST_SEEN); return (last_seen + grace_period < time.tv_sec); }
static double rb_random_by_age_and_rating_get_entry_weight (RBRandomPlayOrder *rorder, RhythmDB *db, RhythmDBEntry *entry) { time_t now; gulong last_play; gulong seconds_since_last_play = 0; gdouble rating; RhythmDBEntry *playing_entry; /* This finds the log of the number of seconds since the last play. * It handles never played automatically, since now-0 is a valid * argument to log(). */ time (&now); playing_entry = rb_play_order_get_playing_entry (RB_PLAY_ORDER (rorder)); if (playing_entry != entry) { last_play = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_LAST_PLAYED); seconds_since_last_play = now - last_play; } if (playing_entry != NULL) rhythmdb_entry_unref (playing_entry); /* The lowest weight should be 0. */ if (seconds_since_last_play < 1) seconds_since_last_play = 1; rating = rhythmdb_entry_get_double (entry, RHYTHMDB_PROP_RATING); /* treat unrated as 2.5 for the purposes of probabilities */ if (rating < 0.01) rating = 2.5; return log (seconds_since_last_play) * (rating + 1.0); }
/** * rb_source_update_play_statistics: * @source: a #RBSource * @db: the #RhythmDB instance * @entry: the #RhythmDBEntry to update * * Updates play count and play time statistics for a database entry. * Sources containing entries that do not normally reach EOS should * call this for an entry when it is no longer being played. */ void rb_source_update_play_statistics (RBSource *source, RhythmDB *db, RhythmDBEntry *entry) { time_t now; gulong current_count; GValue value = { 0, }; g_value_init (&value, G_TYPE_ULONG); current_count = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_PLAY_COUNT); g_value_set_ulong (&value, current_count + 1); /* Increment current play count */ rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_PLAY_COUNT, &value); g_value_unset (&value); /* Reset the last played time */ time (&now); g_value_init (&value, G_TYPE_ULONG); g_value_set_ulong (&value, now); rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_LAST_PLAYED, &value); g_value_unset (&value); rhythmdb_commit (db); }
static gint podcast_post_date_sort_func (RhythmDBEntry *a, RhythmDBEntry *b, RhythmDBQueryModel *model) { gulong a_val, b_val; gint ret; a_val = rhythmdb_entry_get_ulong (a, RHYTHMDB_PROP_POST_TIME); b_val = rhythmdb_entry_get_ulong (b, RHYTHMDB_PROP_POST_TIME); if (a_val != b_val) ret = (a_val > b_val) ? 1 : -1; else ret = rhythmdb_query_model_title_sort_func (a, b, model); return ret; }
/** * rb_transfer_target_check_duplicate: * @target: an #RBTransferTarget * @entry: a #RhythmDBEntry to check * * This checks for an existing entry in the target that matches * the title, album, artist, and track number of the entry being * considered. This can be used to implement @should_transfer. * * Return value: %TRUE if the entry already exists on the target. */ gboolean rb_transfer_target_check_duplicate (RBTransferTarget *target, RhythmDBEntry *entry) { RhythmDBEntryType *entry_type; RhythmDB *db; RBShell *shell; const char *title; const char *album; const char *artist; gulong track_number; GtkTreeModel *query_model; GtkTreeIter iter; gboolean is_dup; g_object_get (target, "shell", &shell, "entry-type", &entry_type, NULL); g_object_get (shell, "db", &db, NULL); g_object_unref (shell); query_model = GTK_TREE_MODEL (rhythmdb_query_model_new_empty (db)); title = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE); album = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM); artist = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST); track_number = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TRACK_NUMBER); rhythmdb_do_full_query (db, RHYTHMDB_QUERY_RESULTS (query_model), RHYTHMDB_QUERY_PROP_EQUALS, RHYTHMDB_PROP_TYPE, entry_type, RHYTHMDB_QUERY_PROP_EQUALS, RHYTHMDB_PROP_ARTIST, artist, RHYTHMDB_QUERY_PROP_EQUALS, RHYTHMDB_PROP_ALBUM, album, RHYTHMDB_QUERY_PROP_EQUALS, RHYTHMDB_PROP_TITLE, title, RHYTHMDB_QUERY_PROP_EQUALS, RHYTHMDB_PROP_TRACK_NUMBER, track_number, RHYTHMDB_QUERY_END); is_dup = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (query_model), &iter); g_object_unref (entry_type); g_object_unref (query_model); g_object_unref (db); if (is_dup) { rb_debug ("not transferring %lu - %s - %s - %s as already present", track_number, title, album, artist); } return is_dup; }
static gboolean burn_source_iter_func (GtkTreeModel *model, GtkTreeIter *iter, char **uri, char **artist, char **title, gulong *duration) { RhythmDBEntry *entry; gtk_tree_model_get (model, iter, 0, &entry, -1); *uri = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_LOCATION); *title = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_TITLE); *artist = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_ARTIST); *duration = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DURATION); return TRUE; }
static char * impl_build_dest_uri (RBRemovableMediaSource *source, RhythmDBEntry *entry, const char *mimetype, const char *extension) { gulong id; char *uri; LIBMTP_filetype_t filetype; if (mimetype == NULL) { mimetype = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MIMETYPE); } filetype = mimetype_to_filetype (RB_MTP_SOURCE (source), mimetype); rb_debug ("using libmtp filetype %d (%s) for source media type %s", filetype, LIBMTP_Get_Filetype_Description (filetype), mimetype); /* the prepare-sink callback needs the entry ID to set up the * upload data, and we want to use the supplied extension for * the filename on the device. * * this is pretty ugly - it'd be much nicer to have a source-defined * structure that got passed around (or was accessible from) the various * hooks and methods called during the track transfer process. probably * something to address in my horribly stalled track transfer rewrite.. * * the structure would either be created when queuing the track for transfer, * or here; passed to any prepare-source or prepare-sink callbacks for the * encoder; and then passed to whatever gets called when the transfer is complete. */ id = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_ENTRY_ID); if (extension == NULL) { extension = ""; } uri = g_strdup_printf ("xrbmtp://%lu/%s/%d", id, extension, filetype); return uri; }
static void info_available_cb (RBPlayer *backend, const char *uri, RBMetaDataField field, GValue *value, RBIRadioSource *source) { RhythmDBEntry *entry; RhythmDBPropType entry_field = 0; gboolean set_field = FALSE; char *str = NULL; /* sanity check */ if (!rb_player_opened (backend)) { rb_debug ("Got info_available but not playing"); return; } GDK_THREADS_ENTER (); entry = rb_shell_player_get_playing_entry (source->priv->player); if (check_entry_type (source, entry) == FALSE) goto out_unlock; /* validate the value */ switch (field) { case RB_METADATA_FIELD_TITLE: case RB_METADATA_FIELD_ARTIST: case RB_METADATA_FIELD_GENRE: case RB_METADATA_FIELD_COMMENT: str = g_value_dup_string (value); if (!g_utf8_validate (str, -1, NULL)) { g_warning ("Invalid UTF-8 from internet radio: %s", str); g_free (str); goto out_unlock; } break; default: break; } switch (field) { /* streaming song information */ case RB_METADATA_FIELD_TITLE: { rb_streaming_source_set_streaming_title (RB_STREAMING_SOURCE (source), str); break; } case RB_METADATA_FIELD_ARTIST: { rb_streaming_source_set_streaming_artist (RB_STREAMING_SOURCE (source), str); break; } /* station information */ case RB_METADATA_FIELD_GENRE: { const char *existing; /* check if the db entry already has a genre; if so, don't change it */ existing = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_GENRE); if ((existing == NULL) || (strcmp (existing, "") == 0) || (strcmp (existing, _("Unknown")) == 0)) { entry_field = RHYTHMDB_PROP_GENRE; rb_debug ("setting genre of iradio station to %s", str); set_field = TRUE; } else { rb_debug ("iradio station already has genre: %s; ignoring %s", existing, str); } break; } case RB_METADATA_FIELD_COMMENT: { const char *existing; const char *location; /* check if the db entry already has a title; if so, don't change it. * consider title==URI to be the same as no title, since that's what * happens for stations imported by DnD or commandline args. * if the station title really is the same as the URI, then surely * the station title in the stream metadata will say that too.. */ existing = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE); location = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION); if ((existing == NULL) || (strcmp (existing, "") == 0) || (strcmp (existing, location) == 0)) { entry_field = RHYTHMDB_PROP_TITLE; rb_debug ("setting title of iradio station to %s", str); set_field = TRUE; } else { rb_debug ("iradio station already has title: %s; ignoring %s", existing, str); } break; } case RB_METADATA_FIELD_BITRATE: if (!rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_BITRATE)) { gulong bitrate; /* GStreamer sends us bitrate in bps, but we need it in kbps*/ bitrate = g_value_get_ulong (value); g_value_set_ulong (value, bitrate/1000); rb_debug ("setting bitrate of iradio station to %lu", g_value_get_ulong (value)); entry_field = RHYTHMDB_PROP_BITRATE; set_field = TRUE; } break; default: break; } if (set_field && entry_field != 0) { rhythmdb_entry_set (source->priv->db, entry, entry_field, value); rhythmdb_commit (source->priv->db); } g_free (str); out_unlock: GDK_THREADS_LEAVE (); }
RBDAAPRecord * rb_daap_record_new (RhythmDBEntry *entry) { RBDAAPRecord *record = NULL; record = RB_DAAP_RECORD (g_object_new (RB_TYPE_DAAP_RECORD, NULL)); /* When browsing, entry will be NULL because we will pull * the metadata from the DAAP query. When sharing, entry will * point to an existing entry from the Rhythmbox DB. */ if (entry) { gchar *ext; record->priv->filesize = rhythmdb_entry_get_uint64 (entry, RHYTHMDB_PROP_FILE_SIZE); record->priv->location = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_LOCATION); record->priv->title = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_TITLE); record->priv->artist = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_ARTIST); record->priv->album = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_ALBUM); /* Since we don't support album id's on Rhythmbox, "emulate" it */ record->priv->albumid = (gintptr) rhythmdb_entry_get_refstring (entry, RHYTHMDB_PROP_ALBUM); record->priv->genre = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_GENRE); /* FIXME: Support transcoding: */ /* FIXME: we should use RHYTHMDB_PROP_MIMETYPE instead */ ext = strrchr (record->priv->location, '.'); if (ext == NULL) { ext = "mp3"; } else { ext++; } record->priv->mediakind = DMAP_MEDIA_KIND_MUSIC; record->priv->real_format = g_strdup (ext); record->priv->format = g_strdup (record->priv->real_format); /* Only support songs */ record->priv->mediakind = 1; record->priv->track = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TRACK_NUMBER); record->priv->duration = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DURATION); record->priv->rating = (gint) rhythmdb_entry_get_double (entry, RHYTHMDB_PROP_RATING); record->priv->year = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_YEAR); record->priv->firstseen = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_FIRST_SEEN); record->priv->mtime = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_MTIME); record->priv->disc = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DISC_NUMBER); record->priv->bitrate = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_BITRATE); } return record; }
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 gboolean start_next (RBTrackTransferBatch *batch) { char *media_type = NULL; char *extension = NULL; if (batch->priv->cancelled == TRUE) { return FALSE; } if (batch->priv->entries == NULL) { /* guess we must be done.. */ g_signal_emit (batch, signals[COMPLETE], 0); return FALSE; } batch->priv->current_fraction = 0.0; batch->priv->current_encoder = rb_encoder_new (); g_signal_connect_object (batch->priv->current_encoder, "progress", G_CALLBACK (encoder_progress_cb), batch, 0); g_signal_connect_object (batch->priv->current_encoder, "overwrite", G_CALLBACK (encoder_overwrite_cb), batch, 0); g_signal_connect_object (batch->priv->current_encoder, "completed", G_CALLBACK (encoder_completed_cb), batch, 0); rb_debug ("%d entries remain in the batch", g_list_length (batch->priv->entries)); while ((batch->priv->entries != NULL) && (batch->priv->cancelled == FALSE)) { RhythmDBEntry *entry; guint64 filesize; gulong duration; double fraction; GList *n; n = batch->priv->entries; batch->priv->entries = g_list_remove_link (batch->priv->entries, n); entry = (RhythmDBEntry *)n->data; g_list_free_1 (n); rb_debug ("attempting to transfer %s", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION)); /* calculate the fraction of the transfer that this entry represents */ filesize = rhythmdb_entry_get_uint64 (entry, RHYTHMDB_PROP_FILE_SIZE); duration = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DURATION); if (batch->priv->total_duration > 0) { g_assert (duration > 0); /* otherwise total_duration would be 0 */ fraction = ((double)duration) / (double) batch->priv->total_duration; } else if (batch->priv->total_size > 0) { g_assert (filesize > 0); /* otherwise total_size would be 0 */ fraction = ((double)filesize) / (double) batch->priv->total_size; } else { int count = g_list_length (batch->priv->entries) + g_list_length (batch->priv->done_entries) + 1; fraction = 1.0 / ((double)count); } g_free (media_type); g_free (extension); media_type = NULL; extension = NULL; if (rb_encoder_get_media_type (batch->priv->current_encoder, entry, batch->priv->media_types, &media_type, &extension) == FALSE) { rb_debug ("skipping entry %s, can't find a destination format", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION)); rhythmdb_entry_unref (entry); batch->priv->total_fraction += fraction; continue; } g_free (batch->priv->current_dest_uri); batch->priv->current_dest_uri = NULL; g_signal_emit (batch, signals[GET_DEST_URI], 0, entry, media_type, extension, &batch->priv->current_dest_uri); if (batch->priv->current_dest_uri == NULL) { rb_debug ("unable to build destination URI for %s, skipping", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION)); rhythmdb_entry_unref (entry); batch->priv->total_fraction += fraction; continue; } batch->priv->current = entry; batch->priv->current_entry_fraction = fraction; break; } if (batch->priv->current == NULL) { g_object_unref (batch->priv->current_encoder); batch->priv->current_encoder = NULL; } else { g_signal_emit (batch, signals[TRACK_STARTED], 0, batch->priv->current, batch->priv->current_dest_uri); rb_encoder_encode (batch->priv->current_encoder, batch->priv->current, batch->priv->current_dest_uri, media_type); } g_free (media_type); g_free (extension); return TRUE; }
static char * impl_build_dest_uri (RBTransferTarget *target, RhythmDBEntry *entry, const char *media_type, const char *extension) { RBAndroidSourcePrivate *priv = GET_PRIVATE (target); const char *in_artist; char *artist, *album, *title; gulong track_number, disc_number; char *number; char *file = NULL; char *storage_uri; char *uri; char *ext; GFile *storage = NULL; if (extension != NULL) { ext = g_strconcat (".", extension, NULL); } else { ext = g_strdup (""); } in_artist = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM_ARTIST); if (in_artist[0] == '\0') { in_artist = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST); } artist = sanitize_path (in_artist); album = sanitize_path (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM)); title = sanitize_path (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE)); /* we really do need to fix this so untagged entries actually have NULL rather than * a translated string. */ if (strcmp (artist, _("Unknown")) == 0 && strcmp (album, _("Unknown")) == 0 && g_str_has_suffix (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION), title)) { /* file isn't tagged, so just use the filename as-is, replacing the extension */ char *p; p = g_utf8_strrchr (title, -1, '.'); if (p != NULL) { *p = '\0'; } file = g_strdup_printf ("%s%s", title, ext); } if (file == NULL) { track_number = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TRACK_NUMBER); disc_number = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DISC_NUMBER); if (disc_number > 0) number = g_strdup_printf ("%.02u.%.02u", (guint)disc_number, (guint)track_number); else number = g_strdup_printf ("%.02u", (guint)track_number); /* artist/album/number - title */ file = g_strdup_printf (G_DIR_SEPARATOR_S "%s" G_DIR_SEPARATOR_S "%s" G_DIR_SEPARATOR_S "%s%%20-%%20%s%s", artist, album, number, title, ext); g_free (number); } g_free (artist); g_free (album); g_free (title); g_free (ext); /* pick storage container to use somehow for (l = priv->storage; l != NULL; l = l->next) { } */ if (priv->storage) storage = priv->storage->data; if (storage == NULL) { rb_debug ("couldn't find a container to store anything in"); g_free (file); return NULL; } storage_uri = g_file_get_uri (storage); uri = g_strconcat (storage_uri, file, NULL); g_free (file); g_free (storage_uri); return uri; }
static gboolean start_next (RBTrackTransferBatch *batch) { GstEncodingProfile *profile = NULL; if (batch->priv->cancelled == TRUE) { return FALSE; } if (batch->priv->entries == NULL) { /* guess we must be done.. */ g_signal_emit (batch, signals[COMPLETE], 0); g_object_notify (G_OBJECT (batch), "task-outcome"); return FALSE; } batch->priv->current_fraction = 0.0; rb_debug ("%d entries remain in the batch", g_list_length (batch->priv->entries)); while ((batch->priv->entries != NULL) && (batch->priv->cancelled == FALSE)) { RhythmDBEntry *entry; guint64 filesize; gulong duration; double fraction; GList *n; char *media_type; char *extension; n = batch->priv->entries; batch->priv->entries = g_list_remove_link (batch->priv->entries, n); entry = (RhythmDBEntry *)n->data; g_list_free_1 (n); rb_debug ("attempting to transfer %s", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION)); /* calculate the fraction of the transfer that this entry represents */ filesize = rhythmdb_entry_get_uint64 (entry, RHYTHMDB_PROP_FILE_SIZE); duration = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DURATION); if (batch->priv->total_duration > 0) { g_assert (duration > 0); /* otherwise total_duration would be 0 */ fraction = ((double)duration) / (double) batch->priv->total_duration; } else if (batch->priv->total_size > 0) { g_assert (filesize > 0); /* otherwise total_size would be 0 */ fraction = ((double)filesize) / (double) batch->priv->total_size; } else { int count = g_list_length (batch->priv->entries) + g_list_length (batch->priv->done_entries) + 1; fraction = 1.0 / ((double)count); } profile = NULL; if (select_profile_for_entry (batch, entry, &profile, FALSE) == FALSE) { rb_debug ("skipping entry %s, can't find an encoding profile", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION)); rhythmdb_entry_unref (entry); batch->priv->total_fraction += fraction; continue; } if (profile != NULL) { media_type = rb_gst_encoding_profile_get_media_type (profile); extension = g_strdup (rb_gst_media_type_to_extension (media_type)); rb_gst_encoding_profile_set_preset (profile, NULL); if (batch->priv->settings != NULL) { GVariant *preset_settings; char *active_preset; preset_settings = g_settings_get_value (batch->priv->settings, "media-type-presets"); active_preset = NULL; g_variant_lookup (preset_settings, media_type, "s", &active_preset); rb_debug ("setting preset %s for media type %s", active_preset, media_type); rb_gst_encoding_profile_set_preset (profile, active_preset); g_free (active_preset); } } else { media_type = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_MEDIA_TYPE); extension = g_strdup (rb_gst_media_type_to_extension (media_type)); if (extension == NULL) { extension = get_extension_from_location (entry); } } g_free (batch->priv->current_dest_uri); batch->priv->current_dest_uri = NULL; g_signal_emit (batch, signals[GET_DEST_URI], 0, entry, media_type, extension, &batch->priv->current_dest_uri); g_free (media_type); g_free (extension); if (batch->priv->current_dest_uri == NULL) { rb_debug ("unable to build destination URI for %s, skipping", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION)); rhythmdb_entry_unref (entry); batch->priv->total_fraction += fraction; continue; } batch->priv->current = entry; batch->priv->current_entry_fraction = fraction; batch->priv->current_profile = profile; break; } if (batch->priv->current != NULL) { g_signal_emit (batch, signals[TRACK_STARTED], 0, batch->priv->current, batch->priv->current_dest_uri); start_encoding (batch, FALSE); g_object_notify (G_OBJECT (batch), "task-detail"); } return TRUE; }
/** * _rb_track_transfer_batch_start: * @batch: a #RBTrackTransferBatch * @queue: the #RBTrackTransferQueue * * Starts the batch transfer. Only to be called by the #RBTrackTransferQueue. */ void _rb_track_transfer_batch_start (RBTrackTransferBatch *batch, GObject *queue) { gboolean total_duration_valid; gboolean total_size_valid; gboolean origin_valid; guint64 filesize; gulong duration; RBSource *origin = NULL; RBShell *shell; GList *l; g_object_get (queue, "shell", &shell, NULL); /* calculate total duration and file size and figure out the * origin source if we weren't given one to start with. */ total_duration_valid = TRUE; total_size_valid = TRUE; origin_valid = TRUE; for (l = batch->priv->entries; l != NULL; l = l->next) { RhythmDBEntry *entry = (RhythmDBEntry *)l->data; filesize = rhythmdb_entry_get_uint64 (entry, RHYTHMDB_PROP_FILE_SIZE); if (total_size_valid && filesize > 0) { batch->priv->total_size += filesize; } else { total_size_valid = FALSE; batch->priv->total_size = 0; } duration = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DURATION); if (total_duration_valid && duration > 0) { batch->priv->total_duration += duration; } else { total_duration_valid = FALSE; batch->priv->total_duration = 0; } if (batch->priv->source == NULL) { RhythmDBEntryType *entry_type; RBSource *entry_origin; entry_type = rhythmdb_entry_get_entry_type (entry); entry_origin = rb_shell_get_source_by_entry_type (shell, entry_type); if (origin == NULL && origin_valid == TRUE) { origin = entry_origin; } else if (origin != entry_origin) { origin = NULL; origin_valid = FALSE; } } } g_object_unref (shell); if (origin != NULL) { batch->priv->source = origin; } batch->priv->queue = RB_TRACK_TRANSFER_QUEUE (queue); batch->priv->cancelled = FALSE; batch->priv->total_fraction = 0.0; g_signal_emit (batch, signals[STARTED], 0); g_object_notify (G_OBJECT (batch), "task-progress"); g_object_notify (G_OBJECT (batch), "task-detail"); start_next (batch); }
static char * impl_build_dest_uri (RBRemovableMediaSource *source, RhythmDBEntry *entry, const char *mimetype, const char *extension) { RBGenericPlayerSourcePrivate *priv = GENERIC_PLAYER_SOURCE_GET_PRIVATE (source); char *artist, *album, *title; gulong track_number, disc_number; const char *folders; char **audio_folders; char *mount_path; char *number; char *file = NULL; char *path; char *ext; rb_debug ("building dest uri for entry at %s", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION)); if (extension != NULL) { ext = g_strconcat (".", extension, NULL); } else { ext = g_strdup (""); } artist = sanitize_path (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST)); album = sanitize_path (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM)); title = sanitize_path (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE)); /* we really do need to fix this so untagged entries actually have NULL rather than * a translated string. */ if (strcmp (artist, _("Unknown")) == 0 && strcmp (album, _("Unknown")) == 0 && g_str_has_suffix (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION), title)) { /* file isn't tagged, so just use the filename as-is, replacing the extension */ char *p; p = g_utf8_strrchr (title, -1, '.'); if (p != NULL) { *p = '\0'; } file = g_strdup_printf ("%s%s", title, ext); } if (file == NULL) { int folder_depth; track_number = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TRACK_NUMBER); disc_number = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DISC_NUMBER); if (disc_number > 0) number = g_strdup_printf ("%.02u.%.02u", (guint)disc_number, (guint)track_number); else number = g_strdup_printf ("%.02u", (guint)track_number); g_object_get (priv->device_info, "folder-depth", &folder_depth, NULL); switch (folder_depth) { case 0: /* artist - album - number - title */ file = g_strdup_printf ("%s - %s - %s - %s%s", artist, album, number, title, ext); break; case 1: /* artist - album/number - title */ file = g_strdup_printf ("%s - %s" G_DIR_SEPARATOR_S "%s - %s%s", artist, album, number, title, ext); break; default: /* use this for players that don't care */ case 2: /* artist/album/number - title */ file = g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s" G_DIR_SEPARATOR_S "%s - %s%s", artist, album, number, title, ext); break; } g_free (number); } g_free (artist); g_free (album); g_free (title); g_free (ext); if (file == NULL) return NULL; g_object_get (priv->device_info, "audio-folders", &audio_folders, NULL); if (audio_folders != NULL && g_strv_length (audio_folders) > 0) { folders = g_strdup (audio_folders[0]); } else { folders = ""; } g_strfreev (audio_folders); mount_path = rb_generic_player_source_get_mount_path (RB_GENERIC_PLAYER_SOURCE (source)); path = g_build_filename (mount_path, folders, file, NULL); g_free (file); g_free (mount_path); /* TODO: check for duplicates, or just overwrite by default? */ rb_debug ("dest file is %s", path); return path; }