Skip to content

Mazuh/bsafe

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

45 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Bsafe

About

Censor NSFW content on your macOS screen in real time. CLI tool, fully offline.

Supports real-time screen censoring, video file processing (with audio preservation), and image censoring — with multiple detection models, censor styles (black boxes, blur, pixelation, text overlay), and per-body-part configuration.

Setting up locally

Requires macOS 14+, Python 3.14, and uv:

uv run bsafe bootstrap

This installs Python dependencies (uv sync) and builds the Swift screen-capture helper. At the end it prints an alias line you can add to your ~/.zshrc to make bsafe globally available.

You must grant Screen Recording permission to your terminal app (System Settings → Privacy & Security → Screen Recording).

Usage

Check that everything is in order:

bsafe doctor

Start real-time screen censoring (no daemonized support yet):

bsafe start

Display selection

By default bsafe start captures only the primary display. Most setups have one primary and one secondary display — the aliases primary and secondary are enough to pick either without looking up IDs.

List connected displays:

bsafe displays

Target a specific display:

bsafe start --display secondary   # first non-primary display
bsafe start --display 1234567     # by numeric ID (from bsafe displays)
bsafe start --display all         # all displays (uses more CPU)

Covering more displays at higher resolutions with more NSFW content increases CPU load and may reduce quality — you are processing and rendering video in real time.

Process video files

Produce censored copies of local videos (originals are never modified):

bsafe video clip.mp4                  # → clip.320n.bsafe.mp4
bsafe video clip.mp4 --blur           # blur instead of black boxes
bsafe video clip.mp4 --pixels         # pixelation effect
bsafe video clip.mp4 --censor-text    # overlay "NSFW" text
bsafe video clip.mp4 --fps 5          # run detection at 5 FPS (output keeps native FPS)
bsafe video clip.mp4 --enhance dim    # low-light enhancement (denoise + adaptive gamma)

Process multiple files at once (shell globs work):

bsafe video *.mp4 --blur              # process all .mp4 files with blur
bsafe video a.mp4 b.mov c.m4v        # explicit file list

Supported formats: .mp4, .m4v, .mov. If ffmpeg is installed, audio is preserved in the output; otherwise the video is written without audio.

Videos are processed in chunks (default: 5000 frames). If interrupted, re-run the same command to resume — completed chunks are skipped automatically. In batch mode, files with existing output are skipped (idempotent). Non-video files and directories are filtered out automatically.

Process image files

Produce censored copies of local images:

bsafe image photo.jpg                 # → photo.320n.bsafe.jpg
bsafe image *.jpg --pixels            # process all .jpg files with pixelation
bsafe image a.png b.webp --blur       # explicit file list

Supported formats: .jpg, .jpeg, .png, .bmp, .webp, .tif, .tiff. Re-running the same command skips files that already have output (idempotent).

Note: -o/--output cannot be used with multiple input files.

Configuration file

bsafe bootstrap creates ~/.config/bsafe/config.toml with all default values. Edit this file to set your preferred defaults — CLI flags always override it.

Sections: [start] for start-only flags, [video] for video-only flags, [common] for shared flags used by both commands.

Options

Shared flags (work with both start and video):

  • --confidence N — minimum detection confidence, 0.0–1.0 (default: 0.0 for NudeNet, 0.2 for EraX)
  • --censor {none,female,male,all} — what to censor (default: all). Use none to skip nudity censoring while still using additive flags like --face-male
  • --padding N — box expansion fraction (default: 0.0)
  • --persist-frames N — frames a box persists after disappearing (default: 8)
  • --smooth-alpha N — EMA smoothing weight, 0.0–1.0 (default: 0.5)
  • --blur [N] — blur effect (default intensity: 1.0)
  • --pixels [N] — pixelation effect (default intensity: 1.0)
  • --censor-text [TEXT] — overlay text on censored regions (default: "NSFW")
  • --model {320n,640m,erax-nano,erax-small,erax-medium} — detection model (default: 320n). See model details below
  • --covered — also censor covered body parts (anus, buttocks; breasts when --censor is female or all)
  • --face-male — also censor male faces
  • --face-female — also censor female faces
  • --feet — also censor exposed feet
  • --full-censor — expand censor area by 3x
  • -v / --verbose — enable debug logging

start-only flags:

  • --fps N — capture frames per second (default: 45)
  • --display VALUE — display to capture: primary, secondary, all, or numeric ID (default: primary)
  • --dry-run — run the loop without the Swift helper or detector

image-only flags:

  • -o / --output PATH — output file path (default: <input>.<model>.bsafe.<ext>)

