File size: 28,240 Bytes
788374c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
"""Standalone Byte-Anchored Title, Year & Episode Span Extractor (`armiger/byte_span_extractor.py`).

Provides four explicitly separated extraction and decoding modes for scientific attribution:
  1. `decode_bio_logits_viterbi(logits_2d, raw_bytes)`:
     Constrained 7x7 BIO Viterbi decoder with hard log-transition constraints (`0.00%` illegal
     transitions) and deterministic ASCII delimiter + 4-digit year boundary snapping
     (`snap_bio_span_boundaries`).
  2. `decode_bio_tags_raw_neural(raw_name, bio_tags)`:
     Pure neural decoding strictly from the 9th neural head (`span_bio` 7-class per-byte BIO tagger:
     `0=O, 1=B-TITLE, 2=I-TITLE, 3=B-YEAR, 4=I-YEAR, 5=B-EP, 6=I-EP`) with zero regex fallback.
  3. `extract_byte_spans_v3(raw_name)`:
     Deterministic UTF-8 byte-offset structural boundary extractor with zero external parser fallback.
  4. `decode_bio_tags_to_spans(raw_name, bio_tags)`:
     Hybrid neural + structural span decoder that uses the neural BIO span when it overlaps (`IoU >= 0.65`)
     and satisfies strict non-technical token hygiene, or falls back to the structural byte boundary.
"""
from __future__ import annotations

import math
import re
import unicodedata
from collections.abc import Sequence
from typing import Any

try:
    import numpy as np
except ImportError:
    np = None  # type: ignore[assignment]

BIO_O = 0
BIO_B_TITLE = 1
BIO_I_TITLE = 2
BIO_B_YEAR = 3
BIO_I_YEAR = 4
BIO_B_EP = 5
BIO_I_EP = 6
SPAN_BIO_CLASSES: tuple[str, ...] = (
    "O",
    "B-TITLE",
    "I-TITLE",
    "B-YEAR",
    "I-YEAR",
    "B-EP",
    "I-EP",
)

SEP_BYTES: frozenset[int] = frozenset(b"_.- []()")
_YEAR_TOKEN_BYTES_RE = re.compile(rb"(?<![0-9])(19[2-9]\d|20[0-2]\d)(?![0-9])")
_EP_TOKEN_BYTES_RE = re.compile(
    rb"(?i)(?<![a-z0-9])("
    rb"s\d{1,2}(?:[\.\s_\-]*e\d{1,3})?"
    rb"|(?:season|episode|chapter|chapters|ep|vol|disc|part)[\.\s_\-]*\d{1,4}(?:[\.\s_\-]*-[\.\s_\-]*\d{1,4})?"
    rb")(?![a-z0-9])"
)
_NEG_INF: float = float("-inf")


def _build_bio_viterbi_tables_py() -> tuple[list[float], list[list[float]]]:
    """Construct the constrained 7-state initial log-prior vector and 7x7 log-transition matrix."""
    init_log_p = [_NEG_INF] * 7
    init_log_p[BIO_O] = 0.0
    init_log_p[BIO_B_TITLE] = 0.0
    init_log_p[BIO_B_YEAR] = 0.0
    init_log_p[BIO_B_EP] = 0.0

    trans = [[_NEG_INF] * 7 for _ in range(7)]
    trans[BIO_O][BIO_O] = 0.0
    trans[BIO_O][BIO_B_TITLE] = 0.0
    trans[BIO_O][BIO_B_YEAR] = 0.0
    trans[BIO_O][BIO_B_EP] = 0.0

    entity_pairs = (
        (BIO_B_TITLE, BIO_I_TITLE),
        (BIO_B_YEAR, BIO_I_YEAR),
        (BIO_B_EP, BIO_I_EP),
    )
    for b_x, i_x in entity_pairs:
        for src in (b_x, i_x):
            trans[src][BIO_O] = 0.0
            trans[src][i_x] = 0.0
            for b_y, _ in entity_pairs:
                trans[src][b_y] = 0.0
    return init_log_p, trans


_BIO_INIT_LOG_P_PY, _BIO_TRANS_LOG_P_PY = _build_bio_viterbi_tables_py()
_BIO_INIT_LOG_P = np.asarray(_BIO_INIT_LOG_P_PY, dtype=np.float64) if np is not None else _BIO_INIT_LOG_P_PY
_BIO_TRANS_LOG_P = np.asarray(_BIO_TRANS_LOG_P_PY, dtype=np.float64) if np is not None else _BIO_TRANS_LOG_P_PY


