feat: add yt-dlp argument builder
This commit is contained in:
@@ -0,0 +1,63 @@
|
|||||||
|
import { buildYtdlpArgs } from '../ytdlp'
|
||||||
|
|
||||||
|
const base = {
|
||||||
|
url: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
|
||||||
|
uuid: 'abc-123',
|
||||||
|
format: 'mp4',
|
||||||
|
quality: 'best',
|
||||||
|
subtitles: false,
|
||||||
|
extraArgs: null,
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('buildYtdlpArgs', () => {
|
||||||
|
it('always includes --no-playlist', () => {
|
||||||
|
expect(buildYtdlpArgs(base)).toContain('--no-playlist')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sets output path with uuid and %(ext)s template', () => {
|
||||||
|
const args = buildYtdlpArgs(base)
|
||||||
|
const idx = args.indexOf('-o')
|
||||||
|
expect(idx).toBeGreaterThan(-1)
|
||||||
|
expect(args[idx + 1]).toContain('abc-123')
|
||||||
|
expect(args[idx + 1]).toContain('%(ext)s')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('adds format filter when quality is not "best"', () => {
|
||||||
|
const args = buildYtdlpArgs({ ...base, quality: '1080p' })
|
||||||
|
expect(args).toContain('-f')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not add -f flag when quality is "best"', () => {
|
||||||
|
expect(buildYtdlpArgs(base)).not.toContain('-f')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('adds subtitle flags when subtitles is true', () => {
|
||||||
|
const args = buildYtdlpArgs({ ...base, subtitles: true })
|
||||||
|
expect(args).toContain('--write-sub')
|
||||||
|
expect(args).toContain('--sub-lang')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not add subtitle flags when subtitles is false', () => {
|
||||||
|
expect(buildYtdlpArgs(base)).not.toContain('--write-sub')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('appends extra args from a JSON array string', () => {
|
||||||
|
const args = buildYtdlpArgs({
|
||||||
|
...base,
|
||||||
|
extraArgs: '["--sponsorblock-remove","all"]',
|
||||||
|
})
|
||||||
|
expect(args).toContain('--sponsorblock-remove')
|
||||||
|
expect(args).toContain('all')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('ignores malformed extraArgs JSON', () => {
|
||||||
|
expect(() =>
|
||||||
|
buildYtdlpArgs({ ...base, extraArgs: 'not-json' })
|
||||||
|
).not.toThrow()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('url is the last argument', () => {
|
||||||
|
const args = buildYtdlpArgs(base)
|
||||||
|
expect(args[args.length - 1]).toBe(base.url)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import path from 'path'
|
||||||
|
import { config } from '../../config/app.config'
|
||||||
|
|
||||||
|
export type YtdlpParams = {
|
||||||
|
url: string
|
||||||
|
uuid: string
|
||||||
|
format: string
|
||||||
|
quality: string
|
||||||
|
subtitles: boolean
|
||||||
|
extraArgs: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildYtdlpArgs(params: YtdlpParams): string[] {
|
||||||
|
const { url, uuid, format, quality, subtitles, extraArgs } = params
|
||||||
|
const outputTemplate = path.join(config.STORAGE_PATH, `${uuid}.%(ext)s`)
|
||||||
|
|
||||||
|
const args: string[] = ['--no-playlist', '-o', outputTemplate]
|
||||||
|
|
||||||
|
if (quality !== 'best') {
|
||||||
|
const height = quality.replace('p', '')
|
||||||
|
args.push('-f', `${format}[height<=?${height}]+bestaudio/best[height<=?${height}]`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subtitles) {
|
||||||
|
args.push('--write-sub', '--sub-lang', 'fr,en')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extraArgs) {
|
||||||
|
try {
|
||||||
|
const extra = JSON.parse(extraArgs) as string[]
|
||||||
|
args.push(...extra)
|
||||||
|
} catch {
|
||||||
|
// malformed extraArgs — skip silently
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
args.push(url)
|
||||||
|
return args
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user