use hunch::hunch;
#[test]
fn movie_basic() {
let r = hunch("The.Matrix.1999.1080p.BluRay.x264-GROUP.mkv");
assert_eq!(r.title(), Some("The Matrix"));
assert_eq!(r.year(), Some(1999));
assert_eq!(r.screen_size(), Some("1080p"));
assert_eq!(r.source(), Some("Blu-ray"));
assert_eq!(r.video_codec(), Some("H.264"));
assert_eq!(r.release_group(), Some("GROUP"));
assert_eq!(r.container(), Some("mkv"));
}
#[test]
fn movie_with_path() {
let r = hunch(
"Movies/Fear and Loathing in Las Vegas (1998)/Fear.and.Loathing.in.Las.Vegas.720p.HDDVD.DTS.x264-ESiR.mkv",
);
assert_eq!(r.title(), Some("Fear and Loathing in Las Vegas"));
assert_eq!(r.year(), Some(1998));
assert_eq!(r.screen_size(), Some("720p"));
assert_eq!(r.audio_codec(), Some("DTS"));
assert_eq!(r.video_codec(), Some("H.264"));
assert_eq!(r.container(), Some("mkv"));
}
#[test]
fn movie_4k_hdr() {
let r = hunch("Blade.Runner.2049.2017.2160p.UHD.BluRay.REMUX.HDR.HEVC.Atmos-EPSiLON.mkv");
assert_eq!(r.title(), Some("Blade Runner"));
assert_eq!(r.year(), Some(2017));
assert_eq!(r.screen_size(), Some("2160p"));
assert_eq!(r.source(), Some("Ultra HD Blu-ray"));
assert_eq!(r.video_codec(), Some("H.265"));
assert_eq!(r.container(), Some("mkv"));
assert_eq!(r.release_group(), Some("EPSiLON"));
}
#[test]
fn movie_dvdrip() {
let r = hunch("Pulp.Fiction.1994.DVDRip.XviD-SAPHiRE.avi");
assert_eq!(r.title(), Some("Pulp Fiction"));
assert_eq!(r.year(), Some(1994));
assert_eq!(r.source(), Some("DVD"));
assert_eq!(r.video_codec(), Some("Xvid"));
assert_eq!(r.release_group(), Some("SAPHiRE"));
assert_eq!(r.container(), Some("avi"));
}
#[test]
fn movie_web_dl() {
let r = hunch("Dune.Part.Two.2024.WEB-DL.1080p.DDP5.1.Atmos.H.264-FLUX.mkv");
assert_eq!(r.title(), Some("Dune"));
assert_eq!(r.part(), Some(2));
assert_eq!(r.year(), Some(2024));
assert_eq!(r.source(), Some("Web"));
assert_eq!(r.screen_size(), Some("1080p"));
assert_eq!(r.container(), Some("mkv"));
assert_eq!(r.release_group(), Some("FLUX"));
}
#[test]
fn episode_sxxexx() {
let r = hunch("The.Walking.Dead.S05E03.720p.BluRay.x264-DEMAND.mkv");
assert_eq!(r.title(), Some("The Walking Dead"));
assert_eq!(r.season(), Some(5));
assert_eq!(r.episode(), Some(3));
assert_eq!(r.screen_size(), Some("720p"));
assert_eq!(r.source(), Some("Blu-ray"));
assert_eq!(r.video_codec(), Some("H.264"));
assert_eq!(r.release_group(), Some("DEMAND"));
assert_eq!(r.container(), Some("mkv"));
}
#[test]
fn episode_with_title() {
let r = hunch("Californication.2x05.Vaginatown.HDTV.XviD-0TV.avi");
assert_eq!(r.title(), Some("Californication"));
assert_eq!(r.season(), Some(2));
assert_eq!(r.episode(), Some(5));
assert_eq!(r.episode_title(), Some("Vaginatown"));
assert_eq!(r.source(), Some("HDTV"));
assert_eq!(r.video_codec(), Some("Xvid"));
assert_eq!(r.release_group(), Some("0TV"));
assert_eq!(r.container(), Some("avi"));
}
#[test]
fn episode_hdtv() {
let r = hunch("Breaking.Bad.S01E01.720p.HDTV.x264-NewbIES.mkv");
assert_eq!(r.title(), Some("Breaking Bad"));
assert_eq!(r.season(), Some(1));
assert_eq!(r.episode(), Some(1));
assert_eq!(r.screen_size(), Some("720p"));
assert_eq!(r.source(), Some("HDTV"));
assert_eq!(r.video_codec(), Some("H.264"));
assert_eq!(r.container(), Some("mkv"));
}
#[test]
fn episode_daily_show() {
let r = hunch("The.Daily.Show.2024.03.15.720p.WEB.h264-EDITH.mkv");
assert_eq!(r.title(), Some("The Daily Show"));
assert_eq!(r.screen_size(), Some("720p"));
assert_eq!(r.source(), Some("Web"));
assert_eq!(r.video_codec(), Some("H.264"));
assert_eq!(r.container(), Some("mkv"));
}
#[test]
fn episode_full_season_pack() {
let r = hunch("Game.of.Thrones.S08.1080p.BluRay.x264-ROVERS.mkv");
assert_eq!(r.title(), Some("Game of Thrones"));
assert_eq!(r.season(), Some(8));
assert_eq!(r.screen_size(), Some("1080p"));
assert_eq!(r.source(), Some("Blu-ray"));
assert_eq!(r.video_codec(), Some("H.264"));
}
#[test]
fn audio_aac() {
let r = hunch("Movie.2024.1080p.WEBRip.AAC2.0.x264.mkv");
assert_eq!(r.audio_codec(), Some("AAC"));
assert_eq!(r.audio_channels(), Some("2.0"));
}
#[test]
fn audio_dts_hd_ma() {
let r = hunch("Movie.2024.1080p.BluRay.DTS-HD.MA.5.1.x264.mkv");
assert_eq!(r.audio_codec(), Some("DTS-HD"));
assert_eq!(r.audio_channels(), Some("5.1"));
}
#[test]
fn audio_truehd_atmos() {
let r = hunch("Movie.2024.2160p.BluRay.TrueHD.7.1.Atmos.x265.mkv");
assert_eq!(r.audio_codec(), Some("Dolby TrueHD"));
assert_eq!(r.audio_channels(), Some("7.1"));
}
#[test]
fn video_h264_variants() {
assert_eq!(hunch("Movie.x264.mkv").video_codec(), Some("H.264"));
assert_eq!(hunch("Movie.h264.mkv").video_codec(), Some("H.264"));
assert_eq!(hunch("Movie.H.264.mkv").video_codec(), Some("H.264"));
}
#[test]
fn video_h265_variants() {
assert_eq!(hunch("Movie.x265.mkv").video_codec(), Some("H.265"));
assert_eq!(hunch("Movie.HEVC.mkv").video_codec(), Some("H.265"));
assert_eq!(hunch("Movie.h265.mkv").video_codec(), Some("H.265"));
}
#[test]
fn video_av1() {
assert_eq!(hunch("Movie.AV1.mkv").video_codec(), Some("AV1"));
}
#[test]
fn screen_sizes() {
assert_eq!(hunch("Movie.480p.mkv").screen_size(), Some("480p"));
assert_eq!(hunch("Movie.720p.mkv").screen_size(), Some("720p"));
assert_eq!(hunch("Movie.1080p.mkv").screen_size(), Some("1080p"));
assert_eq!(hunch("Movie.1080i.mkv").screen_size(), Some("1080i"));
assert_eq!(hunch("Movie.2160p.mkv").screen_size(), Some("2160p"));
assert_eq!(hunch("Movie.4K.mkv").screen_size(), Some("2160p"));
}
#[test]
fn sources() {
assert_eq!(hunch("Movie.BluRay.mkv").source(), Some("Blu-ray"));
assert_eq!(hunch("Movie.BDRip.mkv").source(), Some("Blu-ray"));
assert_eq!(hunch("Movie.WEB-DL.mkv").source(), Some("Web"));
assert_eq!(hunch("Movie.WEBRip.mkv").source(), Some("Web"));
assert_eq!(hunch("Movie.HDTV.mkv").source(), Some("HDTV"));
assert_eq!(hunch("Movie.DVDRip.mkv").source(), Some("DVD"));
}
#[test]
fn editions() {
let r = hunch("Movie.Directors.Cut.1080p.BluRay.mkv");
assert_eq!(r.edition(), Some("Director's Cut"));
let r = hunch("Movie.Unrated.1080p.BluRay.mkv");
assert_eq!(r.edition(), Some("Unrated"));
let r = hunch("Movie.Extended.Edition.1080p.BluRay.mkv");
assert_eq!(r.edition(), Some("Extended"));
assert_eq!(r.year(), None);
}
#[test]
fn containers() {
assert_eq!(hunch("Movie.mkv").container(), Some("mkv"));
assert_eq!(hunch("Movie.avi").container(), Some("avi"));
assert_eq!(hunch("Movie.mp4").container(), Some("mp4"));
assert_eq!(hunch("Movie.m4v").container(), Some("m4v"));
assert_eq!(hunch("Subs.srt").container(), Some("srt"));
}
#[test]
fn no_year() {
let r = hunch("Inception.1080p.BluRay.x264-GROUP.mkv");
assert_eq!(r.title(), Some("Inception"));
assert_eq!(r.year(), None);
}
#[test]
fn title_with_numbers() {
let r = hunch("300.2006.1080p.BluRay.x264.mkv");
assert_eq!(r.title(), Some("300"));
assert_eq!(r.year(), Some(2006));
}
#[test]
fn minimal_input() {
let r = hunch("movie.mkv");
assert_eq!(r.container(), Some("mkv"));
}
#[test]
fn proper_repack() {
let r = hunch("Movie.2024.PROPER.1080p.BluRay.x264-GROUP.mkv");
assert_eq!(r.proper_count(), Some(1));
}
#[test]
fn streaming_service() {
let r = hunch("Movie.2024.NF.WEB-DL.1080p.x264-GROUP.mkv");
assert_eq!(r.streaming_service(), Some("Netflix"));
assert_eq!(r.source(), Some("Web"));
}
#[test]
fn color_depth_10bit() {
let r = hunch("Movie.2024.10bit.1080p.BluRay.x265.mkv");
assert_eq!(r.first(hunch::Property::ColorDepth), Some("10-bit"));
}
#[test]
fn crc32_in_brackets() {
let r = hunch("[SubGroup] Anime Title - 01 [720p] [ABCD1234].mkv");
assert_eq!(r.first(hunch::Property::Crc), Some("ABCD1234"));
}
#[test]
fn bit_rate_kbps() {
let r = hunch("Chuck Berry The Very Best Of Chuck Berry(2010)[320 Kbps]");
assert_eq!(r.audio_bit_rate(), Some("320Kbps"));
assert_eq!(r.video_bit_rate(), None);
assert_eq!(r.year(), Some(2010));
}
#[test]
fn bit_rate_mbps() {
let r = hunch("Title Name [480p][1.5Mbps][.mp4]");
assert_eq!(r.video_bit_rate(), Some("1.5Mbps"));
assert_eq!(r.audio_bit_rate(), None);
assert_eq!(r.screen_size(), Some("480p"));
}
#[test]
fn bit_rate_after_codec() {
let r = hunch("Show.Name.S01E01.H264.384Kbps.mkv");
assert_eq!(r.audio_bit_rate(), Some("384Kbps"));
assert_eq!(r.video_codec(), Some("H.264"));
}
#[test]
fn episode_format_minisode() {
let r = hunch(
"Series/Breaking Bad/Minisodes/Breaking.Bad.(Minisodes).01.Good.Cop.Bad.Cop.WEBRip.XviD.avi",
);
assert_eq!(r.first(hunch::Property::EpisodeFormat), Some("Minisode"));
assert_eq!(r.title(), Some("Breaking Bad"));
assert_eq!(r.episode(), Some(1));
}
#[test]
fn week_in_episode_context() {
let r = hunch("Show Name - S32-Week 45-Ep 6478");
assert_eq!(r.first(hunch::Property::Week), Some("45"));
assert_eq!(r.season(), Some(32));
assert_eq!(r.episode(), Some(6478));
}
use hunch::Property;
#[test]
fn cjk_yamada_full_path() {
let r = hunch(
"[Comicat&KissSub] Yamada-kun to Lv999 no Koi wo Suru \
(01-13Fin WEBRip 1080p AVC AAC TC)/\
[Comicat&KissSub][Yamada-kun to Lv999 no Koi wo Suru]\
[01][1080P][BIG5][MP4].mp4",
);
assert_eq!(r.title(), Some("Yamada-kun to Lv999 no Koi wo Suru"));
assert_eq!(r.episode(), Some(1));
assert_eq!(r.release_group(), Some("Comicat&KissSub"));
assert_eq!(r.screen_size(), Some("1080p"));
assert_eq!(r.source(), Some("Web"));
assert_eq!(r.audio_codec(), Some("AAC"));
assert_eq!(r.video_codec(), Some("H.264"));
assert_eq!(r.container(), Some("mp4"));
assert_eq!(
r.first(Property::SubtitleLanguage),
Some("Traditional Chinese")
);
let sources: Vec<_> = r.all(Property::Source);
assert!(
!sources.contains(&"Telecine"),
"TC should not match as Telecine when subtitle language is present"
);
}
#[test]
fn cjk_saki_zenkoku_mkv() {
let r = hunch(
"[DBD-Raws][天才麻将少女 全国篇][01-13TV全集+特典映像]\
[1080P][BDRip][HEVC-10bit][简繁外挂][FLAC][MKV]/\
[DBD-Raws][Saki Zenkoku Hen][01][1080P][BDRip]\
[HEVC-10bit][FLACx2].mkv",
);
assert_eq!(r.title(), Some("Saki Zenkoku Hen"));
assert_eq!(r.episode(), Some(1));
assert_eq!(r.release_group(), Some("DBD-Raws"));
assert_eq!(r.audio_codec(), Some("FLAC"));
assert_eq!(r.video_codec(), Some("H.265"));
assert_eq!(r.source(), Some("Blu-ray"));
assert_eq!(r.first(Property::ColorDepth), Some("10-bit"));
}
#[test]
fn cjk_saki_zenkoku_sc_ass() {
let r = hunch(
"[DBD-Raws][Saki Zenkoku Hen][01][1080P][BDRip]\
[HEVC-10bit][FLACx2].sc.ass",
);
assert_eq!(r.title(), Some("Saki Zenkoku Hen"));
assert_eq!(r.episode(), Some(1));
assert_eq!(r.release_group(), Some("DBD-Raws"));
assert_eq!(r.container(), Some("ass"));
assert_eq!(
r.first(Property::SubtitleLanguage),
Some("Simplified Chinese")
);
assert_eq!(r.video_codec(), None);
assert_eq!(r.audio_codec(), None);
assert_eq!(r.first(Property::ColorDepth), None);
assert_eq!(r.source(), None);
}
#[test]
fn cjk_saki_zenkoku_tc_ass() {
let r = hunch(
"[DBD-Raws][Saki Zenkoku Hen][01][1080P][BDRip]\
[HEVC-10bit][FLACx2].tc.ass",
);
assert_eq!(
r.first(Property::SubtitleLanguage),
Some("Traditional Chinese")
);
assert_eq!(r.container(), Some("ass"));
}
#[test]
fn cjk_saki_rev_sc_ass() {
let r = hunch(
"[Rev][DBD-Raws][天才麻将少女][01-25TV全集+SP][1080P][BDRip]\
[HEVC-10bit][简繁外挂][FLAC][MKV]/\
[DBD-Raws][Saki][01][1080P][BDRip][HEVC-10bit][FLAC][Rev].sc.ass",
);
assert_eq!(r.title(), Some("Saki"));
assert_eq!(r.episode(), Some(1));
assert_eq!(r.release_group(), Some("DBD-Raws"));
assert_eq!(r.container(), Some("ass"));
assert_eq!(
r.first(Property::SubtitleLanguage),
Some("Simplified Chinese")
);
let others: Vec<_> = r.all(Property::Other);
assert!(
others.contains(&"Revised"),
"[Rev] should be parsed as Revised"
);
}
#[test]
fn cjk_natsume_scjp_ass() {
let r = hunch(
"[DBD-Raws][夏目友人帐 柒][01-12TV全集+SP+特典映像]\
[1080P][BDRip][HEVC-10bit][简繁日双语外挂][FLAC][MKV]/\
[DBD-Raws][Natsume Yuujinchou Shichi][01][1080P][BDRip]\
[HEVC-10bit][FLAC].scjp.ass",
);
assert_eq!(r.title(), Some("Natsume Yuujinchou Shichi"));
assert_eq!(r.episode(), Some(1));
assert_eq!(r.release_group(), Some("DBD-Raws"));
assert_eq!(r.container(), Some("ass"));
assert_eq!(
r.first(Property::SubtitleLanguage),
Some("Simplified Chinese")
);
assert_eq!(r.video_codec(), None);
assert_eq!(r.source(), None);
}
#[test]
fn cjk_natsume_tcjp_ass() {
let r = hunch(
"[DBD-Raws][Natsume Yuujinchou Shichi][01][1080P][BDRip]\
[HEVC-10bit][FLAC].tcjp.ass",
);
assert_eq!(
r.first(Property::SubtitleLanguage),
Some("Traditional Chinese")
);
}
#[test]
fn cjk_natsume_sp_episode() {
let r = hunch(
"[DBD-Raws][Natsume Yuujinchou Shichi][13(SP)][1080P]\
[BDRip][HEVC-10bit][FLAC].mkv",
);
assert_eq!(r.title(), Some("Natsume Yuujinchou Shichi"));
assert_eq!(r.episode(), Some(13));
assert_eq!(r.container(), Some("mkv"));
}
#[test]
fn cjk_saki_achiga_flacx2() {
let r = hunch(
"[DBD-Raws][Saki Achiga Hen Episode of Side-A][01][1080P]\
[BDRip][HEVC-10bit][FLACx2].mkv",
);
assert_eq!(r.title(), Some("Saki Achiga Hen Episode of Side-A"));
assert_eq!(r.episode(), Some(1));
assert_eq!(r.audio_codec(), Some("FLAC"));
}
#[test]
fn cjk_saki_achiga_nc_ver() {
let r = hunch(
"[DBD-Raws][Saki Achiga Hen Episode of Side-A][14][NC.Ver]\
[1080P][BDRip][HEVC-10bit][FLAC].mkv",
);
assert_eq!(r.episode(), Some(14));
}
#[test]
fn cjk_solo_leveling_sxxexx_in_bracket_dir() {
let r = hunch("[H-Enc] Solo Leveling Season 2 (BDRip 1080p HEVC FLAC)/S01E13.mkv");
assert_eq!(r.title(), Some("Solo Leveling"));
assert_eq!(r.season(), Some(1));
assert_eq!(r.episode(), Some(13));
assert_eq!(r.source(), Some("Blu-ray"));
assert_eq!(r.video_codec(), Some("H.265"));
assert_eq!(r.audio_codec(), Some("FLAC"));
}
#[test]
fn cjk_lolihouse_dash_episode() {
let r = hunch(
"[LoliHouse] Kage no Jitsuryokusha ni Naritakute! [01-20]\
[WebRip 1080p HEVC-10bit AAC]/\
[LoliHouse] Kage no Jitsuryokusha ni Naritakute! - 01 \
[WebRip 1080p HEVC-10bit AAC SRTx2].mkv",
);
assert_eq!(r.title(), Some("Kage no Jitsuryokusha ni Naritakute!"));
assert_eq!(r.episode(), Some(1));
assert_eq!(r.release_group(), Some("LoliHouse"));
assert_eq!(r.source(), Some("Web"));
assert_eq!(r.audio_codec(), Some("AAC"));
}
#[test]
fn cjk_lolihouse_season2() {
let r = hunch(
"[LoliHouse] Kage no Jitsuryokusha ni Naritakute! S2 - 03 \
[WebRip 1080p HEVC-10bit AAC SRTx2].mkv",
);
assert_eq!(r.title(), Some("Kage no Jitsuryokusha ni Naritakute!"));
assert_eq!(r.episode(), Some(3));
assert_eq!(r.season(), Some(2));
}
#[test]
fn cjk_cowboy_bebop_from_parent() {
let r = hunch("Cowboy_Bebop[BDrip][1080p]/Cowboy.Bebop.E01.mkv");
assert_eq!(r.title(), Some("Cowboy Bebop"));
assert_eq!(r.episode(), Some(1));
assert_eq!(r.source(), Some("Blu-ray"));
assert_eq!(r.screen_size(), Some("1080p"));
}
#[test]
fn cjk_frieren_with_episode_title() {
let r = hunch(
"Frieren - Beyond Journey's End S01 1080p Dual Audio BDRip \
10 bits DD+ x265-EMBER/\
S01E01-The Journey's End [18D1CE8D].mkv",
);
assert_eq!(r.episode(), Some(1));
assert_eq!(r.season(), Some(1));
assert_eq!(r.episode_title(), Some("The Journey's End"));
assert_eq!(r.release_group(), Some("EMBER"));
assert_eq!(r.first(Property::Crc), Some("18D1CE8D"));
}
#[test]
fn cjk_prejudice_studio_mixed_title() {
let r = hunch(
"[Prejudice-Studio] 我独自升级 Ore dake Level Up na Ken - 01 \
[Bilibili WEB-DL 1080P AVC 8bit AAC MP4][简日内嵌].mp4",
);
assert_eq!(r.episode(), Some(1));
assert_eq!(r.screen_size(), Some("1080p"));
assert_eq!(r.source(), Some("Web"));
assert_eq!(r.container(), Some("mp4"));
assert_eq!(r.release_group(), Some("Prejudice-Studio"));
}
#[test]
fn issue_38_plex_dash_long_episode_title() {
let r = hunch("LEGO Ninjago Dragons Rising - S02E03 - The Temple of the Dragon Cores.mkv");
assert_eq!(r.title(), Some("LEGO Ninjago Dragons Rising"));
assert_eq!(r.season(), Some(2));
assert_eq!(r.episode(), Some(3));
assert_eq!(r.episode_title(), Some("The Temple of the Dragon Cores"));
assert_eq!(r.release_group(), None);
}
#[test]
fn issue_38_plex_dash_simple_episode_title() {
let r = hunch("Bluey - S02E01 - Dance Mode.mkv");
assert_eq!(r.title(), Some("Bluey"));
assert_eq!(r.season(), Some(2));
assert_eq!(r.episode(), Some(1));
assert_eq!(r.episode_title(), Some("Dance Mode"));
assert_eq!(r.release_group(), None);
}
#[test]
fn issue_39_cjk_bracket_big5() {
let r = hunch(
"[Comicat&KissSub][Yamada-kun to Lv999 no Koi wo Suru]\
[01][1080P][BIG5][MP4].mp4",
);
assert_eq!(r.title(), Some("Yamada-kun to Lv999 no Koi wo Suru"));
assert_eq!(r.episode(), Some(1));
assert_eq!(r.release_group(), Some("Comicat&KissSub"));
assert_eq!(r.screen_size(), Some("1080p"));
assert_eq!(
r.first(Property::SubtitleLanguage),
Some("Traditional Chinese")
);
}
#[test]
fn issue_39_cjk_bracket_sp_prefix() {
let r = hunch("[DBD-Raws][Saki][SP][01][1080P][BDRip][HEVC-10bit][FLAC].mkv");
assert_eq!(r.title(), Some("Saki"));
assert!(r.episode().is_some(), "episode should be detected");
assert_eq!(r.release_group(), Some("DBD-Raws"));
assert_eq!(r.episode_details(), Some("Special"));
}
#[test]
fn issue_39_cjk_cowboy_bebop_sp02() {
let r = hunch(
"[TxxZ&POPGO&MGRT][Cowboy_Bebop][BDrip]\
[BDBOX_SP02][CM][1920x1080_x264Hi10P_flac][31C5B7B3].mkv",
);
assert_eq!(r.release_group(), Some("TxxZ&POPGO&MGRT"));
assert_eq!(r.source(), Some("Blu-ray"));
assert_eq!(r.first(Property::Crc), Some("31C5B7B3"));
}
#[test]
fn issue_100_first_bracket_is_title_when_natural_language() {
let r = hunch(
"[Kimetsu no Yaiba Mugen Ressha Hen][JPN+ENG][BDRIP][1080P][H264_FLACx3_DTS-HDMA].mkv",
);
assert_eq!(r.title(), Some("Kimetsu no Yaiba Mugen Ressha Hen"));
assert_eq!(r.release_group(), None);
}
#[test]
fn issue_100_real_release_group_still_detected() {
let r =
hunch("[Prejudice-Studio][Kimetsu no Yaiba Mugen Ressha Hen][JPN+ENG][BDRIP][1080P].mkv");
assert_eq!(r.release_group(), Some("Prejudice-Studio"));
assert_eq!(r.title(), Some("Kimetsu no Yaiba Mugen Ressha Hen"));
}
#[test]
fn issue_35_western_srt_no_video_props() {
let r = hunch("Arcane.S01E01.1080p.NF.WEB-DL.DDP5.1.H.265-npuer.srt");
assert_eq!(r.container(), Some("srt"));
assert_eq!(r.title(), Some("Arcane"));
assert_eq!(r.season(), Some(1));
assert_eq!(r.episode(), Some(1));
assert_eq!(r.video_codec(), None);
assert_eq!(r.audio_codec(), None);
assert_eq!(r.source(), None);
}
#[test]
fn issue_124_anime_multi_segment_title_preserved() {
let r = hunch(
"[Erai-raws] Enen no Shouboutai - San no Shou Part 2 - 13 \
[1080p CR WEB-DL AVC AAC][MultiSub][7FF9B816].mkv",
);
assert_eq!(
r.title(),
Some("Enen no Shouboutai - San no Shou Part 2"),
"the multi-segment title with embedded \" - \" and \"Part 2\" \
must be preserved verbatim (not truncated at the first dash)"
);
assert_eq!(r.episode(), Some(13));
assert_eq!(r.release_group(), Some("Erai-raws"));
assert_eq!(r.screen_size(), Some("1080p"));
assert_eq!(r.container(), Some("mkv"));
}
#[test]
fn issue_124_anime_dash_only_no_part_keyword() {
let r = hunch("[SuperGroup].Show.Name.-.Still.Name.-.11.[1080p].mkv");
assert_eq!(r.release_group(), Some("SuperGroup"));
assert_eq!(r.episode(), Some(11));
assert_eq!(r.screen_size(), Some("1080p"));
assert_eq!(
r.title(),
Some("Show Name - Still Name"),
"the inner \" - \" must be preserved as part of the title (the \
trailing \" - 11\" is the episode marker)"
);
}
#[test]
fn stereoscopic_half_sbs_emits_3d_other() {
let r = hunch("TEST.2015.1080p.3D.BluRay.Half-SBS.x264.DTS-HD.MA.7.1-ABC");
assert!(
r.other().contains(&"3D"),
"Half-SBS must contribute a \"3D\" Other value (stereoscopic delivery format)"
);
assert_eq!(r.title(), Some("TEST"));
assert_eq!(r.year(), Some(2015));
assert_eq!(r.screen_size(), Some("1080p"));
assert_eq!(r.source(), Some("Blu-ray"));
}
#[test]
fn stereoscopic_half_ou_emits_3d_other() {
let r = hunch("TEST.2015.1080p.3D.BluRay.Half-OU.x264.DTS-HD.MA.7.1-ABC");
assert!(
r.other().contains(&"3D"),
"Half-OU must contribute a \"3D\" Other value (stereoscopic delivery format)"
);
assert_eq!(r.source(), Some("Blu-ray"));
}
#[test]
fn dvd_region_codes_r0_through_r6() {
let pairs = [
("R0", "Region 0"),
("R1", "Region 1"),
("R2", "Region 2"),
("R3", "Region 3"),
("R4", "Region 4"),
("R5", "Region 5"),
("R6", "Region 6"),
];
for (token, expected) in pairs {
let filename = format!("Movie.2024.{token}.DVDRip.x264-GROUP.mkv");
let r = hunch(&filename);
assert!(
r.other().contains(&expected),
"{filename} should yield Other = \"{expected}\", got {:?}",
r.other()
);
assert_eq!(r.source(), Some("DVD"), "{filename} source");
}
}
#[test]
fn dvd_region_r5_does_not_break_classic_brave_fixture() {
let r = hunch("Brave.2012.R5.DVDRip.XViD.LiNE-UNiQUE");
assert_eq!(r.title(), Some("Brave"));
assert_eq!(r.year(), Some(2012));
assert_eq!(r.source(), Some("DVD"));
assert_eq!(r.video_codec(), Some("Xvid"));
assert_eq!(r.release_group(), Some("UNiQUE"));
assert!(r.other().contains(&"Region 5"));
}
#[test]
fn mimetype_derived_from_mp4_container() {
let r = hunch("Movie.2024.1080p.WEB-DL.x264.mp4");
assert_eq!(r.container(), Some("mp4"));
assert_eq!(r.mimetype(), Some("video/mp4"));
}
#[test]
fn mimetype_derived_from_mkv_container() {
let r = hunch("Movie.2024.1080p.BluRay.x265.mkv");
assert_eq!(r.container(), Some("mkv"));
assert_eq!(r.mimetype(), Some("video/x-matroska"));
}
#[test]
fn mimetype_none_when_container_unknown() {
let r = hunch("Movie.2024.1080p.WEB-DL.x264.weirdext");
assert_eq!(r.container(), None);
assert_eq!(r.mimetype(), None);
}
#[test]
fn bit_rate_kbps_lowercase_with_channel_collision() {
let r = hunch("Hotel.Hell.S01E01.720p.DD5.1.448kbps-ALANiS");
assert_eq!(r.audio_bit_rate(), Some("448Kbps"));
assert_eq!(r.audio_channels(), Some("5.1"));
assert_eq!(r.audio_codec(), Some("Dolby Digital"));
}
#[test]
fn bit_rate_kbit_short_suffix() {
let r = hunch("Show.Name.S01E01.H264-384kbit_AAC.mp4");
assert_eq!(r.audio_bit_rate(), Some("384Kbps"));
}
#[test]
fn bit_rate_mbits_plural_suffix() {
let r = hunch("[HorribleSubs] Overlord II - 01 [1080p] 19.1mbits - 120fps.mkv");
assert_eq!(r.video_bit_rate(), Some("19.1Mbps"));
assert_eq!(r.frame_rate(), Some("120fps"));
}
#[test]
fn movie_context_drops_heuristic_episode_match() {
let r = hunch("Movie.10.mkv");
assert_eq!(r.media_type(), Some(hunch::MediaType::Movie));
assert_eq!(
r.episode(),
None,
"bare number in movie context must not surface as episode"
);
}
#[test]
fn movie_without_proper_omits_proper_count_field() {
let r = hunch("The.Movie.2024.1080p.BluRay.x264.mkv");
assert_eq!(
r.proper_count(),
None,
"ProperCount must be absent when count is 0"
);
}
#[test]
fn episode_with_proper_emits_proper_count_one() {
let r = hunch("Show.S01E03.PROPER.mkv");
assert_eq!(r.proper_count(), Some(1));
}
#[test]
fn episode_with_repack_and_proper_emits_proper_count_two() {
let r = hunch("Show.S01E03.REPACK.PROPER.mkv");
assert_eq!(r.proper_count(), Some(2));
}