H2 (URL half): one canonical youtubeId in urlHelpers
Consolidates the scattered YouTube-URL parsing (the clean, renderer-contained half of H2): - Move the complete youtubeId (watch/shorts/embed/live/youtu.be) into lib/urlHelpers.ts as the single home. - thumb.ts, queueStats.ts (sameVideo), and store/downloads.ts (titleFromUrl) now import it; the three ad-hoc reimplementations are removed. - titleFromUrl gains correctness: it previously labeled ANY host with a ?v= param as "YouTube video (…)" and missed youtu.be/shorts; it's now host-correct and covers every YouTube shape. sameVideo now also dedupes /shorts/ID against /watch?v=ID. - Unit-tested in test/clipboardLink.test.ts (+4 cases, 247 pass). The formatter half of H2 is deferred to travel with H4: the renderer re-parses speed/eta strings only because raw numbers aren't carried across the IPC boundary (H4), and fmtBytes (1024) vs formatSpeed (1000) differ intentionally. typecheck + 247 tests + eslint + prettier green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,35 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
// Import from the pure utility module directly — no Zustand store init needed (L40).
|
||||
import { looksLikeUrl, looksLikeSingleVideo } from '../src/renderer/src/lib/urlHelpers'
|
||||
import { looksLikeUrl, looksLikeSingleVideo, youtubeId } from '../src/renderer/src/lib/urlHelpers'
|
||||
|
||||
describe('youtubeId', () => {
|
||||
it('extracts the id from a watch URL', () => {
|
||||
expect(youtubeId('https://www.youtube.com/watch?v=dQw4w9WgXcQ')).toBe('dQw4w9WgXcQ')
|
||||
expect(youtubeId('https://youtube.com/watch?v=abc123&list=xyz')).toBe('abc123')
|
||||
expect(youtubeId('https://music.youtube.com/watch?v=musicId')).toBe('musicId')
|
||||
})
|
||||
|
||||
it('extracts the id from a youtu.be short link', () => {
|
||||
expect(youtubeId('https://youtu.be/dQw4w9WgXcQ')).toBe('dQw4w9WgXcQ')
|
||||
expect(youtubeId('https://youtu.be/abc123?t=42')).toBe('abc123')
|
||||
})
|
||||
|
||||
it('extracts the id from shorts / embed / live / v paths', () => {
|
||||
expect(youtubeId('https://www.youtube.com/shorts/shortId1')).toBe('shortId1')
|
||||
expect(youtubeId('https://youtube.com/embed/embedId2')).toBe('embedId2')
|
||||
expect(youtubeId('https://www.youtube.com/live/liveId3')).toBe('liveId3')
|
||||
expect(youtubeId('https://youtube.com/v/vId4?fs=1')).toBe('vId4')
|
||||
})
|
||||
|
||||
it('returns null for non-YouTube, unparseable, or empty input', () => {
|
||||
expect(youtubeId('https://vimeo.com/12345')).toBeNull()
|
||||
expect(youtubeId('https://notyoutube.com/watch?v=x')).toBeNull()
|
||||
expect(youtubeId('https://www.youtube.com/@somechannel')).toBeNull()
|
||||
expect(youtubeId('not a url')).toBeNull()
|
||||
expect(youtubeId(undefined)).toBeNull()
|
||||
expect(youtubeId('')).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('looksLikeUrl', () => {
|
||||
it('accepts http(s) URLs', () => {
|
||||
|
||||
Reference in New Issue
Block a user