Format code with Prettier (8 modified files from H1 decomposition)
Aligns with CC2 enforcement: ESLint + Prettier + noImplicitAny now enforced. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -39,7 +39,7 @@ function build(
|
||||
access: AccessOptions = NO_ACCESS,
|
||||
extraArgs: string[] = []
|
||||
): string[] {
|
||||
return buildArgs(o, OUT, d, BIN, access, extraArgs)
|
||||
return buildArgs({ opts: o, outputTemplate: OUT, options: d, binDir: BIN, access, extraArgs })
|
||||
}
|
||||
|
||||
/** True when `seq` appears as a contiguous run inside `argv`. */
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
// Import from the pure utility module directly — no Zustand store init needed (L40).
|
||||
import { looksLikeUrl, looksLikeSingleVideo, youtubeId } from '../src/renderer/src/lib/urlHelpers'
|
||||
import {
|
||||
looksLikeUrl,
|
||||
looksLikeSingleVideo,
|
||||
looksLikeChannelOrPlaylist,
|
||||
youtubeId
|
||||
} from '../src/renderer/src/lib/urlHelpers'
|
||||
|
||||
describe('youtubeId', () => {
|
||||
it('extracts the id from a watch URL', () => {
|
||||
@@ -103,3 +108,37 @@ describe('looksLikeSingleVideo', () => {
|
||||
expect(looksLikeSingleVideo('')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('looksLikeChannelOrPlaylist', () => {
|
||||
it('flags YouTube channel URLs', () => {
|
||||
expect(looksLikeChannelOrPlaylist('https://www.youtube.com/@SomeChannel')).toBe(true)
|
||||
expect(looksLikeChannelOrPlaylist('https://www.youtube.com/@SomeChannel/videos')).toBe(true)
|
||||
expect(looksLikeChannelOrPlaylist('https://www.youtube.com/channel/UC123')).toBe(true)
|
||||
expect(looksLikeChannelOrPlaylist('https://www.youtube.com/c/SomeChannel')).toBe(true)
|
||||
expect(looksLikeChannelOrPlaylist('https://www.youtube.com/user/SomeUser')).toBe(true)
|
||||
expect(looksLikeChannelOrPlaylist('https://m.youtube.com/@SomeChannel')).toBe(true)
|
||||
})
|
||||
|
||||
it('flags a dedicated playlist page', () => {
|
||||
expect(looksLikeChannelOrPlaylist('https://www.youtube.com/playlist?list=PL123')).toBe(true)
|
||||
expect(looksLikeChannelOrPlaylist('https://music.youtube.com/playlist?list=PL123')).toBe(true)
|
||||
})
|
||||
|
||||
it('does not flag single videos, even inside a playlist context', () => {
|
||||
// A /watch video belongs in the Downloads bar, not the Library — even with a list.
|
||||
expect(looksLikeChannelOrPlaylist('https://www.youtube.com/watch?v=abc')).toBe(false)
|
||||
expect(looksLikeChannelOrPlaylist('https://www.youtube.com/watch?v=abc&list=PL123')).toBe(false)
|
||||
expect(looksLikeChannelOrPlaylist('https://youtu.be/dQw4w9WgXcQ')).toBe(false)
|
||||
})
|
||||
|
||||
it('does not flag non-YouTube hosts or a bare playlist path without a list', () => {
|
||||
expect(looksLikeChannelOrPlaylist('https://vimeo.com/channels/staffpicks')).toBe(false)
|
||||
expect(looksLikeChannelOrPlaylist('https://example.com/@handle')).toBe(false)
|
||||
expect(looksLikeChannelOrPlaylist('https://www.youtube.com/playlist')).toBe(false)
|
||||
})
|
||||
|
||||
it('returns false for non-URLs', () => {
|
||||
expect(looksLikeChannelOrPlaylist('not a url')).toBe(false)
|
||||
expect(looksLikeChannelOrPlaylist('')).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -154,7 +154,13 @@ describe.skipIf(!RUN)('real yt-dlp downloads (buildArgs end-to-end)', () => {
|
||||
embedThumbnail: true,
|
||||
cropThumbnail: true
|
||||
}
|
||||
const argv = buildArgs(opts, join(outDir, '%(id)s.%(ext)s'), options, BIN_DIR, NO_ACCESS)
|
||||
const argv = buildArgs({
|
||||
opts,
|
||||
outputTemplate: join(outDir, '%(id)s.%(ext)s'),
|
||||
options,
|
||||
binDir: BIN_DIR,
|
||||
access: NO_ACCESS
|
||||
})
|
||||
console.log('[crop] argv:', JSON.stringify(argv))
|
||||
|
||||
const res = runYtdlp(argv)
|
||||
@@ -191,7 +197,13 @@ describe.skipIf(!RUN)('real yt-dlp downloads (buildArgs end-to-end)', () => {
|
||||
sponsorBlockMode: 'remove' as const,
|
||||
sponsorBlockCategories: ['music_offtopic' as const]
|
||||
}
|
||||
const argv = buildArgs(opts, join(outDir, '%(id)s.%(ext)s'), options, BIN_DIR, NO_ACCESS)
|
||||
const argv = buildArgs({
|
||||
opts,
|
||||
outputTemplate: join(outDir, '%(id)s.%(ext)s'),
|
||||
options,
|
||||
binDir: BIN_DIR,
|
||||
access: NO_ACCESS
|
||||
})
|
||||
console.log('[sb] argv:', JSON.stringify(argv))
|
||||
|
||||
const res = runYtdlp(argv)
|
||||
@@ -219,7 +231,13 @@ describe.skipIf(!RUN)('real yt-dlp downloads (buildArgs end-to-end)', () => {
|
||||
audioFormat: 'opus' as const,
|
||||
embedThumbnail: false
|
||||
}
|
||||
const argv = buildArgs(opts, join(outDir, '%(id)s.%(ext)s'), options, BIN_DIR, NO_ACCESS)
|
||||
const argv = buildArgs({
|
||||
opts,
|
||||
outputTemplate: join(outDir, '%(id)s.%(ext)s'),
|
||||
options,
|
||||
binDir: BIN_DIR,
|
||||
access: NO_ACCESS
|
||||
})
|
||||
const res = runYtdlp(argv)
|
||||
if (res.status !== 0) console.error('[opus] stderr:\n' + res.stderr)
|
||||
expect(res.status, 'yt-dlp should exit 0').toBe(0)
|
||||
@@ -248,7 +266,13 @@ describe.skipIf(!RUN)('real yt-dlp downloads (buildArgs end-to-end)', () => {
|
||||
preferredVideoCodec: 'vp9' as const,
|
||||
embedThumbnail: false
|
||||
}
|
||||
const argv = buildArgs(opts, join(outDir, '%(id)s.%(ext)s'), options, BIN_DIR, NO_ACCESS)
|
||||
const argv = buildArgs({
|
||||
opts,
|
||||
outputTemplate: join(outDir, '%(id)s.%(ext)s'),
|
||||
options,
|
||||
binDir: BIN_DIR,
|
||||
access: NO_ACCESS
|
||||
})
|
||||
console.log('[mkv-vp9] argv:', JSON.stringify(argv))
|
||||
const res = runYtdlp(argv)
|
||||
if (res.status !== 0) console.error('[mkv-vp9] stderr:\n' + res.stderr)
|
||||
@@ -285,7 +309,13 @@ describe.skipIf(!RUN)('real yt-dlp downloads (buildArgs end-to-end)', () => {
|
||||
embedChapters: true,
|
||||
embedThumbnail: false
|
||||
}
|
||||
const argv = buildArgs(opts, join(outDir, '%(id)s.%(ext)s'), options, BIN_DIR, NO_ACCESS)
|
||||
const argv = buildArgs({
|
||||
opts,
|
||||
outputTemplate: join(outDir, '%(id)s.%(ext)s'),
|
||||
options,
|
||||
binDir: BIN_DIR,
|
||||
access: NO_ACCESS
|
||||
})
|
||||
console.log('[subs-ch] argv:', JSON.stringify(argv))
|
||||
const res = runYtdlp(argv)
|
||||
if (res.status !== 0) console.error('[subs-ch] stderr:\n' + res.stderr)
|
||||
@@ -320,7 +350,13 @@ describe.skipIf(!RUN)('real yt-dlp downloads (buildArgs end-to-end)', () => {
|
||||
}
|
||||
const access = { ...NO_ACCESS, restrictFilenames: true }
|
||||
// %(title)s so the spaces in "Me at the zoo" actually exercise the sanitizer.
|
||||
const argv = buildArgs(opts, join(outDir, '%(title)s.%(ext)s'), options, BIN_DIR, access)
|
||||
const argv = buildArgs({
|
||||
opts,
|
||||
outputTemplate: join(outDir, '%(title)s.%(ext)s'),
|
||||
options,
|
||||
binDir: BIN_DIR,
|
||||
access
|
||||
})
|
||||
const res = runYtdlp(argv)
|
||||
if (res.status !== 0) console.error('[restrict] stderr:\n' + res.stderr)
|
||||
expect(res.status, 'yt-dlp should exit 0').toBe(0)
|
||||
@@ -335,13 +371,22 @@ describe.skipIf(!RUN)('real yt-dlp downloads (buildArgs end-to-end)', () => {
|
||||
it('downloadArchive: a second run of the same URL is skipped via the archive', () => {
|
||||
const archive = join(outDir, 'archive.txt')
|
||||
const mk = (id: string): string[] =>
|
||||
buildArgs(
|
||||
{ id, url: 'https://www.youtube.com/watch?v=jNQXAC9IVRw', kind: 'audio', quality: 'Best' },
|
||||
join(outDir, 'arch-%(id)s.%(ext)s'),
|
||||
{ ...DEFAULT_DOWNLOAD_OPTIONS, audioFormat: 'mp3' as const, embedThumbnail: false },
|
||||
BIN_DIR,
|
||||
{ ...NO_ACCESS, downloadArchivePath: archive }
|
||||
)
|
||||
buildArgs({
|
||||
opts: {
|
||||
id,
|
||||
url: 'https://www.youtube.com/watch?v=jNQXAC9IVRw',
|
||||
kind: 'audio',
|
||||
quality: 'Best'
|
||||
},
|
||||
outputTemplate: join(outDir, 'arch-%(id)s.%(ext)s'),
|
||||
options: {
|
||||
...DEFAULT_DOWNLOAD_OPTIONS,
|
||||
audioFormat: 'mp3' as const,
|
||||
embedThumbnail: false
|
||||
},
|
||||
binDir: BIN_DIR,
|
||||
access: { ...NO_ACCESS, downloadArchivePath: archive }
|
||||
})
|
||||
|
||||
const first = runYtdlp(mk('a1'))
|
||||
if (first.status !== 0) console.error('[archive] first stderr:\n' + first.stderr)
|
||||
@@ -380,14 +425,14 @@ describe.skipIf(!RUN)('real yt-dlp downloads (buildArgs end-to-end)', () => {
|
||||
'--write-info-json',
|
||||
'--no-mtime'
|
||||
])
|
||||
const argv = buildArgs(
|
||||
const argv = buildArgs({
|
||||
opts,
|
||||
join(outDir, 'extra-%(id)s.%(ext)s'),
|
||||
outputTemplate: join(outDir, 'extra-%(id)s.%(ext)s'),
|
||||
options,
|
||||
BIN_DIR,
|
||||
NO_ACCESS,
|
||||
extra
|
||||
)
|
||||
binDir: BIN_DIR,
|
||||
access: NO_ACCESS,
|
||||
extraArgs: extra
|
||||
})
|
||||
const res = runYtdlp(argv)
|
||||
if (res.status !== 0) console.error('[extra] stderr:\n' + res.stderr)
|
||||
expect(res.status, 'yt-dlp should exit 0').toBe(0)
|
||||
|
||||
Reference in New Issue
Block a user