Fix L26: consolidate drag-drop URL extraction into shared urlHelpers

firstUrl() in DownloadBar was a local duplicate of looksLikeUrl iteration
(scanning multi-line text for the first valid URL). Promoted to
firstUrlInText() in src/renderer/src/lib/urlHelpers.ts alongside the other
URL utilities, re-exported from useClipboardLink.ts. DownloadBar now imports
firstUrlInText from there instead of maintaining a local copy.

typecheck + 242 tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-30 14:50:39 -04:00
parent 9abd2c4441
commit ab085f2bfe
4 changed files with 18 additions and 13 deletions
+1 -1
View File
@@ -429,7 +429,7 @@ token system + shared primitives (UI/SIMP — high value, larger effort) · i18n
- [x] **L25 — Taskbar effect over-fires.** `App.tsx` subscribes to the whole downloads store and - [x] **L25 — Taskbar effect over-fires.** `App.tsx` subscribes to the whole downloads store and
recomputes `summarizeQueue` + sends the taskbar IPC on *every* store change (each progress recomputes `summarizeQueue` + sends the taskbar IPC on *every* store change (each progress
tick); throttle or dedupe by computed value. tick); throttle or dedupe by computed value.
- [ ] **L26 — Third URL-sniffing path.** DownloadBar's drag-drop `firstUrl` is a separate - [x] **L26 — Third URL-sniffing path.** DownloadBar's drag-drop `firstUrl` is a separate
"first http(s) line" extractor alongside `useClipboardLink.looksLikeUrl` and deeplink's scan. "first http(s) line" extractor alongside `useClipboardLink.looksLikeUrl` and deeplink's scan.
- [x] **L27 — DownloadBar Enter probes, not downloads.** Enter in the URL field triggers - [x] **L27 — DownloadBar Enter probes, not downloads.** Enter in the URL field triggers
`fetchFormats`; there's no keyboard path to actually start the download (LibraryView's Enter `fetchFormats`; there's no keyboard path to actually start the download (LibraryView's Enter
+2 -11
View File
@@ -37,19 +37,10 @@ import { Hint } from './Hint'
import { SegmentedControl } from './ui/SegmentedControl' import { SegmentedControl } from './ui/SegmentedControl'
import { IconButton } from './ui/IconButton' import { IconButton } from './ui/IconButton'
import { parseUrlShortcutContent } from '@shared/ipc' import { parseUrlShortcutContent } from '@shared/ipc'
import { useClipboardLink, looksLikeUrl } from '../useClipboardLink' import { useClipboardLink, looksLikeUrl, firstUrlInText } from '../useClipboardLink'
import { logError } from '../reportError' import { logError } from '../reportError'
import { THUMB_LG } from '../thumbSizes' import { THUMB_LG } from '../thumbSizes'
/** First http(s) URL in a blob of dropped text (one per line; '#' comments skipped). */
function firstUrl(text: string): string | null {
for (const raw of text.split(/\r?\n/)) {
const line = raw.trim()
if (!line || line.startsWith('#')) continue
if (looksLikeUrl(line)) return line
}
return null
}
/** Pull the URL= target out of a dropped Windows .url Internet Shortcut file. */ /** Pull the URL= target out of a dropped Windows .url Internet Shortcut file. */
function parseUrlFile(content: string): string | null { function parseUrlFile(content: string): string | null {
@@ -299,7 +290,7 @@ export function DownloadBar(): React.JSX.Element {
e.preventDefault() e.preventDefault()
setDragActive(false) setDragActive(false)
const dt = e.dataTransfer const dt = e.dataTransfer
const fromText = firstUrl(dt.getData('text/uri-list') || dt.getData('text/plain') || '') const fromText = firstUrlInText(dt.getData('text/uri-list') || dt.getData('text/plain') || '')
if (fromText) { if (fromText) {
onUrlChange(fromText) onUrlChange(fromText)
return return
+14
View File
@@ -35,3 +35,17 @@ export function looksLikeSingleVideo(text: string): boolean {
} }
return false return false
} }
/**
* Return the first http(s) URL from a multi-line blob of text.
* Lines are trimmed; '#' comment lines are skipped.
* Used for clipboard paste and drag-drop text.
*/
export function firstUrlInText(text: string): string | null {
for (const raw of text.split(/\r?\n/)) {
const line = raw.trim()
if (!line || line.startsWith('#')) continue
if (looksLikeUrl(line)) return line
}
return null
}
+1 -1
View File
@@ -3,7 +3,7 @@ import { useSettings } from './store/settings'
// Pure URL helpers extracted to a standalone module so they can be tested // Pure URL helpers extracted to a standalone module so they can be tested
// without pulling in the Zustand store (L40). Re-exported here for existing // without pulling in the Zustand store (L40). Re-exported here for existing
// consumers (DownloadBar, LibraryView) without an import-path change. // consumers (DownloadBar, LibraryView) without an import-path change.
export { looksLikeUrl, looksLikeSingleVideo } from './lib/urlHelpers' export { looksLikeUrl, looksLikeSingleVideo, firstUrlInText } from './lib/urlHelpers'
import { looksLikeUrl } from './lib/urlHelpers' import { looksLikeUrl } from './lib/urlHelpers'
/** Where an offered link came from — drives the banner's wording. */ /** Where an offered link came from — drives the banner's wording. */