def is_illegal_bio_transition(prev_tag: int, cur_tag: int, *, is_start: bool = False) -> bool:
    """Return True if transitioning from `prev_tag` to `cur_tag` violates constrained 7-tag BIO grammar."""
    c = int(cur_tag)
    if c < 0 or c >= 7:
        return True
    if is_start:
        return not math.isfinite(float(_BIO_INIT_LOG_P_PY[c]))
    p = int(prev_tag)
    if p < 0 or p >= 7:
        return True
    return not math.isfinite(float(_BIO_TRANS_LOG_P_PY[p][c]))


def count_illegal_bio_transitions(tags: Sequence[int] | Any) -> int:
    """Count illegal BIO state transitions (including illegal `I-*` start state at t=0) in `tags`."""
    n = len(tags)
    if n == 0:
        return 0
    cnt = 1 if is_illegal_bio_transition(0, int(tags[0]), is_start=True) else 0
    for t in range(1, n):
        if is_illegal_bio_transition(int(tags[t - 1]), int(tags[t]), is_start=False):
            cnt += 1
    return cnt


def snap_bio_span_boundaries(
    tags: Sequence[int] | Any,
    raw_bytes: bytes | bytearray = b"",
) -> Any:
    """Deterministically snap BIO span boundaries on ASCII delimiters and 4-digit year tokens:
      - Strip leading/trailing ASCII separator bytes (`_`, `.`, `-`, ` `, `[`, `]`, `(`, `)`)
        from `B-*`/`I-*` spans back to `O`, reassigning `B-*` to the first non-separator byte.
      - Snap 4-digit year tokens `(19[2-9]\\d|20[0-2]\\d)` cleanly when `B-YEAR`/`I-YEAR` covers
        >= 2 bytes of the 4-digit token.
    """
    arr_list = [int(x) if 0 <= int(x) < 7 else BIO_O for x in tags]
    n = len(arr_list)
    if n == 0:
        return np.asarray(arr_list, dtype=np.int64) if np is not None else arr_list
    b_raw = bytes(raw_bytes or b"")
    L = min(n, len(b_raw))
    if L == 0:
        return np.asarray(arr_list, dtype=np.int64) if np is not None else arr_list

    entity_groups = (
        (BIO_B_TITLE, BIO_I_TITLE),
        (BIO_B_YEAR, BIO_I_YEAR),
        (BIO_B_EP, BIO_I_EP),
    )

    def _strip_and_normalize_spans() -> None:
        for b_tag, i_tag in entity_groups:
            min_len = 2 if b_tag in (BIO_B_YEAR, BIO_B_EP) else 1
            idx = 0
            while idx < L:
                if arr_list[idx] in (b_tag, i_tag):
                    s = idx
                    idx += 1
                    while idx < L and arr_list[idx] == i_tag:
                        idx += 1
                    e = idx
                    for k in range(s, e):
                        arr_list[k] = BIO_O
                    ns, ne = s, e
                    while ns < ne and b_raw[ns] in SEP_BYTES:
                        ns += 1
                    while ne > ns and b_raw[ne - 1] in SEP_BYTES:
                        ne -= 1
                    if ne - ns >= min_len:
                        arr_list[ns] = b_tag
                        for k in range(ns + 1, ne):
                            arr_list[k] = i_tag
                else:
                    idx += 1

    _strip_and_normalize_spans()

    year_positions = {i for i in range(L) if arr_list[i] in (BIO_B_YEAR, BIO_I_YEAR)}
    if year_positions:
        snapped_years: list[tuple[int, int]] = []
        for m in _YEAR_TOKEN_BYTES_RE.finditer(b_raw[:L]):
            ys, ye = m.start(1), m.end(1)
            if ye <= L:
                overlap = sum(1 for k in range(ys, ye) if k in year_positions)
                if overlap >= 2:
                    snapped_years.append((ys, ye))
        if snapped_years:
            for i in year_positions:
                arr_list[i] = BIO_O
            for ys, ye in snapped_years:
                arr_list[ys] = BIO_B_YEAR
                for k in range(ys + 1, ye):
                    arr_list[k] = BIO_I_YEAR
            _strip_and_normalize_spans()

    ep_spans: list[tuple[int, int]] = []
    idx = 0
    while idx < L:
        if arr_list[idx] in (BIO_B_EP, BIO_I_EP):
            s = idx
            while idx < L and arr_list[idx] in (BIO_B_EP, BIO_I_EP):
                idx += 1
            ep_spans.append((s, idx))
        else:
            idx += 1
    if ep_spans:
        for i in range(L):
            if arr_list[i] in (BIO_B_EP, BIO_I_EP):
                arr_list[i] = BIO_O
        s0, e0 = ep_spans[0]
        ep_set = set(range(s0, e0))
        max_ep_pos = e0 - 1
        for m in _EP_TOKEN_BYTES_RE.finditer(b_raw[:L]):
            es, ee = m.start(1), m.end(1)
            if ee <= L and max_ep_pos <= ee:
                overlap = sum(1 for k in range(es, ee) if k in ep_set)
                if overlap >= 2:
                    s0, e0 = es, ee
                    break
        arr_list[s0] = BIO_B_EP
        for k in range(s0 + 1, e0):
            arr_list[k] = BIO_I_EP
        _strip_and_normalize_spans()

    idx = 0
    while idx < L:
        if arr_list[idx] in (BIO_B_TITLE, BIO_I_TITLE):
            s = idx
            idx += 1
            while idx < L and arr_list[idx] == BIO_I_TITLE:
                idx += 1
            e = idx
            for k in range(s, e):
                arr_list[k] = BIO_O
            ns, ne = s, e
            while ns < ne and b_raw[ns] in SEP_BYTES:
                ns += 1
            while ne > ns and b_raw[ne - 1] in SEP_BYTES:
                ne -= 1
            if ne > ns:
                while ns > 0 and b_raw[ns - 1] not in SEP_BYTES and arr_list[ns - 1] == BIO_O:
                    ns -= 1
                while ne < L and b_raw[ne] not in SEP_BYTES and arr_list[ne] in (BIO_O, BIO_I_TITLE):
                    ne += 1
                while ns < ne and b_raw[ns] in SEP_BYTES:
                    ns += 1
                while ne > ns and b_raw[ne - 1] in SEP_BYTES:
                    ne -= 1
                if ne > ns:
                    arr_list[ns] = BIO_B_TITLE
                    for k in range(ns + 1, ne):
                        arr_list[k] = BIO_I_TITLE
                    idx = max(idx, ne)
        else:
            idx += 1

    for k in range(L, n):
        arr_list[k] = BIO_O
    return np.asarray(arr_list, dtype=np.int64) if np is not None else arr_list


