From cc42f8ecbbb424393e8e76ccab4b0fe2d4164736 Mon Sep 17 00:00:00 2001 From: Connor Johnstone Date: Tue, 24 Mar 2026 15:58:14 -0400 Subject: [PATCH] Added the import/cleanup functionality --- src/queries/albums.rs | 26 ++++++++++++++++++++++++++ src/queries/artists.rs | 39 +++++++++++++++++++++++++++++++++++++++ src/queries/tracks.rs | 21 +++++++++++++++++++++ src/queries/wanted.rs | 16 ++++++++++++++++ 4 files changed, 102 insertions(+) diff --git a/src/queries/albums.rs b/src/queries/albums.rs index fc681a2..11b740e 100644 --- a/src/queries/albums.rs +++ b/src/queries/albums.rs @@ -94,3 +94,29 @@ pub async fn delete(db: &DatabaseConnection, id: i32) -> DbResult<()> { Albums::delete_by_id(id).exec(db).await?; Ok(()) } + +pub async fn delete_by_artist(db: &DatabaseConnection, artist_id: i32) -> DbResult { + let result = Albums::delete_many() + .filter(album::Column::ArtistId.eq(artist_id)) + .exec(db) + .await?; + Ok(result.rows_affected) +} + +/// Delete albums that have no tracks referencing them. +pub async fn delete_empty(db: &DatabaseConnection) -> DbResult { + let all = Albums::find().all(db).await?; + let mut deleted = 0u64; + for a in all { + let has_tracks = crate::entities::track::Entity::find() + .filter(crate::entities::track::Column::AlbumId.eq(a.id)) + .count(db) + .await? + > 0; + if !has_tracks { + Albums::delete_by_id(a.id).exec(db).await?; + deleted += 1; + } + } + Ok(deleted) +} diff --git a/src/queries/artists.rs b/src/queries/artists.rs index e04ed56..8c74eeb 100644 --- a/src/queries/artists.rs +++ b/src/queries/artists.rs @@ -127,6 +127,45 @@ pub async fn list_monitored(db: &DatabaseConnection) -> DbResult> { .await?) } +/// Delete artists that have no tracks, no wanted items, no albums, and are not monitored. +pub async fn delete_unused(db: &DatabaseConnection) -> DbResult { + let conn = db; + let all = Artists::find().all(conn).await?; + let mut deleted = 0u64; + for a in all { + if a.monitored { + continue; + } + let has_tracks = crate::entities::track::Entity::find() + .filter(crate::entities::track::Column::ArtistId.eq(a.id)) + .count(conn) + .await? + > 0; + if has_tracks { + continue; + } + let has_wanted = crate::entities::wanted_item::Entity::find() + .filter(crate::entities::wanted_item::Column::ArtistId.eq(a.id)) + .count(conn) + .await? + > 0; + if has_wanted { + continue; + } + let has_albums = crate::entities::album::Entity::find() + .filter(crate::entities::album::Column::ArtistId.eq(a.id)) + .count(conn) + .await? + > 0; + if has_albums { + continue; + } + Artists::delete_by_id(a.id).exec(conn).await?; + deleted += 1; + } + Ok(deleted) +} + pub async fn update_last_checked(db: &DatabaseConnection, id: i32) -> DbResult { let existing = get_by_id(db, id).await?; let mut active: ActiveModel = existing.into(); diff --git a/src/queries/tracks.rs b/src/queries/tracks.rs index bc5e7da..ac14057 100644 --- a/src/queries/tracks.rs +++ b/src/queries/tracks.rs @@ -175,6 +175,27 @@ pub async fn get_recent(db: &DatabaseConnection, days: u32, limit: u64) -> DbRes .await?) } +pub async fn delete_by_artist(db: &DatabaseConnection, artist_id: i32) -> DbResult { + let result = Tracks::delete_many() + .filter(track::Column::ArtistId.eq(artist_id)) + .exec(db) + .await?; + Ok(result.rows_affected) +} + +/// Delete tracks whose files no longer exist on disk. +pub async fn delete_orphaned(db: &DatabaseConnection) -> DbResult { + let all = Tracks::find().all(db).await?; + let mut deleted = 0u64; + for t in all { + if !std::path::Path::new(&t.file_path).exists() { + Tracks::delete_by_id(t.id).exec(db).await?; + deleted += 1; + } + } + Ok(deleted) +} + /// Get tracks by artist name (case-insensitive match). pub async fn get_by_artist_name(db: &DatabaseConnection, name: &str) -> DbResult> { Ok(Tracks::find() diff --git a/src/queries/wanted.rs b/src/queries/wanted.rs index 96199ac..3f9d965 100644 --- a/src/queries/wanted.rs +++ b/src/queries/wanted.rs @@ -84,6 +84,22 @@ pub async fn remove(db: &DatabaseConnection, id: i32) -> DbResult<()> { Ok(()) } +pub async fn remove_by_artist(db: &DatabaseConnection, artist_id: i32) -> DbResult { + let result = WantedItems::delete_many() + .filter(wanted_item::Column::ArtistId.eq(artist_id)) + .exec(db) + .await?; + Ok(result.rows_affected) +} + +pub async fn remove_by_mbid(db: &DatabaseConnection, musicbrainz_id: &str) -> DbResult { + let result = WantedItems::delete_many() + .filter(wanted_item::Column::MusicbrainzId.eq(musicbrainz_id)) + .exec(db) + .await?; + Ok(result.rows_affected) +} + /// Promote all Downloaded items to Owned status. Returns the count updated. pub async fn promote_downloaded_to_owned(db: &DatabaseConnection) -> DbResult { let now = Utc::now().naive_utc();