fix: new video player subtitle files were missing folder arg

This commit is contained in:
arabcoders 2026-05-04 21:53:13 +03:00
parent cca97d9a57
commit 2ab0db93dc
3 changed files with 44 additions and 13 deletions

View file

@ -429,6 +429,7 @@ let hls: Hls | null = null;
const isApple = /(iPhone|iPod|iPad).*AppleWebKit/i.test(navigator.userAgent);
const mediaFile = computed(() => props.item.filename || '');
const subtitleManifestUrl = computed(() => currentPlaybackUrl('api/player/subtitles/manifest'));
const canPlay = computed(() => Boolean(mediaFile.value && !loadingError.value));
const shouldRender = computed(() => active.value && !loading.value);
const isPlaying = computed(() => !paused.value);
@ -456,7 +457,7 @@ const {
usesAssSubtitleTrack,
hasSubtitles,
} = usePlayerSubtitles({
mediaFile,
manifestUrl: subtitleManifestUrl,
isVideo: computed(() => !isAudio.value),
canPlay,
shouldRender,

View file

@ -8,7 +8,7 @@ import {
toValue,
} from 'vue';
import type { SubtitleManifestResponse, SubtitleTrack } from '~/types/subtitles';
import { encodePath, parse_api_error, request, uri } from '~/utils';
import { parse_api_error, request } from '~/utils';
type AssRendererInstance = {
destroy(): unknown;
@ -22,7 +22,7 @@ type AssRendererConstructor = new (
) => AssRendererInstance;
type UsePlayerSubtitlesOptions = {
mediaFile: MaybeRefOrGetter<string>;
manifestUrl: MaybeRefOrGetter<string>;
isVideo: MaybeRefOrGetter<boolean>;
canPlay: MaybeRefOrGetter<boolean>;
shouldRender: MaybeRefOrGetter<boolean>;
@ -74,7 +74,7 @@ export function usePlayerSubtitles(options: UsePlayerSubtitlesOptions) {
}
async function loadTracks() {
const mediaFile = toValue(options.mediaFile);
const manifestUrl = toValue(options.manifestUrl);
const isVideo = toValue(options.isVideo);
const canPlay = toValue(options.canPlay);
const requestId = ++subtitleRequestId;
@ -84,7 +84,7 @@ export function usePlayerSubtitles(options: UsePlayerSubtitlesOptions) {
tracks.value = [];
subtitleLoadError.value = '';
if (!mediaFile || !isVideo || !canPlay) {
if (!manifestUrl || !isVideo || !canPlay) {
subtitleLoading.value = false;
return;
}
@ -92,7 +92,7 @@ export function usePlayerSubtitles(options: UsePlayerSubtitlesOptions) {
subtitleLoading.value = true;
try {
const res = await request(uri(`/api/player/subtitles/manifest/${encodePath(mediaFile)}`));
const res = await request(manifestUrl);
const payload = (await res.json()) as SubtitleManifestResponse | { error?: string };
if (!res.ok) {
throw new Error(await parse_api_error(payload));
@ -176,7 +176,7 @@ export function usePlayerSubtitles(options: UsePlayerSubtitlesOptions) {
}
watch(
() => [toValue(options.mediaFile), toValue(options.isVideo), toValue(options.canPlay)],
() => [toValue(options.manifestUrl), toValue(options.isVideo), toValue(options.canPlay)],
() => {
void loadTracks();
},

View file

@ -114,7 +114,7 @@ describe('usePlayerSubtitles', () => {
);
const { usePlayerSubtitles } = await import('~/composables/usePlayerSubtitles');
const mediaFile = ref('video file.mkv');
const manifestUrl = ref('/api/player/subtitles/manifest/video%20file.mkv');
const isVideo = ref(true);
const canPlay = ref(true);
const shouldRender = ref(false);
@ -123,7 +123,7 @@ describe('usePlayerSubtitles', () => {
const { hasSubtitles, nativeSubtitleTrack, selectedSubtitleTrack, usesAssSubtitleTrack } =
usePlayerSubtitles({
mediaFile,
manifestUrl,
isVideo,
canPlay,
shouldRender,
@ -140,6 +140,36 @@ describe('usePlayerSubtitles', () => {
expect(usesAssSubtitleTrack.value).toBe(false);
});
it('uses the provided full manifest path including folders', async () => {
fetchMock.mockResolvedValueOnce(
createMockResponse({
ok: true,
status: 200,
jsonData: { subtitles: [] },
}),
);
const { usePlayerSubtitles } = await import('~/composables/usePlayerSubtitles');
usePlayerSubtitles({
manifestUrl: ref(
'/api/player/subtitles/manifest/youtube/Channel%20Name/Season%202026/video%20file.mkv',
),
isVideo: ref(true),
canPlay: ref(true),
shouldRender: ref(false),
video: ref<HTMLVideoElement | null>(document.createElement('video')),
overlay: ref<HTMLElement | null>(document.createElement('div')),
});
await flushPromises();
expect(fetchMock).toHaveBeenCalledWith(
'/api/player/subtitles/manifest/youtube/Channel%20Name/Season%202026/video%20file.mkv',
expect.anything(),
);
});
it('creates and destroys an ASS renderer for ASS subtitles when playback becomes active', async () => {
fetchMock.mockResolvedValueOnce(
createMockResponse({
@ -164,7 +194,7 @@ describe('usePlayerSubtitles', () => {
const loadRenderer = mock(async () => assConstructorMock as any);
const { usePlayerSubtitles } = await import('~/composables/usePlayerSubtitles');
const mediaFile = ref('video.mkv');
const manifestUrl = ref('/api/player/subtitles/manifest/video.mkv');
const isVideo = ref(true);
const canPlay = ref(true);
const shouldRender = ref(false);
@ -172,7 +202,7 @@ describe('usePlayerSubtitles', () => {
const overlay = ref<HTMLElement | null>(document.createElement('div'));
const { usesAssSubtitleTrack } = usePlayerSubtitles({
mediaFile,
manifestUrl,
isVideo,
canPlay,
shouldRender,
@ -195,7 +225,7 @@ describe('usePlayerSubtitles', () => {
expect(assConstructorMock).toHaveBeenCalledTimes(1);
expect(assShowMock).toHaveBeenCalledTimes(1);
mediaFile.value = 'second.mkv';
manifestUrl.value = '/api/player/subtitles/manifest/second.mkv';
fetchMock.mockResolvedValueOnce(
createMockResponse({
ok: true,
@ -235,7 +265,7 @@ describe('usePlayerSubtitles', () => {
const assLayoutVersion = ref(0);
usePlayerSubtitles({
mediaFile: ref('video.mkv'),
manifestUrl: ref('/api/player/subtitles/manifest/video.mkv'),
isVideo: ref(true),
canPlay: ref(true),
shouldRender: ref(true),