refactor: use extend in program schemas instead of omit

seems to positively impact compile time
This commit is contained in:
Christian Benincasa
2026-02-13 21:11:38 -05:00
parent ebaf084413
commit d54a728d2f
7 changed files with 2532 additions and 2460 deletions

File diff suppressed because one or more lines are too long

View File

@@ -367,7 +367,7 @@ export class LocalTvShowScanner extends FileSystemScanner {
continue;
}
const seasonMetadata = this.seasonForNumber(show, seasonNumber);
const seasonMetadata = this.seasonForNumber(seasonNumber);
const season: SeasonWithShow = {
...seasonMetadata,
@@ -460,7 +460,6 @@ export class LocalTvShowScanner extends FileSystemScanner {
);
const seasonMetadata = this.seasonForNumber(
show,
seasonNumber,
episodeFiles.length,
);
@@ -997,7 +996,6 @@ export class LocalTvShowScanner extends FileSystemScanner {
}
private seasonForNumber(
show: Show,
seasonNumber: number,
episodeFileCount?: number,
): SeasonMetadata {
@@ -1024,7 +1022,6 @@ export class LocalTvShowScanner extends FileSystemScanner {
sortTitle: `season ${seasonNumber.toString().padStart(4)}`,
// mediaSourceId: '',
childCount: episodeFileCount,
show,
artwork: [], // Added later
};
}

View File

@@ -406,14 +406,14 @@ describe('StreamProgramCalculator', () => {
),
);
const channel = createChannel({
const channel = createChannelOrm({
uuid: channelId,
number: 1,
startTime: +startTime.subtract(1, 'hour'),
duration: sumBy(lineup, ({ durationMs }) => durationMs),
});
when(channelDB.getChannel(1)).thenReturn(Promise.resolve(channel));
when(channelDB.getChannelOrm(1)).thenReturn(Promise.resolve(channel));
when(channelDB.loadLineup(channelId)).thenReturn(
Promise.resolve({
@@ -516,14 +516,14 @@ describe('StreamProgramCalculator', () => {
),
);
const channel = createChannel({
const channel = createChannelOrm({
uuid: channelId,
number: 1,
startTime: +startTime.subtract(1, 'hour'),
duration: sumBy(lineup, ({ durationMs }) => durationMs),
});
when(channelDB.getChannel(1)).thenReturn(Promise.resolve(channel));
when(channelDB.getChannelOrm(1)).thenReturn(Promise.resolve(channel));
when(channelDB.loadLineup(channelId)).thenReturn(
Promise.resolve({

View File

@@ -318,11 +318,19 @@ export const Director = z.object({
export const Genre = NamedEntity;
export const Studio = NamedEntity;
const HasMediaSourceAndLibraryId = z.object({
const WithMediaSourceDetails = z.object({
mediaSourceId: z.string(),
libraryId: z.string(),
});
const WithTunarrMetadata = z.object({
...WithMediaSourceDetails.shape,
canonicalId: z.string(),
externalId: z
.string()
.describe('Unique identifier for this item in the external media source'),
});
const WithSummaryMetadata = z.object({
summary: z.string().nullable(),
plot: z.string().nullable(),
@@ -337,12 +345,11 @@ export const IdentifierSchema = z.object({
const BaseItem = z.object({
uuid: z.uuid(),
canonicalId: z.string(),
sourceType: SourceTypeSchema,
// externalLibraryId: z.string(),
externalId: z
.string()
.describe('Unique identifier for this item in the external media source'),
// externalId: z
// .string()
// .describe('Unique identifier for this item in the external media source'),
// TODO: break out gropuing types to separate schema
type: z.enum([
...ContentProgramTypeSchema.options,
@@ -355,7 +362,7 @@ const BaseItem = z.object({
title: z.string(),
sortTitle: z.string(),
tags: z.array(z.string()),
...HasMediaSourceAndLibraryId.shape,
// ...HasMediaSourceAndLibraryId.shape,
});
const BaseMediaLocation = z.object({
@@ -465,6 +472,11 @@ export const MediaItem = z.object({
scanKind: z.enum(['unknown', 'progressive', 'interlaced']).nullish(),
});
const WithMediaItemMetadata = z.object({
mediaItem: MediaItem.optional(),
duration: z.number(),
});
const BaseProgram = z.object({
...BaseItem.shape,
type: ContentProgramTypeSchema,
@@ -473,36 +485,31 @@ const BaseProgram = z.object({
year: z.number().positive().nullable(),
releaseDate: z.number().nullable().describe('Epoch timestamp'),
releaseDateString: z.string().nullable(),
mediaItem: MediaItem.optional(),
actors: z.array(Actor).optional(),
writers: z.array(Writer).optional(),
directors: z.array(Director).optional(),
genres: z.array(Genre).optional(),
studios: z.array(Studio).optional(),
duration: z.number(),
externalSubtitles: z.array(MediaSubtitles).nullish(),
artwork: MediaArtwork.array(),
state: z.enum(['ok', 'missing']),
// mediaItem: MediaItem.optional(),
// duration: z.number(),
});
export const Movie = z.object({
export const MovieMetadata = z.object({
...BaseProgram.shape,
...WithSummaryMetadata.shape,
type: z.literal('movie'),
rating: z.string().nullable(),
});
const MetadataOmitMask = {
mediaItem: true,
mediaSourceId: true,
libraryId: true,
externalLibraryId: true,
canonicalId: true,
duration: true,
externalId: true,
} as const;
const WithFullDetails = z.object({
...WithTunarrMetadata.shape,
...WithMediaItemMetadata.shape,
});
export const MovieMetadata = Movie.omit(MetadataOmitMask);
export const Movie = MovieMetadata.extend(WithFullDetails.shape);
const BaseProgramGrouping = z.object({
...BaseItem.shape,
@@ -515,7 +522,7 @@ const BaseProgramGrouping = z.object({
artwork: MediaArtwork.array(),
});
export const Show = z.object({
export const ShowMetadata = z.object({
...BaseProgramGrouping.shape,
type: z.literal('show'),
genres: z.array(Genre),
@@ -525,20 +532,12 @@ export const Show = z.object({
releaseDate: z.number().nullable(),
releaseDateString: z.string().nullable(),
year: z.number().positive().nullable(),
get seasons(): z.ZodOptional<z.ZodArray<typeof BaseSeason>> {
get seasons(): z.ZodOptional<z.ZodArray<typeof _SeasonWithTunarrMetadata>> {
return z.array(Season).optional();
},
});
const BaseSeason = z.object({
...BaseProgramGrouping.shape,
type: z.literal('season'),
studios: z.array(Studio),
index: z.number().nonnegative(),
year: z.number().positive().nullable(),
releaseDate: z.number().nullable(),
releaseDateString: z.string().nullable(),
});
export const Show = ShowMetadata.extend(WithTunarrMetadata.shape);
const BaseEpisode = z.object({
...BaseProgram.shape,
@@ -549,19 +548,33 @@ const BaseEpisode = z.object({
summary: z.string().nullable(),
});
export const Season = z.object({
const BaseEpisodeWithoutJoins = BaseEpisode.extend(
WithTunarrMetadata.shape,
).extend(WithMediaItemMetadata.shape);
export const SeasonMetadata = z.object({
...BaseProgramGrouping.shape,
...BaseSeason.shape,
type: z.literal('season'),
studios: z.array(Studio),
index: z.number().nonnegative(),
year: z.number().positive().nullable(),
releaseDate: z.number().nullable(),
releaseDateString: z.string().nullable(),
});
const _SeasonWithTunarrMetadata = SeasonMetadata.extend(
WithTunarrMetadata.shape,
);
export const Season = SeasonMetadata.extend(WithTunarrMetadata.shape).extend({
get show(): z.ZodOptional<typeof Show> {
return z.optional(Show);
},
get episodes(): z.ZodOptional<z.ZodArray<typeof BaseEpisode>> {
return z.optional(z.array(BaseEpisode));
get episodes(): z.ZodOptional<z.ZodArray<typeof BaseEpisodeWithoutJoins>> {
return z.optional(z.array(BaseEpisodeWithoutJoins));
},
});
export const ShowMetadata = Show.omit(MetadataOmitMask);
export const SeasonMetadata = Season.omit(MetadataOmitMask);
export const SeasonWithShow = z.object({
...Season.shape,
// We have to override this way because of the
@@ -572,28 +585,29 @@ export const SeasonWithShow = z.object({
},
});
export const Episode = z.object({
export const EpisodeMetadata = z.object({
...BaseProgram.shape,
...BaseEpisode.shape,
season: Season.optional(),
show: Show.optional(),
});
export const EpisodeMetadata = Episode.omit(MetadataOmitMask);
export const Episode = EpisodeMetadata.extend(WithFullDetails.shape);
export const EpisodeWithHierarchy = z.object({
...Episode.shape,
season: SeasonWithShow,
});
export const MusicArtist = z.object({
export const MusicArtistMetadata = z.object({
...BaseProgramGrouping.shape,
type: z.literal('artist'),
get albums(): z.ZodOptional<z.ZodArray<typeof BaseMusicAlbum>> {
return z.optional(z.array(BaseMusicAlbum));
get albums(): z.ZodOptional<z.ZodArray<typeof BaseMusicAlbumWithoutJoins>> {
return z.optional(z.array(BaseMusicAlbumWithoutJoins));
},
});
export const MusicArtistMetadata = MusicArtist.omit(MetadataOmitMask);
export const MusicArtist = MusicArtistMetadata.extend(WithTunarrMetadata.shape);
const BaseMusicAlbum = z.object({
...BaseProgramGrouping.shape,
@@ -605,30 +619,36 @@ const BaseMusicAlbum = z.object({
studios: z.array(Studio).optional(),
});
const BaseMusicAlbumWithoutJoins = BaseMusicAlbum.extend(
WithTunarrMetadata.shape,
);
export const MusicAlbumMetadata = z.object({
...BaseProgramGrouping.shape,
...BaseMusicAlbum.shape,
artist: MusicArtist.optional(),
get tracks(): z.ZodOptional<z.ZodArray<typeof BaseMusicTrackWithoutJoins>> {
return z.optional(z.array(BaseMusicTrackWithoutJoins));
},
});
export const MusicAlbum = MusicAlbumMetadata.extend(WithTunarrMetadata.shape);
const BaseMusicTrack = z.object({
...BaseProgram.shape,
type: z.literal('track'),
trackNumber: z.number().nonnegative(),
});
export const MusicAlbum = z.object({
...BaseProgramGrouping.shape,
...BaseMusicAlbum.shape,
artist: MusicArtist.optional(),
get tracks(): z.ZodOptional<z.ZodArray<typeof BaseMusicTrack>> {
return z.optional(z.array(BaseMusicTrack));
},
});
const BaseMusicTrackWithoutJoins = BaseMusicTrack.extend(WithFullDetails.shape);
export const MusicAlbumMetadata = MusicAlbum.omit(MetadataOmitMask);
export const MusicTrack = z.object({
export const MusicTrackMetadata = z.object({
...BaseMusicTrack.shape,
album: MusicAlbum.optional(),
artist: MusicArtist.optional(),
});
export const MusicTrackMetadata = MusicTrack.omit(MetadataOmitMask);
export const MusicTrack = MusicTrackMetadata.extend(WithFullDetails.shape);
export const MusicAlbumWithArtist = MusicAlbum.required({ artist: true });
@@ -637,15 +657,21 @@ export const MusicTrackWithHierarchy = z.object({
album: MusicAlbumWithArtist,
});
export const MusicVideo = BaseProgram.extend({
export const MusicVideo = z.object({
...BaseProgram.shape,
...WithTunarrMetadata.shape,
...WithMediaItemMetadata.shape,
type: z.literal('music_video'),
});
export const OtherVideo = BaseProgram.extend({
export const OtherVideoMetadata = z.object({
...BaseProgram.shape,
type: z.literal('other_video'),
});
export const OtherVideoMetadata = OtherVideo.omit(MetadataOmitMask);
export const OtherVideo = OtherVideoMetadata.extend(
WithTunarrMetadata.shape,
).extend(WithMediaItemMetadata.shape);
export const HasMediaSourceInfo = z.object({
sourceType: MediaSourceType,
@@ -679,19 +705,19 @@ export const BaseStructuralGrouping = z.object({
export const Folder = z.object({
...BaseStructuralGrouping.shape,
...HasMediaSourceAndLibraryId.shape,
...WithMediaSourceDetails.shape,
type: z.literal('folder'),
});
export const Collection = z.object({
...BaseStructuralGrouping.shape,
...HasMediaSourceAndLibraryId.shape,
...WithMediaSourceDetails.shape,
type: z.literal('collection'),
});
export const Playlist = z.object({
...BaseStructuralGrouping.shape,
...HasMediaSourceAndLibraryId.shape,
...WithMediaSourceDetails.shape,
type: z.literal('playlist'),
});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff