Metadata-Version: 2.4
Name: metadata-stripper
Version: 0.2.0
Summary: Read, score and remove metadata (EXIF/GPS/XMP/PDF/Office/audio/video/zip/HEIF) — risk engine, forensics, policies, watcher, HTTP service and plugins, with a Textual TUI.
License: MIT
Keywords: metadata,exif,gps,privacy,cli,tui,forensics,risk,heif,watcher,plugins
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Security
Classifier: Topic :: Multimedia :: Graphics
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: Pillow>=9.0
Requires-Dist: textual>=0.60
Provides-Extra: pdf
Requires-Dist: pypdf>=3.0; extra == "pdf"
Provides-Extra: audio
Requires-Dist: mutagen>=1.45; extra == "audio"
Provides-Extra: ole
Requires-Dist: olefile>=0.46; extra == "ole"
Provides-Extra: all
Requires-Dist: pypdf>=3.0; extra == "all"
Requires-Dist: mutagen>=1.45; extra == "all"
Requires-Dist: olefile>=0.46; extra == "all"
Dynamic: license-file

<div align="center">

# 📷 Metadata Stripper

<img src="https://raw.githubusercontent.com/AnonymoDGH/metadata-stripper/main/logo.png" alt="Metadata Stripper" width="180"/>

**Your photos know more than you do. Read it, then erase it.**