def decode_bio_logits_viterbi(
    logits_2d: Any,
    raw_bytes: bytes | bytearray = b"",
) -> Any:
    """Decode per-byte 7-class `span_bio` logits via constrained 7x7 Viterbi + delimiter boundary snapping."""
    if np is not None:
        arr = np.asarray(logits_2d, dtype=np.float64)
        if arr.ndim == 3 and arr.shape[0] == 1:
            arr = arr[0]
        if arr.ndim != 2 or arr.shape[1] != 7:
            raise ValueError(f"Expected logits_2d of shape (T, 7), got {arr.shape}")

        n_total = int(arr.shape[0])
        if n_total == 0:
            return np.zeros((0,), dtype=np.int64)

        b_raw = bytes(raw_bytes or b"")
        L = min(n_total, len(b_raw)) if len(b_raw) > 0 else n_total
        if L == 0:
            return np.zeros((n_total,), dtype=np.int64)

        active = np.nan_to_num(arr[:L], nan=0.0, posinf=1e12, neginf=-1e12)
        shifted = active - np.max(active, axis=-1, keepdims=True)
        log_probs = shifted - np.log(np.sum(np.exp(np.maximum(shifted, -700.0)), axis=-1, keepdims=True))

        dp = np.full((L, 7), _NEG_INF, dtype=np.float64)
        backptr = np.zeros((L, 7), dtype=np.int64)
        dp[0] = _BIO_INIT_LOG_P + log_probs[0]

        for t in range(1, L):
            scores = dp[t - 1][:, None] + _BIO_TRANS_LOG_P
            best_prev = np.argmax(scores, axis=0)
            backptr[t] = best_prev
            dp[t] = scores[best_prev, np.arange(7)] + log_probs[t]

        path = np.zeros((L,), dtype=np.int64)
        path[L - 1] = int(np.argmax(dp[L - 1]))
        for t in range(L - 2, -1, -1):
            path[t] = backptr[t + 1, path[t + 1]]

        if len(b_raw) > 0:
            path = snap_bio_span_boundaries(path, b_raw[:L])

        full_out = np.zeros((n_total,), dtype=np.int64)
        full_out[:L] = path
        return full_out

    # Pure-Python fallback when numpy is absent
    rows = list(logits_2d)
    if len(rows) == 1 and hasattr(rows[0], "__len__") and len(rows[0]) > 0 and hasattr(rows[0][0], "__len__"):
        rows = list(rows[0])
    n_total = len(rows)
    if n_total == 0:
        return []
    for row in rows:
        if len(row) != 7:
            raise ValueError(f"Expected logits_2d rows of length 7, got {len(row)}")
    b_raw = bytes(raw_bytes or b"")
    L = min(n_total, len(b_raw)) if len(b_raw) > 0 else n_total
    if L == 0:
        return [0] * n_total
    dp_py = [[_NEG_INF] * 7 for _ in range(L)]
    bp_py = [[0] * 7 for _ in range(L)]
    for t in range(L):
        r = [
            0.0 if math.isnan(float(x)) else (1e12 if float(x) > 1e12 else (-1e12 if float(x) < -1e12 else float(x)))
            for x in rows[t]
        ]
        mx = max(r)
        exps = [math.exp(max(x - mx, -700.0)) for x in r]
        lse = math.log(sum(exps))
        lp = [x - mx - lse for x in r]
        if t == 0:
            for j in range(7):
                dp_py[0][j] = _BIO_INIT_LOG_P_PY[j] + lp[j]
        else:
            for j in range(7):
                best_i = 0
                best_sc = dp_py[t - 1][0] + _BIO_TRANS_LOG_P_PY[0][j]
                for i in range(1, 7):
                    sc = dp_py[t - 1][i] + _BIO_TRANS_LOG_P_PY[i][j]
                    if sc > best_sc:
                        best_sc = sc
                        best_i = i
                bp_py[t][j] = best_i
                dp_py[t][j] = best_sc + lp[j]
    path_py = [0] * L
    path_py[L - 1] = max(range(7), key=lambda j: dp_py[L - 1][j])
    for t in range(L - 2, -1, -1):
        path_py[t] = bp_py[t + 1][path_py[t + 1]]
    if len(b_raw) > 0:
        path_py = list(snap_bio_span_boundaries(path_py, b_raw[:L]))
    return path_py + [0] * (n_total - L)


LEADING_PREFIX_RE = re.compile(
    r"^(?:\s*(?:\[[^\]]{1,48}\]|\([^\)]{1,36}\)|【[^】]{1,36}】|β˜…[^β˜…]{1,36}β˜…)\s*[\.\-_ ]*)+"
)
LEADING_SITE_RE = re.compile(
    r"(?i)^(?:www\.[a-z0-9\-]+\.[a-z]{2,6}[\s\._\-]+|\[?[a-z0-9\-]+\.(?:com|org|net|to|me|cc|pe|mx|ro|lol|tv|ru|in)\]?[\s\._\-\|]+)+"
)

BOUNDARY_RE = re.compile(
    r"(?i)(?:"
    r"[\.\s_\-\(\[\{]+(?:19[2-9]\d|20[0-2]\d)(?:[\.\s_\-\)\]\}]|$)"
    r"|[\.\s_\-\(\[\{]+(?:S\d{1,2}[\.\s_\-]*-[\.\s_\-]*S?\d{1,2}|S\d{1,2}(?:E\d{1,3})?|\d{1,2}x\d{2}|Season[\.\s_\-]*\d+|Complete[\.\s_\-]+Series|Mini[\.\s_\-]*Series|E\d{2,3}\b|Ep\.?\s*\d{1,4}\b|Episode[\.\s_\-]*\d{1,4}\b|Cap\.\d{2,4}\b|Temporada[\.\s_\-]*\d+)"
    r"|[\.\s_\-]+-\s*(?:0\d|[1-9]\d{0,2})(?:v\d)?(?:[\.\s_\-\[\(]|$)"
    r"|[\.\s_\-\(\[\{]+v\d+\.\d+(?:\.\d+)?\b"
    r"|[\.\s_\-\(\[\{]+(?:2160p|1080p|1080i|720p|576p|480p|4k|uhd|bluray|blu-ray|bdrip|brrip|remux|web-dl|webdl|webrip|hdtv|dvdrip|hdrip|dvdr|dvd9|dvd5|x264|x265|h264|h265|h\.264|h\.265|hevc|av1|xvid|divx|proper|repack|rerip|extended|unrated|directors[\.\s_\-]*cut|remastered|multi|dual[\.\s_\-]*audio|dual[\.\s_\-]*lat|truefrench|vff|vfq|vfi|vostfr|sub[\.\s_\-]*ita|ita[\.\s_\-]*eng)\b"
    r"|[\.\s_\-\(\[\{]+(?:rus|russian|castellano|latino|german|french|italian|spanish|hindi|korean|japanese|chinese)\b(?=[\.\s_\-\)\]\}]*(?:2160p|1080p|1080i|720p|576p|480p|4k|uhd|bluray|blu-ray|bdrip|brrip|remux|web-dl|webdl|webrip|web|hdtv|dvdrip|hdrip|dvdr|dvd9|dvd5|x264|x265|h264|h265|h\.264|h\.265|hevc|av1|xvid|divx|aac|ac3|eac3|ddp\d*(?:\.\d)?|dts(?:-?hd)?|truehd|atmos|flac|mp3|m4b|dl|dub|dubbed|sub|subbed|subs|vostfr|multi|dual|audio|proper|repack|rerip|internal|limited|complete)\b)"
    r"|\s*[\[\(\{](?:1080p|720p|2160p|480p|BD|WEB|BDRip|BluRay|HEVC|x264|x265|Dual|Multi|ENG|ITA|RUS|SPA|FRE|GER|Sub|AAC|AC3|DTS|FLAC)[^\)\]\}]*[\]\)\}]"
    r")"
)

YEAR_SPAN_RE = re.compile(r"(?:^|[\.\s_\-\(\[\{])((?:19[2-9]\d|20[0-2]\d))(?=[\.\s_\-\)\]\}]|$)")
EPISODE_SPAN_RE = re.compile(
    r"(?i)(?:^|[\.\s_\-\(\[\{])("
    r"S\d{1,2}[\.\s_\-]*-[\.\s_\-]*S?\d{1,2}|S\d{1,2}(?:E\d{1,3}(?:[\-E]\d{1,3})?)?|\d{1,2}x\d{2}|"
    r"Season[\.\s_\-]*\d+(?:[\.\s_\-]*-[\.\s_\-]*\d+)?|Episode[\.\s_\-]*\d{1,4}|Ep\.?\s*\d{1,4}|Cap\.\d{2,4}|Temporada[\.\s_\-]*\d+"
    r")(?=[\.\s_\-\)\]\}]|$)"
)
TRAILING_EXT_RE = re.compile(
    r"(?i)\.(?:mkv|mp4|avi|mov|wmv|m4v|webm|ts|m2ts|mpg|mpeg|iso|rar|zip|7z|tar|gz|epub|pdf|mobi|cbz|cbr|mp3|flac|m4b)$"
)
TRAILING_JUNK_RE = re.compile(
    r"(?i)[\.\s_\-]+(?:by[\.\s_\-]+[a-z0-9_]+|uploaded[\.\s_\-]+by.*|www\.[a-z0-9\.\-]+|\[[^\]]*\]|\([^\)]*\))$"
)
TECH_TOKEN_SET = frozenset({
    "1080p", "1080i", "720p", "2160p", "480p", "576p", "4k", "uhd", "sdr", "hdr", "hdr10", "dv",
    "web", "webdl", "webrip", "bluray", "bdrip", "brrip", "remux", "hdtv", "dvdrip", "hdrip", "dvdr",
    "x264", "x265", "h264", "h265", "hevc", "avc", "xvid", "divx", "av1", "10bit", "8bit",
    "aac", "ac3", "eac3", "ddp", "ddp5", "dts", "dtshd", "truehd", "atmos", "flac", "mp3", "opus",
    "mkv", "mp4", "avi", "proper", "repack", "rerip", "internal", "limited", "multi", "dual",
})


def key_norm(s: str) -> str:
    decomposed = unicodedata.normalize("NFKD", s or "")
    stripped = "".join(ch for ch in decomposed if not unicodedata.combining(ch))
    folded = unicodedata.normalize("NFKC", stripped).casefold()
    return re.sub(r"[\W_]+", " ", folded, flags=re.UNICODE).strip()


