void
rb_generic_player_source_trash_or_delete_entries (RBGenericPlayerSource *source,
						  GList *entries,
						  gboolean _delete)
{
	RBGenericPlayerSourcePrivate *priv = GENERIC_PLAYER_SOURCE_GET_PRIVATE (source);
	GList *tem;

	if (priv->read_only != FALSE)
		return;

	for (tem = entries; tem != NULL; tem = tem->next) {
		RhythmDBEntry *entry;
		const char *uri;
		GFile *file;
		GFile *dir;

		entry = tem->data;
		uri = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
		file = g_file_new_for_uri (uri);
		if (_delete)
			g_file_delete (file, NULL, NULL);
		else
			g_file_trash (file, NULL, NULL);

		/* now walk up the directory structure and delete empty dirs
		 * until we reach the root or one of the device's audio folders.
		 */
		dir = g_file_get_parent (file);
		while (can_delete_directory (source, dir)) {
			GFile *parent;
			char *path;

			path = g_file_get_path (dir);
			rb_debug ("trying to delete %s", path);
			g_free (path);

			if (g_file_delete (dir, NULL, NULL) == FALSE) {
				break;
			}

			parent = g_file_get_parent (dir);
			if (parent == NULL) {
				break;
			}
			g_object_unref (dir);
			dir = parent;
		}

		g_object_unref (dir);
		g_object_unref (file);

		rhythmdb_entry_delete (priv->db, entry);
	}

	rhythmdb_commit (priv->db);
}
Beispiel #2
0
END_TEST

