hunch 2.0.2

A media filename parser for movies, TV, and anime — built in Rust, inspired by guessit
Documentation
# Other property patterns: HDR, Remux, Proper, 3D, region codes, etc.
# Matched token-by-token (or as 2–3-token windows), so no lookaround needed.
#
# This is the sole source of truth for Other patterns (v0.2.1+).
# The legacy other.rs matcher has been retired.
#
# Zone: unrestricted — these tokens are almost never title words.
# Truly ambiguous tokens (HD, DV, Proof) live in other_positional.toml
# with zone_scope = "tech_only". 3D uses requires_nearby (below) for
# context-aware disambiguation.
property = "other"

# Single-token exact matches (case-insensitive).
[exact]
remux       = "Remux"
proper      = "Proper"
repack      = "Proper"
rerip       = "Proper"
reencoded   = "Reencoded"
hdr10       = "HDR10"
sdr         = "Standard Dynamic Range"
fhd         = "Full HD"
ultra       = "Ultra HD"
pal         = "PAL"
ntsc        = "NTSC"
secam       = "SECAM"
# DVD region codes (R0–R6 are the standard MPAA regions; R7–R9 are reserved
# and rarely used in real-world filenames, so we omit them to limit false
# positives on niche release-group/encoding tokens that begin with R).
r0          = "Region 0"
r1          = "Region 1"
r2          = "Region 2"
r3          = "Region 3"
r4          = "Region 4"
r5          = "Region 5"
r6          = "Region 6"
screener    = "Screener"
scr         = "Screener"
hybrid      = "Hybrid"
preair      = "Preair"
2in1        = "2in1"
internal    = "Internal"
xxx         = "XXX"
colorized   = "Colorized"
# NOTE: "Dubbed" as standalone exact match removed — it's handled by a
# pattern with not_after constraint to avoid matching after language names.
# GERMAN.DUBBED → language qualifier, not separate Other:Dubbed.
repost      = "Repost"
obfuscated  = "Obfuscated"
obfuscation = "Obfuscated"
scrambled   = "Obfuscated"
# NOTE: "complete"/"complet" removed from exact — handled by pattern
# with requires_before to avoid false positives on standalone "Complete".
stv         = "Straight to Video"
dirfix      = "Fix"
nfofix      = "Fix"
samplefix   = "Fix"
prooffix    = "Fix"
ova         = "Original Video"
oad         = "Original Animation DVD"
oar         = "Original Aspect Ratio"
ws          = "Widescreen"
upscaled    = "Upscaled"
upscale     = "Upscaled"
rev         = "Revised"
converted   = "Converted"
convert     = "Converted"
extras      = "Extras"
extra       = "Extras"
docu        = "Documentary"
doku        = "Documentary"
dokumentary = "Documentary"
ldtv        = "Low Definition"
hq          = "High Quality"
ld          = "Line Dubbed"

# Case-sensitive exact matches — only tokens that are exclusively these values.
[exact_sensitive]
REAL  = "Proper"

# Multi-token and complex patterns.

[[patterns]]
# HDR10+ (has + suffix, not matched by plain exact)
match = '(?i)^hdr10\+$'
value = "HDR10+"

[[patterns]]
# HDR without number — treat as HDR10
match = '(?i)^hdr$'
value = "HDR10"

[[patterns]]
# Dolby Vision / DolbyVision
match = '(?i)^dolby[- .]?vision$'
value = "Dolby Vision"

[[patterns]]
# BT.2020 / BT-2020 / BT 2020
match = '(?i)^bt[- .]?2020$'
value = "BT.2020"

[[patterns]]
# Full HD / FullHD / Full-HD
match = '(?i)^full[- .]?hd$'
value = "Full HD"

[[patterns]]
# Ultra HD / UltraHD
match = '(?i)^ultra[- .]?hd$'
value = "Ultra HD"

[[patterns]]
# UHD (standalone — not part of UHD TV which is in source)
match = '(?i)^uhd$'
value = "Ultra HD"

[[patterns]]
# Netflix UHD
match = '(?i)^netflix[- .]?uhd$'
value = "Ultra HD"

[[patterns]]
# Micro HD / mHD / HDLight
match = '(?i)^(?:mhd|hdlight)$'
value = "Micro HD"

[[patterns]]
# WideScreen / Wide Screen / Wide-Screen
match = '(?i)^wide[- .]?screen$'
value = "Widescreen"

[[patterns]]
# REPACK + digit suffix (e.g. REPACK2)
match = '(?i)^(?:repack|rerip)\d+$'
value = "Proper"

[[patterns]]
# Re-encoded / re.enc / reenc
match = '(?i)^re[- .]?enc(?:oded)?$'
value = "Reencoded"

[[patterns]]
# BRRip implies re-encoding from Blu-ray
match = '(?i)^brrip$'
value = "Reencoded"

