feat: add quality/transcoding options to live player (#6)

Manual quality profiles (source/1080p/720p/480p) in the player overflow
menu plus an honest/preparatory Auto contract: adaptive when the HLS
manifest exposes multiple levels, single-rendition automatic selection
otherwise.

- server: transcodeQualityProfiles service and qualityMode session option
- player: quality menu, persisted preference, live switch with rollback
- tests: npm test script and unit tests for quality profiles
This commit is contained in:
blomios
2026-09-30 12:01:08 +02:00
parent f715203c4a
commit 4488914b2d
5 changed files with 427 additions and 17 deletions

View File

@ -5,6 +5,7 @@ const path = require('path');
const fs = require('fs').promises;
const db = require('../db');
const transcodeSession = require('../services/transcodeSession');
const { QUALITY_MODES, resolveQualityMode } = require('../services/transcodeQualityProfiles');
/**
* Transcode Routes
@ -31,7 +32,8 @@ transcodeSession.startCleanupInterval();
router.post('/session', async (req, res) => {
const {
url, seekOffset, videoMode, videoCodec, audioCodec, audioChannels,
targetVideoBitrateKbps, targetAudioBitrateKbps, allowHardwareFallback
targetVideoBitrateKbps, targetAudioBitrateKbps, allowHardwareFallback,
qualityMode
} = req.body;
if (!url) {
@ -43,6 +45,7 @@ router.post('/session', async (req, res) => {
const userAgent = db.getUserAgent(settings);
try {
const qualitySelection = resolveQualityMode(qualityMode, settings);
const session = await transcodeSession.createSession(url, {
ffmpegPath,
userAgent,
@ -61,7 +64,8 @@ router.post('/session', async (req, res) => {
videoMode: videoMode, // 'copy' or 'encode'
videoCodec: videoCodec, // 'h264', 'hevc', etc.
audioCodec: audioCodec, // 'aac', 'ac3', etc.
audioChannels: audioChannels // number of channels (2=stereo)
audioChannels: audioChannels, // number of channels (2=stereo)
...(qualitySelection?.sessionOptions || {})
});
await session.start();
@ -80,10 +84,22 @@ router.post('/session', async (req, res) => {
status: session.status,
requestedEncoder: session.requestedEncoder,
effectiveEncoder: session.effectiveEncoder,
hardwareFallbackOccurred: session.hardwareFallbackOccurred
hardwareFallbackOccurred: session.hardwareFallbackOccurred,
...(qualitySelection && {
qualityMode: qualitySelection.qualityMode,
mode: qualitySelection.mode,
selectedProfile: qualitySelection.selectedProfile,
availableProfiles: qualitySelection.availableProfiles
})
});
} catch (err) {
if (err.code === 'INVALID_QUALITY_MODE') {
return res.status(400).json({
error: err.message,
availableProfiles: QUALITY_MODES
});
}
console.error('[Transcode] Session creation failed:', err);
res.status(500).json({ error: 'Failed to create session', details: err.message });
}