START_TEST (test_rhythmdb_multiple)
{
	RhythmDBEntry *entry1, *entry2, *entry3;

	/* add multiple entries */
	entry1 = rhythmdb_entry_new (db, RHYTHMDB_ENTRY_TYPE_IGNORE, "file:///foo.mp3");
	rhythmdb_commit (db);
	fail_unless (entry1 != NULL, "failed to create entry");
	fail_unless (rhythmdb_entry_lookup_by_location (db, "file:///foo.mp3") == entry1, "entry missing");

	entry2 = rhythmdb_entry_new (db, RHYTHMDB_ENTRY_TYPE_IGNORE, "file:///bar.mp3");
	rhythmdb_commit (db);
	fail_unless (entry2 != NULL, "failed to create entry");
	fail_unless (rhythmdb_entry_lookup_by_location (db, "file:///bar.mp3") == entry2, "entry missing");

	entry3 = rhythmdb_entry_new (db, RHYTHMDB_ENTRY_TYPE_IGNORE, "file:///baz.mp3");
	rhythmdb_commit (db);
	fail_unless (entry3 != NULL, "failed to create entry");
	fail_unless (rhythmdb_entry_lookup_by_location (db, "file:///baz.mp3") == entry3, "entry missing");

	/* check they're still there */
	fail_unless (rhythmdb_entry_lookup_by_location (db, "file:///foo.mp3") == entry1, "entry missing");
	fail_unless (rhythmdb_entry_lookup_by_location (db, "file:///bar.mp3") == entry2, "entry missing");
	fail_unless (rhythmdb_entry_lookup_by_location (db, "file:///baz.mp3") == entry3, "entry missing");

	/* remove the middle one and check again */
	rhythmdb_entry_delete (db, entry2);
	rhythmdb_commit (db);

	fail_unless (rhythmdb_entry_lookup_by_location (db, "file:///foo.mp3") == entry1, "entry missing");
	fail_unless (rhythmdb_entry_lookup_by_location (db, "file:///bar.mp3") == NULL, "entry not deleted");
	fail_unless (rhythmdb_entry_lookup_by_location (db, "file:///baz.mp3") == entry3, "entry missing");

	/* and the others */
	rhythmdb_entry_delete (db, entry1);
	rhythmdb_entry_delete (db, entry3);
	rhythmdb_commit (db);

	fail_unless (rhythmdb_entry_lookup_by_location (db, "file:///foo.mp3") == NULL, "entry not deleted");
	fail_unless (rhythmdb_entry_lookup_by_location (db, "file:///bar.mp3") == NULL, "entry not deleted");
	fail_unless (rhythmdb_entry_lookup_by_location (db, "file:///baz.mp3") == NULL, "entry not deleted");
}
Beispiel #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);
}
Beispiel #4
0
static void
copy_track_done_cb (RBTrackTransferBatch *batch,
		    RhythmDBEntry *entry,
		    const char *dest,
		    guint64 dest_size,
		    const char *mediatype,
		    GError *error,
		    RBImportDialog *dialog)
{
	rhythmdb_entry_delete (dialog->priv->db, entry);
	rhythmdb_commit (dialog->priv->db);
}
static void
impl_delete (RBSource *asource)
{
	RBImportErrorsSource *source = RB_IMPORT_ERRORS_SOURCE (asource);
	GList *sel, *tem;

	sel = rb_entry_view_get_selected_entries (source->priv->view);
	for (tem = sel; tem != NULL; tem = tem->next) {
		rhythmdb_entry_delete (source->priv->db, tem->data);
		rhythmdb_commit (source->priv->db);
	}

	g_list_foreach (sel, (GFunc)rhythmdb_entry_unref, NULL);
	g_list_free (sel);
}
static void
impl_delete_selected (RBSource *asource)
{
	RBMissingFilesSource *source = RB_MISSING_FILES_SOURCE (asource);
	GList *sel, *tem;

	sel = rb_entry_view_get_selected_entries (source->priv->view);
	for (tem = sel; tem != NULL; tem = tem->next) {
		rhythmdb_entry_delete (source->priv->db, tem->data);
		rhythmdb_commit (source->priv->db);
	}

	g_list_foreach (sel, (GFunc)rhythmdb_entry_unref, NULL);
	g_list_free (sel);
}
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
impl_delete (RBSource *asource)
{
	RBIRadioSource *source = RB_IRADIO_SOURCE (asource);
	GList *sel;
	GList *l;

	sel = rb_entry_view_get_selected_entries (source->priv->stations);
	for (l = sel; l != NULL; l = g_list_next (l)) {
		rhythmdb_entry_delete (source->priv->db, l->data);
		rhythmdb_commit (source->priv->db);
	}

	g_list_foreach (sel, (GFunc)rhythmdb_entry_unref, NULL);
	g_list_free (sel);
}
static void
missing_plugins_retry_cb (gpointer instance, gboolean installed, RhythmDBImportJob *job)
{
	GSList *retry = NULL;
	GSList *i;

	g_mutex_lock (&job->priv->lock);
	g_assert (job->priv->retried == FALSE);
	if (installed == FALSE) {
		rb_debug ("plugin installation was not successful; job complete");
		g_signal_emit (job, signals[COMPLETE], 0, job->priv->total);
	} else {
		job->priv->retried = TRUE;

		/* reset the job state to just show the retry information */
		job->priv->total = g_slist_length (job->priv->retry_entries);
		rb_debug ("plugin installation was successful, retrying %d entries", job->priv->total);
		job->priv->imported = 0;

		/* remove the import error entries and build the list of URIs to retry */
		for (i = job->priv->retry_entries; i != NULL; i = i->next) {
			RhythmDBEntry *entry = (RhythmDBEntry *)i->data;
			char *uri;

			uri = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_LOCATION);
			rhythmdb_entry_delete (job->priv->db, entry);

			g_hash_table_insert (job->priv->outstanding, g_strdup (uri), GINT_TO_POINTER (1));
			retry = g_slist_prepend (retry, uri);
		}
		rhythmdb_commit (job->priv->db);
		retry = g_slist_reverse (retry);
	}
	g_mutex_unlock (&job->priv->lock);

	for (i = retry; i != NULL; i = i->next) {
		char *uri = (char *)i->data;

		rhythmdb_add_uri_with_types (job->priv->db,
					     uri,
					     job->priv->entry_type,
					     job->priv->ignore_type,
					     job->priv->error_type);
	}

	rb_slist_deep_free (retry);
}
Beispiel #10
0
END_TEST

