fix(api/pages): fallback CBR→ZIP et CBZ→RAR pour archives mal extensionnées
Même correctif que dans le parsers/indexer : un .cbr qui est en réalité un ZIP (et vice-versa) retourne maintenant la bonne page au lieu d'un 500. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -352,8 +352,8 @@ fn render_page(
|
||||
filter: image::imageops::FilterType,
|
||||
) -> Result<Vec<u8>, ApiError> {
|
||||
let page_bytes = match input_format {
|
||||
"cbz" => extract_cbz_page(abs_path, page_number)?,
|
||||
"cbr" => extract_cbr_page(abs_path, page_number)?,
|
||||
"cbz" => extract_cbz_page(abs_path, page_number, true)?,
|
||||
"cbr" => extract_cbr_page(abs_path, page_number, true)?,
|
||||
"pdf" => render_pdf_page(abs_path, page_number, width)?,
|
||||
_ => return Err(ApiError::bad_request("unsupported source format")),
|
||||
};
|
||||
@@ -361,7 +361,7 @@ fn render_page(
|
||||
transcode_image(&page_bytes, out_format, quality, width, filter)
|
||||
}
|
||||
|
||||
fn extract_cbz_page(abs_path: &str, page_number: u32) -> Result<Vec<u8>, ApiError> {
|
||||
fn extract_cbz_page(abs_path: &str, page_number: u32, allow_fallback: bool) -> Result<Vec<u8>, ApiError> {
|
||||
debug!("Opening CBZ archive: {}", abs_path);
|
||||
let file = std::fs::File::open(abs_path).map_err(|e| {
|
||||
if e.kind() == std::io::ErrorKind::NotFound {
|
||||
@@ -372,10 +372,17 @@ fn extract_cbz_page(abs_path: &str, page_number: u32) -> Result<Vec<u8>, ApiErro
|
||||
}
|
||||
})?;
|
||||
|
||||
let mut archive = zip::ZipArchive::new(file).map_err(|e| {
|
||||
error!("Invalid CBZ archive {}: {}", abs_path, e);
|
||||
ApiError::internal(format!("invalid cbz: {e}"))
|
||||
})?;
|
||||
let mut archive = match zip::ZipArchive::new(file) {
|
||||
Ok(a) => a,
|
||||
Err(zip_err) => {
|
||||
if allow_fallback {
|
||||
warn!("CBZ open failed for {}, trying RAR fallback: {}", abs_path, zip_err);
|
||||
return extract_cbr_page(abs_path, page_number, false);
|
||||
}
|
||||
error!("Invalid CBZ archive {}: {}", abs_path, zip_err);
|
||||
return Err(ApiError::internal(format!("invalid cbz: {zip_err}")));
|
||||
}
|
||||
};
|
||||
|
||||
let mut image_names: Vec<String> = Vec::new();
|
||||
for i in 0..archive.len() {
|
||||
@@ -410,15 +417,22 @@ fn extract_cbz_page(abs_path: &str, page_number: u32) -> Result<Vec<u8>, ApiErro
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
fn extract_cbr_page(abs_path: &str, page_number: u32) -> Result<Vec<u8>, ApiError> {
|
||||
fn extract_cbr_page(abs_path: &str, page_number: u32, allow_fallback: bool) -> Result<Vec<u8>, ApiError> {
|
||||
info!("Opening CBR archive: {}", abs_path);
|
||||
let index = page_number as usize - 1;
|
||||
|
||||
// Pass 1: list all image names (in-process, no subprocess)
|
||||
let mut image_names: Vec<String> = {
|
||||
let archive = unrar::Archive::new(abs_path)
|
||||
.open_for_listing()
|
||||
.map_err(|e| ApiError::internal(format!("unrar listing failed: {}", e)))?;
|
||||
let archive = match unrar::Archive::new(abs_path).open_for_listing() {
|
||||
Ok(a) => a,
|
||||
Err(e) => {
|
||||
if allow_fallback {
|
||||
warn!("CBR open failed for {}, trying ZIP fallback: {}", abs_path, e);
|
||||
return extract_cbz_page(abs_path, page_number, false);
|
||||
}
|
||||
return Err(ApiError::internal(format!("unrar listing failed: {}", e)));
|
||||
}
|
||||
};
|
||||
let mut names = Vec::new();
|
||||
for entry in archive {
|
||||
let entry = entry.map_err(|e| ApiError::internal(format!("unrar entry error: {}", e)))?;
|
||||
|
||||
Reference in New Issue
Block a user