Skip to content

Commit

Permalink
checkpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisbenincasa committed Dec 20, 2024
1 parent e507b1e commit 34224bf
Show file tree
Hide file tree
Showing 10 changed files with 75 additions and 58 deletions.
7 changes: 5 additions & 2 deletions server/src/api/debug/debugStreamApi.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { getDatabase } from '@/db/DBAccess.ts';
import { createOfflineStreamLineupItem } from '@/db/derived_types/StreamLineup.ts';
import { withProgramExternalIds } from '@/db/programQueryHelpers.ts';
import { AllChannelTableKeys, Channel } from '@/db/schema/Channel.ts';
import { ProgramDao, ProgramType } from '@/db/schema/Program.ts';
import { ProgramType } from '@/db/schema/Program.ts';
import {
AllTranscodeConfigColumns,
TranscodeConfig,
} from '@/db/schema/TranscodeConfig.ts';
import { ProgramWithExternalIds } from '@/db/schema/derivedTypes.js';
import { MpegTsOutputFormat } from '@/ffmpeg/builder/constants.ts';
import { serverContext } from '@/serverContext.ts';
import { OfflineProgramStream } from '@/stream/OfflinePlayer.ts';
Expand Down Expand Up @@ -130,6 +132,7 @@ export const debugStreamApiRouter: RouterPluginAsyncCallback = async (
.selectFrom('program')
.orderBy((ob) => ob.fn('random'))
.where('type', '=', ProgramType.Episode)
.select(withProgramExternalIds)
.limit(1)
.selectAll()
.executeTakeFirstOrThrow();
Expand Down Expand Up @@ -261,7 +264,7 @@ export const debugStreamApiRouter: RouterPluginAsyncCallback = async (
);

async function initStream(
program: ProgramDao,
program: ProgramWithExternalIds,
channel: Channel,
transcodeConfig: TranscodeConfig,
startTime: number = 0,
Expand Down
36 changes: 15 additions & 21 deletions server/src/db/converters/ProgramMinter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ import {
ProgramExternalIdType,
programExternalIdTypeFromJellyfinProvider,
} from '../custom_types/ProgramExternalIdType.ts';
import {
NewProgramDao as NewRawProgram,
ProgramType,
} from '../schema/Program.ts';
import { NewProgramDao, ProgramType } from '../schema/Program.ts';

/**
* Generates Program DB entities for Plex media
Expand All @@ -29,7 +26,7 @@ class ProgramDaoMinter {
mint(
serverName: string,
program: ContentProgramOriginalProgram,
): NewRawProgram {
): NewProgramDao {
const ret = match(program)
.with(
{ sourceType: 'plex', program: { type: 'movie' } },
Expand Down Expand Up @@ -70,18 +67,17 @@ class ProgramDaoMinter {
private mintProgramForPlexMovie(
serverName: string,
plexMovie: PlexMovie,
): NewRawProgram {
const file = first(first(plexMovie.Media)?.Part ?? []);
): NewProgramDao {
return {
uuid: v4(),
sourceType: ProgramSourceType.PLEX,
originalAirDate: plexMovie.originallyAvailableAt ?? null,
duration: plexMovie.duration ?? 0,
filePath: file?.file ?? null,
// filePath: file?.file ?? null,
externalSourceId: serverName,
externalKey: plexMovie.ratingKey,
plexRatingKey: plexMovie.ratingKey,
plexFilePath: file?.key ?? null,
// plexRatingKey: plexMovie.ratingKey,
// plexFilePath: file?.key ?? null,
rating: plexMovie.contentRating ?? null,
summary: plexMovie.summary ?? null,
title: plexMovie.title,
Expand All @@ -97,7 +93,7 @@ class ProgramDaoMinter {
item: Omit<JellyfinItem, 'Type'> & {
Type: 'Movie' | 'Episode' | 'Audio' | 'Video' | 'MusicVideo' | 'Trailer';
},
): NewRawProgram {
): NewProgramDao {
return {
uuid: v4(),
createdAt: +dayjs(),
Expand Down Expand Up @@ -133,20 +129,19 @@ class ProgramDaoMinter {
private mintProgramForPlexEpisode(
serverName: string,
plexEpisode: PlexEpisode,
): NewRawProgram {
const file = first(first(plexEpisode.Media)?.Part ?? []);
): NewProgramDao {
return {
uuid: v4(),
createdAt: +dayjs(),
updatedAt: +dayjs(),
sourceType: ProgramSourceType.PLEX,
originalAirDate: plexEpisode.originallyAvailableAt,
duration: plexEpisode.duration ?? 0,
filePath: file?.file,
// filePath: file?.file,
externalSourceId: serverName,
externalKey: plexEpisode.ratingKey,
plexRatingKey: plexEpisode.ratingKey,
plexFilePath: file?.key,
// plexRatingKey: plexEpisode.ratingKey,
// plexFilePath: file?.key,
rating: plexEpisode.contentRating,
summary: plexEpisode.summary,
title: plexEpisode.title,
Expand All @@ -164,19 +159,18 @@ class ProgramDaoMinter {
private mintProgramForPlexTrack(
serverName: string,
plexTrack: PlexMusicTrack,
): NewRawProgram {
const file = first(first(plexTrack.Media)?.Part ?? []);
): NewProgramDao {
return {
uuid: v4(),
createdAt: +dayjs(),
updatedAt: +dayjs(),
sourceType: ProgramSourceType.PLEX,
duration: plexTrack.duration ?? 0,
filePath: file?.file,
// filePath: file?.file,
externalSourceId: serverName,
externalKey: plexTrack.ratingKey,
plexRatingKey: plexTrack.ratingKey,
plexFilePath: file?.key,
// plexRatingKey: plexTrack.ratingKey,
// plexFilePath: file?.key,
summary: plexTrack.summary,
title: plexTrack.title,
type: ProgramType.Track,
Expand Down
6 changes: 4 additions & 2 deletions server/src/db/derived_types/StreamLineup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,11 @@ const BaseContentBackedStreamLineupItemSchema =
// ID in the program DB table
programId: z.string().uuid(),
// These are taken from the Program DB entity
plexFilePath: z.string().optional(),
externalSourceId: z.string(),
filePath: z.string().optional(),
// Path to fetch the raw stream from the server
serverPath: z.string().optional(),
// The file path of the underlying media as seen from the media server
serverFilePath: z.string().optional(),
externalKey: z.string(),
programType: ProgramTypeEnum,
externalSource: z.nativeEnum(MediaSourceType),
Expand Down
3 changes: 3 additions & 0 deletions server/src/db/schema/Program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@ export interface ProgramTable extends WithCreatedAt, WithUpdatedAt, WithUuid {
episodeIcon: string | null;
externalKey: string;
externalSourceId: string;
// Deprecated, use program_external_id.direct_file_path
filePath: string | null;
grandparentExternalKey: string | null;
icon: string | null;
originalAirDate: string | null;
parentExternalKey: string | null;
// Deprecated, use program_external_id.external_file_path
plexFilePath: string | null;
// Deprecated, use external_key
plexRatingKey: string | null;
rating: string | null;
seasonIcon: string | null;
Expand Down
1 change: 1 addition & 0 deletions server/src/services/scanner/MediaSourceScanner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export abstract class MediaSourceScanner {}
Empty file.
56 changes: 35 additions & 21 deletions server/src/stream/StreamProgramCalculator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,43 @@ import { ProgramDB } from '@/db/ProgramDB.ts';
import { ProgramExternalIdType } from '@/db/custom_types/ProgramExternalIdType.ts';
import { Channel } from '@/db/schema/Channel.ts';
import { MediaSourceType } from '@/db/schema/MediaSource.ts';
import { ProgramDao as RawProgram } from '@/db/schema/Program.ts';
import type { ProgramDaoWithRelations as RawProgramEntity } from '@/db/schema/derivedTypes.js';
import type {
ProgramWithExternalIds,
ProgramDaoWithRelations as RawProgramEntity,
} from '@/db/schema/derivedTypes.js';
import { FillerPicker } from '@/services/FillerPicker.js';
import { Result } from '@/types/result.js';
import { Maybe, Nullable } from '@/types/util.js';
import { binarySearchRange } from '@/util/binarySearch.js';
import { LoggerFactory } from '@/util/logging/LoggerFactory.js';
import constants from '@tunarr/shared/constants';
import { nullToUndefined } from '@tunarr/shared/util';
import dayjs from 'dayjs';
import { first, isEmpty, isNil, isNull, isUndefined, nth } from 'lodash-es';
import {
find,
first,
isEmpty,
isNil,
isNull,
isUndefined,
nth,
} from 'lodash-es';
import { StrictExclude } from 'ts-essentials';
import { z } from 'zod';
import {
Lineup,
isContentItem,
isOfflineItem,
} from '../db/derived_types/Lineup.ts';
import {
CommercialStreamLineupItem,
EnrichedLineupItem,
OfflineStreamLineupItem,
ProgramStreamLineupItem,
RedirectStreamLineupItem,
StreamLineupItem,
createOfflineStreamLineupItem,
} from '../db/derived_types/StreamLineup.ts';
import {
isNonEmptyString,
nullToUndefined,
zipWithIndex,
} from '../util/index.js';
import { isNonEmptyString, zipWithIndex } from '../util/index.js';
import { ChannelCache } from './ChannelCache.js';
import { wereThereTooManyAttempts } from './StreamThrottler.js';

Expand Down Expand Up @@ -396,16 +404,16 @@ export class StreamProgramCalculator {
externalInfo.sourceType === ProgramExternalIdType.JELLYFIN
? MediaSourceType.Jellyfin
: MediaSourceType.Plex,
plexFilePath: nullToUndefined(externalInfo.externalFilePath),
externalKey: externalInfo.externalKey,
filePath: nullToUndefined(externalInfo.directFilePath),
serverPath: nullToUndefined(externalInfo.externalFilePath),
serverFilePath: nullToUndefined(externalInfo.directFilePath),
externalSourceId: externalInfo.externalSourceId,
duration: backingItem.duration,
programId: backingItem.uuid,
title: backingItem.title,
id: backingItem.uuid,
programType: backingItem.type,
};
} satisfies ProgramStreamLineupItem;
}
}
} else if (isOfflineItem(lineupItem)) {
Expand Down Expand Up @@ -518,7 +526,6 @@ export class StreamProgramCalculator {
// just add the video, starting at 0, playing the entire duration
type: 'commercial',
title: filler.title,
filePath: nullToUndefined(externalInfo.directFilePath),
externalKey: externalInfo.externalKey,
externalSource:
externalInfo.sourceType === ProgramExternalIdType.JELLYFIN
Expand All @@ -533,9 +540,10 @@ export class StreamProgramCalculator {
programId: filler.uuid,
beginningOffset: beginningOffset,
externalSourceId: externalInfo.externalSourceId!,
plexFilePath: nullToUndefined(externalInfo.externalFilePath),
serverFilePath: nullToUndefined(externalInfo.directFilePath),
serverPath: nullToUndefined(externalInfo.externalFilePath),
programType: filler.type,
};
} satisfies CommercialStreamLineupItem;
}
}

Expand All @@ -551,7 +559,7 @@ export class StreamProgramCalculator {
beginningOffset: beginningOffset,
duration: remaining,
start: 0,
};
} satisfies OfflineStreamLineupItem;
}

const originalTimeElapsed = timeElapsed;
Expand All @@ -567,20 +575,26 @@ export class StreamProgramCalculator {
streamDuration: activeProgram.duration - timeElapsed,
beginningOffset: beginningOffset,
id: activeProgram.id,
};
} satisfies ProgramStreamLineupItem;
}

createStreamItemFromProgram(program: RawProgram): ProgramStreamLineupItem {
createStreamItemFromProgram(
program: ProgramWithExternalIds,
): ProgramStreamLineupItem {
return {
...program,
type: 'program',
programType: program.type,
programId: program.uuid,
id: program.uuid,
// HACK
externalSource: z.nativeEnum(MediaSourceType).parse(program.sourceType),
plexFilePath: program.plexFilePath ?? undefined,
filePath: program.filePath ?? undefined,
externalSource: program.sourceType,
serverPath: nullToUndefined(
find(program.externalIds, { sourceType: 'plex' })?.externalFilePath,
),
serverFilePath: nullToUndefined(
find(program.externalIds, { sourceType: 'plex' })?.directFilePath,
),
};
}
}
4 changes: 2 additions & 2 deletions server/src/stream/jellyfin/JellyfinStreamDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import {
// TODO: See if we need separate types for JF and Plex and what is really necessary here
type JellyfinItemStreamDetailsQuery = Pick<
ContentBackedStreamLineupItem,
'programType' | 'externalKey' | 'plexFilePath' | 'filePath' | 'programId'
'programType' | 'externalKey' | 'serverPath' | 'serverFilePath' | 'programId'
>;

export class JellyfinStreamDetails {
Expand Down Expand Up @@ -171,7 +171,7 @@ export class JellyfinStreamDetails {
path: filePath,
};
} else {
const path = details.serverPath ?? item.plexFilePath;
const path = details.serverPath ?? item.serverPath;
if (isNonEmptyString(path)) {
streamSource = new HttpStreamSource(
`${trimEnd(this.server.uri, '/')}/Videos/${trimStart(
Expand Down
9 changes: 3 additions & 6 deletions server/src/stream/plex/PlexStreamDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import {
// The minimum fields we need to get stream details about an item
type PlexItemStreamDetailsQuery = Pick<
ContentBackedStreamLineupItem,
'programType' | 'externalKey' | 'plexFilePath' | 'filePath' | 'programId'
'programType' | 'externalKey' | 'programId' | 'serverPath' | 'serverFilePath'
>;

/**
Expand Down Expand Up @@ -181,7 +181,7 @@ export class PlexStreamDetails {

if (
isNonEmptyString(details.serverPath) &&
details.serverPath !== item.plexFilePath
details.serverPath !== item.serverPath
) {
this.programDB
.updateProgramPlexRatingKey(item.programId, this.server.name, {
Expand Down Expand Up @@ -218,7 +218,7 @@ export class PlexStreamDetails {
path: filePath,
};
} else {
let path = details.serverPath ?? item.plexFilePath;
let path = details.serverPath ?? item.serverPath;

if (isNonEmptyString(path)) {
path = path.startsWith('/') ? path : `/${path}`;
Expand All @@ -228,9 +228,6 @@ export class PlexStreamDetails {
this.server.accessToken
}`,
);
// streamUrl = this.getPlexTranscodeStreamUrl(
// `/library/metadata/${item.externalKey}`,
// );
} else {
throw new Error('Could not resolve stream URL');
}
Expand Down
Loading

0 comments on commit 34224bf

Please sign in to comment.