80 findings, not the 14 the first run showed -- clippy stops at the first failing compilation unit, so `--keep-going` is what makes the list complete. 60 were machine-applicable (`cargo clippy --fix`). The rest by hand: * five descending `sort_by` -> `sort_by_key(Reverse(..))` * `chunks_exact(4)` on both sides of four zips, so the compared items stay `[u8; 4]` rather than one array against one slice * three `type` aliases for the census maps and the captured-quad tuple * `&PathBuf` -> `&Path` in two disc tests * two range loops; one of them keeps `#[allow(needless_range_loop)]` with the reason -- the index is into a map's value, which changes each iteration * the module doc list in `invert_capture` re-indented to markdown's rules * `blit`'s eight arguments get `#[allow(too_many_arguments)]`, not a struct One dead `let off = b.len();` in a `ratc` test is dropped rather than renamed. The sibling test at :162 is the one that asserts an offset; if this one was meant to as well, that is a test change and not a lint fix. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
94 lines
3.2 KiB
Rust
94 lines
3.2 KiB
Rust
use std::fs;
|
|
use std::io::{Read, Seek, SeekFrom};
|
|
use std::process::Command;
|
|
use sylpheed_formats::slb;
|
|
fn rg(disc: &str, g: u64, n: usize) -> Vec<u8> {
|
|
let mut segs = vec![];
|
|
let mut cum = 0u64;
|
|
for i in 0..5 {
|
|
let p = format!("{disc}/dat/sound.p{i:02}");
|
|
if let Ok(m) = fs::metadata(&p) {
|
|
segs.push((cum, m.len(), p));
|
|
cum += m.len();
|
|
}
|
|
}
|
|
let mut out = vec![];
|
|
let (mut need, mut pos) = (n, g);
|
|
for (base, len, path) in &segs {
|
|
if need == 0 || pos >= base + len || pos < *base {
|
|
continue;
|
|
}
|
|
let local = pos - base;
|
|
let take = need.min((len - local) as usize);
|
|
let mut f = fs::File::open(path).unwrap();
|
|
f.seek(SeekFrom::Start(local)).unwrap();
|
|
let mut b = vec![0u8; take];
|
|
f.read_exact(&mut b).unwrap();
|
|
out.extend_from_slice(&b);
|
|
need -= take;
|
|
pos += take as u64;
|
|
}
|
|
out
|
|
}
|
|
fn dur(w: &str) -> String {
|
|
let o = Command::new("ffprobe")
|
|
.args([
|
|
"-v",
|
|
"error",
|
|
"-show_entries",
|
|
"format=duration:stream=channels",
|
|
"-of",
|
|
"default=nw=1:nk=1",
|
|
w,
|
|
])
|
|
.output()
|
|
.unwrap();
|
|
String::from_utf8_lossy(&o.stdout).replace('\n', " ")
|
|
}
|
|
fn movdur(disc: &str, m: &str) -> String {
|
|
dur(&format!("{disc}/dat/movie/{m}"))
|
|
}
|
|
fn main() {
|
|
let disc = std::env::var("SYLPHEED_DISC").unwrap();
|
|
// descriptor trailer global offsets (from scan) => cue N data = [desc(N-1)..desc(N)]
|
|
// (id, end_off, movie)
|
|
let cues = [
|
|
(1600u32, 437044592u64, "ADV.wmv"),
|
|
(1601, 437345648, "RT01A.wmv"),
|
|
(1602, 437712240, "RT01B.wmv"),
|
|
(1603, 438080880, "RT01C_1.wmv"),
|
|
(1604, 438451568, "RT01C_2.wmv"),
|
|
(1605, 438789488, "RT02A.wmv"),
|
|
];
|
|
for k in 1..cues.len() {
|
|
let (id, end, mov) = cues[k];
|
|
let start = cues[k - 1].1;
|
|
let region = rg(&disc, start, (end - start) as usize + 12000); // +tail to include full data before next trailer
|
|
let riffs = slb::to_xma_riffs(®ion);
|
|
let mut total = 0.0f32;
|
|
let mut parts = vec![];
|
|
for (j, r) in riffs.iter().enumerate() {
|
|
let xp = format!("/tmp/cue{id}_{j}.xma.wav");
|
|
let wp = format!("/tmp/cue{id}_{j}.wav");
|
|
fs::write(&xp, r).unwrap();
|
|
let _ = Command::new("ffmpeg")
|
|
.args(["-hide_banner", "-v", "error", "-y", "-i", &xp, &wp])
|
|
.status();
|
|
let d = dur(&wp);
|
|
parts.push(d.clone());
|
|
total += d
|
|
.split_whitespace()
|
|
.next()
|
|
.unwrap_or("0")
|
|
.parse::<f32>()
|
|
.unwrap_or(0.0);
|
|
}
|
|
// spanning?
|
|
let span_adv_end = 437547264u64;
|
|
let _spans = start < span_adv_end && end > span_adv_end || (start / 1_000 != end / 1_000);
|
|
println!("cue {id} ({mov}): region[{start}..{end}] {} bytes, {} riff(s), Σ={:.1}s | movie={} parts={:?}",
|
|
end-start, riffs.len(), total, movdur(&disc,mov), parts);
|
|
}
|
|
println!("\nWAVs at /tmp/cue16XX_*.wav (listen: RT01B=1602, RT01C_1=1603, RT01C_2=1604)");
|
|
}
|