Files
streamyfin/utils/trickplay.ts

66 lines
1.8 KiB
TypeScript

import type { BaseItemDto } from "@jellyfin/sdk/lib/generated-client";
import { apiAtom } from "@/providers/JellyfinProvider";
import { store } from "@/utils/store";
import { ticksToMs } from "@/utils/time";
export interface TrickplayInfo {
resolution: string;
aspectRatio: number;
data: any;
totalImageSheets: number;
}
/**
* Parses the trickplay metadata from a BaseItemDto.
* @param item The Jellyfin media item.
* @returns Parsed trickplay information or null if not available.
*/
export const getTrickplayInfo = (item: BaseItemDto): TrickplayInfo | null => {
if (!item.Id || !item.Trickplay) return null;
const mediaSourceId = item.Id;
const trickplayDataForSource = item.Trickplay[mediaSourceId];
if (!trickplayDataForSource) {
return null;
}
const firstResolution = Object.keys(trickplayDataForSource)[0];
if (!firstResolution) {
return null;
}
const data = trickplayDataForSource[firstResolution];
const { Interval, TileWidth, TileHeight, Width, Height } = data;
if (
!Interval ||
!TileWidth ||
!TileHeight ||
!Width ||
!Height ||
!item.RunTimeTicks
) {
return null;
}
const tilesPerSheet = TileWidth * TileHeight;
const totalTiles = Math.ceil(ticksToMs(item.RunTimeTicks) / Interval);
const totalImageSheets = Math.ceil(totalTiles / tilesPerSheet);
return {
resolution: firstResolution,
aspectRatio: Width / Height,
data,
totalImageSheets,
};
};
/** Generates a trickplay URL based on the item, resolution, and sheet index. */
export const generateTrickplayUrl = (item: BaseItemDto, sheetIndex: number) => {
const api = store.get(apiAtom);
const resolution = getTrickplayInfo(item)?.resolution;
if (!resolution || !api) return null;
return `${api.basePath}/Videos/${item.Id}/Trickplay/${resolution}/${sheetIndex}.jpg?api_key=${api.accessToken}`;
};