START_TEST (test_rhythmdb_modify_after_delete)
{
	RhythmDBEntry *entry;
	GValue val = {0,};

	entry = rhythmdb_entry_new (db, RHYTHMDB_ENTRY_TYPE_IGNORE, "file:///whee.ogg");
	fail_unless (entry != NULL, "failed to create entry");

	g_value_init (&val, G_TYPE_STRING);
	g_value_set_static_string (&val, "Anything");
	rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_GENRE, &val);
	g_value_unset (&val);
	
	g_value_init (&val, G_TYPE_STRING);
	g_value_set_static_string (&val, "Nothing");
	rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_ARTIST, &val);
	g_value_unset (&val);
	
	g_value_init (&val, G_TYPE_STRING);
	g_value_set_static_string (&val, "Something");
	rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_ALBUM, &val);
	g_value_unset (&val);
	
	g_value_init (&val, G_TYPE_STRING);
	g_value_set_static_string (&val, "Thing");
	rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_TITLE, &val);
	g_value_unset (&val);

	rhythmdb_commit (db);
	rhythmdb_entry_ref (entry);

	rhythmdb_entry_delete (db, entry);
	rhythmdb_commit (db);
	
	g_value_init (&val, G_TYPE_STRING);
	g_value_set_static_string (&val, "Something Else");
	rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_ALBUM, &val);
	g_value_unset (&val);
	
	rhythmdb_commit (db);
	rhythmdb_entry_unref (entry);
}
static void
delete_entries (RBAndroidSource *source, GList *entries)
{
	RBAndroidSourcePrivate *priv = GET_PRIVATE (source);
	GList *tem;

	for (tem = entries; tem != NULL; tem = tem->next) {
		RhythmDBEntry *entry;
		const char *uri;
		GFile *file;
		GFile *dir;

		entry = tem->data;
		uri = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
		file = g_file_new_for_uri (uri);
		g_file_delete (file, NULL, NULL);

		/* now walk up the directory structure and delete empty dirs
		 * until we reach the root or one of the device's audio folders.
		 */
		dir = g_file_get_parent (file);
		while (can_delete_directory (source, dir)) {
			GFile *parent;

			if (g_file_delete (dir, NULL, NULL) == FALSE) {
				break;
			}

			parent = g_file_get_parent (dir);
			if (parent == NULL) {
				break;
			}
			g_object_unref (dir);
			dir = parent;
		}

		g_object_unref (dir);
		g_object_unref (file);

		rhythmdb_entry_delete (priv->db, entry);
	}

	rhythmdb_commit (priv->db);
}
static void
song_update_availability (RhythmDBEntryType *entry_type,
			  RhythmDBEntry *entry,
			  RhythmDBEntryAvailability avail)
{
	RhythmDB *db;

	g_object_get (entry_type, "db", &db, NULL);
	switch (avail) {
	case RHYTHMDB_ENTRY_AVAIL_MOUNTED:
		rhythmdb_entry_set_visibility (db, entry, TRUE);
		break;

	case RHYTHMDB_ENTRY_AVAIL_CHECKED:
		update_entry_last_seen (db, entry);
		rhythmdb_entry_set_visibility (db, entry, TRUE);
		break;

	case RHYTHMDB_ENTRY_AVAIL_UNMOUNTED:
		/* update the last-seen time if the entry is currently visible */
		if (rhythmdb_entry_get_boolean (entry, RHYTHMDB_PROP_HIDDEN) == FALSE) {
			update_entry_last_seen (db, entry);
		}
		rhythmdb_entry_set_visibility (db, entry, FALSE);
		break;

	case RHYTHMDB_ENTRY_AVAIL_NOT_FOUND:
		if (check_entry_grace_period (db, entry)) {
			rb_debug ("deleting entry %s; not seen for too long",
				  rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION));
			rhythmdb_entry_delete (db, entry);
		} else {
			rhythmdb_entry_set_visibility (db, entry, FALSE);
		}
		break;

	default:
		g_assert_not_reached ();
	}
	g_object_unref (db);
}
static void
missing_plugins_retry_cb (gpointer instance, gboolean installed, RhythmDBImportJob *job)
{
	GSList *i;

	g_mutex_lock (&job->priv->lock);
	g_assert (job->priv->retried == FALSE);
	if (installed == FALSE) {
		rb_debug ("plugin installation was not successful; job complete");
		job->priv->complete = TRUE;
		g_signal_emit (job, signals[COMPLETE], 0, job->priv->total);
		g_object_notify (G_OBJECT (job), "task-outcome");
	} else {
		job->priv->retried = TRUE;

		/* reset the job state to just show the retry information */
		job->priv->total = g_slist_length (job->priv->retry_entries);
		rb_debug ("plugin installation was successful, retrying %d entries", job->priv->total);
		job->priv->processed = 0;

		/* remove the import error entries and build the list of URIs to retry */
		for (i = job->priv->retry_entries; i != NULL; i = i->next) {
			RhythmDBEntry *entry = (RhythmDBEntry *)i->data;
			char *uri;

			uri = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_LOCATION);
			rhythmdb_entry_delete (job->priv->db, entry);

			g_queue_push_tail (job->priv->outstanding, g_strdup (uri));
		}
		rhythmdb_commit (job->priv->db);
	}

	maybe_start_more (job);

	g_mutex_unlock (&job->priv->lock);
}
static void
import_error_update_availability (RhythmDBEntryType *entry_type,
				  RhythmDBEntry *entry,
				  RhythmDBEntryAvailability avail)
{
	RhythmDB *db;

	switch (avail) {
	case RHYTHMDB_ENTRY_AVAIL_MOUNTED:
	case RHYTHMDB_ENTRY_AVAIL_CHECKED:
		/* do nothing; should never happen anyway */
		break;
	case RHYTHMDB_ENTRY_AVAIL_UNMOUNTED:
	case RHYTHMDB_ENTRY_AVAIL_NOT_FOUND:
		/* no need to keep error entries if the file is unavailable */
		g_object_get (entry_type, "db", &db, NULL);
		rhythmdb_entry_delete (db, entry);
		g_object_unref (db);
		break;

	default:
		g_assert_not_reached ();
	}
}
END_TEST

