Files
streamyfin_mirror/utils/jellyfin/media/getStreamUrl.ts
Fredrik Burmester 68d32bd0de wip
2024-10-21 16:05:36 +02:00

168 lines
4.5 KiB
TypeScript

import iosFmp4 from "@/utils/profiles/iosFmp4";
import { Api } from "@jellyfin/sdk";
import {
BaseItemDto,
MediaSourceInfo,
PlaybackInfoResponse,
} from "@jellyfin/sdk/lib/generated-client/models";
import { getMediaInfoApi } from "@jellyfin/sdk/lib/utils/api";
import { getAuthHeaders } from "../jellyfin";
import native from "@/utils/profiles/native";
export const getStreamUrl = async ({
api,
item,
userId,
startTimeTicks = 0,
maxStreamingBitrate,
sessionData,
deviceProfile = native,
audioStreamIndex = 0,
subtitleStreamIndex = undefined,
mediaSourceId,
}: {
api: Api | null | undefined;
item: BaseItemDto | null | undefined;
userId: string | null | undefined;
startTimeTicks: number;
maxStreamingBitrate?: number;
sessionData?: PlaybackInfoResponse | null;
deviceProfile?: any;
audioStreamIndex?: number;
subtitleStreamIndex?: number;
height?: number;
mediaSourceId?: string | null;
}): Promise<{
url: string | null;
sessionId: string | null;
mediaSource: MediaSourceInfo | undefined;
} | null> => {
if (!api || !userId || !item?.Id) {
return null;
}
let mediaSource: MediaSourceInfo | undefined;
let sessionId: string | null | undefined;
if (item.Type === "Program") {
const res0 = await getMediaInfoApi(api).getPlaybackInfo(
{
userId,
itemId: item.ChannelId!,
},
{
method: "POST",
params: {
startTimeTicks: 0,
isPlayback: true,
autoOpenLiveStream: true,
maxStreamingBitrate,
audioStreamIndex,
},
data: {
deviceProfile,
},
}
);
const transcodeUrl = res0.data.MediaSources?.[0].TranscodingUrl;
sessionId = res0.data.PlaySessionId || null;
if (transcodeUrl) {
return {
url: `${api.basePath}${transcodeUrl}`,
sessionId,
mediaSource: res0.data.MediaSources?.[0],
};
}
}
const itemId = item.Id;
const res2 = await getMediaInfoApi(api).getPlaybackInfo(
{
userId,
itemId: item.Id!,
},
{
method: "POST",
data: {
deviceProfile: native,
userId,
maxStreamingBitrate,
startTimeTicks,
autoOpenLiveStream: true,
mediaSourceId,
audioStreamIndex,
subtitleStreamIndex,
},
}
);
sessionId = res2.data.PlaySessionId || null;
mediaSource = res2.data.MediaSources?.find(
(source: MediaSourceInfo) => source.Id === mediaSourceId
);
if (item.MediaType === "Video") {
if (mediaSource?.TranscodingUrl) {
console.log(
"Video has transcoding URL:",
`${api.basePath}${mediaSource.TranscodingUrl}`
);
return {
url: `${api.basePath}${mediaSource.TranscodingUrl}`,
sessionId: sessionId,
mediaSource,
};
}
if (mediaSource?.SupportsDirectPlay) {
console.log(
"Video is being direct played:",
`${api.basePath}/Videos/${itemId}/stream.mp4?playSessionId=${sessionData?.PlaySessionId}&mediaSourceId=${mediaSource?.Id}&static=true&subtitleStreamIndex=${subtitleStreamIndex}&audioStreamIndex=${audioStreamIndex}&deviceId=${api.deviceInfo.id}&api_key=${api.accessToken}`
);
return {
url: `${api.basePath}/Videos/${itemId}/stream.mp4?playSessionId=${sessionData?.PlaySessionId}&mediaSourceId=${mediaSource?.Id}&static=true&subtitleStreamIndex=${subtitleStreamIndex}&audioStreamIndex=${audioStreamIndex}&deviceId=${api.deviceInfo.id}&api_key=${api.accessToken}`,
sessionId: sessionId,
mediaSource,
};
}
}
if (item.MediaType === "Audio") {
if (mediaSource?.TranscodingUrl) {
return {
url: `${api.basePath}${mediaSource.TranscodingUrl}`,
sessionId,
mediaSource,
};
}
const searchParams = new URLSearchParams({
UserId: userId,
DeviceId: api.deviceInfo.id,
MaxStreamingBitrate: "140000000",
Container:
"opus,webm|opus,mp3,aac,m4a|aac,m4b|aac,flac,webma,webm|webma,wav,ogg",
TranscodingContainer: "mp4",
TranscodingProtocol: "hls",
AudioCodec: "aac",
api_key: api.accessToken,
PlaySessionId: sessionData?.PlaySessionId || "",
StartTimeTicks: "0",
EnableRedirection: "true",
EnableRemoteMedia: "false",
});
return {
url: `${
api.basePath
}/Audio/${itemId}/universal?${searchParams.toString()}`,
sessionId,
mediaSource,
};
}
throw new Error("Unsupported media type");
};