def is_strict_clean_title(extracted: str, raw_name: str) -> bool:
    """Strict non-gameable title validity check:
    - Must have >= 2 normalized characters and >= 1 non-technical token.
    - Every normalized token must be anchored in `raw_name`.
    - Must NOT contain bare resolution/codec/source tokens (`1080p`, `WEB DL`, `x264`, `mkv`).
    - When `raw_name` contains technical/release metadata, `extracted` must strip it (`len(kn_ext) < len(kn_src)`).
    """
    if not extracted or not isinstance(extracted, str):
        return False
    kn_ext = key_norm(extracted)
    kn_src = key_norm(raw_name)
    if len(kn_ext) < 2 or not kn_src:
        return False
    ext_toks = kn_ext.split()
    src_toks = set(kn_src.split())
    if not ext_toks or any(t not in src_toks for t in ext_toks):
        return False
    if any(t in TECH_TOKEN_SET for t in ext_toks):
        return False
    src_has_tech_or_ext = bool(src_toks & TECH_TOKEN_SET) or bool(YEAR_SPAN_RE.search(raw_name)) or bool(EPISODE_SPAN_RE.search(raw_name))
    if src_has_tech_or_ext and len(kn_ext) >= len(kn_src):
        return False
    return True


def title_token_f1(pred_title: str, ref_title: str) -> float:
    """Compute exact normalized token-level F1 between `pred_title` and `ref_title`."""
    p_toks = key_norm(pred_title).split()
    r_toks = key_norm(ref_title).split()
    if not p_toks or not r_toks:
        return 0.0
    if p_toks == r_toks:
        return 1.0
    p_set, r_set = set(p_toks), set(r_toks)
    inter = len(p_set & r_set)
    if inter == 0:
        return 0.0
    prec = inter / len(p_set)
    rec = inter / len(r_set)
    return 2.0 * prec * rec / (prec + rec)


def _utf8_safe_window(raw_name: str, max_bytes: int = 256) -> tuple[str, bytes, bool]:
    """Return `(window_str, window_bytes, was_truncated)` decoded strictly from a UTF-8-safe `max_bytes` prefix."""
    if not raw_name or max_bytes <= 0:
        return "", b"", False
    full_bytes = raw_name.encode("utf-8", errors="replace")
    if len(full_bytes) <= max_bytes:
        win_str = full_bytes.decode("utf-8", errors="ignore")
        return win_str, win_str.encode("utf-8"), False
    win_str = full_bytes[:max_bytes].decode("utf-8", errors="ignore")
    return win_str, win_str.encode("utf-8"), True


def _char_to_byte_span(s: str, c_start: int, c_end: int, max_bytes: int = 256) -> tuple[int, int]:
    b_start = len(s[:max(0, c_start)].encode("utf-8", errors="replace"))
    b_end = len(s[:max(0, c_end)].encode("utf-8", errors="replace"))
    return min(b_start, max_bytes), min(b_end, max_bytes)


