@torrent-tv/proxy 1.0.0 → 2.0.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/package.json
CHANGED
|
@@ -10,8 +10,11 @@ export async function handleApiTranscodeSessionsPost(req, reply, { hlsSessionMan
|
|
|
10
10
|
const sourceKey = typeof payload.sourceKey === "string" ? payload.sourceKey.trim() : "";
|
|
11
11
|
const fileIndex = Number(payload.fileIndex);
|
|
12
12
|
const transcodeVideo = payload.transcodeVideo === true;
|
|
13
|
+
const transcodeAudio = payload.transcodeAudio === true;
|
|
13
14
|
const consumerId = typeof payload.consumerId === "string" ? payload.consumerId.trim() : "";
|
|
14
15
|
const fileName = typeof payload.fileName === "string" ? payload.fileName.trim() : "";
|
|
16
|
+
const targetWidth = Number(payload.targetWidth);
|
|
17
|
+
const targetHeight = Number(payload.targetHeight);
|
|
15
18
|
|
|
16
19
|
if (!sourceKey || !Number.isInteger(fileIndex) || fileIndex < 0) {
|
|
17
20
|
return reply.code(400).send({ error: "sourceKey and valid fileIndex are required." });
|
|
@@ -22,8 +25,11 @@ export async function handleApiTranscodeSessionsPost(req, reply, { hlsSessionMan
|
|
|
22
25
|
sourceKey,
|
|
23
26
|
fileIndex,
|
|
24
27
|
transcodeVideo,
|
|
28
|
+
transcodeAudio,
|
|
25
29
|
consumerId,
|
|
26
|
-
fileName
|
|
30
|
+
fileName,
|
|
31
|
+
targetWidth: Number.isInteger(targetWidth) && targetWidth > 0 ? targetWidth : 0,
|
|
32
|
+
targetHeight: Number.isInteger(targetHeight) && targetHeight > 0 ? targetHeight : 0
|
|
27
33
|
});
|
|
28
34
|
return reply.send({
|
|
29
35
|
sessionId: session.id,
|
|
@@ -13,6 +13,9 @@ const DEFAULT_SESSION_TTL_MS = 30 * 60 * 1000;
|
|
|
13
13
|
const DEFAULT_STARTUP_WAIT_MS = 5_000;
|
|
14
14
|
const MICROSECONDS_PER_SECOND = 1_000_000;
|
|
15
15
|
const PROGRESS_LOG_INTERVAL_MS = 5_000;
|
|
16
|
+
const VIDEO_TRANSCODE_PRESET = "superfast";
|
|
17
|
+
const VIDEO_TRANSCODE_CRF = "24";
|
|
18
|
+
const VIDEO_TRANSCODE_FPS = 24;
|
|
16
19
|
|
|
17
20
|
function delay(ms) {
|
|
18
21
|
return new Promise((resolve) => {
|
|
@@ -200,14 +203,32 @@ export class HlsSessionManager {
|
|
|
200
203
|
this.cleanupTimer.unref();
|
|
201
204
|
}
|
|
202
205
|
|
|
203
|
-
async createOrGetSession({
|
|
206
|
+
async createOrGetSession({
|
|
207
|
+
sourceKey,
|
|
208
|
+
fileIndex,
|
|
209
|
+
transcodeVideo = false,
|
|
210
|
+
transcodeAudio = false,
|
|
211
|
+
consumerId = "",
|
|
212
|
+
fileName = "",
|
|
213
|
+
targetWidth = 0,
|
|
214
|
+
targetHeight = 0
|
|
215
|
+
}) {
|
|
204
216
|
if (!this.enabled) {
|
|
205
217
|
const error = new Error("Audio transcoding is disabled on this proxy.");
|
|
206
218
|
error.code = "TRANSCODE_DISABLED";
|
|
207
219
|
throw error;
|
|
208
220
|
}
|
|
209
221
|
|
|
210
|
-
const
|
|
222
|
+
const normalizedTargetWidth = Number.isInteger(targetWidth) && targetWidth > 0 ? targetWidth : 0;
|
|
223
|
+
const normalizedTargetHeight = Number.isInteger(targetHeight) && targetHeight > 0 ? targetHeight : 0;
|
|
224
|
+
const sourceMapKey = [
|
|
225
|
+
sourceKey,
|
|
226
|
+
String(fileIndex),
|
|
227
|
+
transcodeVideo ? "video" : "audio",
|
|
228
|
+
transcodeAudio ? "a1" : "a0",
|
|
229
|
+
String(normalizedTargetWidth),
|
|
230
|
+
String(normalizedTargetHeight)
|
|
231
|
+
].join(":");
|
|
211
232
|
const existingId = this.sessionIdBySource.get(sourceMapKey);
|
|
212
233
|
if (existingId) {
|
|
213
234
|
const existing = this.sessionsById.get(existingId);
|
|
@@ -238,8 +259,22 @@ export class HlsSessionManager {
|
|
|
238
259
|
const durationSeconds = await probeInputDurationSeconds(this.ffmpegBin, inputUrl.toString());
|
|
239
260
|
|
|
240
261
|
const videoCodecArgs = transcodeVideo
|
|
241
|
-
? [
|
|
262
|
+
? [
|
|
263
|
+
"-vf",
|
|
264
|
+
this.#buildVideoFilter(normalizedTargetWidth, normalizedTargetHeight),
|
|
265
|
+
"-c:v",
|
|
266
|
+
"libx264",
|
|
267
|
+
"-preset",
|
|
268
|
+
VIDEO_TRANSCODE_PRESET,
|
|
269
|
+
"-crf",
|
|
270
|
+
VIDEO_TRANSCODE_CRF,
|
|
271
|
+
"-pix_fmt",
|
|
272
|
+
"yuv420p"
|
|
273
|
+
]
|
|
242
274
|
: ["-c:v", "copy"];
|
|
275
|
+
const audioCodecArgs = transcodeAudio
|
|
276
|
+
? ["-c:a", "aac", "-ac", "2", "-b:a", "128k"]
|
|
277
|
+
: ["-c:a", "copy"];
|
|
243
278
|
|
|
244
279
|
const args = [
|
|
245
280
|
"-hide_banner",
|
|
@@ -255,12 +290,7 @@ export class HlsSessionManager {
|
|
|
255
290
|
"-map",
|
|
256
291
|
"0:a:0?",
|
|
257
292
|
...videoCodecArgs,
|
|
258
|
-
|
|
259
|
-
"aac",
|
|
260
|
-
"-ac",
|
|
261
|
-
"2",
|
|
262
|
-
"-b:a",
|
|
263
|
-
"160k",
|
|
293
|
+
...audioCodecArgs,
|
|
264
294
|
"-f",
|
|
265
295
|
"hls",
|
|
266
296
|
"-hls_time",
|
|
@@ -403,6 +433,12 @@ export class HlsSessionManager {
|
|
|
403
433
|
}
|
|
404
434
|
}
|
|
405
435
|
|
|
436
|
+
#buildVideoFilter(targetWidth, targetHeight) {
|
|
437
|
+
const safeWidth = Number.isInteger(targetWidth) && targetWidth > 0 ? targetWidth : 1280;
|
|
438
|
+
const safeHeight = Number.isInteger(targetHeight) && targetHeight > 0 ? targetHeight : 720;
|
|
439
|
+
return `scale=${safeWidth}:${safeHeight}:force_original_aspect_ratio=decrease:force_divisible_by=2,fps=${VIDEO_TRANSCODE_FPS}`;
|
|
440
|
+
}
|
|
441
|
+
|
|
406
442
|
async waitUntilReady(session) {
|
|
407
443
|
const playlistPath = path.join(session.dirPath, PLAYLIST_FILE_NAME);
|
|
408
444
|
const deadline = Date.now() + this.startupWaitMs;
|