fix git ignore
This commit is contained in:
parent
c3d3337a21
commit
3a1539f985
|
|
@ -1,93 +0,0 @@
|
||||||
# ACH Server Media Import - Agent Instructions
|
|
||||||
|
|
||||||
Guidelines and standards for the ACH Media Import project.
|
|
||||||
|
|
||||||
## Project Overview
|
|
||||||
This project is a Python-based utility that imports media files from an S3-compatible bucket into a PostgreSQL database, enforcing specific naming conventions and metadata validation.
|
|
||||||
|
|
||||||
## Technical Stack
|
|
||||||
- **Language**: Python 3.8+
|
|
||||||
- **Database**: PostgreSQL (via `psycopg2`)
|
|
||||||
- **Cloud Storage**: AWS S3/S3-compatible storage (via `boto3`)
|
|
||||||
- **Containerization**: Docker & Docker Compose
|
|
||||||
- **Environment**: Managed via `.env` and `config.py`
|
|
||||||
|
|
||||||
## Architecture & Modular Design
|
|
||||||
The project uses a utility-based modular architecture orchestrated by `main.py`.
|
|
||||||
- [main.py](main.py): Entry point and workflow orchestrator.
|
|
||||||
- [s3_utils.py](s3_utils.py): S3 client operations and bucket listing.
|
|
||||||
- [db_utils.py](db_utils.py): Database connectivity and SQL execution.
|
|
||||||
- [validation_utils.py](validation_utils.py): Pattern matching and business logic validation.
|
|
||||||
- [logging_config.py](logging_config.py): Centralized logging configuration.
|
|
||||||
- [error_handler.py](error_handler.py): Error handling and notifications.
|
|
||||||
- [email_utils.py](email_utils.py): SMTP integration for alerts.
|
|
||||||
|
|
||||||
## Domain Logic: Inventory Codes
|
|
||||||
The core validation revolves around "Inventory Codes" which MUST follow a strict 12-character format:
|
|
||||||
- `^[VA][OC]-[A-Z0-9]{3}-\d{5}$`
|
|
||||||
- Examples: `VA-C01-12345`, `OC-A99-67890`.
|
|
||||||
- Files not matching this pattern in S3 are logged but skipped.
|
|
||||||
|
|
||||||
## Development Workflows
|
|
||||||
|
|
||||||
### Environment Setup
|
|
||||||
- **Windows**: Use `. .venv\Scripts\Activate.ps1`
|
|
||||||
- **Linux/macOS**: Use `source .venv/bin/activate`
|
|
||||||
- **Dependency installation**: `pip install -r requirements.txt`
|
|
||||||
|
|
||||||
### Local Execution
|
|
||||||
- **Run script**: `python main.py`
|
|
||||||
- **Verify Configuration**: Ensure `.env` is populated with `DB_`, `AWS_`, and `SMTP_` variables.
|
|
||||||
|
|
||||||
### Docker Operations
|
|
||||||
- **Build/Up**: `docker compose up -d --build`
|
|
||||||
- **Logs**: `docker compose logs -f app`
|
|
||||||
- **Stop**: `docker compose stop`
|
|
||||||
|
|
||||||
## Coding Standards & Conventions
|
|
||||||
|
|
||||||
### Logging
|
|
||||||
- Use the custom logger from `logging_config.py`.
|
|
||||||
- **Log Levels**: Use `logging.INFO`, `logging.WARNING`, and the custom `CUSTOM_ERROR_LEVEL` (35) via `error_handler.py`.
|
|
||||||
- Logs are rotated and stored in the `logs/` directory.
|
|
||||||
|
|
||||||
### Error Handling
|
|
||||||
- Wrap critical operations that should trigger notifications in try-except blocks that call `error_handler.notify_error()`.
|
|
||||||
- Avoid silent failures; ensure errors are logged to the appropriate file sync.
|
|
||||||
|
|
||||||
### Configuration
|
|
||||||
- Access settings exclusively via the `config.py` module's dictionaries: `db_config`, `aws_config`, `ach_config`.
|
|
||||||
- Never hardcode credentials or endpoints.
|
|
||||||
|
|
||||||
## Copilot / Agent Behavior
|
|
||||||
|
|
||||||
This repository is used with an AI assistant. When interacting with the assistant, follow these principles:
|
|
||||||
|
|
||||||
- **Do not modify code unless explicitly requested.** The assistant should not change files unless given a clear instruction to do so.
|
|
||||||
- **Ask before acting.** If a change is needed, the assistant should describe the required modification and confirm before applying it.
|
|
||||||
- **Prefer explanation over edits.** When debugging or answering questions, provide guidance and analysis rather than directly editing source files.
|
|
||||||
- **Keep changes minimal.** If a code change is approved, apply the smallest possible edit that resolves the issue.
|
|
||||||
|
|
||||||
## Code Style & Maintainability
|
|
||||||
|
|
||||||
When generating or modifying code, prioritize **maintainability and clarity over optimization**.
|
|
||||||
|
|
||||||
This is **development-stage code**, so it must remain easy to read, understand, and modify by humans.
|
|
||||||
|
|
||||||
Guidelines:
|
|
||||||
|
|
||||||
- Prefer **clear, explicit implementations** rather than clever or overly compact solutions.
|
|
||||||
- Avoid **micro-optimizations** or complex patterns that reduce readability.
|
|
||||||
- Do **not introduce obscure algorithms or creative tricks** that make the code difficult to understand.
|
|
||||||
- Write code that a developer unfamiliar with the project can quickly follow.
|
|
||||||
- Use **meaningful variable and function names**.
|
|
||||||
- Add **thoughtful comments** explaining non-obvious logic, assumptions, and decisions.
|
|
||||||
- Favor **simple and conventional approaches** instead of experimental or highly abstract ones.
|
|
||||||
- Maintain a **consistent structure and formatting**.
|
|
||||||
|
|
||||||
The goal is **clean, maintainable, well-documented code**, not maximum performance or cleverness.
|
|
||||||
|
|
||||||
## Related Files
|
|
||||||
- [query-sql.md](query-sql.md): Reference for database schema and SQL logic.
|
|
||||||
- [requirements.txt](requirements.txt): Project dependencies.
|
|
||||||
- [docker-compose.yml](docker-compose.yml): Deployment configuration.
|
|
||||||
186
TODO-mime.md
186
TODO-mime.md
|
|
@ -1,186 +0,0 @@
|
||||||
Read [](file:///d%3A/02-Programming/20_ACH_20/ACH-server-import-media02/validation_utils.py#1-1), lines 1 to 260
|
|
||||||
|
|
||||||
Searched for regex `allowed_extensions|allowed audio|allowed|endswith\('` (`**/*.py`), 20 results
|
|
||||||
|
|
||||||
Ecco il report sui **processi di validazione** che usano valori “hard-coded” (cioè codificati direttamente nel sorgente, non estratti da config.py o da una tabella centrale). Questo include liste di estensioni, pattern, e regole applicate in modo statico nel codice.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1) Hard-coded estensioni / mime in utils.py
|
|
||||||
|
|
||||||
### 1.1 `check_video_info()` (video)
|
|
||||||
- **Lista fissa di estensioni video** (solo quando il file è sotto `FILE/`):
|
|
||||||
- `['.mov', '.avi', '.m4v', '.mp4', '.mxf', '.mpg', '.mpeg', '.wmv']`
|
|
||||||
- Questa lista viene usata per rifiutare i file che non finiscano con queste estensioni.
|
|
||||||
|
|
||||||
### 1.2 `check_audio_info()` (audio)
|
|
||||||
- **Lista fissa di estensioni audio** (quando il file è sotto `FILE/`):
|
|
||||||
- `['.wav', '.mp3', '.m4a', '.aif', '.aiff']`
|
|
||||||
- Qui è dove saltava l’errore che ti ha dato: se la stringa usata (`@ref` dal JSON) non finisce con una di queste estensioni, la validazione fallisce.
|
|
||||||
- Questa lista non è derivata da `config.EXTENSION_MIME_MAP` ma è hardcoded.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2) Hard-coded pattern/validazione in validation_utils.py
|
|
||||||
|
|
||||||
### 2.1 Inventory code (core validation)
|
|
||||||
- Pattern fisso: `r'^[VA][OC]-[A-Z0-9]{3}-\d{5}$'` (ok, è una regola di business, quindi anche hardcoded è accettabile)
|
|
||||||
|
|
||||||
### 2.2 Regole per l’estensione dopo i 12 caratteri
|
|
||||||
- `file_type_to_regex` è un dizionario hardcoded:
|
|
||||||
- `BTC`, `OA4`, `DVD`, `BRD`, `MCC`, `DBT`, `M4V`, `AVI`, `MOV`, `MP4`, `MXF`, `MPG`
|
|
||||||
- Anche qui: hardcoded ma è fatto apposta (linee guida di formato).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3) Hard-coded estensioni in main.py (filtri e contatori)
|
|
||||||
|
|
||||||
### 3.1 Filtri iniziali (Phase 1)
|
|
||||||
- `valid_extensions = {'.mp3', '.mp4', '.md5', '.json', '.pdf'}` → hardcoded
|
|
||||||
- `excluded_folders` → hardcoded set (per ora `{'DOCUMENTAZIONE_FOTOGRAFICA/', 'TEST-FOLDER-DEV/', 'TST/', 'UMT/'}`)
|
|
||||||
|
|
||||||
### 3.2 Contatori (sempre in main.py)
|
|
||||||
- Conta file con `.mp4`, `.mp3`, `.md5`, `.pdf`, `.json`, `.mov`, `.avi`, `.m4v`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4) Hard-coded estensioni in `validation_utils.validate_mp4_file()`
|
|
||||||
- Filtra semplicemente su `.mp4` con `f.lower().endswith('.mp4')`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 5) Logica MIME in db_utils.py
|
|
||||||
- Anche se usa `EXTENSION_MIME_MAP`, c’è una mappatura “extra” basata su valori di MediaInfo (che è anch’essa hardcoded dentro `get_mime_from_mediainfo`)
|
|
||||||
- Esempi: `'MPEG-4' -> video/mp4`, `'QuickTime' -> video/quicktime`, ecc.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Conclusione (cosa fare/controllare)
|
|
||||||
|
|
||||||
### A) Se vuoi centralizzare le regole (suggerito)
|
|
||||||
- Le liste di estensioni usate in utils.py (audio/video) potrebbe essere prese da **`config.EXTENSION_MIME_MAP`** (o da una struttura simile, per evitare duplicati e incongruenze).
|
|
||||||
- Lo stesso vale per le estensioni usate nei filtri di main.py (valid_extensions).
|
|
||||||
|
|
||||||
### B) Se vuoi sapere cosa esattamente è “errato”
|
|
||||||
- Quelle liste sono i punti dove potrebbero esserci discrepanze rispetto al mapping MIME desiderato.
|
|
||||||
- In particolare, la validazione audio si basa esclusivamente su `@ref` e sulla lista `audio_allowed_extensions`. Se `@ref` non finisce con un’estensione ammessa, viene rifiutato — a prescindere da cosa dice `FileExtension` nel JSON.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Se vuoi, posso farti un report più “operativo”:
|
|
||||||
|
|
||||||
- elenco esatto di tutte le linee contenenti liste hardcoded di estensioni
|
|
||||||
- suggerimenti su come “collegare” queste liste a `EXTENSION_MIME_MAP` per avere un’unica fonte di verità (senza toccare altri comportamenti)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Read [](file:///d%3A/02-Programming/20_ACH_20/ACH-server-import-media02/db_utils.py#1-1), lines 1 to 200
|
|
||||||
|
|
||||||
## ✅ “Logica MIME” in db_utils.py (dettaglio completo)
|
|
||||||
|
|
||||||
In db_utils.py ci sono **due funzioni chiave** che determinano il MIME da associare a un file:
|
|
||||||
|
|
||||||
1. **`get_mime_for_extension(ext)`** — mappa direttamente un’estensione (es. `.mp4`) a un MIME, usando la tabella centrale `EXTENSION_MIME_MAP` in config.py.
|
|
||||||
2. **`get_mime_from_mediainfo(ach_variables)`** — cerca di capire il MIME dal contenuto del sidecar JSON (`mediainfo`), con un lungo flusso di fallback.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔹 1) `get_mime_for_extension(ext)` — mappatura “classica”
|
|
||||||
|
|
||||||
Questa funzione è usata come fallback quando la logica “mediainfo” non trova niente di utilizzabile.
|
|
||||||
|
|
||||||
- Prende un’estensione **con o senza punto**
|
|
||||||
- Normalizza (aggiunge il punto se manca)
|
|
||||||
- Cerca in `EXTENSION_MIME_MAP`
|
|
||||||
- Se non trova, usa **`application/octet-stream`**
|
|
||||||
|
|
||||||
📍 **Dove viene usato:**
|
|
||||||
- Quando non si riesce a inferire un MIME riuscendo dalla metadata JSON (`get_mime_from_mediainfo`), oppure quando si vuole usare solo l’estensione dichiarata del file (es. nel record streaming `.mp4`).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔹 2) `get_mime_from_mediainfo(ach_variables)` — logica “intelligente”
|
|
||||||
|
|
||||||
Questa funzione è quella più complessa e cerca di essere **“corretta” rispetto al master**, perché:
|
|
||||||
|
|
||||||
- La copia master (conservatory copy) potrebbe essere `.mov` (video/quicktime)
|
|
||||||
- ma lo stream nel bucket potrebbe essere `.mp4` (video/mp4) e il JSON potrebbe essere basato su `.mp4`
|
|
||||||
- vogliamo comunque salvare il MIME del **master**, non dello stream
|
|
||||||
|
|
||||||
### Passaggi principali
|
|
||||||
|
|
||||||
#### ✅ 2.1 Priorità master `.mov`
|
|
||||||
Se il codice conosce già che il master è `.mov`, **ritorna subito** `video/quicktime`:
|
|
||||||
|
|
||||||
- controlla `ach_variables['conservative_copy_extension']`
|
|
||||||
- poi controlla `ach_variables['objectKeys']['conservative_copy']` (il path JSON `@ref`)
|
|
||||||
|
|
||||||
> Questo serve a evitare che MediaInfo dica “MPEG-4” e invece venga salvato `video/mp4` per un `.mov`.
|
|
||||||
|
|
||||||
#### ✅ 2.2 Se non è `.mov`, prova con il JSON `mediainfo`
|
|
||||||
- Cerca il track `@type == "General"` (di solito il primo track)
|
|
||||||
- Legge il campo `Format` (es. `MPEG-4`, `AVI`, `AIFF`, …)
|
|
||||||
- Confronta il valore `Format` con una **mappa hardcoded**:
|
|
||||||
|
|
||||||
```py
|
|
||||||
mapping = {
|
|
||||||
'AVI': 'video/x-msvideo',
|
|
||||||
'MOV': 'video/quicktime',
|
|
||||||
'QuickTime': 'video/quicktime',
|
|
||||||
'MPEG-4': 'video/mp4',
|
|
||||||
'MP4': 'video/mp4',
|
|
||||||
'MXF': 'application/mxf',
|
|
||||||
'MPEG': 'video/mpeg',
|
|
||||||
'MPEG-PS': 'video/mpeg',
|
|
||||||
'MPEG-TS': 'video/MP2T',
|
|
||||||
'MPEG Audio': 'audio/mpeg',
|
|
||||||
'MPEG Audio/Layer 3': 'audio/mpeg',
|
|
||||||
'AAC': 'audio/aac',
|
|
||||||
'PCM': 'audio/wav',
|
|
||||||
'WAV': 'audio/wav',
|
|
||||||
'AIFF': 'audio/aiff',
|
|
||||||
'FLAC': 'audio/flac',
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Se `Format` corrisponde esattamente (case-insensitive), restituisce il MIME corretto.
|
|
||||||
|
|
||||||
#### ✅ 2.3 Fallback “fuzzy” sul campo `Format`
|
|
||||||
Se `Format` non è uno di quelli nella mappa, prova a identificare il MIME basandosi su parole chiave nel valore:
|
|
||||||
|
|
||||||
- se contiene `avi` → `video/x-msvideo`
|
|
||||||
- se contiene `mp4` → `video/mp4`
|
|
||||||
- se contiene `mpeg` → `video/mpeg`
|
|
||||||
- se contiene `wav` o `pcm` → `audio/wav`
|
|
||||||
- se contiene `mp3` → `audio/mpeg`
|
|
||||||
|
|
||||||
#### ✅ 2.4 Ultimo fallback: mappa dalle estensioni
|
|
||||||
Se tutto il resto fallisce **ricade su**:
|
|
||||||
|
|
||||||
- `get_mime_for_extension(ach_variables['extension'])`
|
|
||||||
|
|
||||||
Quindi qui la mappatura centrale (`EXTENSION_MIME_MAP`) è l’ultima risorsa.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🧩 In quali casi “sbaglia”?
|
|
||||||
|
|
||||||
Potenziali punti deboli / dove i MIME possono risultare sbagliati:
|
|
||||||
|
|
||||||
1. **`mediainfo.Format` usa valori non previsti** (es. “MPEG-4” per `.mov` → ma abbiamo già fallback `.mov`)
|
|
||||||
2. **`ach_variables['extension']` è errato** (se non deriva dal file giusto)
|
|
||||||
3. **`EXTENSION_MIME_MAP` non contiene un’estensione** usata in produzione (ma l’hai già sistemato)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📍 Dove viene usata la logica
|
|
||||||
`get_mime_from_mediainfo()` viene chiamata in `add_file_record_and_relationship()` quando si aggiunge il “master” al DB (quindi influisce sul `file_type` del master), mentre lo stream usa `get_mime_for_extension()` (“media” record).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Se vuoi, posso evidenziarti:
|
|
||||||
- Esattamente in quale riga `add_file_record_and_relationship` chiama `get_mime_from_mediainfo`
|
|
||||||
- Qual è il valore preciso usato in `ach_variables` nelle diverse fasi (per capire esattamente cosa arriva a `get_mime_from_mediainfo`)
|
|
||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue