Commit Graph
80 Commits
Author SHA1 Message Date
luzadevandClaude Opus 4.7 2d8290579b Riscrivi backend per hosting Node/MariaDB/PM2 (no Cloudflare)
L'utente ha un hosting Virtualmin esistente (musictools.djluza.com)
con Apache + Node 20 + MariaDB + PM2. Tutta l'infrastruttura
Cloudflare (Workers/D1/R2/Pages) e' rimpiazzata con un backend
Express che gira sul server gia' presente, a costo zero.

Cambia:
- server/src/*.ts (Workers) -> server/src/*.js (Node ESM puro)
- D1 (sqlite) -> MariaDB 10.11 via mysql2/promise
- R2 (storage) -> filesystem locale ~/builds/ + signed URL HMAC
- wrangler.toml -> ecosystem.config.cjs (PM2)
- Aggiunto src/migrate.js: runner SQL idempotente

Endpoints invariati - l'app desktop non vede differenze:
- POST /api/license/{activate,validate,deactivate}
- GET  /api/latest, /api/download
- POST /api/webhook/lemonsqueezy
- GET  /api/health

README riscritto con istruzioni complete: creazione DB,
deploy via rsync/git, config Apache reverse proxy via
Virtualmin, gestione PM2, backup, workflow release.

Email rimane su Resend (deliverability) - free tier sufficiente.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-09 00:15:53 +02:00
luzadevandClaude Opus 4.7 339dd4f3cc Foro competente: Tribunale di Chieti (residenza Ortona, CH)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 23:57:56 +02:00
luzadevandClaude Opus 4.7 4e917fd9ef Rafforza Termini: EULA, Acceptable Use, manleva, disclaimer copyright
- terms.html: riscritto da 9 a 18 sezioni con indice cliccabile.
  Include EULA (concessione, restrizioni, IP), Acceptable Use Policy
  (cosa si puo'/non si puo' fare con i Contenuti), disclaimer marchi
  terze parti (Spotify/YouTube/...), procedura DMCA, esclusione
  garanzie AS IS, cap responsabilita = importo pagato negli ultimi
  12 mesi, clausola di manleva (indemnification) a carico dell'utente.
- index.html: nuova box "Uso responsabile" sotto al pricing con i 4
  punti chiave; FAQ ampliate (no affiliazione, segnalazioni copyright);
  testo di accettazione esplicito Termini+Privacy+Refund sotto al CTA;
  footer con titolarita "Luciano Zappacosta".
- css/style.css: stili per use-policy box e price-consent.

Linee guida prese da boilerplate di settore (4K Video Downloader,
JDownloader, MediaHuman) adattate al diritto italiano e GDPR.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 23:56:17 +02:00
luzadevandClaude Opus 4.7 729f3cd8a0 Fix nome titolare nei documenti legali: Luciano Zappacosta
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 23:52:11 +02:00
luzadevandClaude Opus 4.7 4ebfbd472e Landing page per musictools.djluza.com (Cloudflare Pages)
- index.html: hero con mockup app, 6 feature cards, come funziona,
  pricing 39,90 EUR, FAQ accordion, footer
- css/style.css: tema dark Spotify-like coerente con l'app
- js/main.js: animazioni scroll, hook Lemon Squeezy overlay
- legal/{terms,privacy,refund}.html: documenti richiesti da LS/GDPR
- _headers: HSTS, no-sniff, cache lunga per asset
- _redirects: placeholder per futuri /download/{macos,windows}
- README con istruzioni deploy push-to-deploy via Cloudflare Pages

Da fare prima del lancio: sostituire REPLACE_WITH_LS_PRODUCT_URL
in index.html con l'URL del prodotto Lemon Squeezy.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 23:49:58 +02:00
luzadevandClaude Opus 4.7 5202b2c586 Setup commercial launch: licenze + backend Cloudflare Worker
Client (Python/JS):
- core/license.py: attivazione, validazione, deactivate (HTTP client + JWT decode)
- core/config.py: campi license_* + URL endpoint + costanti grace/revalidate
- api/bridge.py: get_init_data ritorna license status; activate_license/
  deactivate_license/revalidate_license/open_purchase_page
- check_update riscritto: punta a musictools.djluza.com/api/latest con
  Bearer token, URL di download firmato dal server solo se licensed
- webui: schermata di attivazione bloccante all'avvio; sezione Licenza
  in Impostazioni con verifica/disattiva

Backend (server/):
- Cloudflare Worker + D1 + R2 (vedi server/README.md)
- Endpoints: /api/license/{activate,validate,deactivate}, /api/latest,
  /api/webhook/lemonsqueezy, /api/health
- JWT HS256 con rotazione; max 3 attivazioni/licenza
- Generazione licenze via webhook Lemon Squeezy + email Resend
- Schema D1 in migrations/0001_init.sql

Memory: nuova musictools-commercial-launch.md, rimosso pending obsoleto

NON taggare finche backend non e' deployato (l'app e' bloccante)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 23:36:41 +02:00
luzadevandClaude Opus 4.7 05a2a58ace Tab Scarica: ricerca diretta per titolo o "Artista - Titolo"
L'input URL ora accetta anche query libere: se non sembra un link
(http/https/spotify:/dominio noto), il testo viene parsato come
{artist, name} e scaricato via download_playlist con una traccia.

Riusa lo stesso flusso ytsearch1: gia in uso per le tracklist da file.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.5.2
2026-06-08 23:13:10 +02:00
luzadevandClaude Opus 4.7 8610f4d95c Fix Windows: nascondi finestra cmd per ogni subprocess yt-dlp/ffmpeg
Aggiunto helper subprocess_flags() in core/paths.py che ritorna
CREATE_NO_WINDOW su Windows. Applicato a tutte le subprocess.run/Popen
in downloader, upgrader e recorder per evitare il flash di console nera
ad ogni traccia scaricata.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.5.1
2026-06-08 23:06:59 +02:00
luzadevandClaude Opus 4.7 b47fdd1ab3 VERSION bump v1.4.0 -> v1.5.0
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.5.0
2026-06-08 11:36:58 +02:00
luzadevandClaude Opus 4.7 e56a975b77 Nuova tab Guida: manuale d'uso completo dentro l'app
Aggiunta una sezione 'Guida' (icona 📖, hero indaco) con manuale
d'uso interno, organizzato in 10 capitoli con sommario sticky a
sinistra:

- Introduzione, Setup iniziale
- Una sezione per ogni tab (Scarica, Video, Upgrade, Metadati,
  Registra, Impostazioni)
- Aggiornamenti
- Troubleshooting con tabella di 8 sintomi/cause/fix
- Risorse esterne (GitHub, yt-dlp FAQ, BlackHole)

UX:
- Layout grid 200px (TOC) + content fluido. Su schermi <900px
  il TOC diventa una row in alto
- TOC sticky con highlight del link attivo via IntersectionObserver
- Link esterni (data-ext) aperti nel browser di sistema via
  open_external_url
- Hint nella tab Registra ora apre la sezione 'Tab Registra' della
  guida invece del README su GitHub
- Box info/success/warn riusabili, stile <code> verde, <pre>
  monospace, tabella troubleshooting

CSS:
- Nuova palette indigo + hero-indigo
- Stili .guide-layout, .guide-toc, .g-section, .g-box, .g-table,
  .kbd, .toc-link.active

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 11:30:48 +02:00
luzadevandClaude Opus 4.7 52002f5184 Icona dell'app: squircle verde con nota musicale
Creata un'icona coerente con la palette dell'app: squircle Apple-style
(corner radius ~22%), gradient verde Spotify -> verde scuro, nota
musicale (♫) bianca centrata con leggero glow, sottile highlight in
alto e bordo soft per definizione.

- assets/generate_icon.py: script PIL riproducibile, produce
  icon.png (master 1024) -> icon.iconset/ -> iconutil -> icon.icns
  (macOS) e icon.ico multi-size (Windows)
- assets/icon.png / icon.icns / icon.ico committati
- assets/icon.iconset/ in .gitignore (intermedio rigenerabile)
- build_macos.py: --icon assets/icon.icns se presente
- build_windows.py: --icon assets/icon.ico se presente

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 11:26:06 +02:00
luzadevandClaude Opus 4.7 878e024c13 Rimuovi playlist personali dal repo
Tolgo dal tracking i file di playlist personali presenti nel
working tree fin dai primi commit:

- Beatport Top 100 Melodic House & Techno.txt
- PlayList_2026.txt
- PlayList_da_scaricare.txt
- Vibes_List.txt

Aggiunti i pattern al .gitignore cosi' non rientrano per sbaglio.
I file rimangono sul disco locale (git rm --cached, non -rf).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 11:19:37 +02:00
luzadevandClaude Opus 4.7 07794052c8 VERSION bump v1.2.2 -> v1.4.0
Allinea la stringa VERSION al numero del tag della prossima release.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.4.0
2026-06-08 11:16:42 +02:00
luzadevandClaude Opus 4.7 850d3f4b6c 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>
2026-06-08 11:15:34 +02:00
luzadevandClaude Opus 4.7 6f5c32165a Video tab: modalita 'Solo audio' (estrazione MP3)
Aggiunto toggle Video/Solo audio nella tab Video. In modalita audio
yt-dlp scarica solo bestaudio ed estrae in MP3 al bitrate impostato
in Impostazioni (default 320 kbps), con embed thumbnail come la tab
Scarica.

- core/downloader.py: download_video() accetta audio_only e
  audio_bitrate; quando True usa format 'bestaudio/best' e
  --extract-audio --audio-format mp3
- api/bridge.py: start_video_download passa audio_only nel worker;
  log mostra 'Solo audio MP3 320K' vs 'Video 1080p'
- webui: segmented control 'Video (MP4)' / 'Solo audio (MP3)' rosa,
  selettore qualita nascosto in modalita audio, hint aggiornato

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 11:11:50 +02:00
luzadevandClaude Opus 4.7 39c92f44f4 Guida registrazione: Setup A/B BlackHole + Multi-Output Device
- README: sezione 'Guida rapida' riscritta con installazione,
  permesso microfono macOS, Setup A (output dedicato a BlackHole)
  e Setup B (Multi-Output Device con BlackHole + altoparlanti,
  Master Device + Drift Correction). Aggiunta tabella
  Troubleshooting (5 sintomi tipici con fix)
- webui: hint nella tab Registra arricchito (riassunto a step
  inline + link al README su GitHub via window open)
- CSS: .hint passa a align-items flex-start per contenuto
  multi-riga, aggiunti stili per <code> e <a> dentro l'hint

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 11:09:26 +02:00
luzadevandClaude Opus 4.7 9f37b7eb94 Recorder: drena stderr di ffmpeg + messaggi di errore leggibili
Il vecchio worker non drenava lo stderr di ffmpeg: dopo ~64KB il
pipe si bloccava e quando ffmpeg falliva subito (es. permesso
microfono negato su macOS) si vedeva solo 'ffmpeg exit -6' senza
contesto.

- Thread dedicato _drain_stderr() che legge stderr in continuo e
  mantiene le ultime 50 righe in un buffer protetto
- _extract_friendly_error() riconosce i casi tipici e produce
  messaggi italiani:
    * exit -6 su macOS -> 'permesso Microfono mancante'
    * Input/Output error -> 'dispositivo non disponibile'
    * 'no such device' -> 'premere Aggiorna'
- Pre-flight check: aspetta che ffmpeg stampi 'Press [q]' (segnale
  di device aperto) prima di emettere 'started'. Se ffmpeg muore
  prima, l'errore viene segnalato senza falso 'recording in corso'

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 11:03:22 +02:00
luzadevandClaude Opus 4.7 5041d3e14c README: aggiornato con tab Metadati, Registra e guida BlackHole
- Tabella riepilogativa delle 6 tab dell'app (Scarica, Video,
  Upgrade, Metadati, Registra, Impostazioni) con descrizione
  breve di ciascuna feature
- Sezione 'Auto-skip dei duplicati' e 'Sottocartella automatica
  per le tracklist' (feature aggiunte in v1.2.x)
- Aggiunta 'mutagen' nelle dipendenze principali
- Nuova sezione 'Guida rapida: registrazione audio di sistema
  (macOS)' con istruzioni complete per installare BlackHole
  e creare un Multi-Output Device per sentire e registrare
  contemporaneamente
- Struttura progetto: aggiunti core/metadata.py e core/recorder.py
- Esempio tag nel paragrafo 'Build & Release' bumpato a v1.3.0
- Nota sull'aggiornamento app: ricorda il vincolo del repo pubblico
  per far funzionare l'API GitHub Releases

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.3.0
2026-06-08 10:47:15 +02:00
luzadevandClaude Opus 4.7 97a440819a Nuova tab Registra: cattura audio da ingresso del computer
Aggiunta sezione per registrare in MP3 320 kbps da qualsiasi
dispositivo di input audio del sistema (mixer, scheda audio
esterna, microfono interno, BlackHole / driver virtuali per audio
di sistema).

- core/recorder.py: list_input_devices() parsa l'output di
  ffmpeg -list_devices su AVFoundation (macOS) e DirectShow (Win),
  marca come 'virtual' i driver loopback noti (BlackHole, Soundflower,
  Loopback, VB-Cable, Stereo Mix, OBS). start_recording() lancia
  ffmpeg in thread e emette eventi tick/started/stopped/error.
- api/bridge.py: list_audio_inputs, start_audio_recording,
  stop_audio_recording, is_audio_recording
- webui: hero rosso, dropdown dispositivi con badge 'loopback',
  selettore bitrate, timer HH:MM:SS animato, bottone REC con
  pulse animation, card 'Ultima registrazione' con durata+path
- Hint visibile: per registrare audio di sistema serve BlackHole

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 10:44:05 +02:00
luzadevandClaude Opus 4.7 1d7832e246 Metadati: campo 'Origine (macOS · kMDItemWhereFroms)'
kMDItemWhereFroms non e un tag ID3/MP4/Vorbis: e' un extended
attribute filesystem di macOS che Safari/Mail/AirDrop e altri tool
impostano per ricordare l'origine di un file scaricato.

- core/metadata.py: _read_where_from / _write_where_from via subprocess
  xattr + plistlib (lettura/scrittura del plist binario embedded
  nell'attributo)
- read_metadata espone 'where_from' (lista URL) e 'is_macos'
- write_metadata applica l'xattr se data['where_from'] e fornito;
  lista vuota -> rimuove l'attributo
- webui: textarea 'Origine' visibile solo su macOS (is_macos=true),
  una URL per riga

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 10:36:18 +02:00
luzadevandClaude Opus 4.7 61879c42d3 Metadati WAV: fallback al chunk RIFF LIST/INFO
Mutagen.wave legge solo i tag ID3 embedded nel WAV, ma molti file
WAV usano il chunk RIFF LIST/INFO originale (es. ffmpeg, vari
encoder semplici).

Aggiunto _read_wav_info_chunk() che parsa manualmente il blocco
RIFF e mappa i campi standard (INAM, IART, IPRD, ICRD, IGNR,
ICMT, ITRK, IBPM, ...) sui campi della UI.

In _read_wav() ora si legge prima il chunk INFO come fallback, poi
l'ID3 sovrascrive i valori se presenti (ID3 ha priorita per i WAV
moderni).

In scrittura si continua a usare ID3 (standard piu ricco e supportato
dai player moderni); i campi INFO esistenti restano nel file ma
diventano ridondanti.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 10:32:58 +02:00
luzadevandClaude Opus 4.7 246ff1b0e5 Metadati: aggiunto supporto WAV (ID3 chunk embedded)
WAV puo' contenere un blocco ID3v2 embedded oltre al PCM raw.
Mutagen.wave.WAVE espone gli stessi frame TIT2/TPE1/APIC etc.
del MP3.

- core/metadata.py: SUPPORTED_EXTS include '.wav', read/write via
  WAVE.tags (con add_tags() se mancante)
- bridge.py: file picker include *.wav nel filter audio

Round-trip verificato: titolo/artista/album/anno/track/bpm/key/
commento + copertina preservati.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 10:29:36 +02:00
luzadevandClaude Opus 4.7 3dcbdfa489 Fix tab Metadati: file dialog non si apriva
I file filter di pywebview vogliono estensioni separate da ';' non
da spazio. Cambiato 'Audio (*.mp3 *.m4a ...)' in
'Audio (*.mp3;*.m4a;...)'. Stesso fix per il dialog copertine.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 10:26:15 +02:00
luzadevandClaude Opus 4.7 946452ef03 Tab Metadati: editor dei tag audio (MP3, M4A, FLAC)
Nuova sezione 'Metadati' nella sidebar con editor completo dei tag:
titolo, artista, album, album artist, anno, traccia, genere, BPM,
key, commento, copertina.

- core/metadata.py: read/write metadati via mutagen, supporto ID3
  (MP3), MP4 atoms (M4A/AAC) e Vorbis comments (FLAC)
- api/bridge.py: pick_audio_file, pick_image_file, read_metadata,
  save_metadata. Cover passata come base64 al frontend per preview
- webui: hero ambra, form a griglia 2 colonne, anteprima cover 180x180,
  bottoni cambia/rimuovi copertina, ricarica file
- requirements.txt: aggiunto mutagen>=1.47.0
- build_macos.py / build_windows.py: --collect-all mutagen

Modifiche correlate (in attesa di decisione utente sulla
distribuzione degli aggiornamenti):
- VERSION bumpato a v1.2.2 in core/config.py
- check_update ora interroga l'API GitHub Releases invece di
  djluza.com/version.json (funzionera quando il repo sara pubblico)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-08 10:24:07 +02:00
luzadevandClaude Opus 4.7 d8423ec215 Tracklist: crea sottocartella col nome del file caricato
Quando si carica un file .txt come tracklist, l'app ora scarica i
brani in <output_dir>/<nome_file>/ anziche direttamente in output_dir.
Es: 'Beatport Top 100 Melodic House & Techno.txt' -> cartella
'Beatport Top 100 Melodic House & Techno/' creata dentro la
cartella output predefinita.

- load_url_list ritorna 'name' (basename senza estensione)
- start_tracks_download accetta 'subfolder' opzionale e fa
  os.path.join con sanitizzazione dei separatori
- JS passa state.loaded.name come subfolder

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.2.1
2026-06-06 00:23:20 +02:00
luzadevandClaude Opus 4.7 4b1524e5f7 Carica lista: auto-detect URL list vs tracklist
Adesso 'Carica lista' nella tab Scarica riconosce automaticamente
il formato del file .txt:

- Se la prima riga e un URL (http/https) -> URL list (come prima)
- Altrimenti -> tracklist parsata 'Artista - Titolo (variant) (durata)'
  e scaricata cercando ogni brano su YouTube (riusa download_playlist)

Parser robusto: gestisce numerazione iniziale (1. / 1) / 1: / 1-),
qualsiasi tipo di dash (-, en-dash, em-dash, ...) e durata finale
'(M:SS)'. Testato sulla Beatport Top 100 Melodic House & Techno
(100/100 tracce parsate).

api/bridge.py: nuovo start_tracks_download, load_url_list ritorna
'kind: urls|tracks'.
webui/js/app.js: badge cambia tra 'X URL' e 'X tracce', avvio
chiama start_tracks_download quando appropriato.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.2.0
2026-06-05 19:37:17 +02:00
luzadevandClaude Opus 4.7 e5158d382f README: riscritto per UI pywebview + tab Video + CI release
- Aggiornata struttura progetto (webui/, api/, niente piu gui/)
- Documentate nuove dipendenze (pywebview, pyobjc-WebKit, pythonnet)
- Sezione build con GitHub Actions e release automatiche su tag
- Esempio uso cookies.txt per Instagram/Facebook privati

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 13:33:38 +02:00
luzadevandClaude Opus 4.7 8d9c05b151 Aggiunta tab Video: YouTube, TikTok, Instagram, Facebook
- core/downloader.py: download_video() con format selector qualita
  (best / 1080p / 720p / 480p), merge MP4, tracking .downloaded_videos
- api/bridge.py: start_video_download / stop_video_download / _video_worker.
  Guard _any_job_running() per evitare concorrenza tra audio e video
  (condividono lo stesso _stop_event)
- webui: nuova nav item, view con hero rosa (gradient pink->black),
  selettore qualita, hint cookies per Instagram/Facebook privati
- CSS: palette pink, .hero-pink, .btn-pink, .progress-fill.pink,
  componente .hint riusabile
- JS: handlers tab Video, canale bridge video:progress/video:done

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.1.0
2026-05-30 13:12:31 +02:00
luzadevandClaude Opus 4.7 c3f6088b58 CI: zip artifacts e Release automatica su tag
- macOS: ditto del .app -> MusicDownload-macOS.zip
- Windows: Compress-Archive di dist/MusicDownload -> MusicDownload-Windows.zip
- Job release con softprops/action-gh-release@v2: parte su tag v*,
  scarica entrambi gli artifact e li allega a una GitHub Release con
  note generate automaticamente.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
v1.0.0
2026-05-30 12:51:02 +02:00
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