fix(soundboard): auto-prepend https:// for URL import
URLs pasted without protocol (e.g. instagram.com/reel/...) now work. normalizeUrl() adds https:// if missing. Input type changed from "url" to "text" to prevent browser validation blocking paste. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
200f03c1f8
commit
df937f3e40
1 changed files with 13 additions and 8 deletions
|
|
@ -414,29 +414,34 @@ export default function SoundboardTab({ data }: SoundboardTabProps) {
|
||||||
}, []);
|
}, []);
|
||||||
const soundKey = useCallback((s: Sound) => s.relativePath ?? s.fileName, []);
|
const soundKey = useCallback((s: Sound) => s.relativePath ?? s.fileName, []);
|
||||||
const YTDLP_HOSTS = ['youtube.com', 'www.youtube.com', 'm.youtube.com', 'youtu.be', 'music.youtube.com', 'instagram.com', 'www.instagram.com'];
|
const YTDLP_HOSTS = ['youtube.com', 'www.youtube.com', 'm.youtube.com', 'youtu.be', 'music.youtube.com', 'instagram.com', 'www.instagram.com'];
|
||||||
|
/** Auto-prepend https:// if missing */
|
||||||
|
const normalizeUrl = useCallback((value: string): string => {
|
||||||
|
const v = value.trim();
|
||||||
|
if (!v) return v;
|
||||||
|
if (/^https?:\/\//i.test(v)) return v;
|
||||||
|
return 'https://' + v;
|
||||||
|
}, []);
|
||||||
const isSupportedUrl = useCallback((value: string) => {
|
const isSupportedUrl = useCallback((value: string) => {
|
||||||
try {
|
try {
|
||||||
const parsed = new URL(value.trim());
|
const parsed = new URL(normalizeUrl(value));
|
||||||
const host = parsed.hostname.toLowerCase();
|
const host = parsed.hostname.toLowerCase();
|
||||||
// Direct MP3 link
|
|
||||||
if (parsed.pathname.toLowerCase().endsWith('.mp3')) return true;
|
if (parsed.pathname.toLowerCase().endsWith('.mp3')) return true;
|
||||||
// YouTube / Instagram
|
|
||||||
if (YTDLP_HOSTS.some(h => host === h || host.endsWith('.' + h))) return true;
|
if (YTDLP_HOSTS.some(h => host === h || host.endsWith('.' + h))) return true;
|
||||||
return false;
|
return false;
|
||||||
} catch {
|
} catch {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}, []);
|
}, [normalizeUrl]);
|
||||||
const getUrlType = useCallback((value: string): 'youtube' | 'instagram' | 'mp3' | null => {
|
const getUrlType = useCallback((value: string): 'youtube' | 'instagram' | 'mp3' | null => {
|
||||||
try {
|
try {
|
||||||
const parsed = new URL(value.trim());
|
const parsed = new URL(normalizeUrl(value));
|
||||||
const host = parsed.hostname.toLowerCase();
|
const host = parsed.hostname.toLowerCase();
|
||||||
if (host.includes('youtube') || host === 'youtu.be') return 'youtube';
|
if (host.includes('youtube') || host === 'youtu.be') return 'youtube';
|
||||||
if (host.includes('instagram')) return 'instagram';
|
if (host.includes('instagram')) return 'instagram';
|
||||||
if (parsed.pathname.toLowerCase().endsWith('.mp3')) return 'mp3';
|
if (parsed.pathname.toLowerCase().endsWith('.mp3')) return 'mp3';
|
||||||
return null;
|
return null;
|
||||||
} catch { return null; }
|
} catch { return null; }
|
||||||
}, []);
|
}, [normalizeUrl]);
|
||||||
|
|
||||||
const guildId = selected ? selected.split(':')[0] : '';
|
const guildId = selected ? selected.split(':')[0] : '';
|
||||||
const channelId = selected ? selected.split(':')[1] : '';
|
const channelId = selected ? selected.split(':')[1] : '';
|
||||||
|
|
@ -632,7 +637,7 @@ export default function SoundboardTab({ data }: SoundboardTabProps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleUrlImport() {
|
async function handleUrlImport() {
|
||||||
const trimmed = importUrl.trim();
|
const trimmed = normalizeUrl(importUrl);
|
||||||
if (!trimmed) return notify('Bitte einen Link eingeben', 'error');
|
if (!trimmed) return notify('Bitte einen Link eingeben', 'error');
|
||||||
if (!isSupportedUrl(trimmed)) return notify('Nur YouTube, Instagram oder direkte MP3-Links', 'error');
|
if (!isSupportedUrl(trimmed)) return notify('Nur YouTube, Instagram oder direkte MP3-Links', 'error');
|
||||||
setImportBusy(true);
|
setImportBusy(true);
|
||||||
|
|
@ -1017,7 +1022,7 @@ export default function SoundboardTab({ data }: SoundboardTabProps) {
|
||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
className="url-import-input"
|
className="url-import-input"
|
||||||
type="url"
|
type="text"
|
||||||
placeholder="YouTube / Instagram / MP3-Link..."
|
placeholder="YouTube / Instagram / MP3-Link..."
|
||||||
value={importUrl}
|
value={importUrl}
|
||||||
onChange={e => setImportUrl(e.target.value)}
|
onChange={e => setImportUrl(e.target.value)}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue