From e1d98b9b34b138918666a3ac39c52901462062b4 Mon Sep 17 00:00:00 2001 From: noctuum <25441068+noctuum@users.noreply.github.com> Date: Fri, 16 Oct 2026 20:56:12 +0000 Subject: [PATCH] refactor: spell American in names and text AniList's CANCELLED status keeps its spelling. --- crates/benshi/src/main.rs | 8 +- crates/cli/src/client.rs | 2 +- crates/cli/src/commands.rs | 20 ++-- crates/cli/src/lib.rs | 2 +- crates/cli/src/prompt.rs | 8 +- crates/cli/src/render.rs | 60 +++++------ .../the_client_sees_what_the_daemon_does.rs | 6 +- crates/core/Cargo.toml | 2 +- crates/core/src/clock.rs | 6 +- crates/core/src/encoding.rs | 6 +- crates/core/src/lib.rs | 22 ++-- crates/core/src/list.rs | 4 +- crates/core/src/path.rs | 38 +++---- crates/core/src/policy.rs | 4 +- .../src/{recognise => recognize}/altname.rs | 12 +-- .../src/{recognise => recognize}/corpus.rs | 6 +- .../src/{recognise => recognize}/index.rs | 12 +-- .../core/src/{recognise => recognize}/mod.rs | 100 +++++++++--------- .../normalise.rs => recognize/normalize.rs} | 4 +- .../src/{recognise => recognize}/parse.rs | 48 ++++----- .../src/{recognise => recognize}/score.rs | 54 +++++----- crates/core/src/session.rs | 52 ++++----- crates/core/src/token.rs | 6 +- crates/core/src/trace.rs | 12 +-- crates/core/tests/fixtures/filenames.jsonl | 90 ++++++++-------- .../tests/recognition_against_the_fixtures.rs | 28 ++--- .../tests/the_session_against_a_recording.rs | 12 +-- crates/daemon/src/bus.rs | 4 +- crates/daemon/src/config.rs | 2 +- crates/daemon/src/detection.rs | 70 ++++++------ crates/daemon/src/ipc.rs | 14 +-- crates/daemon/src/lib.rs | 10 +- crates/daemon/src/listing.rs | 68 ++++++------ crates/daemon/src/protocol.rs | 68 ++++++------ crates/daemon/src/recognition.rs | 96 ++++++++--------- crates/daemon/src/supervisor.rs | 6 +- crates/daemon/tests/replay_is_faithful.rs | 4 +- crates/daemon/tests/the_daemon_runs.rs | 20 ++-- crates/store/src/lib.rs | 2 +- crates/store/src/list.rs | 4 +- crates/store/src/queue.rs | 2 +- crates/store/src/watching.rs | 6 +- crates/sync/src/anilist/mod.rs | 6 +- crates/sync/src/lib.rs | 2 +- crates/sync/tests/fakes/mod.rs | 2 +- 45 files changed, 505 insertions(+), 505 deletions(-) rename crates/core/src/{recognise => recognize}/altname.rs (98%) rename crates/core/src/{recognise => recognize}/corpus.rs (98%) rename crates/core/src/{recognise => recognize}/index.rs (98%) rename crates/core/src/{recognise => recognize}/mod.rs (91%) rename crates/core/src/{recognise/normalise.rs => recognize/normalize.rs} (99%) rename crates/core/src/{recognise => recognize}/parse.rs (96%) rename crates/core/src/{recognise => recognize}/score.rs (94%) diff --git a/crates/benshi/src/main.rs b/crates/benshi/src/main.rs index 38dbf17..d6fae9a 100644 --- a/crates/benshi/src/main.rs +++ b/crates/benshi/src/main.rs @@ -359,9 +359,9 @@ async fn serve(voice: &Arc) -> u8 { } }; // What the store holds of the list is what the first round decides - // against, so a daemon recognises before it reads the list again. - let recogniser = match listing::kept(&store.lock().expect("nothing has used the store yet")) { - Ok(recogniser) => recogniser, + // against, so a daemon recognizes before it reads the list again. + let recognizer = match listing::kept(&store.lock().expect("nothing has used the store yet")) { + Ok(recognizer) => recognizer, Err(unread) => { voice.say(format_args!( "{} cannot be used: {unread}", @@ -384,7 +384,7 @@ async fn serve(voice: &Arc) -> u8 { let running = benshi_daemon::run( || MprisWatcher::connect(SystemClock::new(), SOURCE_DEADLINE), listener, - recogniser, + recognizer, store, SystemTime::now, POLL_INTERVAL, diff --git a/crates/cli/src/client.rs b/crates/cli/src/client.rs index 8de4185..4b7a603 100644 --- a/crates/cli/src/client.rs +++ b/crates/cli/src/client.rs @@ -203,7 +203,7 @@ fn did_not_answer(socket: &Path) -> anyhow::Error { #[cfg(test)] mod tests { #[test] - fn a_request_that_cannot_be_written_says_what_the_serialiser_said() { + fn a_request_that_cannot_be_written_says_what_the_serializer_said() { // A map keyed by a pair is one JSON cannot spell. let unwritable = std::collections::BTreeMap::from([((1, 2), 3)]); let cause = serde_json::to_vec(&unwritable).expect_err("JSON has no such key"); diff --git a/crates/cli/src/commands.rs b/crates/cli/src/commands.rs index d614c27..5f41998 100644 --- a/crates/cli/src/commands.rs +++ b/crates/cli/src/commands.rs @@ -262,7 +262,7 @@ async fn login( // Nothing typed was shown, the end of the line included. writeln!(err).context("prompt could not be printed")?; let token = match typed.context("token could not be read")? { - Typed::Cancelled => bail!("login cancelled"), + Typed::Canceled => bail!("login canceled"), Typed::Line(line) => line.secret().trim().to_owned(), }; if token.is_empty() { @@ -531,7 +531,7 @@ mod tests { use benshi_daemon::ipc::{Server, bind}; use benshi_daemon::listing::Wakes; use benshi_daemon::protocol::{Request, Response}; - use benshi_daemon::recognition::{Decided, Decision, Recogniser}; + use benshi_daemon::recognition::{Decided, Decision, Recognizer}; use benshi_daemon::secrets; use benshi_daemon::supervisor::TaskError; use socket2::{Domain, SockAddr, Socket, Type}; @@ -834,7 +834,7 @@ mod tests { /// round would. fn has_decided(&self, name: &str) { let path = RawPath::from_bytes(name.as_bytes().to_vec()); - let (parsed, answer) = Recogniser::empty().decide(&path); + let (parsed, answer) = Recognizer::empty().decide(&path); self.decided.record(Decision { player: PlayerId(PLAYER.to_owned()), @@ -1028,7 +1028,7 @@ mod tests { /// One answer as the daemon writes it: a line, newline included. fn line_of(answer: &Response) -> Vec { - let mut line = serde_json::to_vec(answer).expect("serialise"); + let mut line = serde_json::to_vec(answer).expect("serialize"); line.push(b'\n'); line @@ -1306,7 +1306,7 @@ mod tests { assert_eq!(outcome, ExitCode::SUCCESS, "stderr said {complained:?}"); assert!(shown.contains(PLAYER), "{shown}"); assert!(shown.contains("\"Show Title\""), "{shown}"); - assert!(shown.contains("unrecognised"), "{shown}"); + assert!(shown.contains("unrecognized"), "{shown}"); assert!(complained.is_empty(), "{complained}"); } @@ -2124,7 +2124,7 @@ mod tests { // nothing on the one it was written for. assert!( !shown.contains("more than it can replay"), - "a recording of a declared source apologised for an undeclared one: {shown:?}" + "a recording of a declared source apologized for an undeclared one: {shown:?}" ); assert_eq!(caught.snapshots, vec![a_reading(0)]); let text = std::fs::read_to_string(&output).expect("a trace was written"); @@ -2173,7 +2173,7 @@ mod tests { // carry the caveat, or the caveat says nothing when it does appear. assert!( !shown.contains(ENDED_EARLY), - "a complete recording apologised for ending early: {shown:?}" + "a complete recording apologized for ending early: {shown:?}" ); assert!( shown.contains(&output.display().to_string()), @@ -2451,19 +2451,19 @@ mod tests { } #[tokio::test] - async fn a_login_cancelled_at_the_prompt_is_no_login() { + async fn a_login_canceled_at_the_prompt_is_no_login() { let daemon = Daemon::logging_in(Logins::default()); let (outcome, shown, complained) = timeout( PATIENCE, - go_typing(Command::Login, &daemon.socket, Typed::Cancelled), + go_typing(Command::Login, &daemon.socket, Typed::Canceled), ) .await .expect("the client ended"); assert_eq!(outcome, ExitCode::FAILURE); assert!(shown.is_empty(), "{shown}"); - assert_eq!(complained, format!("{ASKED}benshi: login cancelled\n")); + assert_eq!(complained, format!("{ASKED}benshi: login canceled\n")); assert!(daemon.accounts.asked().is_empty()); } diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index 9b48741..db89a4c 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -150,7 +150,7 @@ mod tests { #[test] fn a_command_that_does_not_exist_is_refused() { - assert!(Cli::try_parse_from(["benshi", "recognise"]).is_err()); + assert!(Cli::try_parse_from(["benshi", "recognize"]).is_err()); } #[test] diff --git a/crates/cli/src/prompt.rs b/crates/cli/src/prompt.rs index 14477b4..615fcd7 100644 --- a/crates/cli/src/prompt.rs +++ b/crates/cli/src/prompt.rs @@ -25,7 +25,7 @@ pub enum Typed { /// before the end. A token is what a prompt reads, so it is held as one. Line(Token), /// Ctrl-C or Ctrl-D, at a terminal. - Cancelled, + Canceled, } /// Read one line from `input`, which a terminal does not show. @@ -74,7 +74,7 @@ fn line(input: BorrowedFd<'_>, at_a_terminal: bool) -> io::Result { match byte[0] { b'\n' => break, b'\r' if at_a_terminal => break, - CTRL_C | CTRL_D if at_a_terminal => return Ok(Typed::Cancelled), + CTRL_C | CTRL_D if at_a_terminal => return Ok(Typed::Canceled), key if at_a_terminal && BACKSPACE.contains(&key) => { line.pop(); } @@ -254,7 +254,7 @@ mod tests { let terminal = Terminal::new(); let modes = terminal.modes(); - assert_eq!(terminal.typing(b"part of a token\x03"), Typed::Cancelled); + assert_eq!(terminal.typing(b"part of a token\x03"), Typed::Canceled); assert_eq!(terminal.modes(), modes, "the terminal was not put back"); } @@ -263,7 +263,7 @@ mod tests { let terminal = Terminal::new(); let modes = terminal.modes(); - assert_eq!(terminal.typing(b"\x04"), Typed::Cancelled); + assert_eq!(terminal.typing(b"\x04"), Typed::Canceled); assert_eq!(terminal.modes(), modes, "the terminal was not put back"); } diff --git a/crates/cli/src/render.rs b/crates/cli/src/render.rs index 5435d34..ded4a75 100644 --- a/crates/cli/src/render.rs +++ b/crates/cli/src/render.rs @@ -14,7 +14,7 @@ use std::time::{Duration, UNIX_EPOCH}; use benshi_core::encoding::{Confidence, decode}; use benshi_core::policy::Policy; -use benshi_core::recognise::parse::{Episode, Parsed}; +use benshi_core::recognize::parse::{Episode, Parsed}; use benshi_core::{Capabilities, Known, MediaRef, PlayState}; use benshi_daemon::bus::BusEvent; use benshi_daemon::protocol::{DecidedBy, Explanation, Outcome, SourceListing}; @@ -23,7 +23,7 @@ use humantime::format_rfc3339_seconds; /// What is shown for a source that cannot name what it opened. /// /// A source that publishes no location gives recognition nothing but what the -/// page or window calls itself. That is a different problem from recognising a +/// page or window calls itself. That is a different problem from recognizing a /// filename, and a user deciding whether to allow such a source has to be told /// which one they are getting. const TITLE_ONLY: &str = "title only"; @@ -189,16 +189,16 @@ pub fn explanation(of: &Explanation) -> String { /// What recognition answered, as the lines below the parse. /// -/// Each line ends in a newline, and a match takes two: what it was recognised +/// Each line ends in a newline, and a match takes two: what it was recognized /// as, and the stage that decided. fn answer(of: &Outcome) -> String { match of { - Outcome::Recognised { + Outcome::Recognized { title, episode, stage, } => format!( - "recognised: \"{title}\", {}\nstage: {}\n", + "recognized: \"{title}\", {}\nstage: {}\n", episode_words(*episode), decided_by(stage) ), @@ -209,11 +209,11 @@ fn answer(of: &Outcome) -> String { .collect(); format!("ambiguous: {}\n", quoted.join(", ")) } - Outcome::Unrecognised { best: Some(score) } => { - format!("unrecognised: closest candidate scored {score:.2}\n") + Outcome::Unrecognized { best: Some(score) } => { + format!("unrecognized: closest candidate scored {score:.2}\n") } - Outcome::Unrecognised { best: None } => { - "unrecognised: nothing to score against\n".to_owned() + Outcome::Unrecognized { best: None } => { + "unrecognized: nothing to score against\n".to_owned() } } } @@ -345,14 +345,14 @@ mod tests { use benshi_core::clock::Timestamp; use benshi_core::path::RawPath; use benshi_core::policy::Policy; - use benshi_core::recognise::altname::Assignment; - use benshi_core::recognise::parse::Episode; + use benshi_core::recognize::altname::Assignment; + use benshi_core::recognize::parse::Episode; use benshi_core::{ AppName, Capabilities, Known, MediaRef, PlayState, PlayerId, PlayerSnapshot, ShowId, }; use benshi_daemon::bus::BusEvent; use benshi_daemon::protocol::{DecidedBy, Explanation, Outcome, SourceListing}; - use benshi_daemon::recognition::Recogniser; + use benshi_daemon::recognition::Recognizer; // The reason a failure carries comes from here in the daemon, so the tests // that check how one reads take it from here too rather than writing one. use benshi_detect::WatchError; @@ -638,7 +638,7 @@ mod tests { /// the daemon would have decided about. fn explained(path: &[u8], outcome: Outcome) -> Explanation { let path = RawPath::from_bytes(path.to_vec()); - let (spelled, _refused) = Recogniser::empty().decide(&path); + let (spelled, _refused) = Recognizer::empty().decide(&path); Explanation { player: PlayerId("mpv".to_owned()), @@ -650,7 +650,7 @@ mod tests { /// A match of this title by this stage, at episode three. fn found(title: &str, stage: DecidedBy) -> Outcome { - Outcome::Recognised { + Outcome::Recognized { title: title.to_owned(), episode: Episode::Only(3), stage, @@ -678,7 +678,7 @@ mod tests { fn an_explanation_names_the_player_and_the_file_first() { let shown = explanation(&explained( b"/anime/[Group] Show Title - 03.mkv", - Outcome::Unrecognised { best: None }, + Outcome::Unrecognized { best: None }, )); let first = shown.lines().next().expect("a first line"); @@ -696,7 +696,7 @@ mod tests { // the parser cut out of the title. let shown = explanation(&explained( b"[Group] Show Title S02E03 [1080p].mkv", - Outcome::Unrecognised { best: None }, + Outcome::Unrecognized { best: None }, )); let spelled = line_of(&shown, "spelled:"); @@ -710,7 +710,7 @@ mod tests { fn a_name_that_spelled_no_title_says_so() { let shown = explanation(&explained( b"/anime/ep 03.mkv", - Outcome::Unrecognised { best: None }, + Outcome::Unrecognized { best: None }, )); let spelled = line_of(&shown, "spelled:"); @@ -726,7 +726,7 @@ mod tests { // whether the guess was right. let shown = explanation(&explained( SHIFT_JIS_NAME, - Outcome::Unrecognised { best: None }, + Outcome::Unrecognized { best: None }, )); assert!(shown.contains("ソレッタ"), "the name was not read: {shown}"); @@ -757,7 +757,7 @@ mod tests { )); assert!( - line_of(&shown, "recognised:").contains("Kaguya-sama: Love is War -Ultra Romantic-"), + line_of(&shown, "recognized:").contains("Kaguya-sama: Love is War -Ultra Romantic-"), "{shown}" ); let stage = line_of(&shown, "stage:"); @@ -835,22 +835,22 @@ mod tests { // absence says the list is. let close = explanation(&explained( b"Some Other Show - 03.mkv", - Outcome::Unrecognised { best: Some(0.4) }, + Outcome::Unrecognized { best: Some(0.4) }, )); let nothing = explanation(&explained( b"Some Other Show - 03.mkv", - Outcome::Unrecognised { best: None }, + Outcome::Unrecognized { best: None }, )); assert_eq!( - line_of(&close, "unrecognised:"), - "unrecognised: closest candidate scored 0.40" + line_of(&close, "unrecognized:"), + "unrecognized: closest candidate scored 0.40" ); - let unscored = line_of(¬hing, "unrecognised:"); + let unscored = line_of(¬hing, "unrecognized:"); assert!(unscored.contains("nothing"), "{unscored}"); assert!( !unscored.contains("0.00"), - "an absence rendered as a score of nought: {unscored}" + "an absence rendered as a score of zero: {unscored}" ); } @@ -867,18 +867,18 @@ mod tests { for (episode, words) in cases { let shown = explanation(&explained( b"[Group] Show Title - 03.mkv", - Outcome::Recognised { + Outcome::Recognized { title: "Show Title".to_owned(), episode, stage: DecidedBy::Key, }, )); - let recognised = line_of(&shown, "recognised:"); - assert!(recognised.contains(words), "{recognised}"); + let recognized = line_of(&shown, "recognized:"); + assert!(recognized.contains(words), "{recognized}"); assert!( - !recognised.contains("episode 0"), - "an absence rendered as a number: {recognised}" + !recognized.contains("episode 0"), + "an absence rendered as a number: {recognized}" ); } } diff --git a/crates/cli/tests/the_client_sees_what_the_daemon_does.rs b/crates/cli/tests/the_client_sees_what_the_daemon_does.rs index b36c813..4772f39 100644 --- a/crates/cli/tests/the_client_sees_what_the_daemon_does.rs +++ b/crates/cli/tests/the_client_sees_what_the_daemon_does.rs @@ -31,7 +31,7 @@ use benshi_daemon::bus::{BusEvent, EventBus}; use benshi_daemon::detection::{Detection, Seen, Wiring}; use benshi_daemon::ipc::{Server, bind}; use benshi_daemon::listing::Wakes; -use benshi_daemon::recognition::{Current, Decided, Recogniser}; +use benshi_daemon::recognition::{Current, Decided, Recognizer}; use benshi_detect::{PlayerWatcher, PollOutcome, SourceInfo, WatchError}; use benshi_store::Store; use tempfile::TempDir; @@ -154,7 +154,7 @@ impl Daemon { bus: Arc::clone(&bus), policy: Arc::clone(&policy), seen: seen.clone(), - recogniser: Current::new(Recogniser::empty()), + recognizer: Current::new(Recognizer::empty()), wakes: Wakes::new(), decided: decided.clone(), store: Arc::new(Mutex::new(store)), @@ -240,7 +240,7 @@ async fn why_explains_the_reading_a_round_decided() { assert!(shown.contains(PLAYER), "{shown}"); assert!(shown.contains("/anime/ep 03.mkv"), "{shown}"); assert!(shown.contains("episode 3"), "{shown}"); - assert!(shown.contains("unrecognised"), "{shown}"); + assert!(shown.contains("unrecognized"), "{shown}"); } #[tokio::test] diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index e908b06..71fd41f 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -16,7 +16,7 @@ workspace = true # direct runtime dependency, `regex` without its Unicode tables, which brings # `aho-corasick`, `memchr`, `regex-automata` and `regex-syntax` with it. All of # them are Rust, so nothing C arrives and this crate stays free of platform -# code. MPL-2.0, the only non-permissive licence in the graph; section 3.3 +# code. MPL-2.0, the only non-permissive license in the graph; section 3.3 # permits a Larger Work under other terms, so benshi stays MIT. anitomy-ng = "1.0.10" chardetng = "1.0.0" diff --git a/crates/core/src/clock.rs b/crates/core/src/clock.rs index 3310473..2b8081a 100644 --- a/crates/core/src/clock.rs +++ b/crates/core/src/clock.rs @@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize}; /// A monotonic instant, measured from an unspecified epoch. /// -/// Unlike [`std::time::Instant`] this is an ordinary value: it serialises, so a +/// Unlike [`std::time::Instant`] this is an ordinary value: it serializes, so a /// recorded trace replays to exactly the state that was recorded. The epoch is /// arbitrary and only differences between timestamps are meaningful; comparing /// timestamps taken from two different [`Clock`] instances is not defined. @@ -149,8 +149,8 @@ mod tests { clock.advance(Duration::from_micros(1_234_567)); let stamp = clock.now(); - let text = serde_json::to_string(&stamp).expect("serialise"); - let back: Timestamp = serde_json::from_str(&text).expect("deserialise"); + let text = serde_json::to_string(&stamp).expect("serialize"); + let back: Timestamp = serde_json::from_str(&text).expect("deserialize"); assert_eq!(stamp, back); } diff --git a/crates/core/src/encoding.rs b/crates/core/src/encoding.rs index e8e197d..f04f4bf 100644 --- a/crates/core/src/encoding.rs +++ b/crates/core/src/encoding.rs @@ -3,8 +3,8 @@ //! A filename on Linux is bytes, and those bytes are frequently not UTF-8: an //! archive unpacked with the wrong setting, a share mounted from Windows, a //! file copied off a disc pressed in 2004. Refusing such a name means the -//! episode is never recognised; replacing the bytes it cannot read means it is -//! recognised as the wrong thing, which is worse. +//! episode is never recognized; replacing the bytes it cannot read means it is +//! recognized as the wrong thing, which is worse. //! //! So every name is decoded, and the decision is **reported rather than //! hidden**: the caller learns which encoding was used and whether that was a @@ -16,7 +16,7 @@ use serde::{Deserialize, Serialize}; /// How far the text can be trusted. /// /// Two-valued for the same reason [`crate::Known`] is three-valued: a fact and -/// an inference lead to different behaviour, and a type that cannot tell them +/// an inference lead to different behavior, and a type that cannot tell them /// apart forces every consumer to assume the worse of the two or the better. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum Confidence { diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 21c5158..c8ba7eb 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -10,7 +10,7 @@ pub mod encoding; pub mod list; pub mod path; pub mod policy; -pub mod recognise; +pub mod recognize; pub mod session; pub mod timeline; pub mod token; @@ -31,7 +31,7 @@ pub type BoxError = Box; /// /// Three-valued rather than [`Option`], because "the player did not publish a /// length" and "this detection method cannot carry a length" are different -/// facts that lead to different behaviour: the first may be retried or shown as +/// facts that lead to different behavior: the first may be retried or shown as /// unknown, the second means the capability is absent and the user should be /// told so. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] @@ -241,8 +241,8 @@ mod tests { observed_at: Timestamp::epoch(), }; - let text = serde_json::to_string(&snapshot).expect("serialise"); - let back: PlayerSnapshot = serde_json::from_str(&text).expect("deserialise"); + let text = serde_json::to_string(&snapshot).expect("serialize"); + let back: PlayerSnapshot = serde_json::from_str(&text).expect("deserialize"); assert_eq!(snapshot, back); } @@ -252,7 +252,7 @@ mod tests { // A filename from a Japanese archive unpacked with the wrong encoding // is not valid UTF-8, and this is exactly the snapshot a trace has to // carry. Refusing it, or replacing the bytes it cannot read, would make - // the file unrecognisable and the trace a lie. + // the file unrecognizable and the trace a lie. let broken = b"/anime/\x83\x5c\x83\x8c\x83\x62\x83\x5e.mkv".to_vec(); let snapshot = PlayerSnapshot { player: PlayerId("mpv".to_owned()), @@ -263,8 +263,8 @@ mod tests { observed_at: Timestamp::epoch(), }; - let text = serde_json::to_string(&snapshot).expect("serialise"); - let back: PlayerSnapshot = serde_json::from_str(&text).expect("deserialise"); + let text = serde_json::to_string(&snapshot).expect("serialize"); + let back: PlayerSnapshot = serde_json::from_str(&text).expect("deserialize"); assert_eq!(snapshot, back); match back.media { @@ -285,8 +285,8 @@ mod tests { assert_ne!(remote, title); assert_ne!( - serde_json::to_string(&remote).expect("serialise"), - serde_json::to_string(&title).expect("serialise") + serde_json::to_string(&remote).expect("serialize"), + serde_json::to_string(&title).expect("serialize") ); } @@ -297,8 +297,8 @@ mod tests { let unsupported: Known = Known::Unsupported; let not_reported: Known = Known::NotReported; - let a = serde_json::to_string(&unsupported).expect("serialise"); - let b = serde_json::to_string(¬_reported).expect("serialise"); + let a = serde_json::to_string(&unsupported).expect("serialize"); + let b = serde_json::to_string(¬_reported).expect("serialize"); assert_ne!(a, b); } diff --git a/crates/core/src/list.rs b/crates/core/src/list.rs index e078fdc..8a9ea78 100644 --- a/crates/core/src/list.rs +++ b/crates/core/src/list.rs @@ -110,7 +110,7 @@ pub enum Status { /// On AniList each user chooses the format a score is shown in, and the list /// takes and answers a score in a hundred points whichever was chosen. /// MyAnimeList and Shikimori score out of ten and Kitsu out of twenty, and -/// both multiply into a hundred exactly. Nought is not a rating: an entry +/// both multiply into a hundred exactly. Zero is not a rating: an entry /// with no score carries none. #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)] pub struct Rating(u8); @@ -148,7 +148,7 @@ mod tests { #[test] fn a_rating_is_from_one_to_a_hundred() { - // Nought is no rating, and no rating is `None`: two ways to say it + // Zero is no rating, and no rating is `None`: two ways to say it // would be one too many. assert_eq!(Rating::new(0), None); assert_eq!(Rating::new(1).map(Rating::points), Some(1)); diff --git a/crates/core/src/path.rs b/crates/core/src/path.rs index 9101cee..c1a96d1 100644 --- a/crates/core/src/path.rs +++ b/crates/core/src/path.rs @@ -14,7 +14,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer, de}; /// A path on Linux is an arbitrary byte string, so this type holds bytes. It is /// never opened: callers parse the filename and display it. /// -/// The serialised form keeps runs of valid UTF-8 verbatim, so an ordinary name +/// The serialized form keeps runs of valid UTF-8 verbatim, so an ordinary name /// stays readable in a trace, and escapes every other byte, plus the escape /// character itself, as `%XX`. The mapping is reversible for any input. #[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] @@ -33,7 +33,7 @@ impl RawPath { &self.0 } - /// The path as text, in the form the serialised path quotes. + /// The path as text, in the form the serialized path quotes. /// /// Runs of valid UTF-8 are kept verbatim and every other byte becomes /// `%XX`, the escape itself included: a name holding a per-cent sign @@ -60,7 +60,7 @@ impl RawPath { /// Only `/` separates. A backslash does not, because 0x5C is the trailing /// byte of several Shift-JIS characters and splitting on it would cut a /// Japanese filename in half. A platform whose separator is the backslash - /// normalises before constructing this type: which byte separates is + /// normalizes before constructing this type: which byte separates is /// platform knowledge, and an adapter is where platform knowledge lives. #[must_use] pub fn file_name(&self) -> &[u8] { @@ -184,15 +184,15 @@ mod tests { #[test] fn a_utf8_path_round_trips() { let path = RawPath::from_bytes(b"/anime/[Group] Show - 03.mkv".to_vec()); - let text = serde_json::to_string(&path).expect("serialise"); - let back: RawPath = serde_json::from_str(&text).expect("deserialise"); + let text = serde_json::to_string(&path).expect("serialize"); + let back: RawPath = serde_json::from_str(&text).expect("deserialize"); assert_eq!(path, back); } #[test] fn a_japanese_utf8_path_round_trips_and_stays_readable() { let path = RawPath::from_bytes("/anime/日本語.mkv".as_bytes().to_vec()); - let text = serde_json::to_string(&path).expect("serialise"); + let text = serde_json::to_string(&path).expect("serialize"); // Valid UTF-8 passes through unescaped, so a trace stays greppable by // the name a person would type. @@ -201,15 +201,15 @@ mod tests { "expected readable text, got {text}" ); - let back: RawPath = serde_json::from_str(&text).expect("deserialise"); + let back: RawPath = serde_json::from_str(&text).expect("deserialize"); assert_eq!(path, back); } #[test] fn a_shift_jis_path_round_trips_byte_for_byte() { let path = RawPath::from_bytes(SHIFT_JIS.to_vec()); - let text = serde_json::to_string(&path).expect("serialise"); - let back: RawPath = serde_json::from_str(&text).expect("deserialise"); + let text = serde_json::to_string(&path).expect("serialize"); + let back: RawPath = serde_json::from_str(&text).expect("deserialize"); assert_eq!(path, back); assert_eq!(back.as_bytes(), SHIFT_JIS); @@ -218,19 +218,19 @@ mod tests { #[test] fn a_windows_1251_path_round_trips_byte_for_byte() { let path = RawPath::from_bytes(CP1251.to_vec()); - let text = serde_json::to_string(&path).expect("serialise"); - let back: RawPath = serde_json::from_str(&text).expect("deserialise"); + let text = serde_json::to_string(&path).expect("serialize"); + let back: RawPath = serde_json::from_str(&text).expect("deserialize"); assert_eq!(path, back); assert_eq!(back.as_bytes(), CP1251); } #[test] - fn an_invalid_path_still_serialises_as_a_string() { + fn an_invalid_path_still_serializes_as_a_string() { // Not an array of numbers: a trace is read by people, and a wall of // byte values is not readable at any length. let path = RawPath::from_bytes(SHIFT_JIS.to_vec()); - let text = serde_json::to_string(&path).expect("serialise"); + let text = serde_json::to_string(&path).expect("serialize"); assert!(text.starts_with('"'), "expected a JSON string, got {text}"); } @@ -239,8 +239,8 @@ mod tests { // The escape character has to escape itself, or a filename containing // a per-cent sign decodes as something else entirely. let path = RawPath::from_bytes(b"/anime/100%25 Pascal-sensei.mkv".to_vec()); - let text = serde_json::to_string(&path).expect("serialise"); - let back: RawPath = serde_json::from_str(&text).expect("deserialise"); + let text = serde_json::to_string(&path).expect("serialize"); + let back: RawPath = serde_json::from_str(&text).expect("deserialize"); assert_eq!(path, back); } @@ -254,9 +254,9 @@ mod tests { assert_eq!(escaped, "/anime/%FF 100%25.mkv"); assert_eq!( - serde_json::to_string(&path).expect("serialise"), + serde_json::to_string(&path).expect("serialize"), format!("{escaped:?}"), - "and it is what the serialised form quotes" + "and it is what the serialized form quotes" ); } @@ -288,8 +288,8 @@ mod tests { let all: Vec = (0..=u8::MAX).collect(); let path = RawPath::from_bytes(all.clone()); - let text = serde_json::to_string(&path).expect("serialise"); - let back: RawPath = serde_json::from_str(&text).expect("deserialise"); + let text = serde_json::to_string(&path).expect("serialize"); + let back: RawPath = serde_json::from_str(&text).expect("deserialize"); assert_eq!(back.as_bytes(), all.as_slice()); } diff --git a/crates/core/src/policy.rs b/crates/core/src/policy.rs index 4b36d36..d520fb0 100644 --- a/crates/core/src/policy.rs +++ b/crates/core/src/policy.rs @@ -176,12 +176,12 @@ mod tests { } #[test] - fn a_player_is_allowed_however_it_capitalises_its_own_name() { + fn a_player_is_allowed_however_it_capitalizes_its_own_name() { // Not hypothetical, and the reason the list holds published names // rather than commands. mpc-qt registers // org.mpris.MediaPlayer2.MpcQt, which is not the command a user types. // The constructor and a lookup both lowercase, so the published name - // and the entry meet however either is capitalised; the command + // and the entry meet however either is capitalized; the command // spelling never does, hyphen and all. let table = PolicyTable::allowing_video_players(); diff --git a/crates/core/src/recognise/altname.rs b/crates/core/src/recognize/altname.rs similarity index 98% rename from crates/core/src/recognise/altname.rs rename to crates/core/src/recognize/altname.rs index 661aa23..b9df65c 100644 --- a/crates/core/src/recognise/altname.rs +++ b/crates/core/src/recognize/altname.rs @@ -28,9 +28,9 @@ use std::collections::HashMap; use serde::{Deserialize, Serialize}; use crate::ShowId; -use crate::recognise::corpus::Corpus; -use crate::recognise::normalise::Key; -use crate::recognise::parse::Parsed; +use crate::recognize::corpus::Corpus; +use crate::recognize::normalize::Key; +use crate::recognize::parse::Parsed; /// One assignment, as the user made it. /// @@ -206,9 +206,9 @@ mod tests { use super::{Altnames, Assignment, Unnameable}; use crate::ShowId; use crate::path::RawPath; - use crate::recognise::corpus::Corpus; - use crate::recognise::normalise::Key; - use crate::recognise::parse::{Parsed, parse}; + use crate::recognize::corpus::Corpus; + use crate::recognize::normalize::Key; + use crate::recognize::parse::{Parsed, parse}; /// What a file of this name spells. fn named(name: &str) -> Parsed { diff --git a/crates/core/src/recognise/corpus.rs b/crates/core/src/recognize/corpus.rs similarity index 98% rename from crates/core/src/recognise/corpus.rs rename to crates/core/src/recognize/corpus.rs index 893ab1d..799cf8e 100644 --- a/crates/core/src/recognise/corpus.rs +++ b/crates/core/src/recognize/corpus.rs @@ -1,6 +1,6 @@ //! The entries a name reaches, filed under the key each spelling reaches. //! -//! Stage two is an exact match on the normalised key, and this is what it +//! Stage two is an exact match on the normalized key, and this is what it //! matches against. **The caller builds it**, because this crate performs no //! I/O and a list of entries comes from somewhere that does. //! @@ -24,7 +24,7 @@ use std::collections::HashMap; use crate::ShowId; -use crate::recognise::normalise::Key; +use crate::recognize::normalize::Key; /// The shows recognition matches against. /// @@ -168,7 +168,7 @@ impl> FromIterator for Corpus { mod tests { use super::Corpus; use crate::ShowId; - use crate::recognise::normalise::Key; + use crate::recognize::normalize::Key; /// The key a list entry spelled this way is filed under. fn listed(title: &str) -> Key { diff --git a/crates/core/src/recognise/index.rs b/crates/core/src/recognize/index.rs similarity index 98% rename from crates/core/src/recognise/index.rs rename to crates/core/src/recognize/index.rs index 9776864..1b5ccc1 100644 --- a/crates/core/src/recognise/index.rs +++ b/crates/core/src/recognize/index.rs @@ -10,7 +10,7 @@ //! miss it. Their words do not miss. //! //! **The words are read by the key's own rules** through -//! [`super::normalise::words_in`], so everything a key forgives is gone from +//! [`super::normalize::words_in`], so everything a key forgives is gone from //! them as well and this stage repeats none of it. The words cannot be read out //! of a key, because a key erases the breaks between words so that `Fate/Zero` //! and `Fate Zero` reach one. @@ -34,8 +34,8 @@ use std::collections::{HashMap, HashSet}; use crate::ShowId; -use crate::recognise::corpus::Corpus; -use crate::recognise::normalise::words_in; +use crate::recognize::corpus::Corpus; +use crate::recognize::normalize::words_in; /// A word narrows nothing once more than one entry in this many carries it. /// @@ -152,9 +152,9 @@ mod tests { use super::Index; use crate::ShowId; use crate::path::RawPath; - use crate::recognise::by_key; - use crate::recognise::corpus::Corpus; - use crate::recognise::parse::parse; + use crate::recognize::by_key; + use crate::recognize::corpus::Corpus; + use crate::recognize::parse::parse; /// The titles of these shows, in the order they are given. fn titled(corpus: &Corpus, shows: Vec) -> Vec<&str> { diff --git a/crates/core/src/recognise/mod.rs b/crates/core/src/recognize/mod.rs similarity index 91% rename from crates/core/src/recognise/mod.rs rename to crates/core/src/recognize/mod.rs index 6525e93..6e0b0ee 100644 --- a/crates/core/src/recognise/mod.rs +++ b/crates/core/src/recognize/mod.rs @@ -1,7 +1,7 @@ //! What a filename turned out to be, and which stage decided it. //! //! The pipeline has four stages: a mapping the user made by hand, an exact match -//! on a normalised key, a token index that narrows the corpus to a handful, and +//! on a normalized key, a token index that narrows the corpus to a handful, and //! a score over what is left. **Only three of them can answer.** The index //! decides nothing - it hands candidates to the scorer - so [`Stage`] has three //! variants and not four. Why they run in that order is written on [`Stage`]. @@ -17,17 +17,17 @@ pub mod altname; pub mod corpus; pub mod index; -pub mod normalise; +pub mod normalize; pub mod parse; pub mod score; use crate::ShowId; -use crate::recognise::altname::{Altnames, Assignment}; -use crate::recognise::corpus::Corpus; -use crate::recognise::index::Index; -use crate::recognise::normalise::Key; -use crate::recognise::parse::{Episode, Parsed}; -use crate::recognise::score::by_score; +use crate::recognize::altname::{Altnames, Assignment}; +use crate::recognize::corpus::Corpus; +use crate::recognize::index::Index; +use crate::recognize::normalize::Key; +use crate::recognize::parse::{Episode, Parsed}; +use crate::recognize::score::by_score; /// What the stages answer, in the order they are asked. /// @@ -43,7 +43,7 @@ use crate::recognise::score::by_score; #[must_use] pub fn decide(parsed: &Parsed, altnames: &Altnames, corpus: &Corpus, index: &Index) -> Recognition { by_altname(parsed, altnames) - .map(Recognition::Recognised) + .map(Recognition::Recognized) .or_else(|| by_key(parsed, corpus)) .unwrap_or_else(|| { let candidates = parsed @@ -74,12 +74,12 @@ pub fn by_altname(parsed: &Parsed, altnames: &Altnames) -> Option { }) } -/// What an exact match on the normalised key answers, where it answers at all. +/// What an exact match on the normalized key answers, where it answers at all. /// /// Nothing where the name reaches no entry: an exact key hits or misses, and a /// name that misses is what the stages below are for. A refusal is the whole /// sequence's answer rather than this stage's, so nothing here says a name was -/// not recognised - only that this stage did not recognise it. +/// not recognized - only that this stage did not recognize it. /// /// Several entries under one key is an answer, and the answer is that the name /// does not say. Two list entries share a key honestly - a remake spelled like @@ -101,7 +101,7 @@ pub fn by_key(parsed: &Parsed, corpus: &Corpus) -> Option { match candidates.as_slice() { [] => None, - [one] => Some(Recognition::Recognised(Match { + [one] => Some(Recognition::Recognized(Match { show: one.show, title: one.title.clone(), episode: parsed.episode, @@ -122,7 +122,7 @@ pub fn by_key(parsed: &Parsed, corpus: &Corpus) -> Option { /// quietly moved into range makes an explanation disagree with what actually /// happened, and the whole purpose of carrying a score is to be believed. /// -/// Not serialisable, deliberately. A derived `Deserialize` on a newtype is +/// Not serializable, deliberately. A derived `Deserialize` on a newtype is /// transparent and would let a message arriving over the socket carry a score /// of five, which is the kind of hole this crate refuses to open. The wire form /// belongs with the request that needs one, and it can convert through @@ -162,18 +162,18 @@ pub enum Stage { /// user gave and the season and part it was bound to, which is where a /// file of another season fails to match it. Altname(Assignment), - /// An exact match on the normalised key. + /// An exact match on the normalized key. Key, /// The best candidate the scorer found, and how well it scored. /// /// The score lives inside the stage rather than beside it, so that a stage - /// which did not score has no score to lose and none to invent. Nought + /// which did not score has no score to lose and none to invent. Zero /// would read as the worst possible match and one as a perfect comparison /// that never happened; both are false of an exact match. Scored(Score), } -/// A filename that was recognised. +/// A filename that was recognized. /// /// The show is the corpus entry that matched, rather than the text the filename /// spelled. A [`Refusal`] carries that second thing, and confusing the two is how @@ -204,7 +204,7 @@ pub struct Match { pub stage: Stage, } -/// Why a filename was not recognised. +/// Why a filename was not recognized. /// /// Reported and never guessed at. Writing progress against the wrong title is /// the worst failure this program can have, and a best guess below the threshold @@ -262,7 +262,7 @@ pub struct Candidate { #[derive(Debug, Clone, PartialEq)] pub enum Recognition { /// A show, and the stage that decided it. - Recognised(Match), + Recognized(Match), /// Several entries, and nothing in the name to choose between them. /// /// A variant of its own rather than a refusal carrying a list, because a @@ -272,11 +272,11 @@ pub enum Recognition { Ambiguous(Ambiguity), /// Nothing matched, and why. /// - /// A variant rather than an `Err`, because an unrecognised filename is a + /// A variant rather than an `Err`, because an unrecognized filename is a /// fact about the filename and not a failure of the program. Nothing /// retries it, nothing logs it as a fault, and something downstream has to /// tell the user about it. - Unrecognised(Refusal), + Unrecognized(Refusal), } #[cfg(test)] @@ -284,14 +284,14 @@ mod tests { use super::{Ambiguity, Candidate, Match, Recognition, Refusal, Score, Stage, by_key, decide}; use crate::ShowId; use crate::path::RawPath; - use crate::recognise::altname::{Altnames, Assignment}; - use crate::recognise::corpus::Corpus; - use crate::recognise::index::Index; - use crate::recognise::parse::{Episode, Parsed, parse}; + use crate::recognize::altname::{Altnames, Assignment}; + use crate::recognize::corpus::Corpus; + use crate::recognize::index::Index; + use crate::recognize::parse::{Episode, Parsed, parse}; /// A score the tests use where the exact value is not the point. fn a_score(value: f64) -> Score { - Score::new(value).expect("the value is between nought and one") + Score::new(value).expect("the value is between zero and one") } /// What a file of this name spells, so that a test names a file rather @@ -306,8 +306,8 @@ mod tests { } /// A recognition of this show by this stage, for comparing against. - fn recognised(show: i64, title: &str, episode: Episode) -> Recognition { - Recognition::Recognised(Match { + fn recognized(show: i64, title: &str, episode: Episode) -> Recognition { + Recognition::Recognized(Match { show: ShowId(show), title: title.to_owned(), episode, @@ -330,14 +330,14 @@ mod tests { // a key and a best guess among candidates are not the same kind of // certainty, and a stage on its own does not say how close the call // was. The two travel together or neither is worth printing. - let scored = Recognition::Recognised(Match { + let scored = Recognition::Recognized(Match { show: ShowId(1), title: "Show".to_owned(), episode: Episode::Only(3), stage: Stage::Scored(a_score(0.91)), }); - let Recognition::Recognised(found) = &scored else { + let Recognition::Recognized(found) = &scored else { panic!("the answer is a recognition") }; assert_eq!(found.stage, Stage::Scored(a_score(0.91))); @@ -346,7 +346,7 @@ mod tests { #[test] fn a_stage_that_does_not_score_carries_no_score_to_lose() { // An exact match has no score, and a type that carried one anyway would - // need a value invented for it - nought, which reads as the worst + // need a value invented for it - zero, which reads as the worst // possible match, or one, which reads as a perfect comparison that // never happened. Neither is true, so the stage holds the score where // there is one and nothing where there is not. @@ -391,15 +391,15 @@ mod tests { #[test] fn a_filename_nothing_matched_is_an_answer_and_not_an_error() { - // Unrecognised is a fact about the filename, not a failure of the + // Unrecognized is a fact about the filename, not a failure of the // program, so it is a variant rather than an `Err`. It carries what the // parser made of the name, because that is the first thing anybody // asking why will want, and how close the best candidate came. - let nothing_close = Recognition::Unrecognised(Refusal { + let nothing_close = Recognition::Unrecognized(Refusal { parsed: "Some Show".to_owned(), best: Some(a_score(0.41)), }); - let nothing_to_compare = Recognition::Unrecognised(Refusal { + let nothing_to_compare = Recognition::Unrecognized(Refusal { parsed: "Some Show".to_owned(), best: None, }); @@ -408,7 +408,7 @@ mod tests { } #[test] - fn a_score_outside_nought_to_one_is_refused_and_each_bound_is_not() { + fn a_score_outside_zero_to_one_is_refused_and_each_bound_is_not() { // A score is a proportion and nothing else can be one. Refused rather // than clamped, for the reason the watched policy gives: a number // quietly moved into range makes the explanation disagree with what @@ -450,7 +450,7 @@ mod tests { assert_eq!( found("[Group] Show Title - 03 [1080p].mkv", &corpus), - Some(recognised(1, "Show Title", Episode::Only(3))) + Some(recognized(1, "Show Title", Episode::Only(3))) ); } @@ -502,7 +502,7 @@ mod tests { assert_eq!( found("Another Show - 03.mkv", &corpus), - Some(Recognition::Recognised(Match { + Some(Recognition::Recognized(Match { show: ShowId(9), title: "Another Show".to_owned(), episode: Episode::Only(3), @@ -515,7 +515,7 @@ mod tests { fn a_name_no_entry_is_filed_under_leaves_the_answer_to_the_stages_below() { // Not a refusal. An exact key hits or misses, and a name the parser // shortened or a list spells differently misses it while still being - // recognisable further down, so this stage says nothing rather than + // recognizable further down, so this stage says nothing rather than // saying no. let corpus: Corpus = ["Show Title"].into_iter().collect(); @@ -531,7 +531,7 @@ mod tests { assert_eq!( found("Nisekoi: - 03.mkv", &corpus), - Some(recognised(2, "Nisekoi:", Episode::Only(3))) + Some(recognized(2, "Nisekoi:", Episode::Only(3))) ); assert_eq!( found("Nisekoi - 03.mkv", &corpus), @@ -557,7 +557,7 @@ mod tests { assert_eq!( found("Gokushufudou S2 - 03.mkv", &corpus), - Some(recognised(3, "Gokushufudou Season 2", Episode::Only(3))) + Some(recognized(3, "Gokushufudou Season 2", Episode::Only(3))) ); } @@ -581,7 +581,7 @@ mod tests { &corpus, &Index::of(&corpus) ), - Recognition::Recognised(Match { + Recognition::Recognized(Match { show: ShowId(2), title: "Nisekoi:".to_owned(), episode: Episode::Only(3), @@ -626,7 +626,7 @@ mod tests { assert_eq!( decide(&third, &altnames, &corpus, &Index::of(&corpus)), - Recognition::Recognised(Match { + Recognition::Recognized(Match { show: ShowId(2), title: "Kaguya-sama: Love is War -Ultra Romantic-".to_owned(), episode: Episode::Only(3), @@ -646,7 +646,7 @@ mod tests { &corpus, &Index::of(&corpus) ), - recognised(1, "Kaguya-sama: Love is War", Episode::Only(3)) + recognized(1, "Kaguya-sama: Love is War", Episode::Only(3)) ); } @@ -664,7 +664,7 @@ mod tests { &corpus, &Index::of(&corpus) ), - recognised(1, "Show Title", Episode::Only(3)) + recognized(1, "Show Title", Episode::Only(3)) ); } @@ -683,7 +683,7 @@ mod tests { &corpus, &Index::of(&corpus) ), - Recognition::Unrecognised(Refusal { + Recognition::Unrecognized(Refusal { parsed: "Some Other Show".to_owned(), best: Some(a_score(0.4)), }) @@ -691,9 +691,9 @@ mod tests { } #[test] - fn a_refusal_with_nothing_to_score_carries_no_score_rather_than_nought() { + fn a_refusal_with_nothing_to_score_carries_no_score_rather_than_zero() { // No entry shares a word with the name, so the index hands the scorer - // nothing and no comparison is made. Nought would say one was made + // nothing and no comparison is made. Zero would say one was made // and the closest entry shared nothing, which sends a reader to the // name; an absence sends them to the list. let corpus: Corpus = ["Show Title"].into_iter().collect(); @@ -705,7 +705,7 @@ mod tests { &corpus, &Index::of(&corpus) ), - Recognition::Unrecognised(Refusal { + Recognition::Unrecognized(Refusal { parsed: "Completely Different".to_owned(), best: None, }) @@ -725,7 +725,7 @@ mod tests { assert_eq!( decide(¬hing, &Altnames::new(), &corpus, &Index::of(&corpus)), - Recognition::Unrecognised(Refusal { + Recognition::Unrecognized(Refusal { parsed: String::new(), best: None, }) @@ -734,14 +734,14 @@ mod tests { #[test] fn a_file_of_several_episodes_names_its_title_and_none_of_them() { - // The title was recognised and the episode was not, which is one + // The title was recognized and the episode was not, which is one // answer rather than two. A batch reduced to no episode would arrive // looking like a film, and a consumer would mark the series watched. let corpus: Corpus = ["Show Title"].into_iter().collect(); assert_eq!( found("[Group] Show Title 01-12 [BD].mkv", &corpus), - Some(recognised(1, "Show Title", Episode::Several)) + Some(recognized(1, "Show Title", Episode::Several)) ); } } diff --git a/crates/core/src/recognise/normalise.rs b/crates/core/src/recognize/normalize.rs similarity index 99% rename from crates/core/src/recognise/normalise.rs rename to crates/core/src/recognize/normalize.rs index 068a337..0dd09c9 100644 --- a/crates/core/src/recognise/normalise.rs +++ b/crates/core/src/recognize/normalize.rs @@ -57,7 +57,7 @@ use std::ops::Range; use unicode_normalization::UnicodeNormalization; use unicode_normalization::char::is_combining_mark; -use crate::recognise::parse::Parsed; +use crate::recognize::parse::Parsed; /// The form a title is compared in. /// @@ -682,7 +682,7 @@ mod tests { use super::{Key, words_in}; use crate::encoding::Confidence; use crate::path::RawPath; - use crate::recognise::parse::{Episode, Parsed, parse}; + use crate::recognize::parse::{Episode, Parsed, parse}; /// The key a list entry spelled this way is filed under. fn listed(title: &str) -> Key { diff --git a/crates/core/src/recognise/parse.rs b/crates/core/src/recognize/parse.rs similarity index 96% rename from crates/core/src/recognise/parse.rs rename to crates/core/src/recognize/parse.rs index 10a70a7..366126f 100644 --- a/crates/core/src/recognise/parse.rs +++ b/crates/core/src/recognize/parse.rs @@ -3,7 +3,7 @@ //! One function, and everything the parser reports that this crate does not //! read is dropped here rather than further down. **Which kinds are dropped is //! written out rather than caught by a wildcard**, so a kind added upstream -//! stops the build and has to be given an answer instead of changing behaviour +//! stops the build and has to be given an answer instead of changing behavior //! quietly. //! //! Six kinds are kept. `EpisodeTitle` is not one of them: for @@ -24,7 +24,7 @@ use serde::{Deserialize, Serialize}; use crate::encoding::{Confidence, decode}; use crate::path::RawPath; -use crate::recognise::normalise::part_in; +use crate::recognize::normalize::part_in; /// What a filename says about which episode it holds. /// @@ -47,7 +47,7 @@ pub enum Episode { /// One episode, spelled as something other than a whole number. /// /// `5.5` is a real episode of some series and there is nowhere to put it, so - /// it is neither rounded into a neighbour it is not nor called absent. + /// it is neither rounded into a neighbor it is not nor called absent. /// /// **Apart from [`Absent`](Episode::Absent) for the reason [`Several`](Episode::Several) is /// apart from it.** A film spells no episode and is a work this program can @@ -55,7 +55,7 @@ pub enum Episode { /// alike would mark a whole series watched because somebody played a recap. NotWhole, /// None spelled at all: a film, or a name that does not say. A name - /// spelling nought for the season and for the episode at once is read as + /// spelling zero for the season and for the episode at once is read as /// spelling none. Absent, } @@ -76,8 +76,8 @@ pub struct Parsed { /// `Season 2`, `2nd Season` and `Season II` all arrive here as two. A /// numeral ending the title does not: `Show Title II` comes back with the /// numeral still in the title and no season at all, which is why the - /// normaliser carries a rule of its own for it. A season of nought - /// beside an episode of nought is not kept. + /// normalizer carries a rule of its own for it. Season zero beside episode + /// zero is not kept. pub season: Option, /// The part of a season, where the parser reported one or [`parse`] read /// one back from after the season marker. @@ -107,7 +107,7 @@ pub struct Parsed { /// /// **What a stage comparing text is given, and it is not /// [`title`](Parsed::title).** A title ends at the first thing the parser - /// recognises, so a name spelling `Show Title - The Subtitle - 03` reports + /// recognizes, so a name spelling `Show Title - The Subtitle - 03` reports /// a title of `Show Title` and the subtitle belongs to no element at all. /// A stage reading the title alone cannot tell such a file from the series /// it extends. What is struck out is the release group, the episode, the @@ -192,10 +192,10 @@ pub fn parse(name: &RawPath) -> Parsed { [] => Episode::Absent, _ => Episode::Several, }; - // Nought for the season and for the episode at once counts nothing, as + // Zero for the season and for the episode at once counts nothing, as // in a film named with `s00e00`, and the name is read as spelling - // neither. Either nought alone is kept: an episode of nought can - // number a prologue, and an episode in a season of nought a special. + // neither. Either zero alone is kept: episode zero can number a prologue, + // and an episode in season zero a special. if parsed.season == Some(0) && parsed.episode == Episode::Only(0) { parsed.season = None; parsed.episode = Episode::Absent; @@ -444,7 +444,7 @@ mod tests { #[test] fn the_release_is_struck_out_of_the_text_a_stage_compares() { - // A title ends at the first thing the parser recognises, so a subtitle + // A title ends at the first thing the parser recognizes, so a subtitle // beyond it belongs to no element at all and a stage reading the title // alone cannot tell this file from the series it extends. What the // release itself spells goes, because no list entry spells any of it. @@ -700,9 +700,9 @@ mod tests { } #[test] - fn a_season_and_an_episode_of_nought_together_spell_neither() { - // A film named with `s00e00`. Left as spelled, the season of nought - // goes into the key, and the film's entry is filed with no season. + fn season_zero_and_episode_zero_together_spell_neither() { + // A film named with `s00e00`. Left as spelled, season zero goes into + // the key, and the film's entry is filed with no season. let parsed = spelled("Show.Title.The.Movie.s00e00.HD1080p.WEBRip.mp4"); assert_eq!(parsed.title.as_deref(), Some("Show Title The Movie")); @@ -711,7 +711,7 @@ mod tests { } #[test] - fn an_episode_in_a_season_of_nought_keeps_its_season() { + fn an_episode_in_season_zero_keeps_its_season() { // `S00E03` numbers a special. With the season taken off, the name // would reach the series and name its third episode. for (name, episode) in [ @@ -727,8 +727,8 @@ mod tests { } #[test] - fn a_season_of_nought_beside_no_whole_episode_keeps_its_season() { - // A whole episode of nought is all that takes the season with it. + fn season_zero_beside_no_whole_episode_keeps_its_season() { + // A whole episode numbered zero is all that takes the season with it. // Read as spelling no season, a name with no episode beside it would // reach the series and name the whole of it. for (name, episode) in [ @@ -744,8 +744,8 @@ mod tests { } #[test] - fn an_episode_of_nought_outside_a_season_of_nought_is_an_episode() { - // A series can number a prologue nought. + fn episode_zero_outside_season_zero_is_an_episode() { + // A series can number a prologue zero. for name in ["Show Title - 00.mkv", "Show.Title.S01E00.1080p.WEB.mkv"] { let parsed = spelled(name); @@ -768,12 +768,12 @@ mod tests { #[test] fn a_roman_numeral_season_stays_in_the_title() { // The other half, and the parser does not do it: `Show Title II` comes - // back whole, with no season at all, so the normaliser reads the + // back whole, with no season at all, so the normalizer reads the // numeral out of the title. // // The test is here rather than beside that rule because this is a fact // about the parser. A parser that started reading such a numeral would - // change what reaches the normaliser from a filename, and this test is + // change what reaches the normalizer from a filename, and this test is // what would say so. let parsed = spelled("Show Title II - 03.mkv"); @@ -821,7 +821,7 @@ mod tests { #[test] fn an_episode_that_is_not_a_whole_number_is_neither_rounded_nor_absent() { // `05.5` arrives as one episode element whose value is the text "05.5". - // Rounded into a neighbour it would record progress against an episode + // Rounded into a neighbor it would record progress against an episode // nobody watched; called absent it would be indistinguishable from a // film, and a film is a work this program marks watched as a whole. It // is neither. @@ -843,7 +843,7 @@ mod tests { #[test] fn a_part_the_parser_reports_is_kept() { - // `Cour 2` is a part the parser recognises on its own. AniList lists + // `Cour 2` is a part the parser recognizes on its own. AniList lists // the second part of some seasons as an entry of its own, so a name // that spells one has to say so. let parsed = spelled("Show Title Season 2 Cour 2 - 03.mkv"); @@ -909,7 +909,7 @@ mod tests { fn a_part_inside_the_title_stays_in_the_title() { // With no season in front of it, the parser keeps `Part 2` inside the // title. Nothing here reads it out. A list entry is text that never - // meets the parser, so the normaliser has to take a part out of a + // meets the parser, so the normalizer has to take a part out of a // title's text anyway, and one place doing that is one rule where two // would have to agree. let parsed = spelled("Show Title Part 2 - 03.mkv"); diff --git a/crates/core/src/recognise/score.rs b/crates/core/src/recognize/score.rs similarity index 94% rename from crates/core/src/recognise/score.rs rename to crates/core/src/recognize/score.rs index cbcb8a5..ef5c1d5 100644 --- a/crates/core/src/recognise/score.rs +++ b/crates/core/src/recognize/score.rs @@ -8,7 +8,7 @@ //! **The text it scores is the whole name**, through //! [`Parsed::text`](super::parse::Parsed::text), which is the filename with the //! release's own words struck out. A title ends at the first thing the parser -//! recognises, so a file of a special whose name extends a series' name reports +//! recognizes, so a file of a special whose name extends a series' name reports //! the series and nothing of the subtitle that tells the two apart. //! //! **A candidate is judged by how much of the name it accounts for**, as the @@ -54,10 +54,10 @@ use std::collections::HashSet; use crate::ShowId; -use crate::recognise::corpus::Corpus; -use crate::recognise::normalise::wording_of; -use crate::recognise::parse::Parsed; -use crate::recognise::{Match, Recognition, Refusal, Score, Stage}; +use crate::recognize::corpus::Corpus; +use crate::recognize::normalize::wording_of; +use crate::recognize::parse::Parsed; +use crate::recognize::{Match, Recognition, Refusal, Score, Stage}; /// How many words a comparison has to spell before the ordinary margin applies. /// @@ -83,7 +83,7 @@ pub const NEAR_ENOUGH: f64 = 0.70; /// How much of the two the name and the spelling have in common. /// /// The words they share against the words they spell between them, so that -/// neither a long entry nor a long name is favoured by its length alone. +/// neither a long entry nor a long name is favored by its length alone. /// /// # Panics /// @@ -95,7 +95,7 @@ pub fn alike(name: &[String], spelling: &[String]) -> Score { let spelling: HashSet<&String> = spelling.iter().collect(); let between = name.len() + spelling.len(); if between == 0 { - return Score::new(0.0).expect("nought is a proportion"); + return Score::new(0.0).expect("zero is a proportion"); } let shared = name.intersection(&spelling).count(); let of = |count: usize| f64::from(u32::try_from(count).unwrap_or(u32::MAX)); @@ -121,7 +121,7 @@ pub fn alike(name: &[String], spelling: &[String]) -> Score { pub fn by_score(parsed: &Parsed, candidates: &[ShowId], corpus: &Corpus) -> Recognition { let name = wording_of(&parsed.text); let refused = |best| { - Recognition::Unrecognised(Refusal { + Recognition::Unrecognized(Refusal { parsed: parsed.title.clone().unwrap_or_default(), best, }) @@ -160,7 +160,7 @@ pub fn by_score(parsed: &Parsed, candidates: &[ShowId], corpus: &Corpus) -> Reco if best.value() < NEAR_ENOUGH || best.value() - runner_up < ahead { return refused(Some(best)); } - Recognition::Recognised(Match { + Recognition::Recognized(Match { show, title: corpus.title_of(show).unwrap_or_default().to_owned(), episode: parsed.episode, @@ -190,19 +190,19 @@ mod tests { use crate::ShowId; use crate::encoding::Confidence; use crate::path::RawPath; - use crate::recognise::corpus::Corpus; - use crate::recognise::normalise::{Key, words_in}; - use crate::recognise::parse::{Episode, Parsed, parse}; - use crate::recognise::{Match, Recognition, Refusal, Score, Stage}; + use crate::recognize::corpus::Corpus; + use crate::recognize::normalize::{Key, words_in}; + use crate::recognize::parse::{Episode, Parsed, parse}; + use crate::recognize::{Match, Recognition, Refusal, Score, Stage}; /// What a file of this name spells. - fn named(name: &str) -> crate::recognise::parse::Parsed { + fn named(name: &str) -> crate::recognize::parse::Parsed { parse(&RawPath::from_bytes(name.as_bytes().to_vec())) } /// A score the tests use where the exact value is not the point. fn a_score(value: f64) -> Score { - Score::new(value).expect("the value is between nought and one") + Score::new(value).expect("the value is between zero and one") } /// The shows these titles are filed as, for a test that names its @@ -224,7 +224,7 @@ mod tests { /// The match an answer carries, where the test says it has to be one. fn answered(answer: Recognition, must: &str) -> Match { match answer { - Recognition::Recognised(found) => found, + Recognition::Recognized(found) => found, refused => panic!("{must}, got {refused:?}"), } } @@ -256,11 +256,11 @@ mod tests { ); assert!( - matches!(by_the_short, Recognition::Unrecognised(_)), + matches!(by_the_short, Recognition::Unrecognized(_)), "a two-word entry needs a wider win" ); assert!( - matches!(by_the_long, Recognition::Recognised(_)), + matches!(by_the_long, Recognition::Recognized(_)), "the same win is enough for four words" ); } @@ -301,7 +301,7 @@ mod tests { &corpus, ); - assert!(matches!(alone, Recognition::Unrecognised(_))); + assert!(matches!(alone, Recognition::Unrecognized(_))); assert!(alike(&words_in("Some Other Show"), &words_in("Show Title")).value() < NEAR_ENOUGH); } @@ -319,7 +319,7 @@ mod tests { &shows(&corpus, &["Show Title Alpha", "Show Title Beta"]), &corpus ), - Recognition::Unrecognised(_) + Recognition::Unrecognized(_) )); } @@ -341,7 +341,7 @@ mod tests { &shows(&corpus, &["Show Title Alpha", "Show Title Beta Gamma"]), &corpus ), - Recognition::Unrecognised(Refusal { + Recognition::Unrecognized(Refusal { parsed: "Show Title".to_owned(), best: Some(a_score(0.8)), }) @@ -349,14 +349,14 @@ mod tests { } #[test] - fn nothing_to_score_is_no_score_rather_than_nought() { - // No candidate reached the scorer, so no comparison was made. Nought + fn nothing_to_score_is_no_score_rather_than_zero() { + // No candidate reached the scorer, so no comparison was made. Zero // would say one was made and the closest entry shared nothing. let corpus: Corpus = ["Show Title"].into_iter().collect(); assert_eq!( by_score(&named("Show Title - 03.mkv"), &[], &corpus), - Recognition::Unrecognised(Refusal { + Recognition::Unrecognized(Refusal { parsed: "Show Title".to_owned(), best: None, }) @@ -386,7 +386,7 @@ mod tests { #[test] fn the_name_is_scored_rather_than_the_title_the_parser_left() { // What this stage exists for. A title ends at the first thing the - // parser recognises, so this file reports `Show Title` and nothing of + // parser recognizes, so this file reports `Show Title` and nothing of // the subtitle after it. Judged on that title the series wins, and the // special it extends is never answered at all. let corpus: Corpus = ["Show Title", "Show Title Cour 2 The Subtitle"] @@ -460,7 +460,7 @@ mod tests { fn nothing_was_scored(answer: &Recognition) -> bool { matches!( answer, - Recognition::Unrecognised(Refusal { best: None, .. }) + Recognition::Unrecognized(Refusal { best: None, .. }) ) } @@ -622,7 +622,7 @@ mod tests { assert!( matches!( by_another_season, - Recognition::Unrecognised(Refusal { best, .. }) if best.is_some_and(|score| score.value() < NEAR_ENOUGH) + Recognition::Unrecognized(Refusal { best, .. }) if best.is_some_and(|score| score.value() < NEAR_ENOUGH) ), "the words of the other spelling were scored: {by_another_season:?}" ); diff --git a/crates/core/src/session.rs b/crates/core/src/session.rs index d5c5607..5a21bab 100644 --- a/crates/core/src/session.rs +++ b/crates/core/src/session.rs @@ -64,8 +64,8 @@ use std::time::Duration; use crate::clock::Timestamp; use crate::path::RawPath; -use crate::recognise::Recognition; -use crate::recognise::parse::Episode; +use crate::recognize::Recognition; +use crate::recognize::parse::Episode; use crate::timeline::{Progress, Timeline, WatchedPolicy}; use crate::{Known, MediaRef, PlayerId, PlayerSnapshot, ShowId}; @@ -175,8 +175,8 @@ impl<'reading> Named<'reading> { return None; }; let found = match decision? { - Recognition::Recognised(found) => found, - Recognition::Ambiguous(_) | Recognition::Unrecognised(_) => return None, + Recognition::Recognized(found) => found, + Recognition::Ambiguous(_) | Recognition::Unrecognized(_) => return None, }; let episode = match found.episode { Episode::Only(number) => Some(number), @@ -598,11 +598,11 @@ mod tests { use super::{Effect, Question, Resumed, Session}; use crate::clock::{Clock, TestClock, Timestamp}; use crate::path::RawPath; - use crate::recognise::altname::Altnames; - use crate::recognise::corpus::Corpus; - use crate::recognise::index::Index; - use crate::recognise::parse::{Episode, parse}; - use crate::recognise::{Ambiguity, Candidate, Match, Recognition, Refusal, Stage, decide}; + use crate::recognize::altname::Altnames; + use crate::recognize::corpus::Corpus; + use crate::recognize::index::Index; + use crate::recognize::parse::{Episode, parse}; + use crate::recognize::{Ambiguity, Candidate, Match, Recognition, Refusal, Stage, decide}; use crate::timeline::{WATCHED_FALLBACK, WatchedPolicy}; use crate::{Known, MediaRef, PlayState, PlayerId, PlayerSnapshot, ShowId}; use std::cell::Cell; @@ -640,7 +640,7 @@ mod tests { const NOT_LISTED: &str = "/anime/[Group] Some Other Show - 03 [1080p].mkv"; /// What a run answers where it answers nothing, named because an empty - /// array otherwise needs its element type spelt out at every use. + /// array otherwise needs its element type spelled out at every use. const NOTHING: [Effect; 0] = []; /// The readings that recorded an episode in a run that recorded none. @@ -798,8 +798,8 @@ mod tests { } /// A decision written out by hand, for a test that is about the decision. - fn recognised(show: ShowId, episode: Episode) -> Recognition { - Recognition::Recognised(Match { + fn recognized(show: ShowId, episode: Episode) -> Recognition { + Recognition::Recognized(Match { show, title: title_of(show).to_owned(), episode, @@ -2074,7 +2074,7 @@ mod tests { let player = Player::named("mpv"); assert_eq!( decided(&player.playing(THE_FILM)), - Some(recognised(FILM, Episode::Absent)) + Some(recognized(FILM, Episode::Absent)) ); let answers = watch(&mut session, &player, THE_FILM, 150, None); @@ -2092,14 +2092,14 @@ mod tests { #[test] fn a_file_of_several_episodes_is_not_recorded() { - // The show is recognised, which the first assertion holds, so what + // The show is recognized, which the first assertion holds, so what // is refused is the episode: a file of twelve is neither the first // nor the twelfth, and with no episode it would arrive as a film. let mut session = Session::new(half()); let player = Player::named("mpv"); assert_eq!( decided(&player.playing(A_BATCH)), - Some(recognised(SERIES, Episode::Several)) + Some(recognized(SERIES, Episode::Several)) ); let answers = watch(&mut session, &player, A_BATCH, 150, None); @@ -2113,7 +2113,7 @@ mod tests { let player = Player::named("mpv"); assert_eq!( decided(&player.playing(A_HALF)), - Some(recognised(SERIES, Episode::NotWhole)) + Some(recognized(SERIES, Episode::NotWhole)) ); let answers = watch(&mut session, &player, A_HALF, 150, None); @@ -2127,7 +2127,7 @@ mod tests { let player = Player::named("mpv"); assert!(matches!( decided(&player.playing(NOT_LISTED)), - Some(Recognition::Unrecognised(_)) + Some(Recognition::Unrecognized(_)) )); let answers = watch(&mut session, &player, NOT_LISTED, 150, None); @@ -2177,7 +2177,7 @@ mod tests { fn a_reading_that_names_no_file_is_not_recorded_whatever_was_decided() { // What is kept and what is recorded both carry the file. An address // is not one, and neither is a title with nothing underneath it. - let decision = recognised(SERIES, Episode::Only(3)); + let decision = recognized(SERIES, Episode::Only(3)); for media in [ MediaRef::Remote("https://example.invalid/show-title-03.m3u8".to_owned()), @@ -2207,10 +2207,10 @@ mod tests { // and then it is what it was at the start. let mut session = Session::new(half()); let player = Player::named("mpv"); - let the_third = recognised(SERIES, Episode::Only(3)); - let the_fourth = recognised(SERIES, Episode::Only(4)); - let of_the_second = recognised(SECOND_SERIES, Episode::Only(4)); - let nothing = Recognition::Unrecognised(Refusal { + let the_third = recognized(SERIES, Episode::Only(3)); + let the_fourth = recognized(SERIES, Episode::Only(4)); + let of_the_second = recognized(SECOND_SERIES, Episode::Only(4)); + let nothing = Recognition::Unrecognized(Refusal { parsed: "Show Title".to_owned(), best: None, }); @@ -2258,8 +2258,8 @@ mod tests { // old one. let mut session = Session::new(half()); let stamps = Stamps::new(); - let the_third = recognised(SERIES, Episode::Only(3)); - let the_fourth = recognised(SERIES, Episode::Only(4)); + let the_third = recognized(SERIES, Episode::Only(3)); + let the_fourth = recognized(SERIES, Episode::Only(4)); let mut round = |at: u64, decision: &Recognition| { let first = session.advance(&stamps.playing("mpv", THIRD, at), Some(decision)); let second = session.advance(&stamps.playing("vlc", THIRD, at + 200), Some(decision)); @@ -2287,8 +2287,8 @@ mod tests { // total of the other. let mut session = Session::new(half()); let stamps = Stamps::new(); - let of_one = recognised(ShowId(7), Episode::Only(3)); - let of_the_other = recognised(ShowId(9), Episode::Only(3)); + let of_one = recognized(ShowId(7), Episode::Only(3)); + let of_the_other = recognized(ShowId(9), Episode::Only(3)); let one = session.advance(&stamps.playing("mpv", THIRD, 1000), Some(&of_one)); let the_other = session.advance( diff --git a/crates/core/src/token.rs b/crates/core/src/token.rs index daf44fd..67b2d46 100644 --- a/crates/core/src/token.rs +++ b/crates/core/src/token.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; /// /// `{:?}` prints no part of it, so a token formatted into a message, a log /// line or the output of a failed test is not given away there. The text is -/// read with [`Token::secret`] and serialised whole, where the token is sent +/// read with [`Token::secret`] and serialized whole, where the token is sent /// or kept. #[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(transparent)] @@ -50,8 +50,8 @@ mod tests { fn a_token_travels_as_its_text() { let token = Token::new("header.payload.signature"); - let text = serde_json::to_string(&token).expect("serialise"); - let back: Token = serde_json::from_str(&text).expect("deserialise"); + let text = serde_json::to_string(&token).expect("serialize"); + let back: Token = serde_json::from_str(&text).expect("deserialize"); assert_eq!(text, "\"header.payload.signature\""); assert_eq!(back.secret(), "header.payload.signature"); diff --git a/crates/core/src/trace.rs b/crates/core/src/trace.rs index aead4c2..cf4c41e 100644 --- a/crates/core/src/trace.rs +++ b/crates/core/src/trace.rs @@ -122,7 +122,7 @@ struct Version { /// A recording: a header, and the readings taken under it. /// -/// Not serialisable as one value, deliberately. A trace is a file of lines +/// Not serializable as one value, deliberately. A trace is a file of lines /// rather than a JSON document, and a derived `Serialize` would put a second /// representation - one object with an array inside it - beside the format, /// free to drift from it and easy to reach for by mistake. @@ -141,7 +141,7 @@ impl Trace { /// # Errors /// /// [`TraceError::NotWritten`] if the header or a reading cannot be - /// serialised. + /// serialized. pub fn to_jsonl(&self) -> Result { let mut text = header_line(&self.header)?; for snapshot in &self.snapshots { @@ -199,7 +199,7 @@ impl Trace { /// /// # Errors /// -/// [`TraceError::NotWritten`] if the header cannot be serialised. +/// [`TraceError::NotWritten`] if the header cannot be serialized. pub fn header_line(header: &TraceHeader) -> Result { line(header) } @@ -210,7 +210,7 @@ pub fn header_line(header: &TraceHeader) -> Result { /// /// # Errors /// -/// [`TraceError::NotWritten`] if the reading cannot be serialised. +/// [`TraceError::NotWritten`] if the reading cannot be serialized. pub fn snapshot_line(snapshot: &PlayerSnapshot) -> Result { line(snapshot) } @@ -268,7 +268,7 @@ pub enum TraceError { /// A line could not be produced. #[error("trace line could not be written: {source}")] NotWritten { - /// What the serialiser said. + /// What the serializer said. #[source] source: serde_json::Error, }, @@ -718,7 +718,7 @@ mod tests { } #[test] - fn a_line_that_cannot_be_written_says_what_the_serialiser_said() { + fn a_line_that_cannot_be_written_says_what_the_serializer_said() { // A map keyed by a pair is one JSON cannot spell. let unwritable = std::collections::BTreeMap::from([((1, 2), 3)]); diff --git a/crates/core/tests/fixtures/filenames.jsonl b/crates/core/tests/fixtures/filenames.jsonl index 7bd468a..527c483 100644 --- a/crates/core/tests/fixtures/filenames.jsonl +++ b/crates/core/tests/fixtures/filenames.jsonl @@ -1,48 +1,48 @@ -{"name": "[SubsPlease] Show Title - 03 (1080p) [A1B2C3D4].mkv", "rule": "the release group, the resolution, the hash and the extension are not the name", "list": [{"title": "Show Title"}, {"title": "Another Show"}], "expect": {"recognised": {"title": "Show Title", "episode": 3, "stage": "key"}}} -{"name": "Show.Title.S01E03.1080p.WEB-DL.mkv", "rule": "punctuation between words is not the name, and a first season is no season", "list": [{"title": "Show Title"}], "expect": {"recognised": {"title": "Show Title", "episode": 3, "stage": "key"}}} -{"name": "show title - 03.mkv", "rule": "case is not the name", "list": [{"title": "Show Title"}], "expect": {"recognised": {"title": "Show Title", "episode": 3, "stage": "key"}}} -{"name": "SHOW TITLE - 03.mkv", "rule": "a full-width spelling is the ordinary spelling", "list": [{"title": "Show Title"}], "expect": {"recognised": {"title": "Show Title", "episode": 3, "stage": "key"}}} -{"name": "%83\\%83%8C%83b%83^ - 03.mkv", "rule": "a name that is not UTF-8 is read through an inferred encoding and still reaches its entry", "list": [{"title": "ソレッタ"}], "expect": {"recognised": {"title": "ソレッタ", "episode": 3, "stage": "key"}}} -{"name": "[Group] Show Title 01-12 [BD].mkv", "rule": "an episode range is several episodes and none of them", "list": [{"title": "Show Title"}], "expect": {"recognised": {"title": "Show Title", "episode": "several", "stage": "key"}}} -{"name": "Show Title - 05.5.mkv", "rule": "a half episode is not a whole number and not an absence", "list": [{"title": "Show Title"}], "expect": {"recognised": {"title": "Show Title", "episode": "not whole", "stage": "key"}}} -{"name": "Kimi no Na wa (2016) [1080p].mkv", "rule": "a film spells no episode, and a year in brackets is not the name", "list": [{"title": "Kimi no Na wa"}], "expect": {"recognised": {"title": "Kimi no Na wa", "episode": "none", "stage": "key"}}} -{"name": "Show.Title.The.Movie.s00e00.HD1080p.WEBRip.mp4", "rule": "a season and an episode of nought together number nothing, and the name is read as spelling neither", "list": [{"title": "Show Title The Movie"}, {"title": "Show Title"}], "expect": {"recognised": {"title": "Show Title The Movie", "episode": "none", "stage": "key"}}} -{"name": "Show.Title.S00E03.1080p.WEB.mkv", "rule": "an episode in a season of nought is a special, and is no episode of the series", "list": [{"title": "Show Title"}], "expect": {"unrecognised": "nothing_scored"}} -{"name": "Show Title - 03v2.mkv", "rule": "a version suffix is not part of the episode", "list": [{"title": "Show Title"}], "expect": {"recognised": {"title": "Show Title", "episode": 3, "stage": "key"}}} -{"name": "Show Title S02E03.mkv", "rule": "S02 spells the second season", "list": [{"title": "Show Title"}, {"title": "Show Title 2nd Season"}], "expect": {"recognised": {"title": "Show Title 2nd Season", "episode": 3, "stage": "key"}}} -{"name": "Show Title Season 2 - 03.mkv", "rule": "Season 2 spells the second season", "list": [{"title": "Show Title"}, {"title": "Show Title 2nd Season"}], "expect": {"recognised": {"title": "Show Title 2nd Season", "episode": 3, "stage": "key"}}} -{"name": "Show Title 2nd Season - 03.mkv", "rule": "2nd Season spells the second season", "list": [{"title": "Show Title"}, {"title": "Show Title 2nd Season"}], "expect": {"recognised": {"title": "Show Title 2nd Season", "episode": 3, "stage": "key"}}} -{"name": "Show Title II - 03.mkv", "rule": "a roman numeral ending the title spells the second season", "list": [{"title": "Show Title"}, {"title": "Show Title 2nd Season"}], "expect": {"recognised": {"title": "Show Title 2nd Season", "episode": 3, "stage": "key"}}} -{"name": "Gokushufudou S2 - 03.mkv", "rule": "an abbreviated season is the season and not the part of the same number", "list": [{"title": "Gokushufudou"}, {"title": "Gokushufudou Part 2"}, {"title": "Gokushufudou Season 2"}], "expect": {"recognised": {"title": "Gokushufudou Season 2", "episode": 3, "stage": "key"}}} -{"name": "Show Title (Season 1 Part 2) - 03.mkv", "rule": "a part after the season marker is read back from the text the parser left", "list": [{"title": "Show Title"}, {"title": "Show Title Part 2"}], "expect": {"recognised": {"title": "Show Title Part 2", "episode": 3, "stage": "key"}}} -{"name": "K-ON!! - 03.mkv", "rule": "a mark ending the title tells two seasons apart", "list": [{"title": "K-ON!"}, {"title": "K-ON!!"}], "expect": {"recognised": {"title": "K-ON!!", "episode": 3, "stage": "key"}}} +{"name": "[SubsPlease] Show Title - 03 (1080p) [A1B2C3D4].mkv", "rule": "the release group, the resolution, the hash and the extension are not the name", "list": [{"title": "Show Title"}, {"title": "Another Show"}], "expect": {"recognized": {"title": "Show Title", "episode": 3, "stage": "key"}}} +{"name": "Show.Title.S01E03.1080p.WEB-DL.mkv", "rule": "punctuation between words is not the name, and a first season is no season", "list": [{"title": "Show Title"}], "expect": {"recognized": {"title": "Show Title", "episode": 3, "stage": "key"}}} +{"name": "show title - 03.mkv", "rule": "case is not the name", "list": [{"title": "Show Title"}], "expect": {"recognized": {"title": "Show Title", "episode": 3, "stage": "key"}}} +{"name": "SHOW TITLE - 03.mkv", "rule": "a full-width spelling is the ordinary spelling", "list": [{"title": "Show Title"}], "expect": {"recognized": {"title": "Show Title", "episode": 3, "stage": "key"}}} +{"name": "%83\\%83%8C%83b%83^ - 03.mkv", "rule": "a name that is not UTF-8 is read through an inferred encoding and still reaches its entry", "list": [{"title": "ソレッタ"}], "expect": {"recognized": {"title": "ソレッタ", "episode": 3, "stage": "key"}}} +{"name": "[Group] Show Title 01-12 [BD].mkv", "rule": "an episode range is several episodes and none of them", "list": [{"title": "Show Title"}], "expect": {"recognized": {"title": "Show Title", "episode": "several", "stage": "key"}}} +{"name": "Show Title - 05.5.mkv", "rule": "a half episode is not a whole number and not an absence", "list": [{"title": "Show Title"}], "expect": {"recognized": {"title": "Show Title", "episode": "not whole", "stage": "key"}}} +{"name": "Kimi no Na wa (2016) [1080p].mkv", "rule": "a film spells no episode, and a year in brackets is not the name", "list": [{"title": "Kimi no Na wa"}], "expect": {"recognized": {"title": "Kimi no Na wa", "episode": "none", "stage": "key"}}} +{"name": "Show.Title.The.Movie.s00e00.HD1080p.WEBRip.mp4", "rule": "season zero and episode zero together number nothing, and the name is read as spelling neither", "list": [{"title": "Show Title The Movie"}, {"title": "Show Title"}], "expect": {"recognized": {"title": "Show Title The Movie", "episode": "none", "stage": "key"}}} +{"name": "Show.Title.S00E03.1080p.WEB.mkv", "rule": "an episode in season zero is a special, and is no episode of the series", "list": [{"title": "Show Title"}], "expect": {"unrecognized": "nothing_scored"}} +{"name": "Show Title - 03v2.mkv", "rule": "a version suffix is not part of the episode", "list": [{"title": "Show Title"}], "expect": {"recognized": {"title": "Show Title", "episode": 3, "stage": "key"}}} +{"name": "Show Title S02E03.mkv", "rule": "S02 spells the second season", "list": [{"title": "Show Title"}, {"title": "Show Title 2nd Season"}], "expect": {"recognized": {"title": "Show Title 2nd Season", "episode": 3, "stage": "key"}}} +{"name": "Show Title Season 2 - 03.mkv", "rule": "Season 2 spells the second season", "list": [{"title": "Show Title"}, {"title": "Show Title 2nd Season"}], "expect": {"recognized": {"title": "Show Title 2nd Season", "episode": 3, "stage": "key"}}} +{"name": "Show Title 2nd Season - 03.mkv", "rule": "2nd Season spells the second season", "list": [{"title": "Show Title"}, {"title": "Show Title 2nd Season"}], "expect": {"recognized": {"title": "Show Title 2nd Season", "episode": 3, "stage": "key"}}} +{"name": "Show Title II - 03.mkv", "rule": "a roman numeral ending the title spells the second season", "list": [{"title": "Show Title"}, {"title": "Show Title 2nd Season"}], "expect": {"recognized": {"title": "Show Title 2nd Season", "episode": 3, "stage": "key"}}} +{"name": "Gokushufudou S2 - 03.mkv", "rule": "an abbreviated season is the season and not the part of the same number", "list": [{"title": "Gokushufudou"}, {"title": "Gokushufudou Part 2"}, {"title": "Gokushufudou Season 2"}], "expect": {"recognized": {"title": "Gokushufudou Season 2", "episode": 3, "stage": "key"}}} +{"name": "Show Title (Season 1 Part 2) - 03.mkv", "rule": "a part after the season marker is read back from the text the parser left", "list": [{"title": "Show Title"}, {"title": "Show Title Part 2"}], "expect": {"recognized": {"title": "Show Title Part 2", "episode": 3, "stage": "key"}}} +{"name": "K-ON!! - 03.mkv", "rule": "a mark ending the title tells two seasons apart", "list": [{"title": "K-ON!"}, {"title": "K-ON!!"}], "expect": {"recognized": {"title": "K-ON!!", "episode": 3, "stage": "key"}}} {"name": "K-ON - 03.mkv", "rule": "a name that lost its marks reaches every season and says so", "list": [{"title": "K-ON!"}, {"title": "K-ON!!"}], "expect": {"ambiguous": ["K-ON!", "K-ON!!"]}} {"name": "Fruits Basket (2019) - 01.mkv", "rule": "a remake spelled like its original is an ambiguity", "list": [{"title": "Fruits Basket"}, {"title": "Fruits Basket (2019)"}], "expect": {"ambiguous": ["Fruits Basket", "Fruits Basket (2019)"]}, "owed": "the year: the name carries one and no entry does until the list supplies it"} -{"name": "Show Title - 03.mkv", "rule": "a type in brackets is not part of an entry's name", "list": [{"title": "Show Title (TV)"}], "expect": {"recognised": {"title": "Show Title (TV)", "episode": 3, "stage": "key"}}} -{"name": "Show Title 2019 - 03.mkv", "rule": "a year standing as a word of its own is not the name", "list": [{"title": "Show Title"}], "expect": {"recognised": {"title": "Show Title", "episode": 3, "stage": "key"}}} -{"name": "[SubsPlease] Oshi no Ko - 03 (1080p).mkv", "rule": "brackets in a list entry are part of its name", "list": [{"title": "[Oshi no Ko]"}], "expect": {"recognised": {"title": "[Oshi no Ko]", "episode": 3, "stage": "key"}}} -{"name": "Attack on Titan - 03.mkv", "rule": "an entry answers to every spelling it carries", "list": [{"title": "Shingeki no Kyojin", "spellings": ["Attack on Titan", "進撃の巨人"]}, {"title": "Kimi no Na wa"}], "expect": {"recognised": {"title": "Shingeki no Kyojin", "episode": 3, "stage": "key"}}} -{"name": "進撃の巨人 - 03.mkv", "rule": "a native spelling reaches the entry", "list": [{"title": "Shingeki no Kyojin", "spellings": ["Attack on Titan", "進撃の巨人"]}, {"title": "Kimi no Na wa"}], "expect": {"recognised": {"title": "Shingeki no Kyojin", "episode": 3, "stage": "key"}}} -{"name": "Nisekoi - 03.mkv", "rule": "text the user named outranks what the corpus answers", "list": [{"title": "Nisekoi"}, {"title": "Nisekoi:"}], "altnames": [{"spelled": "Nisekoi", "title": "Nisekoi:"}], "expect": {"recognised": {"title": "Nisekoi:", "episode": 3, "stage": "altname"}}} -{"name": "[Group] SnK - 03.mkv", "rule": "an abbreviation no entry spells is what an assignment is for", "list": [{"title": "Shingeki no Kyojin"}], "altnames": [{"spelled": "SnK", "title": "Shingeki no Kyojin"}], "expect": {"recognised": {"title": "Shingeki no Kyojin", "episode": 3, "stage": "altname"}}} -{"name": "Kaguya-sama.Love.is.War.S03E03.1080p.WEB-DL.mkv", "rule": "a file the user named is found by what it spelled, season and all", "list": [{"title": "Kaguya-sama: Love is War"}, {"title": "Kaguya-sama: Love is War -Ultra Romantic-"}], "altnames": [{"file": "Kaguya-sama.Love.is.War.S03E03.1080p.WEB-DL.mkv", "title": "Kaguya-sama: Love is War -Ultra Romantic-"}], "expect": {"recognised": {"title": "Kaguya-sama: Love is War -Ultra Romantic-", "episode": 3, "stage": "altname"}}} -{"name": "Kaguya-sama.Love.is.War.S01E03.1080p.WEB-DL.mkv", "rule": "an assignment made from a third-season file leaves the first season to the corpus", "list": [{"title": "Kaguya-sama: Love is War"}, {"title": "Kaguya-sama: Love is War -Ultra Romantic-"}], "altnames": [{"file": "Kaguya-sama.Love.is.War.S03E03.1080p.WEB-DL.mkv", "title": "Kaguya-sama: Love is War -Ultra Romantic-"}], "expect": {"recognised": {"title": "Kaguya-sama: Love is War", "episode": 3, "stage": "key"}}} -{"name": "Attack on Titan Final - 03.mkv", "rule": "a name the key misses is judged by the entry's closest spelling", "list": [{"title": "Shingeki no Kyojin", "spellings": ["Attack on Titan"]}, {"title": "Kimi no Na wa"}], "expect": {"recognised": {"title": "Shingeki no Kyojin", "episode": 3, "stage": "score"}}} -{"name": "Show Title Cour 2 - The Subtitle - 03.mkv", "rule": "a name the key misses is scored over the whole name, subtitle and all", "list": [{"title": "Show Title"}, {"title": "Show Title Cour 2 The Subtitle"}], "expect": {"recognised": {"title": "Show Title Cour 2 The Subtitle", "episode": 3, "stage": "score"}}} -{"name": "Mushoku Tensei Jobless Reincarnation Cour 2 - Eris the Goblin Slayer - 01.mkv", "rule": "a special extending a series' name reaches the entry it extends", "list": [{"title": "Mushoku Tensei: Jobless Reincarnation"}, {"title": "Mushoku Tensei: Jobless Reincarnation Cour 2"}, {"title": "Mushoku Tensei: Jobless Reincarnation Cour 2 - Eris the Goblin Slayer"}], "expect": {"recognised": {"title": "Mushoku Tensei: Jobless Reincarnation Cour 2", "episode": 1, "stage": "key"}}, "owed": "the list: an entry's format and episode count are what tell a special from the series it extends, and the key answers before the scorer sees the subtitle"} -{"name": "Miss Kobayashi's Dragon Maid - 14.mkv", "rule": "a spelling that names an episode is that episode of the series", "list": [{"title": "Miss Kobayashi's Dragon Maid"}, {"title": "Miss Kobayashi's Dragon Maid Special", "spellings": ["Miss Kobayashi's Dragon Maid Episode 14"]}], "expect": {"recognised": {"title": "Miss Kobayashi's Dragon Maid", "episode": 14, "stage": "key"}}, "owed": "the list: only an entry's episode count can say the series has no fourteenth"} -{"name": "Show Title - 03.mkv", "rule": "two entries running level are refused and not chosen between", "list": [{"title": "Show Title Alpha"}, {"title": "Show Title Beta"}], "expect": {"unrecognised": "scored"}} -{"name": "Some Other Show - 03.mkv", "rule": "one shared word with one entry is not near enough", "list": [{"title": "Show Title"}], "expect": {"unrecognised": "scored"}} -{"name": "Alpha Beta Gamma S02E03.mkv", "rule": "a file of a second season is not given to an entry that spells none", "list": [{"title": "Alpha Beta Gamma"}], "expect": {"unrecognised": "nothing_scored"}} -{"name": "Alpha Beta Gamma - 03.mkv", "rule": "a file that spells no season is not given to a second season", "list": [{"title": "Alpha Beta Gamma 2nd Season"}], "expect": {"unrecognised": "nothing_scored"}} -{"name": "Alpha Beta II - 03.mkv", "rule": "the season a name spells chooses between two seasons its words reach alike", "list": [{"title": "Alpha Beta Gamma"}, {"title": "Alpha Beta Gamma 2nd Season"}], "expect": {"recognised": {"title": "Alpha Beta Gamma 2nd Season", "episode": 3, "stage": "score"}}} -{"name": "Alpha Beta S01E03.mkv", "rule": "the letters of a season and an episode go with their numbers and count against no entry", "list": [{"title": "Alpha Beta Gamma"}], "expect": {"recognised": {"title": "Alpha Beta Gamma", "episode": 3, "stage": "score"}}} -{"name": "Alpha Beta Episode 03.mkv", "rule": "the word that marks an episode goes with its number", "list": [{"title": "Alpha Beta Gamma"}], "expect": {"recognised": {"title": "Alpha Beta Gamma", "episode": 3, "stage": "score"}}} -{"name": "Alpha Beta 2nd Season - 03.mkv", "rule": "a season spelled with an ordinal goes whole, the ordinal and the word", "list": [{"title": "Alpha Beta Gamma 2nd Season"}], "expect": {"recognised": {"title": "Alpha Beta Gamma 2nd Season", "episode": 3, "stage": "score"}}} -{"name": "Alpha Beta - 03 [Uncensored].mkv", "rule": "a word the parser reports as other, such as Uncensored, counts against no entry", "list": [{"title": "Alpha Beta Gamma"}], "expect": {"recognised": {"title": "Alpha Beta Gamma", "episode": 3, "stage": "score"}}} -{"name": "Completely Different - 03.mkv", "rule": "a name no entry shares a word with is refused with nothing scored", "list": [{"title": "Show Title"}], "expect": {"unrecognised": "nothing_scored"}} -{"name": "ep 03.mkv", "rule": "a name that spells no title reaches the end of the sequence and is refused", "list": [{"title": "Show Title"}], "expect": {"unrecognised": "nothing_scored"}} -{"name": "[Group] 文豪ストレイドッグス 『独り歩む』; - 03.mkv", "rule": "a stage cannot find a title in a stray mark", "list": [{"title": "Bungou Stray Dogs: Hitori Ayumu", "spellings": ["文豪ストレイドッグス 『独り歩む』;"]}], "expect": {"unrecognised": "nothing_scored"}, "owed": "the parser: it takes the bracketed part of the name for a release group and drops the rest, leaving a title of one mark that no stage can place"} -{"name": "[Group] E7 - 03 [1080p].mkv", "rule": "a title that looks like an episode marker is read as one", "list": [{"title": "E7"}], "expect": {"unrecognised": "nothing_scored"}, "owed": "the parser: it reads the title as the seventh episode and the episode as the title"} -{"name": "Alpha Beta Remastered - 03.mkv", "rule": "an entry that spells a keyword the parser reports as other is filed without it", "list": [{"title": "Alpha Beta Remastered"}], "expect": {"recognised": {"title": "Alpha Beta Remastered", "episode": 3, "stage": "key"}}} +{"name": "Show Title - 03.mkv", "rule": "a type in brackets is not part of an entry's name", "list": [{"title": "Show Title (TV)"}], "expect": {"recognized": {"title": "Show Title (TV)", "episode": 3, "stage": "key"}}} +{"name": "Show Title 2019 - 03.mkv", "rule": "a year standing as a word of its own is not the name", "list": [{"title": "Show Title"}], "expect": {"recognized": {"title": "Show Title", "episode": 3, "stage": "key"}}} +{"name": "[SubsPlease] Oshi no Ko - 03 (1080p).mkv", "rule": "brackets in a list entry are part of its name", "list": [{"title": "[Oshi no Ko]"}], "expect": {"recognized": {"title": "[Oshi no Ko]", "episode": 3, "stage": "key"}}} +{"name": "Attack on Titan - 03.mkv", "rule": "an entry answers to every spelling it carries", "list": [{"title": "Shingeki no Kyojin", "spellings": ["Attack on Titan", "進撃の巨人"]}, {"title": "Kimi no Na wa"}], "expect": {"recognized": {"title": "Shingeki no Kyojin", "episode": 3, "stage": "key"}}} +{"name": "進撃の巨人 - 03.mkv", "rule": "a native spelling reaches the entry", "list": [{"title": "Shingeki no Kyojin", "spellings": ["Attack on Titan", "進撃の巨人"]}, {"title": "Kimi no Na wa"}], "expect": {"recognized": {"title": "Shingeki no Kyojin", "episode": 3, "stage": "key"}}} +{"name": "Nisekoi - 03.mkv", "rule": "text the user named outranks what the corpus answers", "list": [{"title": "Nisekoi"}, {"title": "Nisekoi:"}], "altnames": [{"spelled": "Nisekoi", "title": "Nisekoi:"}], "expect": {"recognized": {"title": "Nisekoi:", "episode": 3, "stage": "altname"}}} +{"name": "[Group] SnK - 03.mkv", "rule": "an abbreviation no entry spells is what an assignment is for", "list": [{"title": "Shingeki no Kyojin"}], "altnames": [{"spelled": "SnK", "title": "Shingeki no Kyojin"}], "expect": {"recognized": {"title": "Shingeki no Kyojin", "episode": 3, "stage": "altname"}}} +{"name": "Kaguya-sama.Love.is.War.S03E03.1080p.WEB-DL.mkv", "rule": "a file the user named is found by what it spelled, season and all", "list": [{"title": "Kaguya-sama: Love is War"}, {"title": "Kaguya-sama: Love is War -Ultra Romantic-"}], "altnames": [{"file": "Kaguya-sama.Love.is.War.S03E03.1080p.WEB-DL.mkv", "title": "Kaguya-sama: Love is War -Ultra Romantic-"}], "expect": {"recognized": {"title": "Kaguya-sama: Love is War -Ultra Romantic-", "episode": 3, "stage": "altname"}}} +{"name": "Kaguya-sama.Love.is.War.S01E03.1080p.WEB-DL.mkv", "rule": "an assignment made from a third-season file leaves the first season to the corpus", "list": [{"title": "Kaguya-sama: Love is War"}, {"title": "Kaguya-sama: Love is War -Ultra Romantic-"}], "altnames": [{"file": "Kaguya-sama.Love.is.War.S03E03.1080p.WEB-DL.mkv", "title": "Kaguya-sama: Love is War -Ultra Romantic-"}], "expect": {"recognized": {"title": "Kaguya-sama: Love is War", "episode": 3, "stage": "key"}}} +{"name": "Attack on Titan Final - 03.mkv", "rule": "a name the key misses is judged by the entry's closest spelling", "list": [{"title": "Shingeki no Kyojin", "spellings": ["Attack on Titan"]}, {"title": "Kimi no Na wa"}], "expect": {"recognized": {"title": "Shingeki no Kyojin", "episode": 3, "stage": "score"}}} +{"name": "Show Title Cour 2 - The Subtitle - 03.mkv", "rule": "a name the key misses is scored over the whole name, subtitle and all", "list": [{"title": "Show Title"}, {"title": "Show Title Cour 2 The Subtitle"}], "expect": {"recognized": {"title": "Show Title Cour 2 The Subtitle", "episode": 3, "stage": "score"}}} +{"name": "Mushoku Tensei Jobless Reincarnation Cour 2 - Eris the Goblin Slayer - 01.mkv", "rule": "a special extending a series' name reaches the entry it extends", "list": [{"title": "Mushoku Tensei: Jobless Reincarnation"}, {"title": "Mushoku Tensei: Jobless Reincarnation Cour 2"}, {"title": "Mushoku Tensei: Jobless Reincarnation Cour 2 - Eris the Goblin Slayer"}], "expect": {"recognized": {"title": "Mushoku Tensei: Jobless Reincarnation Cour 2", "episode": 1, "stage": "key"}}, "owed": "the list: an entry's format and episode count are what tell a special from the series it extends, and the key answers before the scorer sees the subtitle"} +{"name": "Miss Kobayashi's Dragon Maid - 14.mkv", "rule": "a spelling that names an episode is that episode of the series", "list": [{"title": "Miss Kobayashi's Dragon Maid"}, {"title": "Miss Kobayashi's Dragon Maid Special", "spellings": ["Miss Kobayashi's Dragon Maid Episode 14"]}], "expect": {"recognized": {"title": "Miss Kobayashi's Dragon Maid", "episode": 14, "stage": "key"}}, "owed": "the list: only an entry's episode count can say the series has no fourteenth"} +{"name": "Show Title - 03.mkv", "rule": "two entries running level are refused and not chosen between", "list": [{"title": "Show Title Alpha"}, {"title": "Show Title Beta"}], "expect": {"unrecognized": "scored"}} +{"name": "Some Other Show - 03.mkv", "rule": "one shared word with one entry is not near enough", "list": [{"title": "Show Title"}], "expect": {"unrecognized": "scored"}} +{"name": "Alpha Beta Gamma S02E03.mkv", "rule": "a file of a second season is not given to an entry that spells none", "list": [{"title": "Alpha Beta Gamma"}], "expect": {"unrecognized": "nothing_scored"}} +{"name": "Alpha Beta Gamma - 03.mkv", "rule": "a file that spells no season is not given to a second season", "list": [{"title": "Alpha Beta Gamma 2nd Season"}], "expect": {"unrecognized": "nothing_scored"}} +{"name": "Alpha Beta II - 03.mkv", "rule": "the season a name spells chooses between two seasons its words reach alike", "list": [{"title": "Alpha Beta Gamma"}, {"title": "Alpha Beta Gamma 2nd Season"}], "expect": {"recognized": {"title": "Alpha Beta Gamma 2nd Season", "episode": 3, "stage": "score"}}} +{"name": "Alpha Beta S01E03.mkv", "rule": "the letters of a season and an episode go with their numbers and count against no entry", "list": [{"title": "Alpha Beta Gamma"}], "expect": {"recognized": {"title": "Alpha Beta Gamma", "episode": 3, "stage": "score"}}} +{"name": "Alpha Beta Episode 03.mkv", "rule": "the word that marks an episode goes with its number", "list": [{"title": "Alpha Beta Gamma"}], "expect": {"recognized": {"title": "Alpha Beta Gamma", "episode": 3, "stage": "score"}}} +{"name": "Alpha Beta 2nd Season - 03.mkv", "rule": "a season spelled with an ordinal goes whole, the ordinal and the word", "list": [{"title": "Alpha Beta Gamma 2nd Season"}], "expect": {"recognized": {"title": "Alpha Beta Gamma 2nd Season", "episode": 3, "stage": "score"}}} +{"name": "Alpha Beta - 03 [Uncensored].mkv", "rule": "a word the parser reports as other, such as Uncensored, counts against no entry", "list": [{"title": "Alpha Beta Gamma"}], "expect": {"recognized": {"title": "Alpha Beta Gamma", "episode": 3, "stage": "score"}}} +{"name": "Completely Different - 03.mkv", "rule": "a name no entry shares a word with is refused with nothing scored", "list": [{"title": "Show Title"}], "expect": {"unrecognized": "nothing_scored"}} +{"name": "ep 03.mkv", "rule": "a name that spells no title reaches the end of the sequence and is refused", "list": [{"title": "Show Title"}], "expect": {"unrecognized": "nothing_scored"}} +{"name": "[Group] 文豪ストレイドッグス 『独り歩む』; - 03.mkv", "rule": "a stage cannot find a title in a stray mark", "list": [{"title": "Bungou Stray Dogs: Hitori Ayumu", "spellings": ["文豪ストレイドッグス 『独り歩む』;"]}], "expect": {"unrecognized": "nothing_scored"}, "owed": "the parser: it takes the bracketed part of the name for a release group and drops the rest, leaving a title of one mark that no stage can place"} +{"name": "[Group] E7 - 03 [1080p].mkv", "rule": "a title that looks like an episode marker is read as one", "list": [{"title": "E7"}], "expect": {"unrecognized": "nothing_scored"}, "owed": "the parser: it reads the title as the seventh episode and the episode as the title"} +{"name": "Alpha Beta Remastered - 03.mkv", "rule": "an entry that spells a keyword the parser reports as other is filed without it", "list": [{"title": "Alpha Beta Remastered"}], "expect": {"recognized": {"title": "Alpha Beta Remastered", "episode": 3, "stage": "key"}}} {"name": "Alpha Beta Uncut - 03.mkv", "rule": "a name with a keyword the parser reports as other reaches the entry that spells it and the entry that does not, and says so", "list": [{"title": "Alpha Beta"}, {"title": "Alpha Beta Uncut"}], "expect": {"ambiguous": ["Alpha Beta", "Alpha Beta Uncut"]}} diff --git a/crates/core/tests/recognition_against_the_fixtures.rs b/crates/core/tests/recognition_against_the_fixtures.rs index b3b0767..5063545 100644 --- a/crates/core/tests/recognition_against_the_fixtures.rs +++ b/crates/core/tests/recognition_against_the_fixtures.rs @@ -24,11 +24,11 @@ use benshi_core::ShowId; use benshi_core::path::RawPath; -use benshi_core::recognise::altname::Altnames; -use benshi_core::recognise::corpus::Corpus; -use benshi_core::recognise::index::Index; -use benshi_core::recognise::parse::{Episode, Parsed, parse}; -use benshi_core::recognise::{Recognition, Stage, decide}; +use benshi_core::recognize::altname::Altnames; +use benshi_core::recognize::corpus::Corpus; +use benshi_core::recognize::index::Index; +use benshi_core::recognize::parse::{Episode, Parsed, parse}; +use benshi_core::recognize::{Recognition, Stage, decide}; use serde::Deserialize; const FIXTURES: &str = include_str!("fixtures/filenames.jsonl"); @@ -73,13 +73,13 @@ enum Named { #[derive(Debug, Deserialize)] #[serde(rename_all = "snake_case")] enum Expect { - Recognised { + Recognized { title: String, episode: EpisodeSpelled, stage: StageName, }, Ambiguous(Vec), - Unrecognised(Refused), + Unrecognized(Refused), } /// An episode as the fixture file writes it: a number, or a word for the @@ -109,24 +109,24 @@ enum Refused { /// An answer reduced to what a fixture can say about it. #[derive(Debug, PartialEq)] enum Shape { - Recognised { + Recognized { title: String, episode: Episode, stage: StageName, }, Ambiguous(Vec), - Unrecognised(Refused), + Unrecognized(Refused), } impl Shape { /// What a fixture expects, read into the same shape an answer reduces to. fn expected(of: &Expect, rule: &str) -> Self { match of { - Expect::Recognised { + Expect::Recognized { title, episode, stage, - } => Self::Recognised { + } => Self::Recognized { title: title.clone(), episode: match episode { EpisodeSpelled::Only(number) => Episode::Only(*number), @@ -143,14 +143,14 @@ impl Shape { stage: *stage, }, Expect::Ambiguous(candidates) => Self::Ambiguous(candidates.clone()), - Expect::Unrecognised(refused) => Self::Unrecognised(*refused), + Expect::Unrecognized(refused) => Self::Unrecognized(*refused), } } /// What recognition answered, reduced. fn of(answer: &Recognition) -> Self { match answer { - Recognition::Recognised(found) => Self::Recognised { + Recognition::Recognized(found) => Self::Recognized { title: found.title.clone(), episode: found.episode, stage: match found.stage { @@ -166,7 +166,7 @@ impl Shape { .map(|candidate| candidate.title.clone()) .collect(), ), - Recognition::Unrecognised(refusal) => Self::Unrecognised(if refusal.best.is_some() { + Recognition::Unrecognized(refusal) => Self::Unrecognized(if refusal.best.is_some() { Refused::Scored } else { Refused::NothingScored diff --git a/crates/core/tests/the_session_against_a_recording.rs b/crates/core/tests/the_session_against_a_recording.rs index b640cda..899ba27 100644 --- a/crates/core/tests/the_session_against_a_recording.rs +++ b/crates/core/tests/the_session_against_a_recording.rs @@ -12,11 +12,11 @@ use std::time::Duration; use benshi_core::path::RawPath; -use benshi_core::recognise::altname::Altnames; -use benshi_core::recognise::corpus::Corpus; -use benshi_core::recognise::index::Index; -use benshi_core::recognise::parse::{Episode, parse}; -use benshi_core::recognise::{Match, Recognition, Stage, decide}; +use benshi_core::recognize::altname::Altnames; +use benshi_core::recognize::corpus::Corpus; +use benshi_core::recognize::index::Index; +use benshi_core::recognize::parse::{Episode, parse}; +use benshi_core::recognize::{Match, Recognition, Stage, decide}; use benshi_core::session::{Effect, Session}; use benshi_core::timeline::{WATCHED_MINIMUM, WATCHED_PERCENT_MIN, WatchedPolicy}; use benshi_core::trace::Trace; @@ -67,7 +67,7 @@ fn the_recording_is_kept_interval_by_interval_and_never_recorded() { let readings = recording(); assert_eq!( decided(&readings[0]), - Recognition::Recognised(Match { + Recognition::Recognized(Match { show: SHOW, title: TITLE.to_owned(), episode: Episode::Only(3), diff --git a/crates/daemon/src/bus.rs b/crates/daemon/src/bus.rs index 704d57e..49735dc 100644 --- a/crates/daemon/src/bus.rs +++ b/crates/daemon/src/bus.rs @@ -226,12 +226,12 @@ mod tests { } #[test] - fn an_event_serialises_as_published() { + fn an_event_serializes_as_published() { // `benshi watch` streams these over the socket unchanged, so the wire // form is this type and there is no second representation to drift. let event = BusEvent::Snapshot(a_snapshot()); - let text = serde_json::to_string(&event).expect("serialise"); + let text = serde_json::to_string(&event).expect("serialize"); assert!(text.contains("Snapshot"), "got {text}"); assert!(text.contains("/anime/ep 03.mkv"), "got {text}"); diff --git a/crates/daemon/src/config.rs b/crates/daemon/src/config.rs index 66712d9..e38a834 100644 --- a/crates/daemon/src/config.rs +++ b/crates/daemon/src/config.rs @@ -27,7 +27,7 @@ //! a table this build does not know, and a value a key does not take. What the //! daemon says names the line and the column where `toml` gives a place. //! Running on the defaults in its place would set aside what the file says, -//! `when = "manual"` among it. A key spelt wrong is refused for the same +//! `when = "manual"` among it. A key spelled wrong is refused for the same //! reason, where it would be read as one left out. use std::fmt; diff --git a/crates/daemon/src/detection.rs b/crates/daemon/src/detection.rs index e4a9d48..ddca78d 100644 --- a/crates/daemon/src/detection.rs +++ b/crates/daemon/src/detection.rs @@ -56,7 +56,7 @@ use std::sync::{Arc, Mutex, RwLock}; use std::time::{Duration, SystemTime}; use benshi_core::policy::PolicyTable; -use benshi_core::recognise::Recognition; +use benshi_core::recognize::Recognition; use benshi_core::session::{Effect, Resumed, Session}; use benshi_core::timeline::WatchedPolicy; use benshi_core::{MediaRef, PlayerId, PlayerSnapshot}; @@ -67,7 +67,7 @@ use tokio::time::MissedTickBehavior; use crate::bus::{BusEvent, EventBus}; use crate::listing::Wakes; -use crate::recognition::{Current, Decided, Decision, Recogniser}; +use crate::recognition::{Current, Decided, Decision, Recognizer}; use crate::supervisor::TaskError; /// What is said about a reading whose source the same round did not describe. @@ -195,7 +195,7 @@ pub struct Wiring { /// Where each round leaves the sources it described. pub seen: Seen, /// What a reading's file is decided against. - pub recogniser: Current, + pub recognizer: Current, /// What a name the list does not hold wakes. pub wakes: Wakes, /// Where each round leaves its last decision. @@ -257,7 +257,7 @@ pub struct Detection { bus: Arc, policy: Arc>, seen: Seen, - recogniser: Current, + recognizer: Current, wakes: Wakes, decided: Decided, store: Arc>, @@ -282,7 +282,7 @@ impl Detection { bus, policy, seen, - recogniser, + recognizer, wakes, decided, store, @@ -295,7 +295,7 @@ impl Detection { bus, policy, seen, - recogniser, + recognizer, wakes, decided, store, @@ -337,7 +337,7 @@ impl Detection { /// One round: read the platform, apply policy, record and publish what /// was admitted, and let go of whoever has left. async fn round(&mut self) -> Result<(), TaskError> { - let recogniser = self.recogniser.now(); + let recognizer = self.recognizer.now(); let PollOutcome { sources, snapshots, @@ -382,7 +382,7 @@ impl Detection { if !self.heard.contains(&snapshot.player) { self.heard.insert(snapshot.player.clone()); } - let decision = self.decide(&recogniser, &snapshot); + let decision = self.decide(&recognizer, &snapshot); let effects = self.session.advance(&snapshot, decision.as_ref()); self.carry_out(effects).await?; self.bus.publish(BusEvent::Snapshot(snapshot)); @@ -434,12 +434,12 @@ impl Detection { /// what a client reads is the decision about the reading the daemon last /// acted on. A name that spells a title the list does not hold wakes the /// list's task, which may read the list again. - fn decide(&self, recogniser: &Recogniser, snapshot: &PlayerSnapshot) -> Option { + fn decide(&self, recognizer: &Recognizer, snapshot: &PlayerSnapshot) -> Option { let MediaRef::LocalFile(path) = &snapshot.media else { return None; }; - let (parsed, answer) = recogniser.decide(path); - if let Recognition::Unrecognised(refusal) = &answer + let (parsed, answer) = recognizer.decide(path); + if let Recognition::Unrecognized(refusal) = &answer && !refusal.parsed.is_empty() { self.wakes.missed(); @@ -552,15 +552,15 @@ mod tests { use super::{Detection, Seen, Wiring}; use crate::bus::{BusEvent, EventBus}; use crate::listing::Wakes; - use crate::recognition::{Current, Decided, Recogniser}; + use crate::recognition::{Current, Decided, Recognizer}; use crate::supervisor::TaskError; use benshi_core::clock::{Clock, TestClock, Timestamp}; use benshi_core::path::RawPath; use benshi_core::policy::{Policy, PolicyTable}; - use benshi_core::recognise::Recognition; - use benshi_core::recognise::altname::Altnames; - use benshi_core::recognise::corpus::Corpus; - use benshi_core::recognise::parse::Episode; + use benshi_core::recognize::Recognition; + use benshi_core::recognize::altname::Altnames; + use benshi_core::recognize::corpus::Corpus; + use benshi_core::recognize::parse::Episode; use benshi_core::{ AppName, Capabilities, Known, MediaRef, PlayState, PlayerId, PlayerSnapshot, ShowId, }; @@ -592,7 +592,7 @@ mod tests { const STEP: Duration = Duration::from_secs(5); /// The reading at which half of [`LENGTH`] has been watched, counted - /// from nought. + /// from zero. /// /// The first reading of a sitting adds nothing and each one after it adds /// a [`STEP`], so two minutes are watched at the twenty-fourth after it. @@ -794,13 +794,13 @@ mod tests { } /// The list, and nothing named by hand. - fn a_list() -> Recogniser { + fn a_list() -> Recognizer { let mut corpus = Corpus::new(); for (show, title) in LIST { corpus.file(show, title, Vec::<&str>::new()); } - Recogniser::of(corpus, Altnames::new()) + Recognizer::of(corpus, Altnames::new()) } /// Wiring to this database and [`the_time`], with the table a user starts @@ -810,7 +810,7 @@ mod tests { bus: Arc::new(EventBus::new()), policy: Arc::new(RwLock::new(PolicyTable::allowing_video_players())), seen: Seen::new(), - recogniser: Current::new(Recogniser::empty()), + recognizer: Current::new(Recognizer::empty()), wakes: Wakes::new(), decided: Decided::new(), store: Arc::clone(&database.store), @@ -867,7 +867,7 @@ mod tests { ) -> Detection { let wiring = Wiring { policy, - recogniser: Current::new(a_list()), + recognizer: Current::new(a_list()), ..wired_to(database) }; @@ -1414,7 +1414,7 @@ mod tests { assert_eq!(decision.parsed.title.as_deref(), Some("Show Title")); assert_eq!(decision.parsed.episode, Episode::Only(3)); assert!( - matches!(decision.answer, Recognition::Unrecognised(_)), + matches!(decision.answer, Recognition::Unrecognized(_)), "nothing to match against, got {:?}", decision.answer ); @@ -1645,7 +1645,7 @@ mod tests { } /// What `episodes_seen` holds where nothing was recorded, named because - /// an empty array otherwise needs its element type spelt out. + /// an empty array otherwise needs its element type spelled out. const NOTHING_SEEN: [Viewed; 0] = []; /// The third episode as the store holds it once `watched` of it is kept. @@ -1726,7 +1726,7 @@ mod tests { let mpv = a_source("mpv", "mpv"); let watcher = ScriptedWatcher::of(watching(&mpv, THIRD, 0..=HALF_AT)); let wiring = Wiring { - recogniser: Current::new(a_list()), + recognizer: Current::new(a_list()), now: a_second_on, ..wired_to(&database) }; @@ -1984,7 +1984,7 @@ mod tests { } #[tokio::test] - async fn a_player_that_opens_a_file_nobody_recognised_closes_its_episode() { + async fn a_player_that_opens_a_file_nobody_recognized_closes_its_episode() { let database = Database::new(); let mpv = a_source("mpv", "mpv"); let moved_on = a_round_of(&[&mpv], vec![playing(&mpv, NOT_LISTED, HALF_AT + 1)]); @@ -2087,7 +2087,7 @@ mod tests { } #[tokio::test] - async fn a_file_nobody_recognised_reaches_no_table() { + async fn a_file_nobody_recognized_reaches_no_table() { let database = Database::new(); let mpv = a_source("mpv", "mpv"); let watcher = ScriptedWatcher::of(watching(&mpv, NOT_LISTED, 0..=HALF_AT)); @@ -2199,7 +2199,7 @@ mod tests { let mpv = a_source("mpv", "mpv"); let watcher = ScriptedWatcher::of(watching(&mpv, THIRD, 0..=1)); let wiring = Wiring { - recogniser: Current::new(a_list()), + recognizer: Current::new(a_list()), now: before_1970, ..wired_to(&database) }; @@ -2270,7 +2270,7 @@ mod tests { #[test] fn a_call_a_runtime_that_shut_down_gave_up_stops_the_task() { - // A runtime that shuts down hands back as cancelled a call it had + // A runtime that shuts down hands back as canceled a call it had // not started. Nothing in that is a bug, so it is no panic. let database = Database::new(); let runtime = tokio::runtime::Builder::new_current_thread() @@ -2300,7 +2300,7 @@ mod tests { struct Replacing { rounds: ScriptedWatcher, current: Current, - with: Option, + with: Option, } impl PlayerWatcher for Replacing { @@ -2326,7 +2326,7 @@ mod tests { ) -> (Database, Detection) { let database = Database::new(); let wiring = Wiring { - recogniser: current, + recognizer: current, wakes, decided, ..wired_to(&database) @@ -2356,7 +2356,7 @@ mod tests { #[tokio::test] async fn a_round_that_began_before_a_list_was_put_in_place_decides_against_the_one_before() { - let current = Current::new(Recogniser::empty()); + let current = Current::new(Recognizer::empty()); let decided = Decided::new(); let watcher = Replacing { rounds: reading(THIRD), @@ -2370,7 +2370,7 @@ mod tests { let decision = decided.latest().expect("the reading was decided"); assert!( - matches!(decision.answer, Recognition::Unrecognised(_)), + matches!(decision.answer, Recognition::Unrecognized(_)), "got {:?}", decision.answer ); @@ -2378,7 +2378,7 @@ mod tests { #[tokio::test] async fn a_list_put_in_place_is_decided_against_from_the_next_round() { - let current = Current::new(Recogniser::empty()); + let current = Current::new(Recognizer::empty()); let decided = Decided::new(); let (_database, mut detection) = deciding_against( reading(THIRD), @@ -2393,7 +2393,7 @@ mod tests { let decision = decided.latest().expect("the reading was decided"); assert!( - matches!(&decision.answer, Recognition::Recognised(found) if found.title == SERIES), + matches!(&decision.answer, Recognition::Recognized(found) if found.title == SERIES), "got {:?}", decision.answer ); @@ -2459,7 +2459,7 @@ mod tests { let decided = Decided::new(); let (_database, mut detection) = deciding_against( reading(THIRD), - Current::new(Recogniser::of(corpus, Altnames::new())), + Current::new(Recognizer::of(corpus, Altnames::new())), wakes.clone(), decided.clone(), ); diff --git a/crates/daemon/src/ipc.rs b/crates/daemon/src/ipc.rs index 375f50e..1b85a15 100644 --- a/crates/daemon/src/ipc.rs +++ b/crates/daemon/src/ipc.rs @@ -344,10 +344,10 @@ impl Server { } // Nothing here aborts a connection and the set outlives // the loop, so a cancellation cannot arise. It is - // matched rather than asserted away because a cancelled + // matched rather than asserted away because a canceled // connection has already ended, which is the outcome // above. - Err(_cancelled) => (), + Err(_canceled) => (), } } } @@ -509,12 +509,12 @@ mod tests { use crate::detection::Seen; use crate::listing::Wakes; use crate::protocol::{Outcome, Request, Response}; - use crate::recognition::{Decided, Decision, Recogniser}; + use crate::recognition::{Decided, Decision, Recognizer}; use crate::secrets; use benshi_core::clock::Timestamp; use benshi_core::path::RawPath; use benshi_core::policy::{Policy, PolicyTable}; - use benshi_core::recognise::parse::Episode; + use benshi_core::recognize::parse::Episode; use benshi_core::token::Token; use benshi_core::{ AppName, Capabilities, Known, MediaRef, PlayState, PlayerId, PlayerSnapshot, @@ -716,7 +716,7 @@ mod tests { let MediaRef::LocalFile(path) = &snapshot.media else { panic!("the snapshot has a file open"); }; - let (parsed, answer) = Recogniser::empty().decide(path); + let (parsed, answer) = Recognizer::empty().decide(path); self.decided.record(Decision { player: snapshot.player.clone(), @@ -755,7 +755,7 @@ mod tests { } async fn ask(&mut self, request: &Request) { - let line = serde_json::to_string(request).expect("serialise"); + let line = serde_json::to_string(request).expect("serialize"); self.send(&line).await; } @@ -857,7 +857,7 @@ mod tests { assert_eq!(explained.player, PlayerId("mpv".to_owned())); assert_eq!(explained.media, a_snapshot().media); assert_eq!(explained.spelled.episode, Episode::Only(3)); - assert_eq!(explained.outcome, Outcome::Unrecognised { best: None }); + assert_eq!(explained.outcome, Outcome::Unrecognized { best: None }); } #[tokio::test] diff --git a/crates/daemon/src/lib.rs b/crates/daemon/src/lib.rs index 4b68320..9b1472a 100644 --- a/crates/daemon/src/lib.rs +++ b/crates/daemon/src/lib.rs @@ -30,7 +30,7 @@ use crate::detection::{Detection, Seen, Wiring}; #[cfg(unix)] use crate::ipc::Server; use crate::listing::{Listing, Reader, Source, Wakes}; -use crate::recognition::{Current, Decided, Recogniser}; +use crate::recognition::{Current, Decided, Recognizer}; #[cfg(unix)] use crate::supervisor::{Notice, Supervisor, TaskError, TaskRecord}; @@ -88,7 +88,7 @@ pub mod voice; /// /// The store is opened by the caller for the same reason, and it outlives a /// restart of detection: a detection task that is started again knows nothing -/// of the one before it and goes on from what that one kept. `recogniser` is +/// of the one before it and goes on from what that one kept. `recognizer` is /// what a file's name is decided against until the list's task puts a list /// in its place, and `now` reads the time of day the store writes beside what /// it keeps. `accounts` carries out a login and a @@ -112,7 +112,7 @@ pub mod voice; pub async fn run( mut start_watcher: B, listener: Arc, - recogniser: Recogniser, + recognizer: Recognizer, store: Arc>, now: fn() -> SystemTime, period: Duration, @@ -131,7 +131,7 @@ where bus: Arc::new(EventBus::new()), policy: Arc::new(RwLock::new(PolicyTable::allowing_video_players())), seen: Seen::new(), - recogniser: Current::new(recogniser), + recognizer: Current::new(recognizer), wakes: Wakes::new(), decided: Decided::new(), store, @@ -150,7 +150,7 @@ where list.source, list.reading, Arc::clone(&wiring.store), - wiring.recogniser.clone(), + wiring.recognizer.clone(), wiring.wakes.clone(), list.say, )); diff --git a/crates/daemon/src/listing.rs b/crates/daemon/src/listing.rs index fb10fc1..0c4dd67 100644 --- a/crates/daemon/src/listing.rs +++ b/crates/daemon/src/listing.rs @@ -1,7 +1,7 @@ //! Reading the list, and what a round decides against. //! //! The list's task reads the account's list from AniList, files it in the -//! store, and puts a recogniser of it in place of the one the rounds decide +//! store, and puts a recognizer of it in place of the one the rounds decide //! against. It reads at the times `[list]` names: as the daemon starts, every //! `refresh`, and where a round decided that a name spelling a title is not //! on the list, at most once in `on_miss`. A login wakes it at once. @@ -21,8 +21,8 @@ use std::time::Duration; use benshi_core::ShowId; use benshi_core::list::Entry; -use benshi_core::recognise::altname::Altnames; -use benshi_core::recognise::corpus::Corpus; +use benshi_core::recognize::altname::Altnames; +use benshi_core::recognize::corpus::Corpus; use benshi_core::token::Token; use benshi_store::Store; #[cfg(target_os = "linux")] @@ -35,7 +35,7 @@ use tokio::time::Instant; use crate::config::{Period, Reading}; use crate::detection::POISONED_STORE; -use crate::recognition::{Current, Recogniser}; +use crate::recognition::{Current, Recognizer}; use crate::secrets::{self, ANILIST}; #[cfg(target_os = "linux")] use crate::secrets::{Asking, SecretService, Secrets}; @@ -148,24 +148,24 @@ pub struct Listing { pub say: Say, } -/// A recogniser of these shows of a list and their entries. +/// A recognizer of these shows of a list and their entries. #[must_use] -pub fn recogniser_of(listed: &[(ShowId, Entry)]) -> Recogniser { +pub fn recognizer_of(listed: &[(ShowId, Entry)]) -> Recognizer { let mut corpus = Corpus::new(); for (show, entry) in listed { corpus.file(*show, &entry.title, &entry.spellings); } - Recogniser::of(corpus, Altnames::new()) + Recognizer::of(corpus, Altnames::new()) } -/// A recogniser of the list the store holds. +/// A recognizer of the list the store holds. /// /// # Errors /// /// What [`Store::listed`] fails with. -pub fn kept(store: &Store) -> Result { - store.listed(BACKEND).map(|listed| recogniser_of(&listed)) +pub fn kept(store: &Store) -> Result { + store.listed(BACKEND).map(|listed| recognizer_of(&listed)) } /// The list's task: what it reads from, when, and where it puts what it read. @@ -264,7 +264,7 @@ impl Reader { } } - /// Read the token and the list, file the list and put a recogniser of + /// Read the token and the list, file the list and put a recognizer of /// it in place, and say what came of it. `wait` is how long a failure /// waits before the reading is tried again. async fn read(&self, said: &mut Option, wait: Duration) -> Outcome { @@ -285,8 +285,8 @@ impl Reader { Ok(entries) => { let count = entries.len(); match self.filed(entries).await { - Ok(recogniser) => { - self.current.replace(recogniser); + Ok(recognizer) => { + self.current.replace(recognizer); *said = None; let entries = if count == 1 { "entry" } else { "entries" }; (self.say)(&format!("AniList list read: {count} {entries}")); @@ -319,9 +319,9 @@ impl Reader { } } - /// File `entries` as the list, and answer with a recogniser of what the + /// File `entries` as the list, and answer with a recognizer of what the /// store then holds, or with why it could not be kept. - async fn filed(&self, entries: Vec) -> Result { + async fn filed(&self, entries: Vec) -> Result { let store = Arc::clone(&self.store); let filing = tokio::task::spawn_blocking(move || { let mut store = store.lock().expect(POISONED_STORE); @@ -331,7 +331,7 @@ impl Reader { match filing.await { Ok(listed) => listed - .map(|listed| recogniser_of(&listed)) + .map(|listed| recognizer_of(&listed)) .map_err(|unkept| unkept.to_string()), // Handed on as it was raised. Err(panicked) if panicked.is_panic() => { @@ -385,16 +385,16 @@ mod tests { use benshi_core::list::{Entry, EntryId, Status}; use benshi_core::path::RawPath; - use benshi_core::recognise::Recognition; + use benshi_core::recognize::Recognition; use benshi_core::token::Token; use benshi_store::Store; use tempfile::TempDir; use tokio::task::JoinHandle; use tokio::time::Instant; - use super::{BACKEND, FIRST_RETRY, LAST_RETRY, Reader, Source, Wakes, kept, recogniser_of}; + use super::{BACKEND, FIRST_RETRY, LAST_RETRY, Reader, Source, Wakes, kept, recognizer_of}; use crate::config::{Period, Reading}; - use crate::recognition::{Current, Recogniser}; + use crate::recognition::{Current, Recognizer}; use crate::secrets; use crate::supervisor::TaskError; @@ -427,12 +427,12 @@ mod tests { ] } - /// Whether `recogniser` recognises a file of this title as it. - fn recognises(recogniser: &Recogniser, title: &str) -> bool { + /// Whether `recognizer` recognizes a file of this title as it. + fn recognizes(recognizer: &Recognizer, title: &str) -> bool { let path = RawPath::from_bytes(format!("[Group] {title} - 03.mkv").into_bytes()); matches!( - recogniser.decide(&path).1, - Recognition::Recognised(found) if found.title == title + recognizer.decide(&path).1, + Recognition::Recognized(found) if found.title == title ) } @@ -565,7 +565,7 @@ mod tests { fn running(home: TempDir, store: Store, reading: Reading, source: Scripted) -> Running { let store = Arc::new(Mutex::new(store)); - let current = Current::new(Recogniser::empty()); + let current = Current::new(Recognizer::empty()); let wakes = Wakes::new(); let said = Arc::new(Mutex::new(Vec::new())); let source = Arc::new(source); @@ -610,7 +610,7 @@ mod tests { const NOW: Duration = Duration::from_millis(1); #[test] - fn a_recogniser_of_a_list_recognises_each_entry_under_each_spelling() { + fn a_recognizer_of_a_list_recognizes_each_entry_under_each_spelling() { let listed: Vec<_> = the_list() .into_iter() .enumerate() @@ -626,29 +626,29 @@ mod tests { // the entry only where its spellings are filed. spelled[0].1.spellings = vec!["Kotonaru Namae".to_owned()]; - let recogniser = recogniser_of(&listed); - let spelled = recogniser_of(&spelled); + let recognizer = recognizer_of(&listed); + let spelled = recognizer_of(&spelled); - assert!(recognises(&recogniser, "Show Title")); - assert!(recognises(&recogniser, "Another Show")); + assert!(recognizes(&recognizer, "Show Title")); + assert!(recognizes(&recognizer, "Another Show")); let (_parsed, answer) = spelled.decide(&RawPath::from_bytes( b"[Group] Kotonaru Namae - 03.mkv".to_vec(), )); assert!( - matches!(&answer, Recognition::Recognised(found) if found.title == "Show Title"), + matches!(&answer, Recognition::Recognized(found) if found.title == "Show Title"), "{answer:?}" ); } #[test] - fn a_recogniser_of_the_store_holds_the_list_filed_there() { + fn a_recognizer_of_the_store_holds_the_list_filed_there() { let home = tempfile::tempdir().expect("a directory of our own"); let mut store = Store::open(&home.path().join("benshi.db")).expect("the database opens"); store.file(BACKEND, &the_list()).expect("the list is filed"); - let recogniser = kept(&store).expect("the list reads"); + let recognizer = kept(&store).expect("the list reads"); - assert!(recognises(&recogniser, "Show Title")); + assert!(recognizes(&recognizer, "Show Title")); } #[tokio::test(start_paused = true)] @@ -660,7 +660,7 @@ mod tests { assert_eq!(running.reads(), [Duration::ZERO]); assert_eq!(running.filed(), ["Show Title", "Another Show"]); assert_eq!(running.said(), ["AniList list read: 2 entries"]); - assert!(recognises(&running.current.now(), "Show Title")); + assert!(recognizes(&running.current.now(), "Show Title")); } #[tokio::test(start_paused = true)] diff --git a/crates/daemon/src/protocol.rs b/crates/daemon/src/protocol.rs index b93ae27..eaa54ba 100644 --- a/crates/daemon/src/protocol.rs +++ b/crates/daemon/src/protocol.rs @@ -11,9 +11,9 @@ //! value that is not an object cannot be mistaken for a complete message. use benshi_core::policy::Policy; -use benshi_core::recognise::altname::Assignment; -use benshi_core::recognise::parse::{Episode, Parsed}; -use benshi_core::recognise::{Recognition, Score, Stage}; +use benshi_core::recognize::altname::Assignment; +use benshi_core::recognize::parse::{Episode, Parsed}; +use benshi_core::recognize::{Recognition, Score, Stage}; use benshi_core::token::Token; use benshi_core::{AppName, Capabilities, MediaRef, PlayState, PlayerId}; use benshi_detect::SourceInfo; @@ -192,13 +192,13 @@ impl Explanation { /// What recognition answered, on the wire. /// /// A form of its own rather than the domain's, because a score is a checked -/// proportion that deliberately does not deserialise: a message carrying a +/// proportion that deliberately does not deserialize: a message carrying a /// score of five must not be able to become one. Here a score is a number, and /// a consumer that needs the checked kind converts through the check. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum Outcome { /// A title, an episode and the stage that decided. - Recognised { + Recognized { /// The title as the corpus spells it. title: String, /// The episode in the release's numbering, as it was read from the name. @@ -213,7 +213,7 @@ pub enum Outcome { candidates: Vec, }, /// Nothing matched. - Unrecognised { + Unrecognized { /// How close the best candidate came, where there was one to compare. best: Option, }, @@ -222,7 +222,7 @@ pub enum Outcome { impl Outcome { fn of(answer: &Recognition) -> Self { match answer { - Recognition::Recognised(found) => Self::Recognised { + Recognition::Recognized(found) => Self::Recognized { title: found.title.clone(), episode: found.episode, stage: DecidedBy::of(&found.stage), @@ -234,7 +234,7 @@ impl Outcome { .map(|candidate| candidate.title.clone()) .collect(), }, - Recognition::Unrecognised(refusal) => Self::Unrecognised { + Recognition::Unrecognized(refusal) => Self::Unrecognized { best: refusal.best.map(Score::value), }, } @@ -246,7 +246,7 @@ impl Outcome { pub enum DecidedBy { /// The assignment the user made, as they made it. Altname(Assignment), - /// An exact match on the normalised key. + /// An exact match on the normalized key. Key, /// The best candidate the scorer found, and how well it scored. Scored(f64), @@ -266,13 +266,13 @@ impl DecidedBy { mod tests { use super::{DecidedBy, Explanation, Outcome, Request, Response, SourceListing}; use crate::bus::BusEvent; - use crate::recognition::{Decision, Recogniser}; + use crate::recognition::{Decision, Recognizer}; use benshi_core::clock::Timestamp; use benshi_core::path::RawPath; use benshi_core::policy::Policy; - use benshi_core::recognise::altname::Assignment; - use benshi_core::recognise::parse::Episode; - use benshi_core::recognise::{Ambiguity, Candidate, Match, Recognition, Refusal, Score, Stage}; + use benshi_core::recognize::altname::Assignment; + use benshi_core::recognize::parse::Episode; + use benshi_core::recognize::{Ambiguity, Candidate, Match, Recognition, Refusal, Score, Stage}; use benshi_core::token::Token; use benshi_core::{ AppName, Capabilities, Known, MediaRef, PlayState, PlayerId, PlayerSnapshot, ShowId, @@ -320,7 +320,7 @@ mod tests { let MediaRef::LocalFile(path) = &snapshot.media else { panic!("the snapshot has a file open"); }; - let (parsed, _refused) = Recogniser::empty().decide(path); + let (parsed, _refused) = Recognizer::empty().decide(path); Decision { player: snapshot.player.clone(), @@ -342,7 +342,7 @@ mod tests { /// A match of this title by this stage, for building decisions from. fn found_by(stage: Stage) -> Recognition { - Recognition::Recognised(Match { + Recognition::Recognized(Match { show: ShowId(1), title: "Shingeki no Kyojin".to_owned(), episode: Episode::Only(3), @@ -370,11 +370,11 @@ mod tests { }, ], }), - Recognition::Unrecognised(Refusal { + Recognition::Unrecognized(Refusal { parsed: "Some Other Show".to_owned(), best: Some(Score::new(0.4).expect("a proportion")), }), - Recognition::Unrecognised(Refusal { + Recognition::Unrecognized(Refusal { parsed: String::new(), best: None, }), @@ -432,7 +432,7 @@ mod tests { ] } - /// Every message either side may put on the wire, serialised. + /// Every message either side may put on the wire, serialized. /// /// Both directions, because the rules below are about the transport and /// hold in both. A check written over one of them would say "every message" @@ -441,10 +441,10 @@ mod tests { let mut lines = Vec::new(); for request in every_request() { - lines.push(serde_json::to_string(&request).expect("serialise")); + lines.push(serde_json::to_string(&request).expect("serialize")); } for response in every_response() { - lines.push(serde_json::to_string(&response).expect("serialise")); + lines.push(serde_json::to_string(&response).expect("serialize")); } lines @@ -475,8 +475,8 @@ mod tests { #[test] fn a_request_read_back_is_the_request_that_was_sent() { for request in every_request() { - let text = serde_json::to_string(&request).expect("serialise"); - let back: Request = serde_json::from_str(&text).expect("deserialise"); + let text = serde_json::to_string(&request).expect("serialize"); + let back: Request = serde_json::from_str(&text).expect("deserialize"); assert_eq!(request, back); } @@ -485,8 +485,8 @@ mod tests { #[test] fn a_response_read_back_is_the_response_that_was_sent() { for response in every_response() { - let text = serde_json::to_string(&response).expect("serialise"); - let back: Response = serde_json::from_str(&text).expect("deserialise"); + let text = serde_json::to_string(&response).expect("serialize"); + let back: Response = serde_json::from_str(&text).expect("deserialize"); assert_eq!(response, back); } @@ -497,11 +497,11 @@ mod tests { // A name out of a Japanese archive unpacked with the wrong encoding is // not valid UTF-8, and it is the reading a user is most likely to be // watching when something goes wrong. Replacing the bytes it cannot - // read would make the file unrecognisable and the stream a lie. + // read would make the file unrecognizable and the stream a lie. let published = BusEvent::Snapshot(a_snapshot()); - let text = serde_json::to_string(&Response::Event(published.clone())).expect("serialise"); - let back: Response = serde_json::from_str(&text).expect("deserialise"); + let text = serde_json::to_string(&Response::Event(published.clone())).expect("serialize"); + let back: Response = serde_json::from_str(&text).expect("deserialize"); let Response::Event(BusEvent::Snapshot(snapshot)) = back else { panic!("expected a reading, got {back:?}"); @@ -549,7 +549,7 @@ mod tests { assert_eq!( explained.outcome, - Outcome::Recognised { + Outcome::Recognized { title: "Shingeki no Kyojin".to_owned(), episode: Episode::Only(3), stage: DecidedBy::Altname(an_assignment()), @@ -565,7 +565,7 @@ mod tests { assert_eq!( explained.outcome, - Outcome::Recognised { + Outcome::Recognized { title: "Shingeki no Kyojin".to_owned(), episode: Episode::Only(3), stage: DecidedBy::Scored(0.83), @@ -604,17 +604,17 @@ mod tests { fn an_explanation_of_a_refusal_carries_how_close_the_best_came() { // Absent and low are different answers, and they stay different on // the wire: one points at the list and the other at the name. - let close = Explanation::of(&a_decision(Recognition::Unrecognised(Refusal { + let close = Explanation::of(&a_decision(Recognition::Unrecognized(Refusal { parsed: "Some Other Show".to_owned(), best: Some(Score::new(0.4).expect("a proportion")), }))); - let nothing = Explanation::of(&a_decision(Recognition::Unrecognised(Refusal { + let nothing = Explanation::of(&a_decision(Recognition::Unrecognized(Refusal { parsed: "Some Other Show".to_owned(), best: None, }))); - assert_eq!(close.outcome, Outcome::Unrecognised { best: Some(0.4) }); - assert_eq!(nothing.outcome, Outcome::Unrecognised { best: None }); + assert_eq!(close.outcome, Outcome::Unrecognized { best: Some(0.4) }); + assert_eq!(nothing.outcome, Outcome::Unrecognized { best: None }); } #[test] @@ -624,7 +624,7 @@ mod tests { }; assert_eq!( - serde_json::to_string(&asked).expect("serialise"), + serde_json::to_string(&asked).expect("serialize"), r#"{"type":"Login","body":{"token":"header.payload.signature"}}"# ); assert!(!format!("{asked:?}").contains("payload"), "{asked:?}"); diff --git a/crates/daemon/src/recognition.rs b/crates/daemon/src/recognition.rs index a2f1cce..f2775b7 100644 --- a/crates/daemon/src/recognition.rs +++ b/crates/daemon/src/recognition.rs @@ -1,8 +1,8 @@ //! What the daemon decided a file was, kept for `benshi why`. //! //! Recognition is pure logic in `benshi-core` and decides against a corpus the -//! caller supplies. A [`Recogniser`] holds one, with its index and the names -//! the user gave. Against [`Recogniser::empty`] every name reaches the end of +//! caller supplies. A [`Recognizer`] holds one, with its index and the names +//! the user gave. Against [`Recognizer::empty`] every name reaches the end of //! the sequence and is refused. A round decides, the decision is left here, //! and a client reads it. //! @@ -14,11 +14,11 @@ use std::sync::{Arc, PoisonError, RwLock}; use benshi_core::path::RawPath; -use benshi_core::recognise::altname::Altnames; -use benshi_core::recognise::corpus::Corpus; -use benshi_core::recognise::index::Index; -use benshi_core::recognise::parse::{Parsed, parse}; -use benshi_core::recognise::{Recognition, decide}; +use benshi_core::recognize::altname::Altnames; +use benshi_core::recognize::corpus::Corpus; +use benshi_core::recognize::index::Index; +use benshi_core::recognize::parse::{Parsed, parse}; +use benshi_core::recognize::{Recognition, decide}; use benshi_core::{MediaRef, PlayerId}; /// What is said when the record of the last decision cannot be trusted. @@ -26,13 +26,13 @@ const POISONED: &str = "last decision was poisoned by a panic in another task"; /// What a name is decided against: the corpus, its index and the assignments. #[derive(Debug)] -pub struct Recogniser { +pub struct Recognizer { corpus: Corpus, index: Index, altnames: Altnames, } -impl Recogniser { +impl Recognizer { /// Nothing to match against: an empty corpus and no assignments. /// /// Every name is refused with nothing scored. @@ -68,35 +68,35 @@ impl Recogniser { } } -/// The recogniser the rounds decide against, which the list's task replaces +/// The recognizer the rounds decide against, which the list's task replaces /// when it has read a list. /// /// A round takes the one in place as it begins and decides with it to its /// end, so a round that began before a replacement finishes on the list it /// began with. Cloning shares the place. #[derive(Debug, Clone)] -pub struct Current(Arc>>); +pub struct Current(Arc>>); impl Current { - /// A place holding `recogniser`. + /// A place holding `recognizer`. #[must_use] - pub fn new(recogniser: Recogniser) -> Self { - Self(Arc::new(RwLock::new(Arc::new(recogniser)))) + pub fn new(recognizer: Recognizer) -> Self { + Self(Arc::new(RwLock::new(Arc::new(recognizer)))) } - /// The recogniser in place. + /// The recognizer in place. /// - /// Read through a lock a panic left poisoned: the recogniser is made + /// Read through a lock a panic left poisoned: the recognizer is made /// before the lock is taken and put in whole, so no panic leaves half of /// one in place. #[must_use] - pub fn now(&self) -> Arc { + pub fn now(&self) -> Arc { Arc::clone(&self.0.read().unwrap_or_else(PoisonError::into_inner)) } - /// Put `recogniser` in place of the one there. - pub fn replace(&self, recogniser: Recogniser) { - *self.0.write().unwrap_or_else(PoisonError::into_inner) = Arc::new(recogniser); + /// Put `recognizer` in place of the one there. + pub fn replace(&self, recognizer: Recognizer) { + *self.0.write().unwrap_or_else(PoisonError::into_inner) = Arc::new(recognizer); } } @@ -151,12 +151,12 @@ impl Decided { #[cfg(test)] mod tests { - use super::{Current, Decided, Decision, Recogniser}; + use super::{Current, Decided, Decision, Recognizer}; use benshi_core::path::RawPath; - use benshi_core::recognise::altname::Altnames; - use benshi_core::recognise::corpus::Corpus; - use benshi_core::recognise::parse::Episode; - use benshi_core::recognise::{Match, Recognition, Refusal, Stage}; + use benshi_core::recognize::altname::Altnames; + use benshi_core::recognize::corpus::Corpus; + use benshi_core::recognize::parse::Episode; + use benshi_core::recognize::{Match, Recognition, Refusal, Stage}; use benshi_core::{MediaRef, PlayerId, ShowId}; fn a_path(name: &str) -> RawPath { @@ -179,12 +179,12 @@ mod tests { // `benshi why` explains the most recent decision, so the record holds // one and the next reading's decision takes its place. let decided = Decided::new(); - let recogniser = Recogniser::empty(); + let recognizer = Recognizer::empty(); let first = a_path("/anime/[Group] Show Title - 03.mkv"); let second = a_path("/anime/[Group] Another Show - 07.mkv"); for path in [&first, &second] { - let (parsed, answer) = recogniser.decide(path); + let (parsed, answer) = recognizer.decide(path); decided.record(Decision { player: PlayerId("mpv".to_owned()), media: MediaRef::LocalFile(path.clone()), @@ -204,22 +204,22 @@ mod tests { // a folder named after another show would otherwise carry that show's // words into the name the stages read. let (parsed, _answer) = - Recogniser::empty().decide(&a_path("/anime/Other Show/[Group] Show Title - 03.mkv")); + Recognizer::empty().decide(&a_path("/anime/Other Show/[Group] Show Title - 03.mkv")); assert_eq!(parsed.title.as_deref(), Some("Show Title")); assert_eq!(parsed.episode, Episode::Only(3)); } #[test] - fn a_name_the_list_holds_is_recognised_as_the_list_spells_it() { - let recogniser = Recogniser::of(a_list_of(&["Show Title", "A Film"]), Altnames::new()); + fn a_name_the_list_holds_is_recognized_as_the_list_spells_it() { + let recognizer = Recognizer::of(a_list_of(&["Show Title", "A Film"]), Altnames::new()); let (_parsed, answer) = - recogniser.decide(&a_path("/anime/[Group] Show Title - 03 [1080p].mkv")); + recognizer.decide(&a_path("/anime/[Group] Show Title - 03 [1080p].mkv")); assert_eq!( answer, - Recognition::Recognised(Match { + Recognition::Recognized(Match { show: ShowId(1), title: "Show Title".to_owned(), episode: Episode::Only(3), @@ -235,14 +235,14 @@ mod tests { named .name("ShoTi", ShowId(1), &list) .expect("text that reaches no entry can be named"); - let recogniser = Recogniser::of(list, named); + let recognizer = Recognizer::of(list, named); - let (_parsed, answer) = recogniser.decide(&a_path("/anime/[Group] ShoTi - 03.mkv")); + let (_parsed, answer) = recognizer.decide(&a_path("/anime/[Group] ShoTi - 03.mkv")); assert!( matches!( &answer, - Recognition::Recognised(Match { + Recognition::Recognized(Match { show: ShowId(1), title, episode: Episode::Only(3), @@ -257,18 +257,18 @@ mod tests { fn a_name_the_key_misses_is_found_through_an_index_of_the_list() { // The name spells more than either title, so no key reaches it, and // the scorer is handed the candidates the index narrowed the list to. - let recogniser = Recogniser::of( + let recognizer = Recognizer::of( a_list_of(&["Show Title", "Show Title Cour 2 The Subtitle"]), Altnames::new(), ); let (_parsed, answer) = - recogniser.decide(&a_path("/anime/Show Title Cour 2 - The Subtitle - 03.mkv")); + recognizer.decide(&a_path("/anime/Show Title Cour 2 - The Subtitle - 03.mkv")); assert!( matches!( &answer, - Recognition::Recognised(Match { + Recognition::Recognized(Match { show: ShowId(2), title, episode: Episode::Only(3), @@ -284,41 +284,41 @@ mod tests { // With nothing to match against, a refusal with nothing scored is the // honest answer rather than a guess. It is what an explanation has to // show for every file. - let (_parsed, answer) = Recogniser::empty().decide(&a_path("[Group] Show Title - 03.mkv")); + let (_parsed, answer) = Recognizer::empty().decide(&a_path("[Group] Show Title - 03.mkv")); assert!( matches!( answer, - Recognition::Unrecognised(Refusal { best: None, .. }) + Recognition::Unrecognized(Refusal { best: None, .. }) ), "got {answer:?}" ); } #[test] - fn a_recogniser_put_in_place_is_the_one_taken_after() { - let current = Current::new(Recogniser::empty()); + fn a_recognizer_put_in_place_is_the_one_taken_after() { + let current = Current::new(Recognizer::empty()); let shared = current.clone(); - shared.replace(Recogniser::of(a_list_of(&["Show Title"]), Altnames::new())); + shared.replace(Recognizer::of(a_list_of(&["Show Title"]), Altnames::new())); let (_parsed, answer) = current.now().decide(&a_path("[Group] Show Title - 03.mkv")); assert!( - matches!(answer, Recognition::Recognised(_)), + matches!(answer, Recognition::Recognized(_)), "got {answer:?}" ); } #[test] - fn a_recogniser_taken_before_a_replacement_decides_as_it_did() { - let current = Current::new(Recogniser::empty()); + fn a_recognizer_taken_before_a_replacement_decides_as_it_did() { + let current = Current::new(Recognizer::empty()); let taken = current.now(); - current.replace(Recogniser::of(a_list_of(&["Show Title"]), Altnames::new())); + current.replace(Recognizer::of(a_list_of(&["Show Title"]), Altnames::new())); let (_parsed, answer) = taken.decide(&a_path("[Group] Show Title - 03.mkv")); assert!( - matches!(answer, Recognition::Unrecognised(_)), + matches!(answer, Recognition::Unrecognized(_)), "got {answer:?}" ); } diff --git a/crates/daemon/src/supervisor.rs b/crates/daemon/src/supervisor.rs index 2b9e02c..a848ca1 100644 --- a/crates/daemon/src/supervisor.rs +++ b/crates/daemon/src/supervisor.rs @@ -26,7 +26,7 @@ //! would have two clocks to move, the one a wait is slept on and the one a //! run is measured on, free to disagree about whether a task had been running //! long enough. What the rule is for still holds: `tokio::time` is -//! virtualised under a paused runtime, so +//! virtualized under a paused runtime, so //! `a_long_backoff_does_not_count_as_work` winds through 2223 seconds of //! retries and takes no measurable time to run. @@ -137,7 +137,7 @@ pub enum Stopped { /// It finished what it was doing and returned. Finished, /// A failure that will not pass, rendered here for a person. Usually one - /// the task reported; a task cancelled from outside is recorded here too, + /// the task reported; a task canceled from outside is recorded here too, /// because it is not coming back either. Permanent(String), /// It kept panicking. The last panic is rendered here. @@ -495,7 +495,7 @@ impl Supervisor { // Nothing here aborts a task and the set outlives the loop, so // a cancellation means something else reached in and took the // handle. Recorded rather than guessed at. - Err(_cancelled) => Some(Stopped::Permanent("task was cancelled".to_owned())), + Err(_canceled) => Some(Stopped::Permanent("task was canceled".to_owned())), }; if let Some(stopped_by) = stopped_by { diff --git a/crates/daemon/tests/replay_is_faithful.rs b/crates/daemon/tests/replay_is_faithful.rs index ab5afb9..aaf8deb 100644 --- a/crates/daemon/tests/replay_is_faithful.rs +++ b/crates/daemon/tests/replay_is_faithful.rs @@ -22,7 +22,7 @@ use benshi_core::{Known, PlayState, PlayerId, PlayerSnapshot}; use benshi_daemon::bus::{BusEvent, EventBus}; use benshi_daemon::detection::{Detection, Seen, Wiring}; use benshi_daemon::listing::Wakes; -use benshi_daemon::recognition::{Current, Decided, Recogniser}; +use benshi_daemon::recognition::{Current, Decided, Recognizer}; use benshi_detect::replay::ReplayWatcher; use benshi_store::Store; use tokio::time::timeout; @@ -71,7 +71,7 @@ async fn replayed(trace: Trace) -> Vec { bus: Arc::clone(&bus), policy: Arc::new(RwLock::new(PolicyTable::allowing_video_players())), seen: Seen::new(), - recogniser: Current::new(Recogniser::empty()), + recognizer: Current::new(Recognizer::empty()), wakes: Wakes::new(), decided: Decided::new(), store: Arc::new(Mutex::new(store)), diff --git a/crates/daemon/tests/the_daemon_runs.rs b/crates/daemon/tests/the_daemon_runs.rs index 9c37ba7..d92238f 100644 --- a/crates/daemon/tests/the_daemon_runs.rs +++ b/crates/daemon/tests/the_daemon_runs.rs @@ -27,8 +27,8 @@ use benshi_core::clock::{Clock, TestClock, Timestamp}; use benshi_core::list::{Entry, EntryId, Status}; use benshi_core::path::RawPath; use benshi_core::policy::Policy; -use benshi_core::recognise::altname::Altnames; -use benshi_core::recognise::corpus::Corpus; +use benshi_core::recognize::altname::Altnames; +use benshi_core::recognize::corpus::Corpus; use benshi_core::token::Token; use benshi_core::{ AppName, Capabilities, Known, MediaRef, PlayState, PlayerId, PlayerSnapshot, ShowId, @@ -39,7 +39,7 @@ use benshi_daemon::config::{Period, Reading}; use benshi_daemon::ipc::bind; use benshi_daemon::listing::{Listing, Source}; use benshi_daemon::protocol::{Request, Response, SourceListing}; -use benshi_daemon::recognition::Recogniser; +use benshi_daemon::recognition::Recognizer; use benshi_daemon::secrets; use benshi_daemon::supervisor::{BACKOFF_BASE, Notice, RESTART_LIMIT, Stopped, TaskRecord}; use benshi_detect::{PlayerWatcher, PollOutcome, SourceInfo, WatchError}; @@ -349,7 +349,7 @@ fn a_daemon( tokio::spawn(benshi_daemon::run( platform.factory(), listener, - Recogniser::empty(), + Recognizer::empty(), a_store(home), SystemTime::now, PERIOD, @@ -383,7 +383,7 @@ fn a_daemon_that_tells( tokio::spawn(benshi_daemon::run( platform.factory(), listener, - Recogniser::of(list, Altnames::new()), + Recognizer::of(list, Altnames::new()), Arc::clone(store), the_time, PERIOD, @@ -429,7 +429,7 @@ async fn ask(socket: &Path, request: &Request) -> Response { .expect("the daemon answers"); let (reading, mut writing) = tokio::io::split(stream); - let mut line = serde_json::to_vec(request).expect("serialise"); + let mut line = serde_json::to_vec(request).expect("serialize"); line.push(b'\n'); writing .write_all(&line) @@ -567,7 +567,7 @@ fn a_daemon_reading( tokio::spawn(benshi_daemon::run( platform.factory(), listener, - Recogniser::empty(), + Recognizer::empty(), Arc::clone(store), the_time, PERIOD, @@ -602,7 +602,7 @@ fn the_episode_queued() -> [Operation; 1] { #[tokio::test] async fn a_running_daemon_records_what_the_list_it_read_holds() { // A daemon that starts with nothing to match a name against, and an - // empty store: the file it plays is recognised only by a list its own + // empty store: the file it plays is recognized only by a list its own // task read, filed and put in place for detection. let (home, socket) = a_socket(); let store = an_empty_store(&home); @@ -620,7 +620,7 @@ async fn a_running_daemon_records_what_the_list_it_read_holds() { async fn a_running_daemon_reads_its_list_where_a_name_misses_it() { // Read at no time but on a miss: the file the platform plays misses // the empty list, the round wakes the list's task, and what it reads - // recognises the file. + // recognizes the file. let (home, socket) = a_socket(); let store = an_empty_store(&home); let platform = Platform::default(); @@ -701,7 +701,7 @@ async fn a_running_daemon_streams_what_its_own_detection_published() { .await .expect("the daemon answers"); let (reading, mut writing) = tokio::io::split(stream); - let mut line = serde_json::to_vec(&Request::Watch).expect("serialise"); + let mut line = serde_json::to_vec(&Request::Watch).expect("serialize"); line.push(b'\n'); writing .write_all(&line) diff --git a/crates/store/src/lib.rs b/crates/store/src/lib.rs index 61008ec..994c145 100644 --- a/crates/store/src/lib.rs +++ b/crates/store/src/lib.rs @@ -164,7 +164,7 @@ pub enum Error { /// what they hold it lies on. /// /// The whole second the reading lies in, as `date +%s` prints it: below -/// nought before 1970, and the second that began before a reading between +/// zero before 1970, and the second that began before a reading between /// two. A reading that is not before 1970 is taken to be one after 9999, /// since the store raises [`Error::Instant`] for no other. fn out_of_range(at: &SystemTime) -> String { diff --git a/crates/store/src/list.rs b/crates/store/src/list.rs index 865a6b0..818f0b5 100644 --- a/crates/store/src/list.rs +++ b/crates/store/src/list.rs @@ -212,7 +212,7 @@ mod tests { Entry { id: EntryId(id), title: title.to_owned(), - spellings: vec![format!("{title} Spelt Otherwise"), format!("{title} 2")], + spellings: vec![format!("{title} Spelled Otherwise"), format!("{title} 2")], format: Some(Format::Tv), episodes: Some(12), episode_length: Some(Duration::from_mins(24)), @@ -666,7 +666,7 @@ mod tests { } #[test] - fn a_length_below_nought_is_refused() { + fn a_length_below_zero_is_refused() { let (_home, mut store) = a_store(); store .file(BACKEND, &[a_series(21, "Show Title")]) diff --git a/crates/store/src/queue.rs b/crates/store/src/queue.rs index 8250815..b972431 100644 --- a/crates/store/src/queue.rs +++ b/crates/store/src/queue.rs @@ -28,7 +28,7 @@ use crate::{Error, Store}; /// Kept in two columns: the name of the variant in `kind` and its fields as /// JSON in `payload`. The name decides how the payload is read, and a payload /// is read whole or refused. A name this build does not know, a field the -/// kind does not have, a field it has that is missing and a field spelt twice +/// kind does not have, a field it has that is missing and a field spelled twice /// are each an [`Error::Operation`]. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde( diff --git a/crates/store/src/watching.rs b/crates/store/src/watching.rs index d2d5f38..cdf73ee 100644 --- a/crates/store/src/watching.rs +++ b/crates/store/src/watching.rs @@ -97,7 +97,7 @@ impl Store { /// [`Error::Busy`] when the database cannot be read because another /// connection has it, which in WAL a connection that writes to it does /// not cause. [`Error::Write`] when the row cannot be read for any other - /// reason, a total below nought included. [`Error::Media`] for a row + /// reason, a total below zero included. [`Error::Media`] for a row /// whose media is not a path as this store writes one. pub fn resume(&self, show: ShowId, episode: Option) -> Result, Error> { let row = self @@ -740,8 +740,8 @@ mod tests { } #[test] - fn a_total_below_nought_is_refused() { - // Only a hand writes one, and neither nought nor its size is a + fn a_total_below_zero_is_refused() { + // Only a hand writes one, and neither zero nor its size is a // total anybody watched. let (_home, mut store) = a_store(); store diff --git a/crates/sync/src/anilist/mod.rs b/crates/sync/src/anilist/mod.rs index f7bb393..87feb18 100644 --- a/crates/sync/src/anilist/mod.rs +++ b/crates/sync/src/anilist/mod.rs @@ -386,7 +386,7 @@ mod tests { "english": "The Show Title", "native": "Show Native Title" }, - "synonyms": ["Show Title Spelt Otherwise", "The Show Title"] + "synonyms": ["Show Title Spelled Otherwise", "The Show Title"] } }) } @@ -399,7 +399,7 @@ mod tests { spellings: vec![ "The Show Title".to_owned(), "Show Native Title".to_owned(), - "Show Title Spelt Otherwise".to_owned(), + "Show Title Spelled Otherwise".to_owned(), ], format: Some(Format::Tv), episodes: Some(12), @@ -926,7 +926,7 @@ mod tests { } #[tokio::test(start_paused = true)] - async fn a_score_of_nought_is_no_score() { + async fn a_score_of_zero_is_no_score() { let mut entry = a_series_entry(); entry["score"] = json!(0); diff --git a/crates/sync/src/lib.rs b/crates/sync/src/lib.rs index 31bd202..c1cc684 100644 --- a/crates/sync/src/lib.rs +++ b/crates/sync/src/lib.rs @@ -66,7 +66,7 @@ pub enum Error { Unreadable(#[source] BoxError), } -/// A remote list a local record can be synchronised to. +/// A remote list a local record can be synchronized to. /// /// Every call carries the deadline of the backend that makes it, and a /// service that never answers is an [`Error::Timeout`] once it has passed. diff --git a/crates/sync/tests/fakes/mod.rs b/crates/sync/tests/fakes/mod.rs index 0e7c1dd..edd8035 100644 --- a/crates/sync/tests/fakes/mod.rs +++ b/crates/sync/tests/fakes/mod.rs @@ -29,7 +29,7 @@ pub fn a_series(id: EntryId) -> Entry { Entry { id, title: "Show Title".to_owned(), - spellings: vec!["Show Title Spelt Otherwise".to_owned()], + spellings: vec!["Show Title Spelled Otherwise".to_owned()], format: Some(Format::Tv), episodes: Some(12), episode_length: Some(Duration::from_mins(24)),