Skip to content

Commit

Permalink
feat: ffmpeg pipeline builder overhaul
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisbenincasa committed Nov 13, 2024
1 parent c2c52b6 commit 3b84fe2
Show file tree
Hide file tree
Showing 146 changed files with 8,435 additions and 484 deletions.
11 changes: 11 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@ export default tseslint.config(
tsconfigRootDir: import.meta.dirname,
},
},
rules: {
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': [
'warn', // or "error"
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_',
},
],
},
},
{
files: ['web/src/**/*.tsx', 'web/src/**/*.ts'],
Expand Down
16 changes: 8 additions & 8 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@
"thread-stream": "^3.1.0",
"tmp": "^0.2.1",
"tmp-promise": "^3.0.3",
"ts-essentials": "^9.4.2",
"ts-essentials": "^10.0.0",
"ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0",
"tsify": "^5.0.4",
Expand Down
76 changes: 48 additions & 28 deletions server/src/api/debug/debugStreamApi.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { jsonObjectFrom } from 'kysely/helpers/sqlite';
import { first, isNumber, isUndefined, random } from 'lodash-es';
import { first, isNumber, isUndefined, nth, random } from 'lodash-es';
import { PassThrough } from 'stream';
import { z } from 'zod';
import { createOfflineStreamLineupItem } from '../../dao/derived_types/StreamLineup.ts';
Expand All @@ -9,13 +9,14 @@ import {
Channel,
} from '../../dao/direct/schema/Channel.ts';
import { Program, ProgramType } from '../../dao/direct/schema/Program.ts';
import { MpegTsOutputFormat } from '../../ffmpeg/OutputFormat.ts';
import { MpegTsOutputFormat } from '../../ffmpeg/builder/constants.ts';
import { serverContext } from '../../serverContext.ts';
import { OfflineProgramStream } from '../../stream/OfflinePlayer.ts';
import { PlayerContext } from '../../stream/PlayerStreamContext.ts';
import { ProgramStream } from '../../stream/ProgramStream.ts';
import { JellyfinProgramStream } from '../../stream/jellyfin/JellyfinProgramStream.ts';
import { PlexProgramStream } from '../../stream/plex/PlexProgramStream.ts';
import { TruthyQueryParam } from '../../types/schemas.ts';
import { RouterPluginAsyncCallback } from '../../types/serverType.ts';

export const debugStreamApiRouter: RouterPluginAsyncCallback = async (
Expand All @@ -28,6 +29,7 @@ export const debugStreamApiRouter: RouterPluginAsyncCallback = async (
schema: {
querystring: z.object({
duration: z.coerce.number().default(30_000),
useNewPipeline: TruthyQueryParam.default(false),
}),
},
},
Expand All @@ -36,6 +38,7 @@ export const debugStreamApiRouter: RouterPluginAsyncCallback = async (
.selectFrom('channel')
.selectAll()
.executeTakeFirstOrThrow();

const stream = new OfflineProgramStream(
false,
new PlayerContext(
Expand All @@ -47,6 +50,7 @@ export const debugStreamApiRouter: RouterPluginAsyncCallback = async (
false,
false,
true,
req.query.useNewPipeline,
),
MpegTsOutputFormat,
);
Expand All @@ -58,32 +62,38 @@ export const debugStreamApiRouter: RouterPluginAsyncCallback = async (
},
);

fastify.get('/streams/error', async (_, res) => {
const channel = await directDbAccess()
.selectFrom('channel')
.selectAll()
.executeTakeFirstOrThrow();
const stream = new OfflineProgramStream(
true,
new PlayerContext(
{
...createOfflineStreamLineupItem(30_000),
streamDuration: 30_000,
title: 'Error',
},
channel,
false,
false,
fastify.get(
'/streams/error',
{
schema: {
querystring: z.object({
useNewPipeline: TruthyQueryParam.default(false),
}),
},
},
async (req, res) => {
const channel = await directDbAccess()
.selectFrom('channel')
.selectAll()
.executeTakeFirstOrThrow();
const stream = new OfflineProgramStream(
true,
),
MpegTsOutputFormat,
);
PlayerContext.error(
30_000,
'',
channel,
true,
req.query.useNewPipeline,
),
MpegTsOutputFormat,
);

const out = new PassThrough();
stream.on('error', () => out.end());
await stream.start(out);
return res.header('Content-Type', 'video/mp2t').send(out);
});
const out = new PassThrough();
stream.on('error', () => out.end());
await stream.start(out);
return res.header('Content-Type', 'video/mp2t').send(out);
},
);

fastify.get('/streams/random', async (_, res) => {
const program = await directDbAccess()
Expand Down Expand Up @@ -126,6 +136,7 @@ export const debugStreamApiRouter: RouterPluginAsyncCallback = async (
}),
querystring: z.object({
start: z.literal('random').or(z.coerce.number()).optional(),
useNewPipeline: TruthyQueryParam.default(false),
}),
},
},
Expand Down Expand Up @@ -158,7 +169,7 @@ export const debugStreamApiRouter: RouterPluginAsyncCallback = async (
)
.execute();

let firstChannel = channels?.[0].channel;
let firstChannel = nth(channels, 0)?.channel;

if (!firstChannel) {
firstChannel = await req.serverCtx.channelDB
Expand All @@ -173,6 +184,7 @@ export const debugStreamApiRouter: RouterPluginAsyncCallback = async (
program,
firstChannel,
startTime * 1000,
req.query.useNewPipeline,
);
return res.header('Content-Type', 'video/mp2t').send(outStream);
},
Expand All @@ -182,12 +194,20 @@ export const debugStreamApiRouter: RouterPluginAsyncCallback = async (
program: Program,
channel: Channel,
startTime: number = 0,
useNewPipeline: boolean = false,
) {
const lineupItem = serverContext()
.streamProgramCalculator()
.createStreamItemFromProgram(program);
lineupItem.start = startTime;
const ctx = new PlayerContext(lineupItem, channel, false, false, true);
const ctx = new PlayerContext(
lineupItem,
channel,
false,
false,
true,
useNewPipeline,
);

let stream: ProgramStream;
switch (program.sourceType) {
Expand Down
1 change: 1 addition & 0 deletions server/src/api/debugApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import z from 'zod';
import { ArchiveDatabaseBackup } from '../dao/backup/ArchiveDatabaseBackup.js';
import { directDbAccess } from '../dao/direct/directDbAccess.js';
import { MediaSourceType } from '../dao/direct/schema/MediaSource.ts';

import { LineupCreator } from '../services/dynamic_channels/LineupCreator.js';
import { PlexTaskQueue } from '../tasks/TaskQueue.js';
import { SavePlexProgramExternalIdsTask } from '../tasks/plex/SavePlexProgramExternalIdsTask.js';
Expand Down
10 changes: 7 additions & 3 deletions server/src/api/streamApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export const streamApi: RouterPluginAsyncCallback = async (fastify) => {
streamMode: ChannelStreamModeSchema.optional(),
token: z.string().uuid().optional(),
audioOnly: TruthyQueryParam.optional().default(false),
useNewPipeline: TruthyQueryParam.optional().default(false),
}),
},
},
Expand All @@ -59,11 +60,11 @@ export const streamApi: RouterPluginAsyncCallback = async (fastify) => {
case 'hls':
case 'hls_slower':
return res.redirect(
`/stream/channels/${channel.uuid}.m3u8?streamMode=${mode}`,
`/stream/channels/${channel.uuid}.m3u8?streamMode=${mode}&useNewPipeline=${req.query.useNewPipeline}`,
);
case 'mpegts':
return res.redirect(
`/stream/channels/${channel.uuid}.ts?streamMode=${mode}`,
`/stream/channels/${channel.uuid}.ts?streamMode=${mode}&useNewPipeline=${req.query.useNewPipeline}`,
);
}
},
Expand Down Expand Up @@ -260,6 +261,7 @@ export const streamApi: RouterPluginAsyncCallback = async (fastify) => {
}),
querystring: z.object({
mode: ChannelStreamModeSchema.optional(),
useNewPipeline: TruthyQueryParam.optional().default(false),
}),
},
},
Expand Down Expand Up @@ -294,7 +296,9 @@ export const streamApi: RouterPluginAsyncCallback = async (fastify) => {
switch (mode) {
case 'hls':
sessionResult = await req.serverCtx.sessionManager
.getOrCreateHlsSession(channelId, req.ip, connectionDetails, {})
.getOrCreateHlsSession(channelId, req.ip, connectionDetails, {
useNewPipeline: req.query.useNewPipeline,
})
.then((result) =>
result.mapAsync(async (session) => {
session.recordHeartbeat(req.ip);
Expand Down
9 changes: 6 additions & 3 deletions server/src/bootstrap.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import constants from '@tunarr/shared/constants';
import fs from 'node:fs/promises';
import path from 'path';
import { DeepPartial } from 'ts-essentials';
import {
initDirectDbAccess,
syncMigrationTablesIfNecessary,
} from './dao/direct/directDbAccess.ts';
import { getSettings } from './dao/settings.js';
import { SettingsFile, getSettings } from './dao/settings.js';
import { globalOptions } from './globals.js';
import { copyDirectoryContents, fileExists } from './util/fsUtil.js';
import { LoggerFactory, RootLogger } from './util/logging/LoggerFactory.js';
Expand Down Expand Up @@ -58,10 +59,12 @@ export async function initDbDirectories() {
return hasTunarrDb;
}

export async function bootstrapTunarr() {
export async function bootstrapTunarr(
initialSettings?: DeepPartial<SettingsFile>,
) {
await initDbDirectories();
initDirectDbAccess(path.join(globalOptions().databaseDirectory, 'db.db'));
await syncMigrationTablesIfNecessary();
const settingsDb = getSettings();
const settingsDb = getSettings(undefined, initialSettings);
LoggerFactory.initialize(settingsDb);
}
11 changes: 9 additions & 2 deletions server/src/dao/legacy_migration/legacyDbMigration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import {
DefaultHardwareAccel,
DefaultVideoFormat,
FfmpegSettingsSchema,
SupportedHardwareAccels,
SupportedVideoFormats,
} from '@tunarr/types/schemas';
Expand All @@ -32,6 +33,7 @@ import {
} from 'lodash-es';
import path, { dirname, join } from 'path';
import { v4 } from 'uuid';
import { z } from 'zod';
import { MediaSourceApiFactory } from '../../external/MediaSourceApiFactory.js';
import { globalOptions } from '../../globals.js';
import { serverContext } from '../../serverContext.js';
Expand Down Expand Up @@ -444,8 +446,12 @@ export class LegacyDbMigrator {
audioBufferSize: ffmpegSettings['audioBufSize'] as number,
audioSampleRate: ffmpegSettings['audioSampleRate'] as number,
audioChannels: ffmpegSettings['audioChannels'] as number,
errorScreen: ffmpegSettings['errorScreen'] as string,
errorAudio: ffmpegSettings['errorAudio'] as string,
errorScreen: ffmpegSettings['errorScreen'] as z.infer<
typeof FfmpegSettingsSchema
>['errorScreen'],
errorAudio: ffmpegSettings['errorAudio'] as z.infer<
typeof FfmpegSettingsSchema
>['errorAudio'],
normalizeVideoCodec: ffmpegSettings[
'normalizeVideoCodec'
] as boolean,
Expand All @@ -469,6 +475,7 @@ export class LegacyDbMigrator {
disableChannelPrelude:
(ffmpegSettings['disablePreludes'] as Maybe<boolean>) ??
false,
useNewFfmpegPipeline: false,
},
defaultFfmpegSettings,
),
Expand Down
Loading

0 comments on commit 3b84fe2

Please sign in to comment.