[![Python](https://img.shields.io/badge/python-3.9%2B-blue.svg)](https://www.python.org/)
[![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
[![PyPI](https://img.shields.io/badge/PyPI-metadata--stripper-orange.svg)](https://pypi.org/project/metadata-stripper/)
[![Platform](https://img.shields.io/badge/platform-osx%20%7C%20linux%20%7C%20windows-lightgrey.svg)]()

> *"The photo was innocent. The GPS coordinates were not."*

</div>

---

## What is it?

Every file whispers: *where it was taken, with what camera, by whom and at
what exact moment*. That whisper is metadata — and half the time it includes
GPS coordinates. **Metadata Stripper v2** reads the whisper, shows it to you
in a beautiful Textual TUI, and then removes it for good.

```
JPEG / PNG / WebP / TIFF / BMP / GIF / ICO     — EXIF, GPS, XMP, ICC, thumbnail
HEIC / HEIF / AVIF                            — ISOBMFF container, EXIF/XMP items
PDF                                           — document info, XMP packet
DOCX / XLSX / PPTX / ODT / ODS / ODP          — core/app/custom properties
ZIP                                           — comments, timestamps, junk files
MP3 / FLAC / WAV / OGG / OPUS                 — ID3, vorbis, RIFF INFO
MP4 / MOV / MKV / WEBM / AVI                  — tags, covr, LIST INFO
DOC / XLS / PPT / MSG (OLE2)                  — read-only analysis
```

## Run it

```bash
pip install "metadata-stripper[all]"   # or: pip install -e .[all]
metastrip                              # 🚀 opens the TUI
```

`metastrip` with **no arguments opens the Textual TUI** — the main
interface. All subcommands below also work for scripting.

## The TUI

Eight tabs, keyboard-first, dark theme with a fire-gradient dragon banner:

| Tab | What you can do |
|---|---|
| **Explorar** | type a path, scan (F5), filter GPS-only / high-risk, click a file |
| **Detalle** | every metadata field grouped (EXIF/GPS/XMP/ICC/doc/audio…) |
| **GPS** | decimal + DMS coordinates, geohash, plus code, altitude, **nearest cities**, map/OSM links, plausibility check |
| **Riesgo** | field-level privacy score: per-field 0-10 bar, category, verdict, per-category points |
| **Limpiar** | profile select (full/gps/dates/author/device/paper), keep/remove fields, dry-run, rename, output dir, live log |
| **Batch** | parallel mass-clean with N workers, progress bar, cancel |
| **Reporte** | export scan results as JSON / CSV / HTML |
| **Renombrar** | chameleon rename: random or `{index} {name} {ext} {date} {time} {rand}` |

Key bindings: `F5` rescan · `Ctrl+S` clean selection · `Ctrl+B` clean all ·
`R` rename · `E` export · `Q` quit.

## CLI (scripting)

```bash
metastrip scan ~/fotos -v                    # risk report per file
metastrip exif photo.jpg                     # full technical dump
metastrip gps show photo.jpg                 # coordinates + cities + map URL
metastrip gps remove photo.jpg               # strip only GPS
metastrip strip photo.jpg --profile gps      # selective by profile
metastrip strip ./export --keep make,model   # keep camera info
metastrip batch ./export --workers 8 --report html
metastrip report ./dir --format html --out report.html
metastrip verify clean.jpg                   # exit 0 = clean
metastrip rename ./dir --mode random         # no date hints
metastrip profiles                           # list cleaning profiles

# v0.2 additions
metastrip risk ~/fotos -v                    # field-level privacy scores
metastrip diff a.jpg b.jpg --verify          # what changed; exit 1 on leaks
metastrip watch ~/inbox --out ~/clean        # auto-strip new files (SQLite state)
metastrip serve --port 8710 --api-key s3cret # HTTP strip service (loopback)
metastrip forensics integrity ~/fotos        # detect already-stripped/tampered
metastrip forensics timeline ~/fotos         # movement timeline from GPS+time
metastrip forensics fingerprint ~/fotos      # identify capture devices
metastrip policy list                        # built-in stripping policies
metastrip policy apply ~/fotos --builtin social --out ~/clean
```

## Cleaning profiles

| Profile | What it removes |
|---|---|
| `full` | everything |
| `gps` | coordinates, latitude, longitude, altitude, geotag |
| `dates` | date/time/created/modified/datetime |
| `author` | author/creator/artist/owner/company/last |
| `device` | make/model/software/lens/camera/focal |
| `paper` | keeps only resolution/width/height/dpi/orientation/pixel |

## New in v0.2

### Risk engine (`risk.py`)
Every metadata *field* is scored 0-10 by sensitivity (GPS = 10, device
serial = 9, author/email = 8, camera make/model = 6, software = 4, dates = 3,
comments = 2, structure = 1). Files get a 0-100 score with a verdict that
names the dominant exposure; batches rank their worst offenders; and
`risk_delta` / `strip_and_measure` prove how much exposure a strip actually
removed.

### Forensics (`forensics.py`)
Read the silence, not just the whisper:
- **integrity** — detect files that were *already* stripped or tampered with
  (camera JPEG with no EXIF, missing Make/Model, missing docProps, zeroed ZIP
  dates, editor-tool fingerprints in Software, EXIF-after-mtime, digitized-
  before-original date orderings).
- **timeline** — fuse EXIF timestamps + GPS from a photo batch into a
  movement log: events, legs with distance/speed, and *stops* where the
  photographer lingered.
- **fingerprint** — identify the capture device from EXIF patterns
  (make/model/software, maker-note vendor, tag set) against a built-in
  device-profile database (smartphone / DSLR / mirrorless / drone…).

### Policies (`policy.py`)
Declarative keep/scrub rules per format, in JSON or TOML (stdlib only).
Validate, diff and apply them; four built-ins ship: `paranoid`, `social`,
`photographer`, `archive`.

### Watcher (`watch.py`)
Polling filesystem watcher (no watchdog): auto-strips new/changed files in a
folder with debounce and a SQLite state db, so restarts never double-strip.

### HTTP service (`server.py`)
`metastrip serve` runs a loopback HTTP service on the stdlib `http.server`:
POST a file to `/strip` and get the stripped file back (JSON+b64 or raw
bytes) plus a risk before/after report; `/risk` scores without stripping.
Optional `X-API-Key` auth.

### Plugins (`plugins.py`)
Drop a `.py` file into a plugin directory and it becomes a format handler:
declare `PLUGIN = {name, version, extensions}` plus `read_metadata` /
`strip_metadata`. Discovery, validation and sandboxed-ish execution included;
two sample plugins ship in `sample_plugins/` (JSON documents, CSV logs).

### Deep EXIF (`exif_deep.py`)
Recursive TIFF/IFD walker below Pillow's surface: sub-IFD traversal,
maker-note vendor detection, embedded thumbnail extraction & stripping, and a
minimal TIFF writer used to rebuild EXIF blobs.

## Optional dependencies

`Pillow` + `textual` are required. Everything else is optional per format:

```bash
pip install "metadata-stripper[pdf]"    # pypdf
pip install "metadata-stripper[audio]"  # mutagen
pip install "metadata-stripper[ole]"    # olefile
pip install "metadata-stripper[all]"    # everything
```

Without an optional dep the format simply isn't registered (the TUI and CLI
keep working) and a clear `pip install` hint is shown if you try to use it.

## Tests

```bash
pip install pytest
pytest
```

270 tests cover every format handler (including the HEIF container walker),
GPS parsing, risk scoring, batch, reports, rename, redaction, deep EXIF,
policies, diffs, the watcher, the HTTP service, plugins and forensics. All
fixtures are built in code — no binary blobs in the repo.

## License

[MIT](LICENSE) — clean your own files and let the protagonist's geotag be a
plot point, not a leak.
