Files
musicdownload/build_windows.py
T
luzadevandClaude Opus 4.7 8c06a26ddb Initial commit: MusicDownload con UI pywebview
- Frontend HTML/CSS/JS in webui/ (stile Spotify-like, hero gradient, modal blur)
- API bridge JS<->Python in api/bridge.py
- Core invariato: downloader yt-dlp, upgrader, spotify client, config
- Build scripts macOS (WebKit) e Windows (EdgeChromium)
- .gitignore esclude credenziali (config.json, cookies.txt) e artefatti build

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 12:48:58 +02:00

180 lines
5.5 KiB
Python

"""
Build script per creare MusicDownload.exe su Windows.
Uso:
python build_windows.py
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
Requisiti:
pip install pyinstaller
pip install -r requirements.txt
"""
import io
import os
import shutil
import stat
import subprocess
import sys
import urllib.request
import zipfile
from pathlib import Path
ROOT = Path(__file__).resolve().parent
BUILD_DIR = ROOT / "build"
DIST_DIR = ROOT / "dist"
BUNDLE_DIR = ROOT / "bundle_bin"
YTDLP_URL = "https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe"
FFMPEG_URL = "https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-win64-gpl.zip"
def log(msg):
print(f"\n>>> {msg}")
# =========================================================================
# 1. Scarica yt-dlp.exe
# =========================================================================
def download_ytdlp():
dest = BUNDLE_DIR / "yt-dlp.exe"
if dest.exists():
log(f"yt-dlp.exe gia presente: {dest}")
return dest
log(f"Scarico yt-dlp.exe ...")
BUNDLE_DIR.mkdir(parents=True, exist_ok=True)
urllib.request.urlretrieve(YTDLP_URL, dest)
log(f"yt-dlp.exe scaricato ({dest.stat().st_size // 1024 // 1024} MB)")
return dest
# =========================================================================
# 2. Scarica ffmpeg static build
# =========================================================================
def download_ffmpeg():
ffmpeg_exe = BUNDLE_DIR / "ffmpeg.exe"
ffprobe_exe = BUNDLE_DIR / "ffprobe.exe"
if ffmpeg_exe.exists() and ffprobe_exe.exists():
log("ffmpeg.exe e ffprobe.exe gia presenti")
return
log("Scarico ffmpeg static build per Windows ...")
BUNDLE_DIR.mkdir(parents=True, exist_ok=True)
# Scarica lo zip in memoria
response = urllib.request.urlopen(FFMPEG_URL)
zip_data = io.BytesIO(response.read())
log("Download completato, estraggo ffmpeg.exe e ffprobe.exe ...")
with zipfile.ZipFile(zip_data) as zf:
for member in zf.namelist():
basename = Path(member).name
if basename in ("ffmpeg.exe", "ffprobe.exe"):
# Estrai solo il file, senza sottocartelle
data = zf.read(member)
dest = BUNDLE_DIR / basename
dest.write_bytes(data)
log(f" Estratto: {basename} ({len(data) // 1024 // 1024} MB)")
if not ffmpeg_exe.exists():
print("ERRORE: ffmpeg.exe non trovato nello zip!")
sys.exit(1)
# =========================================================================
# 3. PyInstaller
# =========================================================================
def run_pyinstaller():
log("Eseguo PyInstaller...")
# Genera lista --add-binary per i binari bundled
add_binaries = []
for f in BUNDLE_DIR.iterdir():
if f.is_file() and f.suffix in (".exe", ""):
add_binaries.extend(["--add-binary", f"{f};."])
cmd = [
sys.executable, "-m", "PyInstaller",
"--name", "MusicDownload",
"--windowed",
"--onedir",
"--noconfirm",
# Icona (se presente)
# "--icon", str(ROOT / "icon.ico"),
# Web UI assets (HTML/CSS/JS) — usati da pywebview
"--add-data", f"{ROOT / 'webui'};webui",
# Hidden imports per pywebview (EdgeChromium su Windows)
"--hidden-import", "webview",
"--hidden-import", "webview.platforms.edgechromium",
"--hidden-import", "clr",
"--hidden-import", "requests",
# Collegamenti completi alle DLL .NET di pywebview/pythonnet
"--collect-all", "webview",
# Binari bundled
*add_binaries,
# Entry point
str(ROOT / "main.py"),
]
log(f"Comando: {' '.join(cmd[:10])}...")
subprocess.run(cmd, check=True, cwd=str(ROOT))
exe_path = DIST_DIR / "MusicDownload" / "MusicDownload.exe"
if exe_path.exists():
log(f"Build completata: {exe_path}")
else:
log("ATTENZIONE: MusicDownload.exe non trovato, controlla l'output")
# =========================================================================
# Main
# =========================================================================
def main():
print("=" * 50)
print(" MusicDownload - Build Windows")
print("=" * 50)
if sys.platform != "win32":
print("\nATTENZIONE: Questo script va eseguito su Windows!")
print("PyInstaller non supporta cross-compilation.")
print("Copia il progetto su una macchina Windows e rilancia.")
sys.exit(1)
# Verifica pyinstaller
try:
import PyInstaller
log(f"PyInstaller {PyInstaller.__version__}")
except ImportError:
log("Installo PyInstaller...")
subprocess.run([sys.executable, "-m", "pip", "install", "pyinstaller"],
check=True)
# Pulisci bundle precedente
if BUNDLE_DIR.exists():
shutil.rmtree(BUNDLE_DIR)
download_ytdlp()
download_ffmpeg()
run_pyinstaller()
print("\n" + "=" * 50)
print(" DONE!")
print("=" * 50)
dist = DIST_DIR / "MusicDownload"
if dist.exists():
print(f"\n L'app e in: {dist}")
print(f" Eseguibile: {dist / 'MusicDownload.exe'}")
print(f"\n Per distribuirla, comprimi la cartella:")
print(f" Comprimi {dist} -> MusicDownload_Windows.zip")
print()
if __name__ == "__main__":
main()