@torrent-tv/proxy 2.76.0 → 2.76.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 +5 -0
- package/package.json +1 -1
- package/services/hls-session-manager.js +31 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
## 2.76.1
|
|
2
|
+
|
|
3
|
+
- **New**: How long it takes to read a file's keyframe table is recorded, once per file, with the container that answered and how many times it found. That read decides which branch a picture takes — with the table it is copied, without it the whole picture is re-encoded — and nothing measured it. The one figure printed until now, `keyframes=` on the session-create line, is what the SESSION waited for, which is the remainder of a read the playback plan had already started, and reads zero whenever the plan finished first.
|
|
4
|
+
- **Chore**: The comment promising this read a short timeout and "never more than ~6 s to session start" is gone. Nothing in that path has ever had a timeout: the fall back to re-encoding fires when the table is ABSENT, which is a statement about the file, not about how long a read ran. The file comes off a torrent, so the bytes the table lives in may still be arriving and the read waits for them, without a bound.
|
|
5
|
+
|
|
1
6
|
## 2.76.0
|
|
2
7
|
|
|
3
8
|
- **Fix**: A viewer who changed quality twice lost the soundtrack they had chosen. The three link fields between sessions were replaced by a relation indexed both ways — an output holds its viewers, a viewer holds its outputs — and leaving an output was written as "delete the viewer from the one they came off". The one they came off can be the picture itself, which happens whenever somebody goes down a step, back to the picture's own height and down again: the picture then forgot them entirely, and with them their language, their position and their link. What followed was not a lost setting but silence — the soundtrack they were listening to was the one nobody was listening to any more, so its encoder was stopped as unwanted. A viewer is never dropped from the picture: it is the only id the browser holds, and everything a viewer has chosen is recorded there. Reproduced through the public path before the fix and pinned by a check that fails without it.
|
package/package.json
CHANGED
|
@@ -2281,10 +2281,17 @@ export class HlsSessionManager {
|
|
|
2281
2281
|
} else if (hasDuration && !transcodeVideo && !audioOnly) {
|
|
2282
2282
|
// Video-COPY path: keyframeTimes are REQUIRED to build correct segment
|
|
2283
2283
|
// boundaries (the playlist itself), so this MUST block session creation —
|
|
2284
|
-
// an incorrect playlist is worse than a slower start.
|
|
2285
|
-
//
|
|
2286
|
-
//
|
|
2287
|
-
// more than ~6 s to session start
|
|
2284
|
+
// an incorrect playlist is worse than a slower start.
|
|
2285
|
+
//
|
|
2286
|
+
// There is NO bound on this wait. A comment here used to promise a short
|
|
2287
|
+
// timeout and "never more than ~6 s to session start"; nothing in this
|
|
2288
|
+
// path has ever had a timeout, and the fallback below fires when the
|
|
2289
|
+
// index is ABSENT, which is a statement about the file and not about how
|
|
2290
|
+
// long a read ran. The file comes off a torrent, so the bytes the table
|
|
2291
|
+
// lives in may still be arriving and the read waits for them. What the
|
|
2292
|
+
// bound should be has to come from what this read costs on real hosts —
|
|
2293
|
+
// roadmap item 74, and the reading it needs is the line printed by
|
|
2294
|
+
// #readContainerKeyframes.
|
|
2288
2295
|
const keyframeStartMs = Date.now();
|
|
2289
2296
|
// Read the container's OWN keyframe table (Cues/stss) rather than
|
|
2290
2297
|
// scanning the media. On the copy path ffmpeg can only cut at the
|
|
@@ -3130,11 +3137,31 @@ export class HlsSessionManager {
|
|
|
3130
3137
|
if (running) {
|
|
3131
3138
|
return running;
|
|
3132
3139
|
}
|
|
3140
|
+
// What this read costs is what decides whether a picture can be copied, and
|
|
3141
|
+
// until now nothing recorded it: the one figure printed — `keyframes=` on
|
|
3142
|
+
// the session-create line — is what the SESSION waited for, which is the
|
|
3143
|
+
// remainder of a read the plan had already started, and is zero whenever
|
|
3144
|
+
// the plan finished first. The read itself is a fact of the file and is
|
|
3145
|
+
// timed here, where it is made exactly once per file.
|
|
3146
|
+
const startedMs = Date.now();
|
|
3133
3147
|
const work = this.#readContainerKeyframesOnce({ sourceKey, fileIndex, inputUrl, logName })
|
|
3134
3148
|
.then((result) => {
|
|
3135
3149
|
this.keyframeIndexCache.set(cacheKey, result);
|
|
3150
|
+
const tookMs = Date.now() - startedMs;
|
|
3151
|
+
const found = Array.isArray(result?.times) ? result.times.length : 0;
|
|
3152
|
+
logger.info(
|
|
3153
|
+
`keyframe index "${logName}": ${found > 0 ? `${found} times` : "none"} from the ` +
|
|
3154
|
+
`${result?.format ?? "unrecognised"} container in ${tookMs}ms`
|
|
3155
|
+
);
|
|
3136
3156
|
return result;
|
|
3137
3157
|
})
|
|
3158
|
+
.catch((error) => {
|
|
3159
|
+
logger.warn(
|
|
3160
|
+
`keyframe index "${logName}": the read failed after ${Date.now() - startedMs}ms — ` +
|
|
3161
|
+
`${error?.message ?? error}`
|
|
3162
|
+
);
|
|
3163
|
+
throw error;
|
|
3164
|
+
})
|
|
3138
3165
|
.finally(() => {
|
|
3139
3166
|
this.keyframeIndexPending.delete(cacheKey);
|
|
3140
3167
|
});
|