mirror of
https://github.com/chrisbenincasa/tunarr.git
synced 2026-04-18 09:03:35 -04:00
checkpoint
This commit is contained in:
@@ -442,7 +442,7 @@ export class FfmpegStreamFactory extends IFFMPEG {
|
||||
new FrameState({
|
||||
isAnamorphic: false,
|
||||
scaledSize,
|
||||
paddedSize, // TODO
|
||||
paddedSize,
|
||||
videoBitrate: playbackParams.videoBitrate,
|
||||
videoBufferSize: playbackParams.videoBufferSize,
|
||||
pixelFormat: playbackParams.pixelFormat, //match(), TODO: Make this customizable...
|
||||
|
||||
26
server/src/ffmpeg/builder/filter/DrawTextFilter.ts
Normal file
26
server/src/ffmpeg/builder/filter/DrawTextFilter.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { FilterOption } from './FilterOption.ts';
|
||||
|
||||
interface DrawTextOptions {
|
||||
fontfile: string;
|
||||
text: string;
|
||||
border?: {
|
||||
color: string;
|
||||
width: number;
|
||||
};
|
||||
color: string;
|
||||
size: string;
|
||||
position: {
|
||||
x: string;
|
||||
y: string;
|
||||
};
|
||||
}
|
||||
|
||||
export class DrawTextFilter extends FilterOption {
|
||||
constructor(private opts: DrawTextOptions) {
|
||||
super();
|
||||
}
|
||||
|
||||
get filter() {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,7 @@ export class SoftwarePipelineBuilder extends BasePipelineBuilder {
|
||||
currentState = this.setScale(currentState);
|
||||
currentState = this.setPad(currentState);
|
||||
currentState = this.setWatermark(currentState);
|
||||
this.setStillImageLoop();
|
||||
}
|
||||
|
||||
if (!this.hasVideoEncoderPipelineStep()) {
|
||||
|
||||
@@ -24,6 +24,7 @@ export const DefaultFrameState: Omit<
|
||||
deinterlace: false,
|
||||
pixelFormat: null,
|
||||
bitDepth: 8,
|
||||
displayTrackInfo: true,
|
||||
};
|
||||
|
||||
export class FrameState {
|
||||
@@ -42,6 +43,7 @@ export class FrameState {
|
||||
frameDataLocation: FrameDataLocation;
|
||||
deinterlace: boolean;
|
||||
pixelFormat: Nullable<PixelFormat>;
|
||||
displayTrackInfo: boolean;
|
||||
|
||||
constructor(
|
||||
fields: MarkOptional<FrameStateFields, keyof typeof DefaultFrameState>,
|
||||
|
||||
@@ -133,7 +133,7 @@ export type StreamOptions = {
|
||||
startTime: Duration;
|
||||
duration: Duration;
|
||||
watermark?: Watermark;
|
||||
realtime?: boolean; // = true,
|
||||
realtime: boolean;
|
||||
extraInputHeaders?: Record<string, string>;
|
||||
outputFormat: OutputFormat;
|
||||
ptsOffset?: number;
|
||||
|
||||
@@ -49,7 +49,7 @@ export abstract class ProgramStream extends (events.EventEmitter as new () => Ty
|
||||
}
|
||||
|
||||
async setup(
|
||||
opts?: Partial<StreamOptions>,
|
||||
opts: Partial<StreamOptions> = {},
|
||||
): Promise<Result<FfmpegTranscodeSession>> {
|
||||
if (this.isInitialized()) {
|
||||
return Result.success(this._transcodeSession);
|
||||
@@ -86,7 +86,7 @@ export abstract class ProgramStream extends (events.EventEmitter as new () => Ty
|
||||
protected shutdownInternal(): void {}
|
||||
|
||||
protected abstract setupInternal(
|
||||
opts?: Partial<StreamOptions>,
|
||||
opts: Partial<StreamOptions>,
|
||||
): Promise<Result<FfmpegTranscodeSession>>;
|
||||
|
||||
get transcodeSession() {
|
||||
|
||||
@@ -299,8 +299,8 @@ export class PlexStreamDetails {
|
||||
videoStream.scanType === 'interlaced'
|
||||
? 'interlaced'
|
||||
: videoStream.scanType === 'progressive'
|
||||
? 'progressive'
|
||||
: 'unknown',
|
||||
? 'progressive'
|
||||
: 'unknown',
|
||||
width: videoStream.width,
|
||||
height: videoStream.height,
|
||||
framerate: videoStream.frameRate,
|
||||
@@ -358,6 +358,14 @@ export class PlexStreamDetails {
|
||||
audioDetails: isEmpty(audioStreamDetails)
|
||||
? undefined
|
||||
: (audioStreamDetails as NonEmptyArray<AudioStreamDetails>),
|
||||
musicMetadata:
|
||||
media.type === 'track'
|
||||
? {
|
||||
albumName: media.parentTitle ?? '',
|
||||
artistName: media.grandparentTitle,
|
||||
trackName: media.title,
|
||||
}
|
||||
: undefined,
|
||||
};
|
||||
|
||||
if (
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { Nullable } from '@/types/util.js';
|
||||
import { isNonEmptyString } from '@/util/index.js';
|
||||
import type { Duration } from 'dayjs/plugin/duration.js';
|
||||
import { first, isNull, isUndefined } from 'lodash-es';
|
||||
import type { Dictionary } from 'ts-essentials';
|
||||
import type { Dictionary, NonEmptyArray } from 'ts-essentials';
|
||||
import type { PixelFormat } from '../ffmpeg/builder/format/PixelFormat.ts';
|
||||
import {
|
||||
KnownPixelFormats,
|
||||
@@ -11,19 +11,27 @@ import {
|
||||
PixelFormatYuv420P10Le,
|
||||
} from '../ffmpeg/builder/format/PixelFormat.ts';
|
||||
|
||||
type StreamMusicMetadata = {
|
||||
artistName: string;
|
||||
trackName: string;
|
||||
albumName: string;
|
||||
};
|
||||
|
||||
export type StreamDetails = {
|
||||
duration?: Duration;
|
||||
// This is the total bitrate
|
||||
bitrate?: number;
|
||||
|
||||
// If defined, there is at least one video stream
|
||||
videoDetails?: [VideoStreamDetails, ...VideoStreamDetails[]];
|
||||
audioDetails?: [AudioStreamDetails, ...AudioStreamDetails[]];
|
||||
videoDetails?: NonEmptyArray<VideoStreamDetails>;
|
||||
audioDetails?: NonEmptyArray<AudioStreamDetails>;
|
||||
|
||||
audioOnly?: boolean;
|
||||
placeholderImage?: StreamSource;
|
||||
serverPath?: string;
|
||||
directFilePath?: string;
|
||||
|
||||
musicMetadata?: StreamMusicMetadata;
|
||||
};
|
||||
|
||||
export type VideoStreamDetails = {
|
||||
|
||||
Reference in New Issue
Block a user