Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05a2a58ace |
No files matched your search
+1
-1
@@ -5,7 +5,7 @@ import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
VERSION = "v1.5.1"
|
||||
VERSION = "v1.5.2"
|
||||
|
||||
|
||||
APP_NAME = "MusicTools"
|
||||
|
||||
+4
-2
@@ -146,8 +146,10 @@ def download_playlist(
|
||||
progress_callback(i, total, "", "stopped", 0)
|
||||
return
|
||||
|
||||
query = f"{track['name']} - {track['artist']}"
|
||||
track_only = track['name']
|
||||
artist = (track.get('artist') or "").strip()
|
||||
name = (track.get('name') or "").strip()
|
||||
query = f"{name} - {artist}" if artist else name
|
||||
track_only = name
|
||||
|
||||
# Salta brani gia scaricati in precedenza (file di tracking)
|
||||
if query in done_set:
|
||||
|
||||
+9
-2
@@ -75,15 +75,22 @@
|
||||
<div class="card">
|
||||
<div class="field">
|
||||
<label class="field-label">
|
||||
URL
|
||||
URL o titolo brano
|
||||
<span class="badge" id="urlListBadge" hidden></span>
|
||||
</label>
|
||||
<div class="row">
|
||||
<input type="text" id="urlInput" class="input pill" placeholder="Incolla qui un link Spotify, YouTube o SoundCloud…" />
|
||||
<input type="text" id="urlInput" class="input pill" placeholder="Link Spotify/YouTube… oppure Artista - Titolo · Titolo brano" />
|
||||
<button class="btn btn-ghost pill" id="loadListBtn">
|
||||
<span>📂</span> Carica lista
|
||||
</button>
|
||||
</div>
|
||||
<div class="hint">
|
||||
<span class="hint-ico">ⓘ</span>
|
||||
<div>
|
||||
Puoi incollare un <strong>link</strong> (Spotify, YouTube, SoundCloud…) oppure scrivere direttamente
|
||||
<strong>Artista - Titolo</strong> o solo il <strong>titolo del brano</strong>: l'app cerca il match migliore su YouTube e scarica in MP3.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
|
||||
+33
-1
@@ -27,6 +27,24 @@ function waitApi() {
|
||||
});
|
||||
}
|
||||
|
||||
// Riconosce se una stringa e un URL (incluso schema spotify:)
|
||||
function looksLikeUrl(s) {
|
||||
if (!s) return false;
|
||||
if (/^(https?|spotify):/i.test(s)) return true;
|
||||
if (s.includes("://")) return true;
|
||||
// Domini comuni anche senza http (es. "youtube.com/...")
|
||||
return /^(www\.)?(youtube\.com|youtu\.be|spotify\.com|soundcloud\.com|tiktok\.com|instagram\.com|facebook\.com|fb\.watch)\//i.test(s);
|
||||
}
|
||||
|
||||
// Trasforma una query libera in {name, artist}.
|
||||
// Formati riconosciuti: "Artista - Titolo" (anche con – o —) oppure solo "Titolo".
|
||||
function parseQueryToTrack(q) {
|
||||
const s = (q || "").trim();
|
||||
const m = s.match(/^(.+?)\s+[-–—]\s+(.+)$/);
|
||||
if (m) return { artist: m[1].trim(), name: m[2].trim() };
|
||||
return { artist: "", name: s };
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Bridge — eventi spinti dal backend
|
||||
// ============================================================
|
||||
@@ -340,11 +358,25 @@ $("#downloadBtn").addEventListener("click", async () => {
|
||||
if (!urls.length) {
|
||||
const single = $("#urlInput").value.trim();
|
||||
if (!single) {
|
||||
toast("Inserisci un URL o carica una lista", "error");
|
||||
toast("Inserisci un URL, un titolo o carica una lista", "error");
|
||||
bridgeHandlers["download:done"]();
|
||||
return;
|
||||
}
|
||||
if (looksLikeUrl(single)) {
|
||||
urls = [single];
|
||||
} else {
|
||||
const track = parseQueryToTrack(single);
|
||||
res = await window.pywebview.api.start_tracks_download({
|
||||
tracks: [track],
|
||||
output_dir: state.dlOutputDir,
|
||||
subfolder: "",
|
||||
});
|
||||
if (!res.ok) {
|
||||
toast(res.error || "Errore", "error");
|
||||
bridgeHandlers["download:done"]();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
res = await window.pywebview.api.start_download({
|
||||
urls,
|
||||
|
||||
Reference in new issue
Block a user