Rockbox open source high quality audio player as a Music Player Daemon
mpris rockbox mpd libadwaita audio rust zig deno
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add is_remote to tracks and exclude remotes

Add migration to add an is_remote column and flag HTTP/HTTPS paths.
Run the migration at DB pool creation (no-op if the column exists).
Propagate is_remote when saving audio/stream metadata and add the
field to Track. Update repo queries to exclude remote tracks and only
surface albums/artists with non-remote tracks.

+42 -17
+2
crates/library/migrations/20260428000000_add_is_remote_to_track.sql
··· 1 + ALTER TABLE track ADD COLUMN is_remote INTEGER NOT NULL DEFAULT 0; 2 + UPDATE track SET is_remote = 1 WHERE path LIKE 'http://%' OR path LIKE 'https://%';
+2
crates/library/src/audio_scan.rs
··· 225 225 artist_id: artist_id.clone(), 226 226 album_id: album_id.clone(), 227 227 album_art, 228 + is_remote: is_remote_path(path), 228 229 ..Default::default() 229 230 }, 230 231 ) ··· 323 324 album_id: album_id.clone(), 324 325 created_at: Utc::now(), 325 326 updated_at: Utc::now(), 327 + is_remote: is_remote_path(url), 326 328 ..Default::default() 327 329 }, 328 330 )
+1
crates/library/src/entity/track.rs
··· 29 29 pub artist_id: String, 30 30 pub album_id: String, 31 31 pub genre_id: String, 32 + pub is_remote: bool, 32 33 #[serde(with = "chrono::serde::ts_seconds")] 33 34 pub created_at: DateTime<Utc>, 34 35 #[serde(with = "chrono::serde::ts_seconds")]
+10
crates/library/src/lib.rs
··· 85 85 Err(_) => println!("playlist tables already exist"), 86 86 } 87 87 88 + match pool 89 + .execute(include_str!( 90 + "../migrations/20260428000000_add_is_remote_to_track.sql" 91 + )) 92 + .await 93 + { 94 + Ok(_) => {} 95 + Err(_) => println!("is_remote column already exists"), 96 + } 97 + 88 98 sqlx::query("PRAGMA journal_mode=WAL") 89 99 .execute(&pool) 90 100 .await?;
+6 -2
crates/library/src/repo/album.rs
··· 81 81 ) -> Result<Vec<Album>, sqlx::Error> { 82 82 match sqlx::query_as::<_, Album>( 83 83 r#" 84 - SELECT * FROM album WHERE artist_id = $1 ORDER BY title ASC 84 + SELECT * FROM album WHERE artist_id = $1 AND EXISTS ( 85 + SELECT 1 FROM track WHERE track.album_id = album.id AND track.is_remote = 0 86 + ) ORDER BY title ASC 85 87 "#, 86 88 ) 87 89 .bind(artist_id) ··· 117 119 pub async fn all(pool: Pool<Sqlite>) -> Result<Vec<Album>, sqlx::Error> { 118 120 match sqlx::query_as::<_, Album>( 119 121 r#" 120 - SELECT * FROM album ORDER BY title ASC 122 + SELECT * FROM album WHERE EXISTS ( 123 + SELECT 1 FROM track WHERE track.album_id = album.id AND track.is_remote = 0 124 + ) ORDER BY title ASC 121 125 "#, 122 126 ) 123 127 .fetch_all(&pool)
+3 -1
crates/library/src/repo/artist.rs
··· 88 88 pub async fn all(pool: Pool<Sqlite>) -> Result<Vec<Artist>, Error> { 89 89 match sqlx::query_as::<_, Artist>( 90 90 r#" 91 - SELECT * FROM artist ORDER BY name ASC 91 + SELECT * FROM artist WHERE EXISTS ( 92 + SELECT 1 FROM track WHERE track.artist_id = artist.id AND track.is_remote = 0 93 + ) ORDER BY name ASC 92 94 "#, 93 95 ) 94 96 .fetch_all(&pool)
+18 -14
crates/library/src/repo/track.rs
··· 26 26 updated_at, 27 27 artist_id, 28 28 album_id, 29 - album_art 29 + album_art, 30 + is_remote 30 31 ) 31 - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22) 32 + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23) 32 33 "#, 33 34 ) 34 35 .bind(&track.id) ··· 53 54 .bind(&track.artist_id) 54 55 .bind(&track.album_id) 55 56 .bind(&track.album_art) 57 + .bind(track.is_remote) 56 58 .execute(&pool) 57 59 .await { 58 60 Ok(_) => Ok(track.id.clone()), ··· 76 78 pool: Pool<Sqlite>, 77 79 r#where: (String, Vec<String>), 78 80 ) -> Result<Vec<Track>, Error> { 79 - let sql = format!("SELECT * FROM track WHERE {}", r#where.0); 81 + let sql = format!("SELECT * FROM track WHERE is_remote = 0 AND {}", r#where.0); 80 82 let mut query = sqlx::query_as(&sql); 81 83 82 84 for value in r#where.1 { ··· 104 106 } 105 107 106 108 pub async fn all(pool: Pool<Sqlite>) -> Result<Vec<Track>, Error> { 107 - let result: Vec<Track> = sqlx::query_as("SELECT * FROM track ORDER BY title ASC") 108 - .fetch_all(&pool) 109 - .await?; 109 + let result: Vec<Track> = 110 + sqlx::query_as("SELECT * FROM track WHERE is_remote = 0 ORDER BY title ASC") 111 + .fetch_all(&pool) 112 + .await?; 110 113 Ok(result) 111 114 } 112 115 ··· 120 123 } 121 124 122 125 pub async fn find_by_artist(pool: Pool<Sqlite>, artist: &str) -> Result<Vec<Track>, Error> { 123 - let result: Vec<Track> = 124 - sqlx::query_as("SELECT * FROM track WHERE artist = $1 ORDER BY title ASC") 125 - .bind(artist) 126 - .fetch_all(&pool) 127 - .await?; 126 + let result: Vec<Track> = sqlx::query_as( 127 + "SELECT * FROM track WHERE is_remote = 0 AND artist = $1 ORDER BY title ASC", 128 + ) 129 + .bind(artist) 130 + .fetch_all(&pool) 131 + .await?; 128 132 Ok(result) 129 133 } 130 134 131 135 pub async fn find_by_album(pool: Pool<Sqlite>, album: &str) -> Result<Vec<Track>, Error> { 132 136 let result: Vec<Track> = 133 - sqlx::query_as("SELECT * FROM track WHERE album = $1 ORDER BY title ASC") 137 + sqlx::query_as("SELECT * FROM track WHERE is_remote = 0 AND album = $1 ORDER BY title ASC") 134 138 .bind(album) 135 139 .fetch_all(&pool) 136 140 .await?; ··· 139 143 140 144 pub async fn find_by_title(pool: Pool<Sqlite>, title: &str) -> Result<Vec<Track>, Error> { 141 145 let result: Vec<Track> = 142 - sqlx::query_as("SELECT * FROM track WHERE title = $1 ORDER BY title ASC") 146 + sqlx::query_as("SELECT * FROM track WHERE is_remote = 0 AND title = $1 ORDER BY title ASC") 143 147 .bind(title) 144 148 .fetch_all(&pool) 145 149 .await?; ··· 184 188 date: &str, 185 189 ) -> Result<Vec<Track>, Error> { 186 190 let result: Vec<Track> = sqlx::query_as( 187 - "SELECT * FROM track WHERE artist = $1 AND album = $2 AND year_string = $3 ORDER BY title ASC", 191 + "SELECT * FROM track WHERE is_remote = 0 AND artist = $1 AND album = $2 AND year_string = $3 ORDER BY title ASC", 188 192 ) 189 193 .bind(artist) 190 194 .bind(album)