forked from Ninjalama/streamyfin_mirror
132 lines
3.3 KiB
TypeScript
132 lines
3.3 KiB
TypeScript
import generateDeviceProfile from "@/utils/profiles/native";
|
|
import type { Api } from "@jellyfin/sdk";
|
|
import type {
|
|
BaseItemDto,
|
|
MediaSourceInfo,
|
|
PlaybackInfoResponse,
|
|
} from "@jellyfin/sdk/lib/generated-client/models";
|
|
import { getMediaInfoApi } from "@jellyfin/sdk/lib/utils/api";
|
|
import { Alert } from "react-native";
|
|
|
|
export const getStreamUrl = async ({
|
|
api,
|
|
item,
|
|
userId,
|
|
startTimeTicks = 0,
|
|
maxStreamingBitrate,
|
|
playSessionId,
|
|
deviceProfile = generateDeviceProfile(),
|
|
audioStreamIndex = 0,
|
|
subtitleStreamIndex = undefined,
|
|
mediaSourceId,
|
|
download = false,
|
|
deviceId,
|
|
}: {
|
|
api: Api | null | undefined;
|
|
item: BaseItemDto | null | undefined;
|
|
userId: string | null | undefined;
|
|
startTimeTicks: number;
|
|
maxStreamingBitrate?: number;
|
|
playSessionId?: string | null;
|
|
deviceProfile?: any;
|
|
audioStreamIndex?: number;
|
|
subtitleStreamIndex?: number;
|
|
height?: number;
|
|
mediaSourceId?: string | null;
|
|
download?: bool;
|
|
deviceId?: string | null;
|
|
}): Promise<{
|
|
url: string | null;
|
|
sessionId: string | null;
|
|
mediaSource: MediaSourceInfo | undefined;
|
|
} | null> => {
|
|
if (!api || !userId || !item?.Id) {
|
|
console.warn("Missing required parameters for getStreamUrl");
|
|
return null;
|
|
}
|
|
|
|
let mediaSource: MediaSourceInfo | undefined;
|
|
let sessionId: string | null | undefined;
|
|
|
|
const res = await getMediaInfoApi(api).getPlaybackInfo(
|
|
{
|
|
itemId: item.Id!,
|
|
},
|
|
{
|
|
method: "POST",
|
|
data: {
|
|
userId,
|
|
deviceProfile,
|
|
subtitleStreamIndex,
|
|
startTimeTicks,
|
|
isPlayback: true,
|
|
autoOpenLiveStream: true,
|
|
maxStreamingBitrate,
|
|
audioStreamIndex,
|
|
mediaSourceId,
|
|
},
|
|
},
|
|
);
|
|
|
|
if (res.status !== 200) {
|
|
console.error("Error getting playback info:", res.status, res.statusText);
|
|
}
|
|
|
|
sessionId = res.data.PlaySessionId || null;
|
|
mediaSource = res.data.MediaSources[0];
|
|
let transcodeUrl = mediaSource.TranscodingUrl;
|
|
|
|
if (transcodeUrl) {
|
|
if (download) {
|
|
transcodeUrl = transcodeUrl.replace("master.m3u8", "stream");
|
|
}
|
|
console.log("Video is being transcoded:", transcodeUrl);
|
|
return {
|
|
url: `${api.basePath}${transcodeUrl}`,
|
|
sessionId,
|
|
mediaSource,
|
|
};
|
|
}
|
|
|
|
let downloadParams = {};
|
|
|
|
if (download) {
|
|
// We need to disable static so we can have a remux with subtitle.
|
|
downloadParams = {
|
|
subtitleMethod: "Embed",
|
|
enableSubtitlesInManifest: true,
|
|
static: "false",
|
|
allowVideoStreamCopy: true,
|
|
allowAudioStreamCopy: true,
|
|
playSessionId: sessionId || "",
|
|
container: "ts",
|
|
};
|
|
}
|
|
|
|
const streamParams = new URLSearchParams({
|
|
static: "true",
|
|
container: "mp4",
|
|
mediaSourceId: mediaSource?.Id || "",
|
|
subtitleStreamIndex: subtitleStreamIndex?.toString() || "",
|
|
audioStreamIndex: audioStreamIndex?.toString() || "",
|
|
deviceId: deviceId || api.deviceInfo.id,
|
|
api_key: api.accessToken,
|
|
startTimeTicks: startTimeTicks.toString(),
|
|
maxStreamingBitrate: maxStreamingBitrate?.toString() || "",
|
|
userId: userId || "",
|
|
...downloadParams,
|
|
});
|
|
|
|
const directPlayUrl = `${
|
|
api.basePath
|
|
}/Videos/${item.Id}/stream?${streamParams.toString()}`;
|
|
|
|
console.log("Video is being direct played:", directPlayUrl);
|
|
|
|
return {
|
|
url: directPlayUrl,
|
|
sessionId: sessionId || playSessionId,
|
|
mediaSource,
|
|
};
|
|
};
|