video-only flags:

  • -o / --output PATH — output file path (default: <input>.<model>.bsafe.<ext>)
  • --fps N — detection FPS override (default: native video FPS)
  • --chunk-frames N — frames per processing chunk (default: 5000). Smaller chunks use less memory but may cause brief tracking gaps at chunk boundaries.
  • --enhance dim — low-light enhancement for dim-but-visible footage. Pre-scans the video, applies FFmpeg temporal denoising (hqdn3d), then adaptive per-frame gamma/contrast correction. Automatically skips enhancement for already-bright footage. Requires ffmpeg for denoising (enhancement still works without it).

Detection models

The default 320n model is bundled with NudeNet. Other models require a manual download.

Model Backend Size Notes
320n NudeNet bundled Fast, default
640m NudeNet ~90 MB More accurate
erax-nano EraX YOLO ~5 MB Fastest EraX, mAP 0.438
erax-small EraX YOLO ~40 MB Balanced, mAP 0.453
erax-medium EraX YOLO ~19 MB Best EraX accuracy, mAP 0.467

NudeNet models have broader coverage (faces, covered parts, feet) and are lightweight — best for real-time bsafe start. EraX models are more targeted (e.g. nipple-specific) and heavier — better suited for bsafe image and bsafe video where FPS isn't a constraint.

Using the 640m model

mkdir -p ~/.config/bsafe/models
curl -Lo ~/.config/bsafe/models/640m.onnx \
  https://github.com/notAI-tech/NudeNet/releases/download/v3.4-weights/640m.onnx
bsafe start --model 640m

Using EraX models

EraX models use ultralytics YOLO and require an extra dependency:

uv sync --extra erax

Download a model (e.g. erax-nano):

mkdir -p ~/.config/bsafe/models
curl -Lo ~/.config/bsafe/models/erax-anti-nsfw-yolo11n-v1.1.pt \
  https://huggingface.co/erax-ai/EraX-Anti-NSFW-V1.1/resolve/main/erax-anti-nsfw-yolo11n-v1.1.pt

Other variants:

# erax-small
curl -Lo ~/.config/bsafe/models/erax-anti-nsfw-yolo11s-v1.1.pt \
  https://huggingface.co/erax-ai/EraX-Anti-NSFW-V1.1/resolve/main/erax-anti-nsfw-yolo11s-v1.1.pt

# erax-medium
curl -Lo ~/.config/bsafe/models/erax-anti-nsfw-yolo11m-v1.1.pt \
  https://huggingface.co/erax-ai/EraX-Anti-NSFW-V1.1/resolve/main/erax-anti-nsfw-yolo11m-v1.1.pt

Then use with --model:

bsafe start --model erax-nano
bsafe image photo.jpg --model erax-small
bsafe video clip.mp4 --model erax-medium

Privacy & censor strength

Real-time screen mode (bsafe start) draws a transparent overlay window on top of your screen. It does not modify the underlying applications or websites in any way — censoring is purely visual and disappears when bsafe stops.

Video and image modes (bsafe video, bsafe image) produce new files with the censored pixels baked into the output. The original file is never modified. However, not all censor styles destroy information equally:

  • Black boxes (default) replace every pixel in the censored region with solid black. The original data is completely destroyed — recovery is impossible regardless of technique or computing power.
  • Blur (--blur) applies a Gaussian blur that removes high-frequency detail. At default or higher intensity this is practically irreversible, but the exact kernel parameters are deterministic from the box dimensions and intensity (both visible or inferable from the output). At low intensity, deconvolution techniques can partially recover edges and shapes.
  • Pixelation (--pixels) downscales each region and scales it back up, producing uniform color blocks. Each block preserves the average color of the original pixels, retaining more information than the other modes. Published machine-learning attacks have demonstrated recovering recognizable faces and text from pixelated images. This is the weakest censor mode.

If your priority is ensuring censored content cannot be recovered from the output file, use black boxes (the default). If you use blur or pixelation for aesthetic reasons, consider using higher intensity values (e.g. --blur 3, --pixels 3) to reduce the amount of recoverable information.

When using --fps to skip detection frames in video mode, content that first appears between detection frames will go uncensored for a few frames until the next detection cycle picks it up. The default --persist-frames setting keeps boxes active across gaps, but cannot predict content that hasn't been seen yet.

License

Under MIT License.

Copyright (c) 2026 Marcell "Mazuh" G. C. da Silva.

About

Censor NSFW content on your macOS screen in real time. CLI tool, fully offline.

Resources

License

Stars

Watchers

Forks

Contributors