def extract_byte_spans_v3(raw_name: str, max_bytes: int = 256) -> dict[str, Any]:
    """Extract byte-anchored `(title, year, episode_spec)` spans from a UTF-8-safe `max_bytes` window of `raw_name`."""
    nm, _nm_bytes, was_truncated = _utf8_safe_window(raw_name or "", max_bytes=max_bytes)
    work = TRAILING_EXT_RE.sub("", nm) if not was_truncated else nm

    c_start = 0
    m_site = LEADING_SITE_RE.match(work)
    if m_site and (was_truncated or m_site.end() < len(work) - 3):
        c_start = m_site.end()
    m_pref = LEADING_PREFIX_RE.match(work[c_start:])
    if m_pref and (was_truncated or (c_start + m_pref.end()) < len(work) - 2):
        c_start += m_pref.end()

    if was_truncated:
        m_unclosed = re.match(r"^\s*(?:\[[^\]]*|\([^\)]*|【[^】]*|β˜…[^β˜…]*)$", work[c_start:])
        if m_unclosed:
            c_start = len(work)

    while c_start < len(work) and work[c_start] in " ._-|:/":
        c_start += 1

    tail = work[c_start:]
    c_end = len(work)

    for m in BOUNDARY_RE.finditer(tail):
        pos = m.start()
        prefix_candidate = tail[:pos].strip(" ._-([{|:")
        if len(key_norm(prefix_candidate)) >= 2:
            c_end = c_start + pos
            break

    while c_end > c_start and work[c_end - 1] in " ._-([{|:/":
        c_end -= 1
    m_junk = TRAILING_JUNK_RE.search(work[c_start:c_end])
    if m_junk:
        c_end = c_start + m_junk.start()
        while c_end > c_start and work[c_end - 1] in " ._-([{|:/":
            c_end -= 1
    base_c_start = c_start
    token_spans = list(re.finditer(r"[^\._\s]+", work[base_c_start:c_end]))
    while len(token_spans) > 1 and key_norm(token_spans[-1].group(0)) in TECH_TOKEN_SET:
        token_spans.pop()
        c_end = base_c_start + token_spans[-1].end()
        while c_end > base_c_start and work[c_end - 1] in " ._-([{|:/":
            c_end -= 1

    valid_tok_matches = [m for m in token_spans if m.group(0).strip(" ._-([{|:") != ""]
    if valid_tok_matches:
        c_start = base_c_start + valid_tok_matches[0].start()
        c_end = base_c_start + valid_tok_matches[-1].end()
        while c_start < c_end and work[c_start] in " ._-([{|:/":
            c_start += 1
        while c_end > c_start and work[c_end - 1] in " ._-([{|:/":
            c_end -= 1
        words = [
            m.group(0).strip(" ._-([{|:")
            for m in re.finditer(r"[^\._\s]+", work[c_start:c_end])
            if m.group(0).strip(" ._-([{|:") != ""
        ]
        clean_title = " ".join(words).strip()
    else:
        clean_title = ""
        c_start, c_end = 0, 0

    if len(key_norm(clean_title)) < 2:
        if base_c_start < len(work):
            fb_matches = [
                m
                for m in re.finditer(r"[^\._\s]+", work[base_c_start:])
                if m.group(0).strip(" ._-([{|:") != "" and key_norm(m.group(0)) not in TECH_TOKEN_SET
            ][:6]
        else:
            fb_matches = []
        if fb_matches:
            c_start = base_c_start + fb_matches[0].start()
            c_end = base_c_start + fb_matches[-1].end()
            while c_start < c_end and work[c_start] in " ._-([{|:/":
                c_start += 1
            while c_end > c_start and work[c_end - 1] in " ._-([{|:/":
                c_end -= 1
            clean_title = " ".join(
                m.group(0).strip(" ._-([{|:")
                for m in re.finditer(r"[^\._\s]+", work[c_start:c_end])
                if m.group(0).strip(" ._-([{|:") != "" and key_norm(m.group(0)) not in TECH_TOKEN_SET
            ).strip()
        if len(key_norm(clean_title)) < 2:
            clean_title = ""
            c_start, c_end = 0, 0

    t_bstart, t_bend = _char_to_byte_span(nm, c_start, c_end, max_bytes=max_bytes)
    if not clean_title or t_bstart >= t_bend:
        clean_title = ""
        t_bstart, t_bend = 0, 0

    year_val = None
    year_bspan = None
    ym = YEAR_SPAN_RE.search(nm, pos=max(0, c_end - 1)) or YEAR_SPAN_RE.search(nm)
    if ym:
        yb_s, yb_e = _char_to_byte_span(nm, ym.start(1), ym.end(1), max_bytes=max_bytes)
        if yb_e - yb_s == 4:
            year_val = int(ym.group(1))
            year_bspan = (yb_s, yb_e)

    ep_val = None
    ep_bspan = None
    em = EPISODE_SPAN_RE.search(nm, pos=max(0, c_end - 1)) or EPISODE_SPAN_RE.search(nm)
    if em:
        eb_s, eb_e = _char_to_byte_span(nm, em.start(1), em.end(1), max_bytes=max_bytes)
        if eb_s < eb_e:
            ep_val = em.group(1).strip()
            ep_bspan = (eb_s, eb_e)

    anchored = bool(clean_title and t_bstart < t_bend and is_strict_clean_title(clean_title, nm))
    return {
        "title": clean_title,
        "title_byte_span": (t_bstart, t_bend),
        "year": year_val,
        "year_byte_span": year_bspan,
        "episode_spec": ep_val,
        "episode_byte_span": ep_bspan,
        "is_anchored": anchored,
        "extractor_source": "structural_byte_span",
    }


def _extract_contiguous_bio_runs(tags: Sequence[int], b_tag: int, i_tag: int) -> list[tuple[int, int]]:
    """Decode contiguous BIO entity spans `[start, end)`, honoring `b_tag` as starting a new entity."""
    runs: list[tuple[int, int]] = []
    cur_s: int | None = None
    cur_e: int = 0
    for idx, t in enumerate(tags):
        if t == b_tag:
            if cur_s is not None:
                runs.append((cur_s, cur_e))
            cur_s = idx
            cur_e = idx + 1
        elif t == i_tag:
            if cur_s is not None and idx == cur_e:
                cur_e = idx + 1
            else:
                if cur_s is not None:
                    runs.append((cur_s, cur_e))
                cur_s = idx
                cur_e = idx + 1
        else:
            if cur_s is not None:
                runs.append((cur_s, cur_e))
                cur_s = None
    if cur_s is not None:
        runs.append((cur_s, cur_e))
    return runs


