--- aliases: ["MonitorOsservatorio"] type: progetto status: new --- # CLAUDE.md — MonitorOsservatorioPy **Versione:** v3 **Ultimo aggiornamento:** 2026-07-16 Evoluzione Python di MonitorOsservatorio.xlsm (VBA Excel). Gestisce dati ascolti TV per **Spagna** e **Germania** ricevuti dal Marketing (file .xlsx). --- ## Scopo - **Importa** file `.xlsx` Marketing (2 righe header, dati da riga 3) - Mostra dati in griglia HTML/JS editabile (Flask + pywebview) - **Aggancio** righe → SCHEDA_PRODOTTO (manuale via form, o automatico per titolo) - **Esporta** `.xlsx` sidecar → cartella `export\` sessione utente, aperto con app predefinita ## Deploy - **Produzione:** `\\Mediaset.it\cologno\Osservatorio_Progetti\MonitorOsservatorio\MonitorOsservatorioPy\` - **Tier 1** — Python embedded standalone, zero setup su macchine client - Gli utenti lanciano `run.bat` dal path UNC sopra - `deploy.bat` fa robocopy dalla dev verso il path UNC (include `python\` embedded) - Installa `pywebview` nell'embedded se non presente; rimuove `PyQt6-WebEngine` (~300MB) - `monitor.db` viene aggiornato da Access via ODBC all'avvio dell'app (non da Frank) ## Session storage (per utente) `\\Mediaset.it\cologno\...\MonitorOsservatorioPy\{USERNAME}\` - `current_source.xlsx` — file importato - `current_session.json` + 3 backup rotanti — annotazioni 1TV/aggancio - `export\` — export xlsx - `monitor.log` — log loguru (1 MB rotation, 3 file) - Fallback automatico su `%APPDATA%\MonitorOsservatorio` se share non raggiungibile ## Struttura ``` MonitorOsservatorioPy\ ├── python\ ← Python embedded 3.11.9 (non in git) ├── monitor.db ← SQLite mirror SCHEDA_PRODOTTO (non in git) ├── run.bat ├── deploy.bat ← robocopy dev → produzione UNC └── app\ ├── main.py ├── importer.py ← parsing .xlsx Marketing ├── exporter.py ← sidecar xlsx (colonne 1TV INVERTITA + CODICE) ├── db.py ← accesso SQLite monitor.db + sync da Access ├── session.py ← persistenza sessione per utente su share ├── state.py ← stato globale Flask ├── server.py ← API Flask └── templates/ └── index.html ``` ## Tracciato input (.xlsx Marketing) | Col | Campo | Note | |---|---|---| | A | Channel | canale TV | | B | Weekday | giorno settimana | | C | Date | data emissione | | D | Start time | ora inizio | | E | Title | titolo programma | | F | Description | sottotitolo/episodio | | G | Duration | formato `HHMM:SS` | | H-I | Share + Rtg(000) | Ind. 4+ (inv) | | J-K | Share + Rtg(000) | Target Commerciale 16-59 | | L-M | Share + Rtg(000) | MEN 16+ | | N-O | Share + Rtg(000) | WOMEN 16+ | | P-Q | Share + Rtg(000) | MEN 16-59 | | R-S | Share + Rtg(000) | WOMEN 16-59 | Header su righe 1-2, dati da riga 3. ## DB SQLite (monitor.db) Tabella `SCHEDA_PRODOTTO` — mirror da `db.accdb` Access: - TITOLO, TIPOLOGIA, ANNO, GENERE, PAESE, RETE, CodOss ## Paesi supportati - **Spagna** — canali: La1, La2, A3, CUATRO, T5, SEXT, ecc. - **Germania** — da definire quando arriva file di esempio ## Frank sync `frank_sync/sync_db.py` — placeholder per eventuale sync futuro da Frank. Per ora il sync avviene all'avvio dell'app direttamente via pyodbc (gli utenti hanno il driver ODBC). ## Architettura UI - **`main.py`**: avvia Flask in thread, poi `webview.start()` (pywebview + WebView2 di sistema) - **Nessun PyQt6** — rimosso completamente. Avvio ~2-3s vs ~12s precedenti (era QtWebEngine bundled) - **Export**: Flask salva xlsx in `session.export_dir()`, JS chiama `window.pywebview.api.open_file(path)` - `decoder.load()` e `sync_from_access()` girano in thread background — non bloccano l'avvio ## Gotcha - Colonna Duration: formato stringa `HHMM:SS` (es. `0053:45`) — non un timedelta standard - Alcune celle Duration sono `timedelta` Python (openpyxl le converte) — gestire entrambi - Caratteri speciali nei titoli spagnoli (es. `SUE\xc3\xb1OS`) — leggere in UTF-8 - pywebview richiede `pythonnet` su Windows (già presente nell'embedded); usa WebView2 (Edge di sistema)