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:
+1
-1
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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. */
|
||||||
|
|||||||
Reference in New Issue
Block a user