[[patterns]]
# Audio Fix / Audio-Fix
match = '(?i)^audio[- .]?fix(?:ed)?$'
value = "Audio Fixed"

[[patterns]]
# Sync Fix / Sync-Fix
match = '(?i)^sync[- .]?fix(?:ed)?$'
value = "Sync Fixed"

[[patterns]]
# Hardcoded Subtitles: HCSUB / HC SUBS / HARDCODED SUBS
match = '(?i)^(?:hardcoded|hc)[- .]?subs?$'
value = "Hardcoded Subtitles"

[[patterns]]
# Fan Sub / FanSubbed / FanSub
match = '(?i)^fan[- .]?sub(?:bed|titled|s)?$'
value = "Fan Subtitled"

[[patterns]]
# Fast Sub / FastSubbed
match = '(?i)^fast[- .]?sub(?:bed|titled|s)?$'
value = "Fast Subtitled"

[[patterns]]
# Dual Audio / Dual.Audio
match = '(?i)^dual[- .]?audio$'
value = "Dual Audio"

[[patterns]]
# Dual before media keywords (DVD, BD, Sub, etc.) implies Dual Audio
match = '(?i)^dual$'
value = "Dual Audio"
requires_after = ["dvd", "bd", "br", "web", "bluray", "sub", "subs", "subtitulos"]

[[patterns]]
# Multi Audio / Multi-Audio
match = '(?i)^multi[- .]?audio$'
value = "Multi Audio"

[[patterns]]
# Side-by-Side (full form — unambiguous)
match = '(?i)^(?:half[- .]?)?side[- .]?by[- .]?side$'
value = "3D"

[[patterns]]
# Over-Under (full form — unambiguous)
match = '(?i)^(?:half[- .]?)?over[- .]?under$'
value = "3D"

[[patterns]]
# Pre-Air / PreAir
match = '(?i)^pre[- .]?air$'
value = "Preair"

[[patterns]]
# Read.NFO / ReadNFO
match = '(?i)^read\.?nfo$'
value = "Read NFO"

[[patterns]]
# Mux variants
match = '(?i)^(?:divx|xvid)?[- .]?mux$'
value = "Mux"

[[patterns]]
# Straight to Video
match = '(?i)^straight[- .]?to[- .]?video$'
value = "Straight to Video"

[[patterns]]
# Original Aspect Ratio (multi-token)
match = '(?i)^original[- .]?aspect[- .]?ratio$'
value = "Original Aspect Ratio"

[[patterns]]
# Open Matte / Open-Matte
match = '(?i)^open[- .]?matte$'
value = "Open Matte"

[[patterns]]
# East/West Coast Feed
match = '(?i)^(?:east|est)[- .]?(?:coast[- .]?)?feed$'
value = "East Coast Feed"

[[patterns]]
match = '(?i)^(?:west|wst)[- .]?(?:coast[- .]?)?feed$'
value = "West Coast Feed"

[[patterns]]
# Documentary variants: DOKU, DOCU, DOCUMENTARY
match = '(?i)^dok[cu](?:mentary)?$'
value = "Documentary"

[[patterns]]
# Complete / Complet — match when tech context exists (anchors),
# OR when preceded by season/series keywords (fallback for anchor-less cases).
match = '(?i)^complet(?:e|s)?$'
value = "Complete"
requires_context = true
requires_before = ["season", "saison", "temporada", "staffel", "serie", "series"]

[[patterns]]
# Dubbed — only when NOT immediately after a language name.
# GERMAN.DUBBED → language qualifier (not Other), but DUBBED alone → Other.
match = '(?i)^dubbed$'
value = "Dubbed"
not_after = ["english", "french", "spanish", "german", "italian", "portuguese", "russian", "japanese", "chinese", "korean", "arabic", "hindi", "dutch", "swedish", "norwegian", "danish", "finnish", "polish", "czech", "turkish", "greek", "hungarian", "romanian", "thai", "vietnamese", "catalan", "croatian", "serbian", "bulgarian", "ukrainian", "hebrew", "deutsch", "italiano", "castellano", "eng", "fre", "ger", "spa", "ita", "jpn", "rus", "kor", "dut", "por", "ara", "hin"]

[[patterns]]
# 3D — ambiguous: "Pacific Rim 3D" (metadata) vs "Harold & Kumar 3D Christmas" (title).
# Confident when tech tokens (BluRay, 1080p, etc.) appear nearby;
# reclaimable (title may absorb) when no tech context exists.
match = '(?i)^3d$'
value = "3D"
requires_nearby = ["bluray", "bdrip", "brrip", "remux", "1080p", "720p", "2160p", "4k", "uhd", "hdr", "hdr10", "web", "webrip", "webdl", "dvdrip", "hdtv", "x264", "x265", "h264", "h265", "hevc", "avc", "dts", "atmos", "truehd"]