import { describe, expect, it } from 'vitest'; import { assessBrowserPlayback, assessGeneratedResultPreview, buildPlaybackMimeCandidates, } from '../../../src/media/browser-playback'; import type { MediaProbe, MediaStreamProbe, } from '../../../src/media/media.types'; import { selectDefaultStreams, streamSelectionMapArgs, validateStreamSelection, } from '../../../src/media/stream-selection'; function stream( index: number, type: MediaStreamProbe['type'], overrides: Partial = {} ): MediaStreamProbe { return { index, type, disposition: {}, tags: {}, ...overrides, }; } function probe(streams: MediaStreamProbe[]): MediaProbe { return { formatNames: ['mov', 'mp4'], tags: {}, streams, chapters: [], warnings: [], }; } describe('stream selection', () => { const media = probe([ stream(0, 'video', { codecName: 'h264' }), stream(1, 'audio', { language: 'eng', disposition: { default: true }, }), stream(2, 'audio', { language: 'de-DE', }), stream(3, 'subtitle', { language: 'deu' }), stream(4, 'video', { disposition: { attached_pic: true } }), ]); it('chooses default streams, avoids cover art and can include subtitles', () => { expect( selectDefaultStreams(media, { preferredAudioLanguages: ['de'], preferredSubtitleLanguages: ['deu'], includeSubtitles: true, }) ).toEqual({ videoStreamIndex: 0, audioStreamIndexes: [2], subtitleStreamIndexes: [3], }); }); it('validates stream existence, type and duplicate mappings', () => { const result = validateStreamSelection(media, { videoStreamIndex: 1, audioStreamIndexes: [2, 2, 99], subtitleStreamIndexes: [], }); expect(result.valid).toBe(false); expect(result.issues.map((issue) => issue.code)).toEqual([ 'wrong-stream-type', 'duplicate-stream', 'stream-not-found', ]); }); it('generates structured map arguments in deterministic order', () => { expect( streamSelectionMapArgs({ videoStreamIndex: 0, audioStreamIndexes: [2], subtitleStreamIndexes: [3], }) ).toEqual(['-map', '0:0', '-map', '0:2', '-map', '0:3']); }); }); describe('browser playback assessment', () => { const mp4 = probe([ stream(0, 'video', { codecName: 'h264' }), stream(1, 'audio', { codecName: 'aac' }), ]); it('builds codec-qualified and container-only MIME candidates', () => { expect(buildPlaybackMimeCandidates(mp4)).toEqual([ 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"', 'video/mp4', ]); }); it('keeps browser support separate from FFmpeg readability', () => { expect( assessBrowserPlayback(mp4, (mime) => mime.includes('codecs') ? 'probably' : '' ) ).toMatchObject({ support: 'probably', needsPreviewProxy: false, }); expect(assessBrowserPlayback(mp4, () => '')).toMatchObject({ support: 'unsupported', needsPreviewProxy: true, }); }); it('does not treat an audio/video MIME prefix as playable when the browser rejects it', () => { expect( assessGeneratedResultPreview( { fileName: 'generated.flac', mimeType: 'audio/flac', }, () => '' ) ).toMatchObject({ kind: 'audio', previewable: false, support: 'unsupported', }); expect( assessGeneratedResultPreview( { fileName: 'generated.mp4', mimeType: 'video/mp4', probe: mp4, }, (mime) => (mime.includes('codecs') ? 'probably' : '') ) ).toMatchObject({ kind: 'video', previewable: true, support: 'probably', }); expect( assessGeneratedResultPreview( { fileName: 'frame.png', mimeType: 'image/png', }, () => '' ) ).toMatchObject({ kind: 'image', previewable: true }); expect( assessGeneratedResultPreview( { fileName: 'frame.tiff', mimeType: 'image/tiff', }, () => '' ) ).toMatchObject({ kind: 'image', previewable: false, support: 'unsupported', }); }); });