Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 27 additions & 5 deletions Channel-Maparr/matching_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -702,9 +702,21 @@ def _trailing_number(name):
'KIND', 'KING', 'KINGS', 'KISS', 'KITE', 'KNEE', 'KNEW', 'KNOW', 'KNOWN',
})

# OTA branding context that immediately follows a station callsign: a channel
# number (optionally prefixed by a broadcast suffix), e.g. "KING 5", "WAVE 3",
# "WOOD TV8", "WHO 13". Used to rescue a denylisted common-word callsign in a
# loose position WITHOUT also rescuing bare program words ("King of the Hill",
# "Doctor Who"), which never carry this trailing number. bug-098.
_OTA_NUMBER_CONTEXT = re.compile(r'^\s+(?:TV|DT|CD|LP|LD)?\s*\d{1,3}\b', re.IGNORECASE)

def _is_callsign_allowed(self, callsign):
"""A candidate callsign is allowed if it is not denylisted, OR the plugin
supplied a known-real callsign set that contains it (DB rescue)."""
supplied a known-real callsign set that contains it (DB rescue).

NOTE: this full rescue is used only at the PARENTHESIZED priorities (1/1b),
where the parentheses are an unambiguous OTA signal. The end-of-name and
loose priorities deliberately do NOT use it for denylisted words -- see
bug-098 hardening in _compute_callsign_with_confidence."""
return (callsign not in self._CALLSIGN_DENYLIST
or (self._known_callsigns is not None and callsign in self._known_callsigns))

Expand Down Expand Up @@ -746,18 +758,28 @@ def _compute_callsign_with_confidence(self, channel_name):
if paren_suffix_match:
return paren_suffix_match.group(1).upper(), True

# Priority 3: Callsigns at the end
# Priority 3: Callsigns at the end. A denylisted common word at the end
# ("WOLF KING", "Doctor Who") is NOT rescued here -- end position alone is
# too weak a signal for a word that is also a real callsign. Non-denylisted
# callsigns (and suffixed forms like "KING-TV") still match. bug-098.
end_match = re.search(r'\b([KW][A-Z]{2,4}(?:-(?:TV|CD|LP|DT|LD))?)\s*(?:\.[a-z]+)?\s*$', channel_name, re.IGNORECASE)
if end_match:
callsign = end_match.group(1).upper()
if self._is_callsign_allowed(callsign):
if callsign not in self._CALLSIGN_DENYLIST:
return callsign, True

# Priority 4: Any word matching callsign pattern (low confidence)
# Priority 4: Any word matching callsign pattern (low confidence). A
# denylisted common word is rescued here ONLY in OTA branding context --
# immediately followed by a channel number ("KING 5", "WAVE 3", "WOOD
# TV8", "WHO 13") -- never as a bare program word ("King of the Hill",
# "Doctor Who", "Will Ferrell"). bug-098.
word_match = re.search(r'\b([KW][A-Z]{2,4}(?:-(?:TV|CD|LP|DT|LD))?)\b', channel_name, re.IGNORECASE)
if word_match:
callsign = word_match.group(1).upper()
if self._is_callsign_allowed(callsign):
if callsign not in self._CALLSIGN_DENYLIST:
return callsign, False
if (self._known_callsigns is not None and callsign in self._known_callsigns
and self._OTA_NUMBER_CONTEXT.match(channel_name[word_match.end():])):
return callsign, False

return None, False
Expand Down
2 changes: 1 addition & 1 deletion Channel-Maparr/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Channel Mapparr",
"version": "1.26.1791324",
"version": "1.26.1801833",
"description": "Standardizes broadcast (OTA) and premium/cable channel names using network data and channel lists. Supports M3U stream import, category organization, and fuzzy matching across 42K+ channels in 11 countries.",
"author": "PiratesIRC",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion Channel-Maparr/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
class PluginConfig:
"""Configuration constants for Channel Maparr."""

PLUGIN_VERSION = "1.26.1791324"
PLUGIN_VERSION = "1.26.1801833"

# Channel Database Settings
DEFAULT_CHANNEL_DATABASES = "US"
Expand Down
2 changes: 1 addition & 1 deletion scripts/core_manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"matching_core.py": "2ac7ac4cb283306152701bfd977ff2f13700d63d8023fdfa280b1480f5a969dc"
"matching_core.py": "d9a2d065584fb797789f3afe3d51dbd94d3d28a1666361b1f22c8eec6b03943b"
}
Loading