# mmguero/cleanvid architecture

> Architecture diagram of the GitHub repository mmguero/cleanvid, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-11-11). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/mmguero/cleanvid
- Repository: https://github.com/mmguero/cleanvid

## Overview

cleanvid is a command-line tool that identifies profanity in subtitles and produces muted video or subtitle-based alternatives. Its main workflow acquires subtitles, filters and rewrites matching entries, then uses FFmpeg to mute the corresponding audio intervals and remultiplex the result. It also supports subtitle-only output, MPlayer EDL, JSON, PlexAutoSkip, and optional subtitle embedding. The workflow and these capabilities are documented in the README; the sampled implementation excerpt is partial, so some internal links rely on that documentation.

Main entry points: [`src/cleanvid/cleanvid.py`](https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py) (CLI workflow), [`src/cleanvid/swears.txt`](https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/swears.txt) (Profanity rules), [`src/cleanvid/caselessdictionary.py`](https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/caselessdictionary.py) (Case-insensitive map)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_subtitle_input["Subtitle input"]
  node_cli["CLI workflow<br/>[cleanvid.py]"]
  node_subtitle_extract["Subtitle extraction<br/>[cleanvid.py]"]
  node_subtitle_download["Subtitle download<br/>[cleanvid.py]"]
  node_srt_input["SRT input"]
  node_subtitle_tools["Subtitle libraries"]
end

subgraph group_filtering["Profanity filtering"]
  node_srt_parser["SRT parsing<br/>[cleanvid.py]"]
  node_profanity_rules["Profanity rules<br/>[swears.txt]"]
  node_case_map["Case-insensitive map"]
  node_filtered_segments["Filtered segments<br/>[cleanvid.py]"]
end

subgraph group_outputs["Clean outputs"]
  node_clean_srt["Clean subtitles<br/>[cleanvid.py]"]
  node_edl_output["MPlayer EDL<br/>[cleanvid.py]"]
  node_json_output["JSON outputs<br/>[cleanvid.py]"]
  node_plex_output["PlexAutoSkip data<br/>[cleanvid.py]"]
end

subgraph group_media_processing["Media processing"]
  node_mute_intervals["Mute intervals<br/>[cleanvid.py]"]
  node_ffmpeg["FFmpeg"]
  node_video_input["Video input"]
  node_clean_video["Clean video<br/>[cleanvid.py]"]
end

node_user(("User"))

node_user -->|"provides inputs"| node_cli
node_cli -->|"extracts subtitles"| node_subtitle_extract
node_cli -.->|"downloads subtitles"| node_subtitle_download
node_cli -->|"accepts subtitles"| node_srt_input
node_subtitle_extract -->|"reads embedded tracks"| node_video_input
node_subtitle_extract -->|"extracts tracks"| node_ffmpeg
node_subtitle_download -->|"uses subliminal"| node_subtitle_tools
node_cli -->|"processes subtitles"| node_srt_parser
node_srt_parser -->|"parses with pysrt"| node_subtitle_tools
node_srt_parser -->|"checks phrases"| node_profanity_rules
node_srt_parser -->|"uses mapping"| node_case_map
node_srt_parser -->|"selects matches"| node_filtered_segments
node_filtered_segments -->|"writes subtitles"| node_clean_srt
node_cli -->|"generates EDL"| node_edl_output
node_cli -->|"generates JSON"| node_json_output
node_cli -->|"generates Plex data"| node_plex_output
node_cli -->|"builds mute intervals"| node_mute_intervals
node_cli -->|"invokes processing"| node_ffmpeg
node_ffmpeg -->|"reads video"| node_video_input
node_mute_intervals -->|"specifies mute timing"| node_ffmpeg
node_ffmpeg -->|"creates remuxed video"| node_clean_video
node_clean_srt -.->|"embeds optionally"| node_clean_video

