[READ-ONLY] Mirror of https://github.com/probablykasper/ferrum. Music library app for Mac, Linux and Windows ferrum.kasper.space
electron linux macos music music-library music-player napi windows
0

Configure Feed

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

Simple async fn for read_cover_async

Kasper (Sep 15, 2025, 8:33 AM +0200) 2893a6e3 07d26575

+16 -56
+1 -5
ferrum-addon/addon.d.ts
··· 123 123 124 124 export declare function playlist_filter_duplicates(playlistId: TrackID, ids: Array<string>): Array<TrackID> 125 125 126 - export declare function read_cover_async(trackId: string, index: number): Promise<ReadCoverResult> 126 + export declare function read_cover_async(filePath: string, index: number): Promise<Buffer | null> 127 127 128 128 /** Returns `None` if the file does not have an image */ 129 129 export declare function read_small_cover_async(path: string, index: number, cacheDbPath: string): Promise<Buffer | null> 130 - 131 - export type ReadCoverResult = 132 - | { type: 'Ok', field0?: Buffer } 133 - | { type: 'Err', field0: string } 134 130 135 131 export declare function remove_from_playlist(playlistId: TrackID, itemIds: Array<ItemId>): void 136 132
+9 -39
src-native/tracks/cover.rs
··· 216 216 Ok(img_bytes) 217 217 } 218 218 219 - // This enum is now exposed to JavaScript 220 - #[napi] 221 - pub enum ReadCoverResult { 222 - Ok(Option<Buffer>), 223 - Err(String), 224 - } 225 - 226 - #[napi( 227 - js_name = "read_cover_async", 228 - ts_return_type = "Promise<ReadCoverResult>" 229 - )] 219 + #[napi(js_name = "read_cover_async")] 230 220 #[allow(dead_code)] 231 - pub fn read_cover_async<'env>( 232 - track_id: String, 233 - index: u16, 234 - env: &'env Env, 235 - ) -> Result<PromiseRaw<'env, ReadCoverResult>> { 236 - let data = get_data(&env); 237 - let track = id_to_track(&env, &track_id).expect("Track ID not found"); 238 - 239 - let tracks_dir = &data.paths.tracks_dir; 240 - let file_path = tracks_dir.join(&track.file); 241 - 242 - let result = env 243 - .spawn_future(async move { 244 - let tag = match Tag::read_from_path(&file_path) { 245 - Ok(tag) => tag, 246 - Err(err) => return Ok(ReadCoverResult::Err(err.to_string())), 247 - }; 248 - let image = match tag.get_image_consume(index.into()) { 249 - Ok(Some(image)) => image, 250 - Ok(None) => { 251 - return Ok(ReadCoverResult::Ok(None)); 252 - } 253 - Err(err) => return Ok(ReadCoverResult::Err(err.to_string())), 254 - }; 255 - Ok(ReadCoverResult::Ok(Some(Buffer::from(image.data)))) 256 - }) 257 - .context("Failed to spawn async future")?; 258 - Ok(result) 221 + pub async fn read_cover_async(file_path: String, index: u16) -> Result<Option<Buffer>> { 222 + let file_path = PathBuf::from(file_path); 223 + let tag = Tag::read_from_path(&file_path)?; 224 + let image = match tag.get_image_consume(index.into())? { 225 + Some(image) => image, 226 + None => return Ok(None), 227 + }; 228 + Ok(Some(Buffer::from(image.data))) 259 229 }
+2 -5
src/lib/data.ts
··· 199 199 save() 200 200 }) 201 201 } 202 - export function read_cover_async(id: TrackID, index: number) { 203 - return inner_addon.read_cover_async(id, index).catch((error) => { 204 - console.log('Could not read cover', error) 205 - throw error 206 - }) 202 + export function read_cover_async(file_path: string, index: number) { 203 + return inner_addon.read_cover_async(file_path, index) 207 204 } 208 205 export function update_track_info(id: TrackID, md: TrackMd) { 209 206 strict_call((data) => data.update_track_info(id, md))
+4 -7
src/lib/player.ts
··· 91 91 return { 92 92 async newFromTrackId(id: TrackID) { 93 93 try { 94 - const result = await read_cover_async(id, 0) 95 - if (result.type === 'Err') { 94 + const file_path = join_paths(paths.tracksDir, get_track(id).file) 95 + const result = await read_cover_async(file_path, 0) 96 + if (!result) { 96 97 set(null) 97 - return 98 - } else if (!result.field0) { 99 - set(null) 100 - return 101 98 } else { 102 99 // this should be zero-copy 103 - const uint8 = new Uint8Array(result.field0) 100 + const uint8 = new Uint8Array(result) 104 101 // Blob() does copy 105 102 const url = URL.createObjectURL(new Blob([uint8], {})) 106 103 set(url)