Don't embed CJK episode titles in generated filenames
TVDB has no English episode title at all for some shows (entire seasons of otherwise-English-titled shows came back Japanese-only) — using it verbatim put unreadable-to-most-tooling script into an otherwise Latin-script library. Falls back to the no-title filename shape instead.
This commit is contained in:
parent
60d01657eb
commit
dcf9ee241c
1 changed files with 30 additions and 1 deletions
|
|
@ -227,6 +227,24 @@ pub(crate) fn season_dir(root_folder: &str, season_number: u32) -> PathBuf {
|
||||||
Path::new(root_folder).join(format!("Season {season_number:02}"))
|
Path::new(root_folder).join(format!("Season {season_number:02}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TVDB stores some shows' episode titles only in their original-airing
|
||||||
|
/// language (verified live: entire seasons of otherwise-English-titled
|
||||||
|
/// shows came back with Japanese-only episode titles, no English fallback
|
||||||
|
/// available from the API at all) — using that title verbatim in a
|
||||||
|
/// generated filename buries a CJK title inside an otherwise-Latin-script
|
||||||
|
/// library, which nothing downstream (search, external tools, a user
|
||||||
|
/// scanning a directory listing) can actually read. Better to just omit the
|
||||||
|
/// episode title than emit a filename with random plaintext.
|
||||||
|
fn has_cjk(s: &str) -> bool {
|
||||||
|
s.chars().any(|c| {
|
||||||
|
matches!(c,
|
||||||
|
'\u{3040}'..='\u{30FF}' // hiragana + katakana
|
||||||
|
| '\u{4E00}'..='\u{9FFF}' // CJK unified ideographs
|
||||||
|
| '\u{FF00}'..='\u{FFEF}' // fullwidth forms
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn deterministic_filename(
|
pub(crate) fn deterministic_filename(
|
||||||
series_title: &str,
|
series_title: &str,
|
||||||
season: u32,
|
season: u32,
|
||||||
|
|
@ -235,7 +253,7 @@ pub(crate) fn deterministic_filename(
|
||||||
ext: &str,
|
ext: &str,
|
||||||
) -> String {
|
) -> String {
|
||||||
let series = sanitize(series_title);
|
let series = sanitize(series_title);
|
||||||
match episode_title.filter(|t| !t.is_empty()) {
|
match episode_title.filter(|t| !t.is_empty() && !has_cjk(t)) {
|
||||||
Some(t) => format!(
|
Some(t) => format!(
|
||||||
"{series} - S{season:02}E{episode:02} - {}.{ext}",
|
"{series} - S{season:02}E{episode:02} - {}.{ext}",
|
||||||
sanitize(t)
|
sanitize(t)
|
||||||
|
|
@ -2714,6 +2732,17 @@ mod tests {
|
||||||
assert_eq!(sanitize("Kill: Ao / Blue?"), "Kill_ Ao _ Blue_");
|
assert_eq!(sanitize("Kill: Ao / Blue?"), "Kill_ Ao _ Blue_");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn omits_a_cjk_only_episode_title_instead_of_embedding_it() {
|
||||||
|
// TVDB sometimes has no English episode title at all for a given
|
||||||
|
// show, only the original Japanese one — verified live across
|
||||||
|
// several real shows' entire seasons.
|
||||||
|
assert_eq!(
|
||||||
|
deterministic_filename("Helck", 1, 3, Some("未知の敵"), "mkv"),
|
||||||
|
"Helck - S01E03.mkv"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn nearest_existing_ancestor_returns_the_path_itself_when_it_exists() {
|
fn nearest_existing_ancestor_returns_the_path_itself_when_it_exists() {
|
||||||
let dir = std::env::temp_dir();
|
let dir = std::env::temp_dir();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue