@torrent-tv/proxy 2.9.52 → 2.9.53
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 +4 -0
- package/package.json +1 -1
- package/services/hls-session-manager.js +38 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
## 2.9.53
|
|
2
|
+
|
|
3
|
+
- **Fix**: On the video RE-ENCODE path, `processedSeconds` silently switched reference frame partway through every encode run — absolute (matching `startPositionSeconds`) for the placeholder set at restart, then RELATIVE-to-the-run (counting from ~0) the moment ffmpeg's own `-progress out_time`/`out_time_ms` started overwriting it — because `-output_ts_offset` (used to relabel the MUXED output's timestamps onto the absolute grid) does NOT affect what `-progress` reports; verified empirically (a 5s clip encoded with `-output_ts_offset 100` still reports `out_time` counting 0→5, not 100→105). Every consumer of `session.progress.processedSeconds` assumes it is absolute: `computeProgressMetrics` (percent/remaining), `#applyBudgetDownshift`'s mid-run restart point, and — the field-diagnosed symptom — `#ensureEncodingFor`'s look-ahead window, which anchors on `Math.max(head, segmentIndexForTime(processed))`; with `processed` wrongly near-zero this floor pins the window's advancing edge at the run's OWN start segment for its entire lifetime instead of tracking real progress, so any segment request more than `MAX_LOOKAHEAD_SEGMENTS` (8, ≈32s) past the SEEK TARGET reads as "far" and triggers ANOTHER restart — even while the encoder is happily producing well past that point. Field example (verified with a pure-math replay of the exact logged values): seek to 1824s, window pinned at segments 456–464 for the whole run regardless of real progress reaching segment 465+ within seconds, at 6x realtime. This is the mechanism behind "buffering pill stuck at 0% until playback finally starts" and very likely a contributor to the broader "seek gets stuck" class of reports this cycle. Fixed by rebasing `out_time`/`out_time_ms` onto the absolute timeline (`+ session.progress.startPositionSeconds`) for the re-encode branch only — the copy branch already reports absolute time via `-copyts`, unaffected. Verified: a standalone replay of the field's `processed`/`startPos` sequence through the actual `#segmentIndexForTime` algorithm shows the window frozen at the run's start before the fix, correctly advancing with real progress after.
|
|
4
|
+
|
|
1
5
|
## 2.9.52
|
|
2
6
|
|
|
3
7
|
- **Chore**: `npm audit` fixes. `@fastify/static` 9.1.3 → 10.1.2 (fixes GHSA-83w8-p2f5-377r route-guard path-traversal bypass and GHSA-8pvw-jcv7-9cmj non-canonical-path authorization bypass — no API change to our usage, verified with a live smoke test: healthz, tunnel connect, and static registration all still work). `brace-expansion`/`fast-uri`/`find-my-way` bumped via `npm audit fix` (transitive, no direct dependency change). Residual: `ip` (via `webtorrent@2.8.5` → `torrent-discovery` → `bittorrent-tracker`) stays flagged high (GHSA-2p57-rm9w-gvfp / CVE-2024-29415, SSRF via `isPublic()` misclassification) — investigated and left as an accepted risk, not an oversight: the advisory has no upstream fix (`first_patched_version: null`, every published version of `ip` is flagged) and `npm audit fix --force`'s only offered fix is downgrading `webtorrent` to 0.7.3, which would reintroduce the exact download-freeze regressions 2.9.44 rolled back from 3.x to avoid. The only actual call site in our dependency tree (`bittorrent-tracker/lib/server/parse-udp.js`) uses `ip.toString()` for UDP-integer→string formatting in the tracker-SERVER's request parser — code we never execute (WebTorrent only uses `bittorrent-tracker` as a tracker CLIENT) — and the vulnerable function itself, `isPublic()`, is not called anywhere in the chain. Revisit if/when a maintained `ip` replacement lands upstream in `bittorrent-tracker`.
|
package/package.json
CHANGED
|
@@ -1720,6 +1720,42 @@ export class HlsSessionManager {
|
|
|
1720
1720
|
this.#wireEncodeProcess(session, ffmpeg);
|
|
1721
1721
|
}
|
|
1722
1722
|
|
|
1723
|
+
/**
|
|
1724
|
+
* Rebase ffmpeg's `-progress` `out_time`/`out_time_ms` onto the SOURCE
|
|
1725
|
+
* (absolute) timeline, so `session.progress.processedSeconds` is always
|
|
1726
|
+
* comparable to `session.progress.startPositionSeconds` — which
|
|
1727
|
+
* `computeProgressMetrics` and the client's own cushion-percent/ETA math
|
|
1728
|
+
* both assume.
|
|
1729
|
+
*
|
|
1730
|
+
* Branch B (video copy, `-copyts`) already reports `out_time` on the
|
|
1731
|
+
* source's absolute timeline — no rebase needed. Branch A (video re-encode)
|
|
1732
|
+
* does NOT: `-output_ts_offset` (used there to relabel the MUXED output's
|
|
1733
|
+
* timestamps onto the absolute grid) does not affect what `-progress`
|
|
1734
|
+
* reports — verified empirically (a 5s clip encoded with
|
|
1735
|
+
* `-output_ts_offset 100` still reports `out_time` counting 0→5, not
|
|
1736
|
+
* 100→105). Left unrebased, `processedSeconds` jumps from the post-restart
|
|
1737
|
+
* placeholder (`session.progress.startPositionSeconds`, absolute) down to a
|
|
1738
|
+
* near-zero RELATIVE value the moment real ffmpeg progress starts flowing —
|
|
1739
|
+
* `processedSeconds - startPositionSeconds` then goes deeply negative,
|
|
1740
|
+
* clamps to 0, and the client's cushion percent/ETA reads as permanently
|
|
1741
|
+
* stuck at 0% for the whole run even while the encode is actively
|
|
1742
|
+
* producing (field-diagnosed 2026-08-01: a re-encode session logged
|
|
1743
|
+
* `processed=39.5 startPos=1824` at a healthy 6x realtime speed).
|
|
1744
|
+
*
|
|
1745
|
+
* @param {HlsSession} session
|
|
1746
|
+
* @param {number} rawSeconds - As parsed from `out_time`/`out_time_ms`.
|
|
1747
|
+
* @returns {number}
|
|
1748
|
+
*/
|
|
1749
|
+
#toAbsoluteProcessedSeconds(session, rawSeconds) {
|
|
1750
|
+
if (!session.transcodeVideo) {
|
|
1751
|
+
return rawSeconds;
|
|
1752
|
+
}
|
|
1753
|
+
const offset = Number.isFinite(session.progress?.startPositionSeconds)
|
|
1754
|
+
? session.progress.startPositionSeconds
|
|
1755
|
+
: 0;
|
|
1756
|
+
return rawSeconds + offset;
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1723
1759
|
/**
|
|
1724
1760
|
* Wire stdout (progress), stderr (errors) and exit handlers for an ffmpeg
|
|
1725
1761
|
* encode process. Handlers no-op when the process has been superseded by a
|
|
@@ -1747,12 +1783,12 @@ export class HlsSessionManager {
|
|
|
1747
1783
|
if (key === "out_time_ms") {
|
|
1748
1784
|
const numeric = Number(value);
|
|
1749
1785
|
if (Number.isFinite(numeric) && numeric >= 0) {
|
|
1750
|
-
session.progress.processedSeconds = numeric / MICROSECONDS_PER_SECOND;
|
|
1786
|
+
session.progress.processedSeconds = this.#toAbsoluteProcessedSeconds(session, numeric / MICROSECONDS_PER_SECOND);
|
|
1751
1787
|
}
|
|
1752
1788
|
} else if (key === "out_time") {
|
|
1753
1789
|
const parsed = parseFfmpegTimestamp(value);
|
|
1754
1790
|
if (parsed != null) {
|
|
1755
|
-
session.progress.processedSeconds = parsed;
|
|
1791
|
+
session.progress.processedSeconds = this.#toAbsoluteProcessedSeconds(session, parsed);
|
|
1756
1792
|
}
|
|
1757
1793
|
} else if (key === "speed") {
|
|
1758
1794
|
session.progress.speed = value;
|