click node_cli "https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py"
click node_subtitle_extract "https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py"
click node_subtitle_download "https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py"
click node_srt_parser "https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py"
click node_profanity_rules "https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/swears.txt"
click node_case_map "https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/caselessdictionary.py"
click node_filtered_segments "https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py"
click node_clean_srt "https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py"
click node_edl_output "https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py"
click node_json_output "https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py"
click node_plex_output "https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py"
click node_mute_intervals "https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py"
click node_clean_video "https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_cli,node_subtitle_extract,node_subtitle_download,node_srt_input,node_subtitle_tools,node_user toneBlue
class node_srt_parser,node_profanity_rules,node_case_map,node_filtered_segments toneAmber
class node_clean_srt,node_edl_output,node_json_output,node_plex_output toneMint
class node_mute_intervals,node_ffmpeg,node_video_input,node_clean_video toneRose
```

## Components

### Subtitle input

- [CLI workflow](https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py): `src/cleanvid/cleanvid.py`
- [Subtitle extraction](https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py): `src/cleanvid/cleanvid.py`
- [Subtitle download](https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py): `src/cleanvid/cleanvid.py`
- **SRT input**
- **Subtitle libraries**

### Profanity filtering

- [SRT parsing](https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py): `src/cleanvid/cleanvid.py`
- [Profanity rules](https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/swears.txt): `src/cleanvid/swears.txt`
- [Case-insensitive map](https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/caselessdictionary.py): `src/cleanvid/caselessdictionary.py`
- [Filtered segments](https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py): `src/cleanvid/cleanvid.py`

### Clean outputs

- [Clean subtitles](https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py): `src/cleanvid/cleanvid.py`
- [MPlayer EDL](https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py): `src/cleanvid/cleanvid.py`
- [JSON outputs](https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py): `src/cleanvid/cleanvid.py`
- [PlexAutoSkip data](https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py): `src/cleanvid/cleanvid.py`

### Media processing

- [Mute intervals](https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py): `src/cleanvid/cleanvid.py`
- **FFmpeg**
- **Video input**
- [Clean video](https://github.com/mmguero/cleanvid/blob/main/src/cleanvid/cleanvid.py): `src/cleanvid/cleanvid.py`

### Other components

- **User**

## Connections

- User → CLI workflow: provides inputs (evidence: `README.md`)
- CLI workflow → Subtitle extraction: extracts subtitles (evidence: `README.md`)
- CLI workflow → Subtitle download: downloads subtitles (evidence: `README.md`)
- CLI workflow → SRT input: accepts subtitles (evidence: `README.md`)
- Subtitle extraction → Video input: reads embedded tracks (evidence: `README.md`)
- Subtitle extraction → FFmpeg: extracts tracks (evidence: `README.md`)
- Subtitle download → Subtitle libraries: uses subliminal (evidence: `README.md`)
- CLI workflow → SRT parsing: processes subtitles (evidence: `README.md`)
- SRT parsing → Subtitle libraries: parses with pysrt (evidence: `README.md`)
- SRT parsing → Profanity rules: checks phrases (evidence: `README.md`)
- SRT parsing → Case-insensitive map: uses mapping (evidence: `src/cleanvid/cleanvid.py`)
- SRT parsing → Filtered segments: selects matches (evidence: `README.md`)
- Filtered segments → Clean subtitles: writes subtitles (evidence: `README.md`)
- CLI workflow → MPlayer EDL: generates EDL (evidence: `README.md`)
- CLI workflow → JSON outputs: generates JSON (evidence: `README.md`)
- CLI workflow → PlexAutoSkip data: generates Plex data (evidence: `README.md`)
- CLI workflow → Mute intervals: builds mute intervals (evidence: `README.md`)
- CLI workflow → FFmpeg: invokes processing (evidence: `README.md`)
- FFmpeg → Video input: reads video (evidence: `README.md`)
- Mute intervals → FFmpeg: specifies mute timing (evidence: `README.md`)
- FFmpeg → Clean video: creates remuxed video (evidence: `README.md`)
- Clean subtitles → Clean video: embeds optionally (evidence: `README.md`)
