Rename: l'app si chiama MusicTools (non piu MusicDownload)

- main.py: titolo finestra pywebview -> 'MusicTools'
- core/config.py: APP_NAME='MusicTools', cartella config bundled
  ora ~/Library/Application Support/MusicTools/ e %APPDATA%/MusicTools/.
  Migrazione one-shot: se non esiste la nuova ma esiste la legacy
  'MusicDownload', il config.json viene copiato cosi' le impostazioni
  non vanno perse dopo l'aggiornamento
- core/recorder.py: messaggio errore permesso microfono
- api/bridge.py: User-Agent update check + guida Spotify menzionano
  MusicTools
- build_macos.py / build_windows.py / .github/workflows/build.yml:
  prodotti rinominati (MusicTools.app, MusicTools.exe,
  MusicTools-macOS.zip, MusicTools-Windows.zip, Release 'Build MusicTools')
- webui: <title>, brand-name sidebar, intestazioni commenti
- README: tutti i riferimenti aggiornati + nota che il repo Git
  conserva il nome storico 'musicdownload' (URL stabili per
  release gia' pubblicate)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
luzadevandClaude Opus 4.7 committed 2026-06-08 11:15:34 +02:00
1 parent 6f5c32165a
commit 850d3f4b6c
11 files changed
+77 -57

No files matched your search

+14 -14
View File
@@ -1,4 +1,4 @@
name: Build MusicDownload
name: Build MusicTools
on:
workflow_dispatch:
@@ -36,14 +36,14 @@ jobs:
- name: Package .app -> zip
run: |
cd dist
ditto -c -k --sequesterRsrc --keepParent MusicDownload.app ../MusicDownload-macOS.zip
ls -lh ../MusicDownload-macOS.zip
ditto -c -k --sequesterRsrc --keepParent MusicTools.app ../MusicTools-macOS.zip
ls -lh ../MusicTools-macOS.zip
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: MusicDownload-macOS
path: MusicDownload-macOS.zip
name: MusicTools-macOS
path: MusicTools-macOS.zip
retention-days: 14
# =========================================================
@@ -69,14 +69,14 @@ jobs:
- name: Package -> zip
shell: pwsh
run: |
Compress-Archive -Path dist/MusicDownload/* -DestinationPath MusicDownload-Windows.zip -CompressionLevel Optimal
Get-Item MusicDownload-Windows.zip
Compress-Archive -Path dist/MusicTools/* -DestinationPath MusicTools-Windows.zip -CompressionLevel Optimal
Get-Item MusicTools-Windows.zip
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: MusicDownload-Windows
path: MusicDownload-Windows.zip
name: MusicTools-Windows
path: MusicTools-Windows.zip
retention-days: 14
# =========================================================
@@ -90,22 +90,22 @@ jobs:
- name: Download macOS artifact
uses: actions/download-artifact@v4
with:
name: MusicDownload-macOS
name: MusicTools-macOS
path: artifacts/macos
- name: Download Windows artifact
uses: actions/download-artifact@v4
with:
name: MusicDownload-Windows
name: MusicTools-Windows
path: artifacts/windows
- name: Create Release
uses: softprops/action-gh-release@v2
with:
name: MusicDownload ${{ github.ref_name }}
name: MusicTools ${{ github.ref_name }}
tag_name: ${{ github.ref_name }}
generate_release_notes: true
fail_on_unmatched_files: true
files: |
artifacts/macos/MusicDownload-macOS.zip
artifacts/windows/MusicDownload-Windows.zip
artifacts/macos/MusicTools-macOS.zip
artifacts/windows/MusicTools-Windows.zip
+15 -13
View File
@@ -1,4 +1,4 @@
# MusicDownload
# MusicTools
Applicazione desktop per **scaricare musica e video**, **modificare i metadati** dei file audio e **registrare l'audio** da qualsiasi ingresso del computer.
@@ -8,6 +8,8 @@ Sviluppata da **LuZa**.
Repo: <https://github.com/luzadev/musicdownload>
> ℹ️ Il repo Git conserva il nome storico **`musicdownload`** (l'app prima si chiamava così); URL stabili per release già pubblicate e installazioni esistenti.
## Funzionalità
| Tab | Cosa fa |
@@ -91,14 +93,14 @@ brew install blackhole-2ch
Anche se non è un microfono fisico, macOS richiede il permesso "Microfono" per leggere da BlackHole via AVFoundation.
Vai su **Preferenze di Sistema → Privacy e sicurezza → Microfono** e abilita l'app da cui lanci MusicDownload (Terminal/iTerm in sviluppo, oppure MusicDownload.app per la build distribuita). Se non vedi nessuna voce, comparirà un popup la prima volta che premi REC — accetta.
Vai su **Preferenze di Sistema → Privacy e sicurezza → Microfono** e abilita l'app da cui lanci MusicTools (Terminal/iTerm in sviluppo, oppure MusicTools.app per la build distribuita). Se non vedi nessuna voce, comparirà un popup la prima volta che premi REC — accetta.
### 3. Setup A — minimo (registri ma non senti l'audio durante)
1. Click sull'icona altoparlante nella barra menu → **Output → BlackHole 2ch**
*Oppure: Preferenze di Sistema → Audio → Uscita → BlackHole 2ch*
2. Fai partire lo stream (Spotify/YouTube): non sentirai nulla — è normale, l'audio va a BlackHole
3. App MusicDownload → tab **● Registra** → dispositivo **🔄 BlackHole 2ch (loopback)** → **REC**
3. App MusicTools → tab **● Registra** → dispositivo **🔄 BlackHole 2ch (loopback)** → **REC**
4. **Stop** e riascolta il file MP3 generato
### 4. Setup B — completo (registri E senti l'audio contemporaneamente, consigliato)
@@ -119,7 +121,7 @@ Adesso ogni audio del sistema viene riprodotto sugli speaker (lo senti) e contem
| Sintomo | Causa probabile | Fix |
|---|---|---|
| BlackHole non compare nel dropdown | CoreAudio non l'ha ancora caricato dopo l'install | `sudo killall coreaudiod` poi premi **↻ Aggiorna** |
| Errore `ffmpeg exit -6` o `permesso Microfono mancante` | macOS nega l'accesso al device | Privacy e sicurezza → Microfono → abilita Terminal/MusicDownload |
| Errore `ffmpeg exit -6` o `permesso Microfono mancante` | macOS nega l'accesso al device | Privacy e sicurezza → Microfono → abilita Terminal/MusicTools |
| File MP3 muto | Output di sistema non passa per BlackHole | Cambia output su BlackHole o Multi-Output Device (vedi Setup A/B) |
| Audio doppio/eco nel file | Stai registrando da BlackHole *e* da microfono fisico simultaneamente | Verifica che nel dropdown ci sia solo `BlackHole 2ch` |
| Audio crackly/distorto | Sample rate non allineato | In Audio MIDI Setup, BlackHole + altoparlanti tutti a 48 kHz |
@@ -127,7 +129,7 @@ Adesso ogni audio del sistema viene riprodotto sugli speaker (lo senti) e contem
## Struttura progetto
```
MusicDownload/
MusicTools/
├── main.py # Entry point — bootstrap pywebview
├── requirements.txt
├── build_macos.py # Script build macOS (.app)
@@ -169,8 +171,8 @@ Il file `config.json` viene creato automaticamente al primo avvio:
Posizione:
- **Sviluppo**: directory del progetto
- **macOS bundle**: `~/Library/Application Support/MusicDownload/`
- **Windows bundle**: `%APPDATA%/MusicDownload/`
- **macOS bundle**: `~/Library/Application Support/MusicTools/`
- **Windows bundle**: `%APPDATA%/MusicTools/`
## Build locale
@@ -182,7 +184,7 @@ pip install pyinstaller
python3 build_macos.py
```
Produce `dist/MusicDownload.app` con yt-dlp, ffmpeg, ffprobe e tutte le dylib bundled (rpath patchati con `install_name_tool`).
Produce `dist/MusicTools.app` con yt-dlp, ffmpeg, ffprobe e tutte le dylib bundled (rpath patchati con `install_name_tool`).
### Windows
@@ -191,14 +193,14 @@ pip install pyinstaller
python build_windows.py
```
Produce `dist/MusicDownload/MusicDownload.exe`. Lo script scarica automaticamente `yt-dlp.exe` e `ffmpeg.exe`/`ffprobe.exe` static build.
Produce `dist/MusicTools/MusicTools.exe`. Lo script scarica automaticamente `yt-dlp.exe` e `ffmpeg.exe`/`ffprobe.exe` static build.
## Build & Release automatiche (GitHub Actions)
Ogni push di un tag `v*` triggera la pipeline `.github/workflows/build.yml`:
1. **`build-macos`** (runner `macos-latest`) → `MusicDownload-macOS.zip` (la `.app` zippata con `ditto`)
2. **`build-windows`** (runner `windows-latest`) → `MusicDownload-Windows.zip`
1. **`build-macos`** (runner `macos-latest`) → `MusicTools-macOS.zip` (la `.app` zippata con `ditto`)
2. **`build-windows`** (runner `windows-latest`) → `MusicTools-Windows.zip`
3. **`release`** → crea automaticamente una GitHub Release con entrambi gli asset allegati
Per pubblicare una nuova versione:
@@ -211,10 +213,10 @@ git push origin v1.3.0
Per fare solo una build di test (senza release):
```bash
gh workflow run "Build MusicDownload" --ref main
gh workflow run "Build MusicTools" --ref main
```
oppure dalla UI: **Actions → Build MusicDownload → Run workflow**.
oppure dalla UI: **Actions → Build MusicTools → Run workflow**.
Le release ufficiali sono disponibili su <https://github.com/luzadev/musicdownload/releases>.
+2 -2
View File
@@ -38,7 +38,7 @@ SPOTIFY_GUIDE_TEXT = """\
1) Vai su https://developer.spotify.com/dashboard e accedi (anche con account free).
2) Clicca "Create app".
3) Compila:
- App name: MusicDownload (o quello che vuoi)
- App name: MusicTools (o quello che vuoi)
- Description: a piacere
- Redirect URI: http://localhost:8888/callback (obbligatorio ma non usato)
- Seleziona "Web API"
@@ -148,7 +148,7 @@ class Api:
API_URL = "https://api.github.com/repos/luzadev/musicdownload/releases/latest"
try:
resp = requests.get(API_URL, headers={
"User-Agent": "MusicDownload",
"User-Agent": "MusicTools",
"Accept": "application/vnd.github+json",
}, timeout=10)
resp.raise_for_status()
+9 -9
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
"""
Build script per creare MusicDownload.app su macOS.
Build script per creare MusicTools.app su macOS.
Uso:
python3 build_macos.py
@@ -8,7 +8,7 @@ Uso:
Cosa fa:
1. Scarica il binario standalone di yt-dlp per macOS
2. Raccoglie ffmpeg + ffprobe + tutte le loro dylib da Homebrew
3. Esegue PyInstaller per creare MusicDownload.app
3. Esegue PyInstaller per creare MusicTools.app
Requisiti:
pip3 install pyinstaller
@@ -210,7 +210,7 @@ def run_pyinstaller():
cmd = [
sys.executable, "-m", "PyInstaller",
"--name", "MusicDownload",
"--name", "MusicTools",
"--windowed",
"--onedir",
"--noconfirm",
@@ -230,7 +230,7 @@ def run_pyinstaller():
log(f"Comando: {' '.join(cmd[:10])}...")
subprocess.run(cmd, check=True, cwd=str(ROOT))
app_path = DIST_DIR / "MusicDownload.app"
app_path = DIST_DIR / "MusicTools.app"
if app_path.exists():
log(f"Build completata: {app_path}")
# Mostra dimensione
@@ -238,8 +238,8 @@ def run_pyinstaller():
log(f"Dimensione: {size / 1024 / 1024:.0f} MB")
else:
log("ATTENZIONE: .app non trovata, controlla l'output di PyInstaller")
# Potrebbe essere in dist/MusicDownload/ (non .app)
alt = DIST_DIR / "MusicDownload"
# Potrebbe essere in dist/MusicTools/ (non .app)
alt = DIST_DIR / "MusicTools"
if alt.exists():
log(f"Trovata directory: {alt}")
@@ -249,7 +249,7 @@ def run_pyinstaller():
# =========================================================================
def main():
print("=" * 50)
print(" MusicDownload — Build macOS")
print(" MusicTools — Build macOS")
print("=" * 50)
# Verifica pyinstaller
@@ -272,12 +272,12 @@ def main():
print("\n" + "=" * 50)
print(" DONE!")
print("=" * 50)
app = DIST_DIR / "MusicDownload.app"
app = DIST_DIR / "MusicTools.app"
if app.exists():
print(f"\n L'app e in: {app}")
print(f" Per testarla: open '{app}'")
print(f"\n Per distribuirla, comprimi la cartella:")
print(f" zip -r MusicDownload.zip dist/MusicDownload.app")
print(f" zip -r MusicTools.zip dist/MusicTools.app")
print()
+9 -9
View File
@@ -1,5 +1,5 @@
"""
Build script per creare MusicDownload.exe su Windows.
Build script per creare MusicTools.exe su Windows.
Uso:
python build_windows.py
@@ -7,7 +7,7 @@ Uso:
Cosa fa:
1. Scarica il binario standalone di yt-dlp per Windows
2. Scarica ffmpeg static build per Windows
3. Esegue PyInstaller per creare MusicDownload.exe
3. Esegue PyInstaller per creare MusicTools.exe
Requisiti:
pip install pyinstaller
@@ -101,7 +101,7 @@ def run_pyinstaller():
cmd = [
sys.executable, "-m", "PyInstaller",
"--name", "MusicDownload",
"--name", "MusicTools",
"--windowed",
"--onedir",
"--noconfirm",
@@ -126,11 +126,11 @@ def run_pyinstaller():
log(f"Comando: {' '.join(cmd[:10])}...")
subprocess.run(cmd, check=True, cwd=str(ROOT))
exe_path = DIST_DIR / "MusicDownload" / "MusicDownload.exe"
exe_path = DIST_DIR / "MusicTools" / "MusicTools.exe"
if exe_path.exists():
log(f"Build completata: {exe_path}")
else:
log("ATTENZIONE: MusicDownload.exe non trovato, controlla l'output")
log("ATTENZIONE: MusicTools.exe non trovato, controlla l'output")
# =========================================================================
@@ -138,7 +138,7 @@ def run_pyinstaller():
# =========================================================================
def main():
print("=" * 50)
print(" MusicDownload - Build Windows")
print(" MusicTools - Build Windows")
print("=" * 50)
if sys.platform != "win32":
@@ -167,12 +167,12 @@ def main():
print("\n" + "=" * 50)
print(" DONE!")
print("=" * 50)
dist = DIST_DIR / "MusicDownload"
dist = DIST_DIR / "MusicTools"
if dist.exists():
print(f"\n L'app e in: {dist}")
print(f" Eseguibile: {dist / 'MusicDownload.exe'}")
print(f" Eseguibile: {dist / 'MusicTools.exe'}")
print(f"\n Per distribuirla, comprimi la cartella:")
print(f" Comprimi {dist} -> MusicDownload_Windows.zip")
print(f" Comprimi {dist} -> MusicTools_Windows.zip")
print()
+21 -3
View File
@@ -8,21 +8,39 @@ from pathlib import Path
VERSION = "v1.2.2"
APP_NAME = "MusicTools"
_LEGACY_NAME = "MusicDownload"
def _get_config_dir() -> Path:
"""Ritorna la directory per config.json.
Frozen (bundle PyInstaller):
- macOS: ~/Library/Application Support/MusicDownload/
- Windows: %APPDATA%/MusicDownload/
- macOS: ~/Library/Application Support/MusicTools/
- Windows: %APPDATA%/MusicTools/
Dev (non frozen):
- directory del progetto
Se la cartella nuova non esiste ma quella legacy 'MusicDownload' si',
viene migrata (copia di config.json) cosi' l'utente non perde le
impostazioni dopo il rename.
"""
if getattr(sys, "frozen", False):
if sys.platform == "win32":
base = Path(os.environ.get("APPDATA", Path.home()))
else:
base = Path.home() / "Library" / "Application Support"
config_dir = base / "MusicDownload"
config_dir = base / APP_NAME
legacy_dir = base / _LEGACY_NAME
# Migrazione one-shot: se non esiste la nuova ma esiste la vecchia
if not config_dir.exists() and legacy_dir.exists():
try:
config_dir.mkdir(parents=True, exist_ok=True)
legacy_cfg = legacy_dir / "config.json"
if legacy_cfg.exists():
(config_dir / "config.json").write_bytes(legacy_cfg.read_bytes())
except OSError:
pass
config_dir.mkdir(parents=True, exist_ok=True)
return config_dir
return Path(__file__).resolve().parent.parent
+1 -1
View File
@@ -350,7 +350,7 @@ def _extract_friendly_error(rc: int) -> str:
return "Dispositivo non disponibile (riavvia il servizio audio o ricontrolla la selezione)."
if "permission" in text or "not authorized" in text or "not permitted" in text:
return "Permesso microfono negato da macOS. Abilita Python/MusicDownload in Privacy → Microfono."
return "Permesso microfono negato da macOS. Abilita Python/MusicTools in Privacy → Microfono."
if "no such device" in text or "no such audio device" in text:
return "Dispositivo non trovato. Premi '↻ Aggiorna' e riseleziona."
+2 -2
View File
@@ -1,4 +1,4 @@
"""MusicDownload — Entry point (pywebview + WebKit/EdgeChromium)."""
"""MusicTools — Entry point (pywebview + WebKit/EdgeChromium)."""
import os
import sys
@@ -23,7 +23,7 @@ def main():
index_path = _resource_path("webui", "index.html")
window = webview.create_window(
title="MusicDownload",
title="MusicTools",
url=index_path,
js_api=api,
width=1080,
+1 -1
View File
@@ -1,5 +1,5 @@
/* ===============================
MusicDownload — Spotify-like UI
MusicTools — Spotify-like UI
=============================== */
:root {
+2 -2
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>MusicDownload</title>
<title>MusicTools</title>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
@@ -15,7 +15,7 @@
<div class="brand-logo">
<span>♫</span>
</div>
<div class="brand-name">MusicDownload</div>
<div class="brand-name">MusicTools</div>
</div>
<div class="divider"></div>
+1 -1
View File
@@ -1,5 +1,5 @@
/* ======================================================
MusicDownload — Frontend (vanilla JS)
MusicTools — Frontend (vanilla JS)
====================================================== */
const $ = (sel) => document.querySelector(sel);