v1.9.2: whitelist-laag (onmiskenbare OV-termen als altijd-door-signaal) + inchecken/uitchecken naar zwak (Schiphol-inchecken is geen OV)

This commit is contained in:
Eddy de Vink 2026-09-10 20:43:13 +02:00
commit 6e9f9b1b0f
2 changed files with 59 additions and 2 deletions

View file

@ -88,13 +88,14 @@ MATCH_FILTER_FAMILIES: list[tuple[str, int]] = [
# medium (2) # medium (2)
(r"\btrams?\b", 2), (r"\btrams?\b", 2),
(r"\bmetro(?:'?s)?\b", 2), (r"\bmetro(?:'?s)?\b", 2),
(r"\b(?:openbaar vervoer|dienstregeling|inchecken|uitchecken|lightrail|pendelbus|shuttlebus|halte|bushokje|busbaan|vervoerder|reiziger)\w*\b", 2), (r"\b(?:openbaar vervoer|dienstregeling|lightrail|pendelbus|shuttlebus|halte|bushokje|busbaan|vervoerder|reiziger)\w*\b", 2),
(r"\b(?:ov-chipkaart|chipkaart|ovpay|ov-pay|reisproduct|studentenreisproduct|vervoersbewijs|vervoerbewijs)\w*\b", 2), (r"\b(?:ov-chipkaart|chipkaart|ovpay|ov-pay|reisproduct|studentenreisproduct|vervoersbewijs|vervoerbewijs)\w*\b", 2),
(r"\b(?:ov-staking|conducteursstaking)\w*\b", 2), (r"\b(?:ov-staking|conducteursstaking)\w*\b", 2),
(r"\bconduct(?:eur|eurs)\b", 2), # trein-/buspersoneel: onmiskenbaar OV-jargon (r"\bconduct(?:eur|eurs)\b", 2), # trein-/buspersoneel: onmiskenbaar OV-jargon
(r"\b(?:pont|ponten)\b", 2), # waterbus/veerdienst (r"\b(?:pont|ponten)\b", 2), # waterbus/veerdienst
# zwak (1) — dubbelzinnig, moet combineren # zwak (1) — dubbelzinnig, moet combineren
(r"(?<!-)\bbus(?:sen)?\b", 1), # ná een koppelteken geen OV: 'VW-bus', 'school-bus' (r"(?<!-)\bbus(?:sen)?\b", 1), # ná een koppelteken geen OV: 'VW-bus', 'school-bus'
(r"\b(?:inchecken|uitchecken)\w*\b", 1), # ook op luchthavens/hotels — geen OV-jargon, moet combineren
(r"\bbreng\b", 1), # vervoerder Breng vs werkwoord "brengen" ("hoe breng je ... in beeld") (r"\bbreng\b", 1), # vervoerder Breng vs werkwoord "brengen" ("hoe breng je ... in beeld")
(r"\boverweg\b", 1), # spoorwegovergang vs idioom "goed met elkaar overweg kunnen" (r"\boverweg\b", 1), # spoorwegovergang vs idioom "goed met elkaar overweg kunnen"
(r"\boverwegen\b", 1), # meervoud van overweg vs werkwoord ("een gratieverlening overwegen") (r"\boverwegen\b", 1), # meervoud van overweg vs werkwoord ("een gratieverlening overwegen")
@ -127,10 +128,48 @@ MATCH_FILTER_BLACKLIST: frozenset[str] = frozenset({
"stationnement", "stationering", "stationnement", "stationering",
}) })
# MATCH_FILTER_WHITELIST: termen die een bericht per definitie OV maken. Eén enkele
# hit in titel óf samenvatting laat ALTIJD door (geen familiescore nodig) — dit is het
# expliciete "onmiskenbaar OV"-signaal, zodat we voor deze termen niet op de gewogen
# heuristiek hoeven te leunen. Vergelijking is case-insensitive, dus ook 'nederlandse
# spoorwegen', 'prorail' en 'NS' in all-caps titels tellen mee.
# Termen MOETEN in elke context OV betekenen. Niet hierop (algemeen/dubbelzinnig):
# los 'trein', 'bus', 'metro', 'tram', 'station', 'lijn', 'ov', 'reiziger',
# 'inchecken' (Schiphol/hotel), 'sein' (brandweerjargon), 'overweg', 'treinramp'
# (films) — die blijven in de gewogen families.
MATCH_FILTER_WHITELIST: frozenset[str] = frozenset({
# Vervoerders en OV-merken (incl. multi-woord termen)
"nederlandse spoorwegen", "ns", "prorail", "randstadrail", "arriva", "qbuzz",
"connexxion", "transdev", "keolis", "ret", "gvb", "htm", "ebs", "syntus",
"u-ov", "allgo", "blauwnet", "r-net", "valleilijn", "hermes", "rrreis",
"qliner", "flixbus", "eurostar", "thalys", "gvu", "ovpay",
# Spoorinfra-jargon (samenvoegingen, onmiskenbaar OV)
"spoorstoring", "spoorverkeer", "spoorwegovergang", "spoorlijn", "spoorbaan",
"spoorbrug", "spoorstaking", "perron", "wisselstoring", "seinstoring",
"ontsporing", "ontspoord", "ontspoorde", "treinstoring", "treinverkeer",
"treinstaking", "treinongeval", "treinbotsing", "treinstel",
# Bus/tram/metro-jargon
"bushalte", "bushaltes", "busstation", "busbaan", "buslijn", "busnet",
"busstaking", "tramhalte", "tramlijn", "tramnet", "tramverkeer",
"metrostation", "metrolijn", "metroverkeer",
# Tarief/vervoerder-jargon
"ov-chipkaart", "ov-staking", "lightrail", "pendelbus", "shuttlebus",
"conducteur", "conducteurs", "dienstregeling", "vervoersbewijs",
"openbaar vervoer",
})
_compiled_match_families: list[tuple[re.Pattern, int]] = [ _compiled_match_families: list[tuple[re.Pattern, int]] = [
(re.compile(pat, re.IGNORECASE), w) for pat, w in MATCH_FILTER_FAMILIES (re.compile(pat, re.IGNORECASE), w) for pat, w in MATCH_FILTER_FAMILIES
] ]
# Whitelist: enkel-woord termen als \\b-term\\b (geen substring-botsingen zoals
# 'ns' in 'kunstenaar'), multi-woord termen als exacte frase.
_WHITELIST_RE = re.compile(
r"\b(?:" + "|".join(re.escape(w) for w in MATCH_FILTER_WHITELIST if " " not in w) + r")\b",
re.IGNORECASE,
)
_WHITELIST_PHRASES: tuple[str, ...] = tuple(w for w in MATCH_FILTER_WHITELIST if " " in w)
class Config(BaseProxyConfig): class Config(BaseProxyConfig):
def do_update(self, helper: ConfigUpdateHelper) -> None: def do_update(self, helper: ConfigUpdateHelper) -> None:
@ -258,6 +297,18 @@ class RSSBot(Plugin):
als tekst houden — inclusief URL's en attributen, die dan vals scoren.""" als tekst houden — inclusief URL's en attributen, die dan vals scoren."""
return re.sub(r"<[^>]+>", "", html.unescape(raw)) return re.sub(r"<[^>]+>", "", html.unescape(raw))
@staticmethod
def _whitelist_hit(text: str) -> bool:
"""True als een onmiskenbare OV-term uit MATCH_FILTER_WHITELIST in text zit.
Enkele-woord termen matchen op woordgrens ('ns' telt NIET binnen 'kunstenaar'),
multi-woord termen ('nederlandse spoorwegen') als exacte frase, beide
case-insensitive."""
if _WHITELIST_RE.search(text):
return True
low = text.lower()
return any(ph in low for ph in _WHITELIST_PHRASES)
@staticmethod @staticmethod
def _fam_hits(text: str) -> list[tuple[int, int]]: def _fam_hits(text: str) -> list[tuple[int, int]]:
"""(familie-index, gewicht) voor elke OV-familie die in text voorkomt (1× per familie). """(familie-index, gewicht) voor elke OV-familie die in text voorkomt (1× per familie).
@ -289,6 +340,9 @@ class RSSBot(Plugin):
'sein brandmeester' en figuratief 'weer op de rails'. 'sein brandmeester' en figuratief 'weer op de rails'.
Bewust doorgelaten: krant 'De Metro'/café 'De Tram' (medium), film-'treinramp' Bewust doorgelaten: krant 'De Metro'/café 'De Tram' (medium), film-'treinramp'
en atleet-'sprinter' (sterk).""" en atleet-'sprinter' (sterk)."""
# Whitelist: één onmiskenbare OV-term (titel óf samenvatting) laat altijd door.
if RSSBot._whitelist_hit(title) or RSSBot._whitelist_hit(summary):
return True
t_hits = RSSBot._fam_hits(title) t_hits = RSSBot._fam_hits(title)
s_hits = RSSBot._fam_hits(summary) s_hits = RSSBot._fam_hits(summary)
score = 2 * sum(w for _, w in t_hits) + sum(w for _, w in s_hits) score = 2 * sum(w for _, w in t_hits) + sum(w for _, w in s_hits)
@ -309,6 +363,9 @@ class RSSBot(Plugin):
"- Medium (2): tram, metro, openbaar vervoer/dienstregeling/inchecken, halte, bushokje, busbaan, vervoerder, reiziger, " "- Medium (2): tram, metro, openbaar vervoer/dienstregeling/inchecken, halte, bushokje, busbaan, vervoerder, reiziger, "
"ov-chipkaart/ovpay/reisproduct, ov-staking, pont\n" "ov-chipkaart/ovpay/reisproduct, ov-staking, pont\n"
"- Zwak (1): losse 'bus' (niet ná een koppelteken), 'trein', 'breng', 'overweg', 'overwegen', 'sein', 'kaartje', 'opwaarderen', 'rails' — moet combineren met een ander OV-woord\n\n" "- Zwak (1): losse 'bus' (niet ná een koppelteken), 'trein', 'breng', 'overweg', 'overwegen', 'sein', 'kaartje', 'opwaarderen', 'rails' — moet combineren met een ander OV-woord\n\n"
"**Whitelist (altijd door):** één onmiskenbare OV-term in titel óf samenvatting is genoeg "
"(NS, ProRail, Nederlandse Spoorwegen, spoorstoring, perron, bushalte, metrostation, conducteur, "
"ov-chipkaart, ovpay, openbaar vervoer, dienstregeling, ...)\n\n"
"Uitgesloten (blacklist): woorden die wél matchen maar geen OV-waarde hebben, " "Uitgesloten (blacklist): woorden die wél matchen maar geen OV-waarde hebben, "
"o.a. straatnamen rond stations ('stationsstraat', 'stationsweg', ...) en niet-OV-vormen als 'stationcar' en 'stationair'\n\n" "o.a. straatnamen rond stations ('stationsstraat', 'stationsweg', ...) en niet-OV-vormen als 'stationcar' en 'stationair'\n\n"
"Doorlaten: `2×(titel-score) + 1×(samenvatting-score) ≥ 3`" "Doorlaten: `2×(titel-score) + 1×(samenvatting-score) ≥ 3`"

View file

@ -1,5 +1,5 @@
id: nl.eddydevink.rss id: nl.eddydevink.rss
version: 1.9.1 version: 1.9.2
modules: modules:
- buzzrss - buzzrss
main_class: RSSBot main_class: RSSBot