#!/usr/bin/env python3
#
# Scan ~/webGoggles (or given path) for all session screenshots.
# For each user (site/username), pick the one with the highest
# skin-to-total pixel ratio and save it as most_skin.png
# next to their bio_screenshot.png.
#
# Usage:
# ./pick-most-skin [--force] [path ...]
#
# If no path given, defaults to ~/webGoggles.
# Multiple paths can be specified.
#
# Requires: opencv-python (pip install opencv-python)
import os
import sys
import glob as _glob
import shutil
# If cv2 isn't on the normal path, check pipx-installed opencv-python
try:
import cv2
import numpy as np
except ImportError:
_pipx_venv = os.path.expanduser(
"~/.local/pipx/venvs/opencv-python/lib/python*/site-packages"
)
_matches = sorted(_glob.glob(_pipx_venv))
if _matches:
sys.path.insert(0, _matches[-1])
import cv2
import numpy as np
else:
print("Error: opencv-python not installed.")
print(" pip install opencv-python")
sys.exit(1)
# HSV ranges for skin tones (tunable)
SKIN_RANGES = [
((0, 20, 70), (20, 255, 255)), # warm/peach
((170, 20, 70), (180, 255, 255)), # reddish wrap-around
]
def skin_ratio(path: str) -> float:
"""Return fraction of pixels that look like skin (0.0 – 1.0)."""
img = cv2.imread(path)
if img is None:
return 0.0
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = np.zeros(img.shape[:2], dtype=np.uint8)
for lower, upper in SKIN_RANGES:
mask |= cv2.inRange(hsv, np.array(lower, dtype=np.uint8),
np.array(upper, dtype=np.uint8))
return float(cv2.countNonZero(mask)) / (img.shape[0] * img.shape[1])
def find_most_skin(site_user: str) -> tuple[float, str | None]:
"""Walk sessions under site/user/, return (best_ratio, best_path)."""
sessions_dir = os.path.join(site_user, "sessions")
if not os.path.isdir(sessions_dir):
return 0.0, None
best_ratio = 0.0
best_path = None
for root, dirs, files in os.walk(sessions_dir):
if "screenshot.png" not in files:
continue
path = os.path.join(root, "screenshot.png")
ratio = skin_ratio(path)
if ratio > best_ratio:
best_ratio = ratio
best_path = path
return best_ratio, best_path
def main() -> None:
args = [a for a in sys.argv[1:] if not a.startswith("-")]
force = "--force" in sys.argv[1:]
roots = args if args else [os.path.expanduser("~/webGoggles")]
for root in roots:
root = os.path.abspath(root)
if not os.path.isdir(root):
print(f"[pick-most-skin] Skipping {root} – not a directory")
continue
print(f"[pick-most-skin] Scanning {root}")
# Walk site/user directories
for site in sorted(os.listdir(root)):
site_path = os.path.join(root, site)
if not os.path.isdir(site_path):
continue
for user in sorted(os.listdir(site_path)):
user_path = os.path.join(site_path, user)
if not os.path.isdir(user_path):
continue
dest = os.path.join(user_path, "most_skin.png")
if os.path.exists(dest) and not force:
print(f" {site}/{user}: most_skin.png exists (use --force to re-scan)")
continue
ratio, best = find_most_skin(user_path)
if best is None:
continue
shutil.copy2(best, dest)
print(f" {site}/{user}: {ratio:.1%} skin -> {dest}")
# Build/refresh GALLERY symlinks
gallery = os.path.join(root, "GALLERY")
os.makedirs(gallery, exist_ok=True)
# Remove stale symlinks
for entry in os.listdir(gallery):
if entry == "index.html":
continue
entry_path = os.path.join(gallery, entry)
if os.path.islink(entry_path) or entry.endswith("_ms.png"):
os.unlink(entry_path)
entries = []
for site in sorted(os.listdir(root)):
site_path = os.path.join(root, site)
if not os.path.isdir(site_path):
continue
for user in sorted(os.listdir(site_path)):
user_path = os.path.join(site_path, user)
most_skin = os.path.join(user_path, "most_skin.png")
if not os.path.isfile(most_skin):
continue
link_name = f"{user}_ms.png"
full_link = os.path.join(gallery, link_name)
os.symlink(os.path.relpath(most_skin, gallery), full_link)
entries.append((user, link_name))
# Generate gallery HTML
html_path = os.path.join(gallery, "index.html")
count = len(entries)
rows = "".join(
f' {u}\n'
for i, (u, fn) in enumerate(entries)
)
lbs = "".join(
f'