def decode_bio_tags_raw_neural(raw_name: str, bio_tags: Sequence[int] | Any) -> dict[str, Any]:
    """Pure neural BIO span decoder:
    Decodes `(title, year, episode_spec)` strictly from the 9th neural head `bio_tags`
    (`0=O, 1=B-TITLE, 2=I-TITLE, 3=B-YEAR, 4=I-YEAR, 5=B-EP, 6=I-EP`) with zero call to `extract_byte_spans_v3`.
    """
    nm, raw_bytes, _ = _utf8_safe_window(raw_name or "", max_bytes=256)
    L = min(len(raw_bytes), len(bio_tags))
    tags = [int(bio_tags[i]) for i in range(L)]

    title_idx = [i for i, t in enumerate(tags) if t in (1, 2)]
    if title_idx:
        runs: list[tuple[int, int]] = []
        run_s = title_idx[0]
        prev = run_s
        for ii in title_idx[1:]:
            if ii <= prev + 2:
                prev = ii
            else:
                runs.append((run_s, prev + 1))
                run_s = ii
                prev = ii
        runs.append((run_s, prev + 1))
        tb, te = max(runs, key=lambda r: r[1] - r[0])
        cand_raw = raw_bytes[tb:te].decode("utf-8", errors="replace")
        words = re.sub(r"[\._]+", " ", cand_raw).strip(" ._-[({/|:").split()
        clean_title = " ".join(words).strip()
    else:
        tb, te = 0, 0
        clean_title = ""

    year_runs = _extract_contiguous_bio_runs(tags, BIO_B_YEAR, BIO_I_YEAR)
    year_candidates: list[tuple[int, tuple[int, int]]] = []
    for ys, ye in year_runs:
        if ye - ys < 4:
            continue
        for m_y in re.finditer(rb"(?<!\d)(19[2-9]\d|20[0-2]\d)(?!\d)", raw_bytes[ys:ye]):
            exact_yb, exact_ye = ys + m_y.start(1), ys + m_y.end(1)
            if exact_ye - exact_yb == 4:
                year_candidates.append((int(m_y.group(1).decode("ascii")), (exact_yb, exact_ye)))

    year_val = None
    year_bspan = None
    if year_candidates:
        post_title = [c for c in year_candidates if c[1][0] >= te]
        selected_year = post_title[0] if post_title else year_candidates[0]
        year_val, year_bspan = selected_year

    ep_runs = _extract_contiguous_bio_runs(tags, BIO_B_EP, BIO_I_EP)
    ep_val = None
    ep_bspan = None
    for es, ee in ep_runs:
        if ee - es < 2:
            continue
        while es < ee and raw_bytes[es : es + 1] in b" ._-[({/|:)]}":
            es += 1
        while ee > es and raw_bytes[ee - 1 : ee] in b" ._-[({/|:)]}":
            ee -= 1
        if ee - es >= 2:
            cand_ep = raw_bytes[es:ee].decode("utf-8", errors="replace").strip()
            if cand_ep:
                ep_val = cand_ep
                ep_bspan = (es, ee)
                if es >= te:
                    break

    return {
        "title": clean_title,
        "title_byte_span": (tb, te),
        "year": year_val,
        "year_byte_span": year_bspan,
        "episode_spec": ep_val,
        "episode_byte_span": ep_bspan,
        "is_anchored": is_strict_clean_title(clean_title, nm),
        "extractor_source": "raw_neural_span_bio",
    }


def decode_bio_tags_to_spans(raw_name: str, bio_tags: Sequence[int] | Any) -> dict[str, Any]:
    """Hybrid Neural + Structural Span Decoder."""
    neural_res = decode_bio_tags_raw_neural(raw_name, bio_tags)
    struct_res = extract_byte_spans_v3(raw_name)
    if neural_res["is_anchored"]:
        nb, ne = neural_res["title_byte_span"]
        sb, se = struct_res["title_byte_span"]
        inter = max(0, min(ne, se) - max(nb, sb))
        union = max(1, max(ne, se) - min(nb, sb))
        if inter / union >= 0.65:
            return neural_res
    return struct_res