feat: MPV player for both Android and iOS with added HW decoding PiP (with subtitles) (#1332)

Co-authored-by: Alex Kim <alexkim@Alexs-MacBook-Pro.local>
Co-authored-by: Alex <111128610+Alexk2309@users.noreply.github.com>
Co-authored-by: Simon-Eklundh <simon.eklundh@proton.me>
This commit is contained in:
Fredrik Burmester
2026-01-10 19:35:27 +01:00
committed by GitHub
parent df2f44e086
commit f1575ca48b
98 changed files with 3257 additions and 7448 deletions

View File

@@ -1,7 +1,7 @@
import type { Api } from "@jellyfin/sdk";
import type { MediaSourceInfo } from "@jellyfin/sdk/lib/generated-client/models";
import { getMediaInfoApi } from "@jellyfin/sdk/lib/utils/api";
import native from "@/utils/profiles/native";
import trackPlayerProfile from "@/utils/profiles/trackplayer";
export interface AudioStreamResult {
url: string;
@@ -26,7 +26,7 @@ export const getAudioStreamUrl = async (
method: "POST",
data: {
userId,
deviceProfile: native,
deviceProfile: trackPlayerProfile,
startTimeTicks: 0,
isPlayback: true,
autoOpenLiveStream: true,

View File

@@ -4,7 +4,10 @@ import type {
MediaSourceInfo,
} from "@jellyfin/sdk/lib/generated-client/models";
import { Bitrate } from "@/components/BitrateSelector";
import { generateDeviceProfile } from "@/utils/profiles/native";
import {
type AudioTranscodeModeType,
generateDeviceProfile,
} from "@/utils/profiles/native";
import { getDownloadStreamUrl, getStreamUrl } from "./getStreamUrl";
export const getDownloadUrl = async ({
@@ -16,6 +19,7 @@ export const getDownloadUrl = async ({
audioStreamIndex,
subtitleStreamIndex,
deviceId,
audioMode = "auto",
}: {
api: Api;
item: BaseItemDto;
@@ -25,6 +29,7 @@ export const getDownloadUrl = async ({
audioStreamIndex: number;
subtitleStreamIndex: number;
deviceId: string;
audioMode?: AudioTranscodeModeType;
}): Promise<{
url: string | null;
mediaSource: MediaSourceInfo | null;
@@ -39,7 +44,7 @@ export const getDownloadUrl = async ({
audioStreamIndex,
subtitleStreamIndex,
deviceId,
deviceProfile: generateDeviceProfile(),
deviceProfile: generateDeviceProfile({ audioMode }),
});
if (maxBitrate.key === "Max" && !streamDetails?.mediaSource?.TranscodingUrl) {
@@ -59,6 +64,7 @@ export const getDownloadUrl = async ({
maxStreamingBitrate: maxBitrate.value,
audioStreamIndex,
subtitleStreamIndex,
audioMode,
});
return {

View File

@@ -5,7 +5,8 @@ import type {
} from "@jellyfin/sdk/lib/generated-client/models";
import { BaseItemKind } from "@jellyfin/sdk/lib/generated-client/models/base-item-kind";
import { getMediaInfoApi } from "@jellyfin/sdk/lib/utils/api";
import download from "@/utils/profiles/download";
import { generateDownloadProfile } from "@/utils/profiles/download";
import type { AudioTranscodeModeType } from "@/utils/profiles/native";
interface StreamResult {
url: string;
@@ -265,6 +266,7 @@ export const getDownloadStreamUrl = async ({
subtitleStreamIndex = undefined,
mediaSourceId,
deviceId,
audioMode = "auto",
}: {
api: Api | null | undefined;
item: BaseItemDto | null | undefined;
@@ -274,6 +276,7 @@ export const getDownloadStreamUrl = async ({
subtitleStreamIndex?: number;
mediaSourceId?: string | null;
deviceId?: string | null;
audioMode?: AudioTranscodeModeType;
}): Promise<{
url: string | null;
sessionId: string | null;
@@ -292,7 +295,7 @@ export const getDownloadStreamUrl = async ({
method: "POST",
data: {
userId,
deviceProfile: download,
deviceProfile: generateDownloadProfile(audioMode),
subtitleStreamIndex,
startTimeTicks: 0,
isPlayback: true,