@torrent-tv/proxy 2.55.5 → 2.55.6

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,7 @@
1
+ ## 2.55.6
2
+
3
+ - **Chore**: Every step of the subtitle push chain now logs on success, not only on failure. Field report 2026-08-22, playing `Minions.and.Monsters.1080p.mkv`: a track was switched on over a minute after the seed fetch found nothing (`bytes=7`, an empty `WEBVTT` — expected, the torrent had barely started), and no cues appeared. The proxy log carried no evidence either way — `warmActiveFiles` posted `Event.SUBTITLE_CUES_READY` silently, `publishSubtitleCues` sent (or found no subscriber for) a push silently, and `subscribeSubtitles` registered a channel silently. Confirmed separately by reading WebTorrent's own source that `verified` fires on every live piece completion (`_markVerified` inside `store.put`'s callback in `torrent.js`, not only at startup), so the event source itself is real; what could not be told apart without these lines is subscription, discovery, and delivery. Logs now name each: `subtitle push: channel subscribed to …`, `… cue(s) found, posting to main thread`, `… sent N cue(s) … to M/T channel(s)` (or `found no subscribed channel`).
4
+
1
5
  ## 2.55.5
2
6
 
3
7
  - **New**: Subtitle cues are now PUSHED to the browser the moment they are read, over the WebRTC data channel — not fetched by the browser on a timer. Every declared track was already being warmed off the piece-`verified` event (2.55.4); what changed is that the result now travels to the browser unprompted instead of sitting on the proxy until the next poll asked for it. `data-channel-handler.js` remembers which channel last asked about a file's subtitles (piggy-backing on the browser's own first `/api/subtitles?trackIndex=` request — no separate subscribe message) and sends new cues there directly (`{ type: "subtitle-cues", fileIndex, trackIndex, cues, language }`), for every track the container declares, not only the one on screen. Rides the existing `proxy-control` data channel — the same one the request itself used, which is never the one carrying segment bytes, so a push cannot queue behind video. `finalizeCues` (end-time synthesis + ASS-dialogue stripping) is factored out of the HTTP route into `services/torrent-worker/subtitle-cues.js` so a pushed cue and a pulled one are built the same way. A browser's one-off seed fetch per track (for whatever is already read at the moment a file opens) and the external-subtitle-FILE path (`.srt`/`.ass` beside the video — a single whole-file read, no incremental delivery to begin with) are unchanged.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@torrent-tv/proxy",
3
- "version": "2.55.5",
3
+ "version": "2.55.6",
4
4
  "description": "Torrent proxy client that exposes webseed-like HTTP stream endpoint.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "publishConfig": {
@@ -324,7 +324,11 @@ export function createDataChannelHandler({ proxyPort, onLog, getTransportSnapsho
324
324
  set = new Set();
325
325
  subtitleSubscribers.set(key, set);
326
326
  }
327
+ const isNew = !set.has(channel);
327
328
  set.add(channel);
329
+ if (isNew) {
330
+ log(`[dc] subtitle push: channel subscribed to ${key} (${set.size} channel(s) now)`);
331
+ }
328
332
  }
329
333
 
330
334
  /** @param {DataChannel} channel */
@@ -346,18 +350,29 @@ export function createDataChannelHandler({ proxyPort, onLog, getTransportSnapsho
346
350
  function publishSubtitleCues({ sourceKey, fileIndex, trackIndex, cues, language }) {
347
351
  const set = subtitleSubscribers.get(`${sourceKey}:${fileIndex}`);
348
352
  if (!set || set.size === 0) {
353
+ log(
354
+ `[dc] subtitle push: ${cues.length} cue(s) for ${sourceKey.slice(0, 8)}:${fileIndex} track ${trackIndex} ` +
355
+ "found no subscribed channel"
356
+ );
349
357
  return;
350
358
  }
351
359
  const message = { type: "subtitle-cues", fileIndex, trackIndex, cues, language };
360
+ const total = set.size;
361
+ let sent = 0;
352
362
  for (const channel of set) {
353
363
  try {
354
364
  channel.sendMessage(JSON.stringify(message));
365
+ sent += 1;
355
366
  } catch {
356
367
  // Closed between the subscription and this send; onClosed will not
357
368
  // fire for a channel that is already gone, so drop it here too.
358
369
  set.delete(channel);
359
370
  }
360
371
  }
372
+ log(
373
+ `[dc] subtitle push: sent ${cues.length} cue(s) for ${sourceKey.slice(0, 8)}:${fileIndex} track ${trackIndex} ` +
374
+ `to ${sent}/${total} channel(s)`
375
+ );
361
376
  }
362
377
 
363
378
  /** Request id → its ASCII bytes; see {@link requestIdBytes}. */
@@ -525,6 +525,10 @@ function warmActiveFiles(sourceKey, torrent) {
525
525
  warmSubtitleCues(torrent, fileIndex, sourceKey)
526
526
  .then((fresh) => {
527
527
  for (const entry of fresh) {
528
+ log(
529
+ `subtitle push ${sourceKey.slice(0, 8)}:${fileIndex} track ${entry.trackIndex}: ` +
530
+ `${entry.cues.length} new cue(s) found, posting to main thread`
531
+ );
528
532
  parentPort.postMessage({
529
533
  type: Event.SUBTITLE_CUES_READY,
530
534
  sourceKey,