mirror of
https://github.com/markuryy/shark.git
synced 2026-06-18 18:41:03 +00:00
feat: re-encode cover images for rockbox compatibility
This commit is contained in:
@@ -37,6 +37,14 @@ fn read_audio_metadata(path: String) -> Result<metadata::AudioMetadata, String>
|
|||||||
metadata::read_audio_metadata(&path)
|
metadata::read_audio_metadata(&path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Re-encode cover image as baseline JPEG for broad player compatibility
|
||||||
|
#[tauri::command]
|
||||||
|
async fn reencode_cover_image(data: Vec<u8>, quality: u8) -> Result<Vec<u8>, String> {
|
||||||
|
tauri::async_runtime::spawn_blocking(move || tagger::reencode_cover_image(&data, quality))
|
||||||
|
.await
|
||||||
|
.map_err(|e| format!("Re-encode task failed: {}", e))?
|
||||||
|
}
|
||||||
|
|
||||||
/// Decrypt Deezer track data (legacy - kept for backwards compatibility)
|
/// Decrypt Deezer track data (legacy - kept for backwards compatibility)
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
async fn decrypt_deezer_track(data: Vec<u8>, track_id: String) -> Result<Vec<u8>, String> {
|
async fn decrypt_deezer_track(data: Vec<u8>, track_id: String) -> Result<Vec<u8>, String> {
|
||||||
@@ -405,6 +413,7 @@ pub fn run() {
|
|||||||
greet,
|
greet,
|
||||||
tag_audio_file,
|
tag_audio_file,
|
||||||
read_audio_metadata,
|
read_audio_metadata,
|
||||||
|
reencode_cover_image,
|
||||||
decrypt_deezer_track,
|
decrypt_deezer_track,
|
||||||
download_and_decrypt_track,
|
download_and_decrypt_track,
|
||||||
device_sync::index_and_compare,
|
device_sync::index_and_compare,
|
||||||
|
|||||||
@@ -2,8 +2,10 @@ use id3::{
|
|||||||
frame::{Picture, PictureType},
|
frame::{Picture, PictureType},
|
||||||
Tag as ID3Tag, TagLike, Version,
|
Tag as ID3Tag, TagLike, Version,
|
||||||
};
|
};
|
||||||
|
use image::codecs::jpeg::JpegEncoder;
|
||||||
use metaflac::Tag as FlacTag;
|
use metaflac::Tag as FlacTag;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::io::Cursor;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
/// Metadata structure for audio file tagging
|
/// Metadata structure for audio file tagging
|
||||||
@@ -356,3 +358,20 @@ fn detect_mime_type_str(data: &[u8]) -> &'static str {
|
|||||||
"image/jpeg"
|
"image/jpeg"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Re-encode image data as a baseline (non-progressive) JPEG in sRGB.
|
||||||
|
/// This ensures compatibility with players like Rockbox that can't
|
||||||
|
/// decode progressive JPEGs or non-sRGB colorspaces.
|
||||||
|
pub fn reencode_cover_image(data: &[u8], quality: u8) -> Result<Vec<u8>, String> {
|
||||||
|
let img = image::load_from_memory(data)
|
||||||
|
.map_err(|e| format!("Failed to decode image: {}", e))?;
|
||||||
|
|
||||||
|
let rgb = img.to_rgb8();
|
||||||
|
|
||||||
|
let mut buf = Cursor::new(Vec::new());
|
||||||
|
let encoder = JpegEncoder::new_with_quality(&mut buf, quality);
|
||||||
|
rgb.write_with_encoder(encoder)
|
||||||
|
.map_err(|e| format!("Failed to encode JPEG: {}", e))?;
|
||||||
|
|
||||||
|
Ok(buf.into_inner())
|
||||||
|
}
|
||||||
|
|||||||
@@ -87,14 +87,20 @@ export async function downloadTrack(
|
|||||||
// Get user settings
|
// Get user settings
|
||||||
const appSettings = get(settings);
|
const appSettings = get(settings);
|
||||||
|
|
||||||
// Download cover art if enabled
|
// Download cover art if enabled, re-encode as baseline JPEG for player compatibility
|
||||||
let coverData: Uint8Array | undefined;
|
let coverData: Uint8Array | undefined;
|
||||||
if ((appSettings.embedCoverArt || appSettings.saveCoverToFolder) && track.albumCoverUrl) {
|
if ((appSettings.embedCoverArt || appSettings.saveCoverToFolder) && track.albumCoverUrl) {
|
||||||
try {
|
try {
|
||||||
console.log('Downloading cover art...');
|
console.log('Downloading cover art...');
|
||||||
coverData = await downloadCover(track.albumCoverUrl);
|
const rawCover = await downloadCover(track.albumCoverUrl);
|
||||||
|
const reencoded = await invoke<number[]>('reencode_cover_image', {
|
||||||
|
data: Array.from(rawCover),
|
||||||
|
quality: appSettings.coverImageQuality
|
||||||
|
});
|
||||||
|
coverData = new Uint8Array(reencoded);
|
||||||
|
console.log(`[ImageDownload] Re-encoded cover: ${rawCover.length} -> ${coverData.length} bytes (q=${appSettings.coverImageQuality})`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('Failed to download cover art:', error);
|
console.warn('Failed to download/re-encode cover art:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user