@torrent-tv/proxy 2.68.0 → 2.69.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,24 @@
1
+ ## 2.69.1
2
+
3
+ - **Fix**: The change trigger on the torrent worker's memory line watched the one figure that does not move. A thread's watched quantity was `heapTotal`, and through the session of 2026-09-02 that stood at 31-173 MB while the same isolate's `arrayBuffers` swung between 130 and 950 MB — so nothing ever earned a line and every reading of the quantity that grew came out on the quiet minute. Each of `heapTotal`, `external` and `arrayBuffers` is now compared against its own last written value and any one of them moving writes the line. Nothing is summed: `arrayBuffers` is documented as part of `external` and reads larger than it here, and this code has no business resolving that.
4
+ - **Fix**: The process line was read once a minute, which cannot see what kills this process. Both out-of-memory kills of 2026-09-02 fell inside a single gap of that cadence — the last line before the first said `rss=602MB` and the kernel recorded `anon-rss:1722836kB` 34 seconds later; before the second it said `rss=1171MB` and the kernel recorded `anon-rss:1905024kB` nine seconds later. The figure is read every second now and written when `rss` has moved by 25 MB or when a quiet minute is up, so a rise of a gigabyte is a curve instead of one number and then a death.
5
+ - **Chore**: A quiet second costs one call to `process.memoryUsage()`. Every /proc read — `meminfo`, `smaps_rollup`, `smaps`, the free-space call — moved behind the decision to write, where only `smaps` already was. The `high rss … watch for OOM` warning moved with them, or at one reading a second it would have printed a line a second for as long as the process stayed large.
6
+ - **Chore**: The piece-buffer counters are on the memory line itself rather than on a timer of their own. Both sides read them at the same instant now — the worker's own buffers beside its `arrayBuffers`, and the ones handed to the main thread beside the process's `rss`. On separate timers they were up to a minute apart: 950 MB of `arrayBuffers` at 14:10:40 could only be checked against readings half a minute either side saying 14 and 130 buffers were alive, and the arithmetic did not close. `watchedFigures` is exported and pinned, with two checks in `test/memory-budget.test.js`.
7
+
8
+ ## 2.69.0
9
+
10
+ - **Fix**: The language detector no longer states an answer the text cannot support. Measured 2026-09-02 over Wikipedia extracts in seventeen languages, 120 random windows per language per length: franc's answer for Russian walks between Bulgarian, Serbian and Russian until about 650 characters, while Korean is settled by 40 and English by 130 — the figure is the language's own, because Russian competes with three neighbours for the same trigrams and Korean competes with nothing. The detector now asks franc for a candidate, refuses when the text is shorter than THAT candidate's measured figure, and refuses again when the answer does not survive losing either half of the text. The margin to the runner-up was tried first and rejected on measurement: it is 0.026 where the answer is wrong and 0.015 where it is right, so it separates nothing. `research/franc-boundary-2026-09-02.md`.
11
+ - **New**: The reading is re-taken as the film downloads. `warmSubtitleCues` re-runs detection over every cue held so far on each push and sends it as `detectedLanguage`; the browser moves the track's label onto it. This is what makes the refusal above cost the viewer nothing — a track opens as Unknown and becomes Russian a minute later, instead of opening as Bulgarian and staying wrong for the session. About 6 ms per push, measured; franc costs ~2 ms whatever the size.
12
+ - **Chore**: The stability test is worth its own line because it needs no table: across 38 400 trials franc alone was wrong 2197 times, and requiring the two halves to agree with the whole left 255 of those standing while keeping 81.8 % of the right answers.
13
+ - **Chore**: `test/worker-channel.test.js` waits for the chunk it is about instead of sleeping 50 ms and hoping. It has been on the flaky list since roadmap item 53, and this change is what pushed it over: the torrent worker gained one more module to load, and the chosen interval stopped being enough. A test that samples the clock does not test.
14
+
15
+ ## 2.68.1
16
+
17
+ - **Fix**: A Russian subtitle file was reported to the viewer as English, and the proxy was the one saying so. Field 2026-09-01: `Sub/[Stan WarHammer & Nesitach]/[HorribleSubs] Drifters - 03 [1080p].ass` came back with `X-Subtitle-Language: en` and a body whose first cue is `Ты видишь их?`. The cause is what the detector was FED, not the detector. An ASS file is markup by half — measured on that file, 5040 Latin characters of Aegisub headers, style and font names, `Format:`/`Dialogue:` field prefixes and `{\…}` override groups against 5983 Cyrillic characters of dialogue — and `franc` scores letter trigrams over the whole string it is handed: `franc(the file) = eng`, `franc(the dialogue) = rus`. The markup-free WebVTT was already built two lines above and the detection was given the raw file anyway.
18
+ - **Fix**: The same mistake at the two other places a language is read, both found by looking rather than reported. An embedded ASS track was detected on its RAW cue text — a cluster-held cue is the dialogue row without its `Dialogue:` header, so it carries nine comma-separated fields and the override groups, which are Latin on a Russian track; it now reads the cues through `finalizeCues`, the same conversion that produces what is served. And the ffmpeg extraction path detected on the first 4096 BYTES of its WebVTT output, where a byte cut lands mid-character on any non-Latin track and most of those bytes are timestamps; it now reads the whole document's cue text.
19
+ - **Chore**: `language-detect.js` gains `cueTextOfVtt` — the words of a WebVTT document, with the header, `NOTE`/`STYLE`/`REGION` blocks, cue identifiers, timing lines, inline tags and character references removed — and `detectLanguageFromVtt` over it. One rule does most of it: a block with no timing line is not a cue. Six checks in `test/subtitle-language.test.js`.
20
+ - **Chore**: The embedded path now detects on every cue held so far rather than on the `fresh` subset being sent, because a re-subscription after a reconnect asks for only what that page missed and a handful of lines is not a sample of a language. This matters more than it sounds: measured 2026-09-01, `franc`'s answer among the Cyrillic languages is unstable on a small sample — one Russian text grown line by line answered `bul` at 129 characters, `srp` at 158 and 241, `bul` again at 292, then `rus` at every length from 337 to 881. Every change here gives the detector more text rather than less; the instability itself is not fixed and is recorded as its own roadmap item.
21
+
1
22
  ## 2.68.0
2
23
 
3
24
  - **Fix**: The background fetch of a soundtrack now stands aside after a stall, not only during one. Pausing only while a reader is blocked is not enough on a swarm with no surplus: between stalls the fetch still takes bandwidth the picture needs, and the stalls themselves are the proof there was none to spare. Field 2026-08-31 — the swarm delivered 200-600 KB/s against the 399 KB/s the film eats, one piece waited 101 s after a seek, and the picture stood still 145.6 s before the player gave up. A chunk is fetched only when the stall count has not moved since the previous one, re-baselined after each quiet pause so it can resume; on a starving swarm it stops altogether, which is the right answer.