Compare commits

...

2 Commits

Author SHA1 Message Date
d37694e4d3 Refresh local videos on each listing request 2026-06-15 19:44:49 -07:00
0ad0df5612 realtime flag for http urls 2026-06-14 19:07:58 -07:00
2 changed files with 14 additions and 8 deletions

View File

@@ -110,7 +110,7 @@ Frame output:
- Maps `0:v:0` - Maps `0:v:0`
- Disables audio with `-an` - Disables audio with `-an`
- Applies `fps=<fps>,scale=w='min(<width>,iw)':h=-2:flags=bicubic:out_range=pc,format=yuvj420p` - Applies `fps=<fps>,scale=w='min(<width>,iw)':h=-2:flags=bicubic:out_range=pc,format=yuvj420p,realtime`
- Encodes `mjpeg` - Encodes `mjpeg`
- Uses `-pix_fmt yuvj420p`, `-color_range pc`, `-q:v <quality>` - Uses `-pix_fmt yuvj420p`, `-color_range pc`, `-q:v <quality>`
- Outputs `image2pipe` to either `pipe:1` or `pipe:3` - Outputs `image2pipe` to either `pipe:1` or `pipe:3`

View File

@@ -132,6 +132,8 @@ app.get('/api/favorites', (_request, response) => {
}); });
app.get('/api/local-videos', async (_request, response) => { app.get('/api/local-videos', async (_request, response) => {
response.set('Cache-Control', 'no-store');
if (!LOCAL_VIDEOS_ROOT) { if (!LOCAL_VIDEOS_ROOT) {
response.json({ enabled: false, videos: [] }); response.json({ enabled: false, videos: [] });
return; return;
@@ -658,10 +660,13 @@ function getLocalVideosRealRoot() {
} }
if (!localVideosRealRootPromise) { if (!localVideosRealRootPromise) {
localVideosRealRootPromise = fs.realpath(LOCAL_VIDEOS_ROOT).catch((error) => { localVideosRealRootPromise = fs.realpath(LOCAL_VIDEOS_ROOT)
localVideosRealRootPromise = null; .catch((error) => {
throw new Error(`Local videos directory is unavailable: ${error.message}`); throw new Error(`Local videos directory is unavailable: ${error.message}`);
}); })
.finally(() => {
localVideosRealRootPromise = null;
});
} }
return localVideosRealRootPromise; return localVideosRealRootPromise;
@@ -2798,6 +2803,7 @@ function buildFrameArgs(session, inputUrl, inputOptions) {
} }
function buildInputArgs(inputUrl, { seekable = true, startTime = 0 } = {}) { function buildInputArgs(inputUrl, { seekable = true, startTime = 0 } = {}) {
const isHttpInput = isHttpInputUrl(inputUrl);
const args = [ const args = [
'-hide_banner', '-hide_banner',
'-nostdin', '-nostdin',
@@ -2806,7 +2812,7 @@ function buildInputArgs(inputUrl, { seekable = true, startTime = 0 } = {}) {
'-nostats', '-nostats',
]; ];
if (seekable) { if (seekable && isHttpInput) {
args.push('-seekable', startTime > 0 ? '1' : FFMPEG_INPUT_SEEKABLE); args.push('-seekable', startTime > 0 ? '1' : FFMPEG_INPUT_SEEKABLE);
} }
@@ -2814,7 +2820,7 @@ function buildInputArgs(inputUrl, { seekable = true, startTime = 0 } = {}) {
args.push('-ss', formatFfmpegSeconds(startTime)); args.push('-ss', formatFfmpegSeconds(startTime));
} }
if (FFMPEG_HTTP_RECONNECT && isHttpInputUrl(inputUrl)) { if (FFMPEG_HTTP_RECONNECT && isHttpInput) {
args.push( args.push(
'-reconnect', '-reconnect',
'1', '1',
@@ -2849,7 +2855,7 @@ function formatFfmpegSeconds(seconds) {
function buildFrameOutputArgs(session, outputUrl) { function buildFrameOutputArgs(session, outputUrl) {
const { fps, quality, width } = session.options; const { fps, quality, width } = session.options;
const videoFilter = `fps=${fps},scale=w='min(${width},iw)':h=-2:flags=bicubic:out_range=pc,format=yuvj420p`; const videoFilter = `fps=${fps},scale=w='min(${width},iw)':h=-2:flags=bicubic:out_range=pc,format=yuvj420p,realtime`;
return [ return [
'-an', '-an',