/* this tests that chained query models, where the base shows hidden entries
 * forwards visibility changes correctly. This is basically what static playlists do */
START_TEST (test_hidden_chain_filter)
{
	RhythmDBQueryModel *base_model;
	RhythmDBQueryModel *filter_model;
	RhythmDBQuery *query;
	RhythmDBEntry *entry;
	GtkTreeIter iter;
	GValue val = {0,};

	start_test_case ();

	/* setup */
	base_model = rhythmdb_query_model_new_empty (db);
	g_object_set (base_model, "show-hidden", TRUE, NULL);

	filter_model = rhythmdb_query_model_new_empty (db);
	g_object_set (filter_model, "base-model", base_model, NULL);
	query = g_ptr_array_new ();
	g_object_set (filter_model, "query", query, NULL);
	rhythmdb_query_free (query);

	entry = rhythmdb_entry_new (db, RHYTHMDB_ENTRY_TYPE_IGNORE, "file:///whee.ogg");
	rhythmdb_commit (db);

	g_value_init (&val, G_TYPE_BOOLEAN);


	/* add entry to base, should be in both */
	rhythmdb_query_model_add_entry (base_model, entry, -1);
	fail_unless (rhythmdb_query_model_entry_to_iter (base_model, entry, &iter));
	fail_unless (rhythmdb_query_model_entry_to_iter (filter_model, entry, &iter));

	end_step ();

	/* hide entry, should be in base and not filtered */
	g_value_set_boolean (&val, TRUE);
	set_waiting_signal (G_OBJECT (db), "entry-changed");
	rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_HIDDEN, &val);
	rhythmdb_commit (db);
	wait_for_signal ();

	fail_unless (rhythmdb_query_model_entry_to_iter (base_model, entry, &iter));
	fail_if (rhythmdb_query_model_entry_to_iter (filter_model, entry, &iter));

	end_step ();

	/* show entry again, should be in both */
	g_value_set_boolean (&val, FALSE);
	set_waiting_signal (G_OBJECT (db), "entry-changed");
	rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_HIDDEN, &val);
	rhythmdb_commit (db);
	wait_for_signal ();

	fail_unless (rhythmdb_query_model_entry_to_iter (base_model, entry, &iter));
	fail_unless (rhythmdb_query_model_entry_to_iter (filter_model, entry, &iter));

	end_step ();

	/* tidy up */
	rhythmdb_entry_delete (db, entry);
	g_object_unref (base_model);
	g_object_unref (filter_model);
	g_value_unset (&val);

	end_test_case ();
}