fix: new video player subtitle files were missing folder arg
This commit is contained in:
parent
cca97d9a57
commit
2ab0db93dc
3 changed files with 44 additions and 13 deletions
|
|
@ -429,6 +429,7 @@ let hls: Hls | null = null;
|
||||||
|
|
||||||
const isApple = /(iPhone|iPod|iPad).*AppleWebKit/i.test(navigator.userAgent);
|
const isApple = /(iPhone|iPod|iPad).*AppleWebKit/i.test(navigator.userAgent);
|
||||||
const mediaFile = computed(() => props.item.filename || '');
|
const mediaFile = computed(() => props.item.filename || '');
|
||||||
|
const subtitleManifestUrl = computed(() => currentPlaybackUrl('api/player/subtitles/manifest'));
|
||||||
const canPlay = computed(() => Boolean(mediaFile.value && !loadingError.value));
|
const canPlay = computed(() => Boolean(mediaFile.value && !loadingError.value));
|
||||||
const shouldRender = computed(() => active.value && !loading.value);
|
const shouldRender = computed(() => active.value && !loading.value);
|
||||||
const isPlaying = computed(() => !paused.value);
|
const isPlaying = computed(() => !paused.value);
|
||||||
|
|
@ -456,7 +457,7 @@ const {
|
||||||
usesAssSubtitleTrack,
|
usesAssSubtitleTrack,
|
||||||
hasSubtitles,
|
hasSubtitles,
|
||||||
} = usePlayerSubtitles({
|
} = usePlayerSubtitles({
|
||||||
mediaFile,
|
manifestUrl: subtitleManifestUrl,
|
||||||
isVideo: computed(() => !isAudio.value),
|
isVideo: computed(() => !isAudio.value),
|
||||||
canPlay,
|
canPlay,
|
||||||
shouldRender,
|
shouldRender,
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import {
|
||||||
toValue,
|
toValue,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
import type { SubtitleManifestResponse, SubtitleTrack } from '~/types/subtitles';
|
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 = {
|
type AssRendererInstance = {
|
||||||
destroy(): unknown;
|
destroy(): unknown;
|
||||||
|
|
@ -22,7 +22,7 @@ type AssRendererConstructor = new (
|
||||||
) => AssRendererInstance;
|
) => AssRendererInstance;
|
||||||
|
|
||||||
type UsePlayerSubtitlesOptions = {
|
type UsePlayerSubtitlesOptions = {
|
||||||
mediaFile: MaybeRefOrGetter<string>;
|
manifestUrl: MaybeRefOrGetter<string>;
|
||||||
isVideo: MaybeRefOrGetter<boolean>;
|
isVideo: MaybeRefOrGetter<boolean>;
|
||||||
canPlay: MaybeRefOrGetter<boolean>;
|
canPlay: MaybeRefOrGetter<boolean>;
|
||||||
shouldRender: MaybeRefOrGetter<boolean>;
|
shouldRender: MaybeRefOrGetter<boolean>;
|
||||||
|
|
@ -74,7 +74,7 @@ export function usePlayerSubtitles(options: UsePlayerSubtitlesOptions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadTracks() {
|
async function loadTracks() {
|
||||||
const mediaFile = toValue(options.mediaFile);
|
const manifestUrl = toValue(options.manifestUrl);
|
||||||
const isVideo = toValue(options.isVideo);
|
const isVideo = toValue(options.isVideo);
|
||||||
const canPlay = toValue(options.canPlay);
|
const canPlay = toValue(options.canPlay);
|
||||||
const requestId = ++subtitleRequestId;
|
const requestId = ++subtitleRequestId;
|
||||||
|
|
@ -84,7 +84,7 @@ export function usePlayerSubtitles(options: UsePlayerSubtitlesOptions) {
|
||||||
tracks.value = [];
|
tracks.value = [];
|
||||||
subtitleLoadError.value = '';
|
subtitleLoadError.value = '';
|
||||||
|
|
||||||
if (!mediaFile || !isVideo || !canPlay) {
|
if (!manifestUrl || !isVideo || !canPlay) {
|
||||||
subtitleLoading.value = false;
|
subtitleLoading.value = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -92,7 +92,7 @@ export function usePlayerSubtitles(options: UsePlayerSubtitlesOptions) {
|
||||||
subtitleLoading.value = true;
|
subtitleLoading.value = true;
|
||||||
|
|
||||||
try {
|
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 };
|
const payload = (await res.json()) as SubtitleManifestResponse | { error?: string };
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
throw new Error(await parse_api_error(payload));
|
throw new Error(await parse_api_error(payload));
|
||||||
|
|
@ -176,7 +176,7 @@ export function usePlayerSubtitles(options: UsePlayerSubtitlesOptions) {
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => [toValue(options.mediaFile), toValue(options.isVideo), toValue(options.canPlay)],
|
() => [toValue(options.manifestUrl), toValue(options.isVideo), toValue(options.canPlay)],
|
||||||
() => {
|
() => {
|
||||||
void loadTracks();
|
void loadTracks();
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ describe('usePlayerSubtitles', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
const { usePlayerSubtitles } = await import('~/composables/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 isVideo = ref(true);
|
||||||
const canPlay = ref(true);
|
const canPlay = ref(true);
|
||||||
const shouldRender = ref(false);
|
const shouldRender = ref(false);
|
||||||
|
|
@ -123,7 +123,7 @@ describe('usePlayerSubtitles', () => {
|
||||||
|
|
||||||
const { hasSubtitles, nativeSubtitleTrack, selectedSubtitleTrack, usesAssSubtitleTrack } =
|
const { hasSubtitles, nativeSubtitleTrack, selectedSubtitleTrack, usesAssSubtitleTrack } =
|
||||||
usePlayerSubtitles({
|
usePlayerSubtitles({
|
||||||
mediaFile,
|
manifestUrl,
|
||||||
isVideo,
|
isVideo,
|
||||||
canPlay,
|
canPlay,
|
||||||
shouldRender,
|
shouldRender,
|
||||||
|
|
@ -140,6 +140,36 @@ describe('usePlayerSubtitles', () => {
|
||||||
expect(usesAssSubtitleTrack.value).toBe(false);
|
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 () => {
|
it('creates and destroys an ASS renderer for ASS subtitles when playback becomes active', async () => {
|
||||||
fetchMock.mockResolvedValueOnce(
|
fetchMock.mockResolvedValueOnce(
|
||||||
createMockResponse({
|
createMockResponse({
|
||||||
|
|
@ -164,7 +194,7 @@ describe('usePlayerSubtitles', () => {
|
||||||
const loadRenderer = mock(async () => assConstructorMock as any);
|
const loadRenderer = mock(async () => assConstructorMock as any);
|
||||||
|
|
||||||
const { usePlayerSubtitles } = await import('~/composables/usePlayerSubtitles');
|
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 isVideo = ref(true);
|
||||||
const canPlay = ref(true);
|
const canPlay = ref(true);
|
||||||
const shouldRender = ref(false);
|
const shouldRender = ref(false);
|
||||||
|
|
@ -172,7 +202,7 @@ describe('usePlayerSubtitles', () => {
|
||||||
const overlay = ref<HTMLElement | null>(document.createElement('div'));
|
const overlay = ref<HTMLElement | null>(document.createElement('div'));
|
||||||
|
|
||||||
const { usesAssSubtitleTrack } = usePlayerSubtitles({
|
const { usesAssSubtitleTrack } = usePlayerSubtitles({
|
||||||
mediaFile,
|
manifestUrl,
|
||||||
isVideo,
|
isVideo,
|
||||||
canPlay,
|
canPlay,
|
||||||
shouldRender,
|
shouldRender,
|
||||||
|
|
@ -195,7 +225,7 @@ describe('usePlayerSubtitles', () => {
|
||||||
expect(assConstructorMock).toHaveBeenCalledTimes(1);
|
expect(assConstructorMock).toHaveBeenCalledTimes(1);
|
||||||
expect(assShowMock).toHaveBeenCalledTimes(1);
|
expect(assShowMock).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
mediaFile.value = 'second.mkv';
|
manifestUrl.value = '/api/player/subtitles/manifest/second.mkv';
|
||||||
fetchMock.mockResolvedValueOnce(
|
fetchMock.mockResolvedValueOnce(
|
||||||
createMockResponse({
|
createMockResponse({
|
||||||
ok: true,
|
ok: true,
|
||||||
|
|
@ -235,7 +265,7 @@ describe('usePlayerSubtitles', () => {
|
||||||
const assLayoutVersion = ref(0);
|
const assLayoutVersion = ref(0);
|
||||||
|
|
||||||
usePlayerSubtitles({
|
usePlayerSubtitles({
|
||||||
mediaFile: ref('video.mkv'),
|
manifestUrl: ref('/api/player/subtitles/manifest/video.mkv'),
|
||||||
isVideo: ref(true),
|
isVideo: ref(true),
|
||||||
canPlay: ref(true),
|
canPlay: ref(true),
|
||||||
shouldRender: ref(true),
|
shouldRender: ref(true),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue