feat: browser-only screen mirroring prototype
A FastAPI server with two pages and one WebSocket. /mirror captures a window, screen or tab through the OS-native getDisplayMedia picker; /watch shows every live mirror as a wall and takes one fullscreen on click. Any number of sharers and watchers, at the same time. Media never touches the server: each watcher gets its own RTCPeerConnection to the sharer, and the Python process only relays JSON. The roster lives in registry.py, which is transport-free by design -- every operation returns the envelopes to deliver, so admission, fan-out and teardown policy are all unit-testable without a socket. Registry rules worth stating: a signal frame is relayed only along an existing subscription in either direction; viewer-to-peer traffic is refused; and teardown is broadcast to every viewer rather than only the subscribers, because a tile is drawn on stream_added and a viewer that has not yet subscribed still has a stale tile to clear. Frontend is hand-written ES modules with no build step and no external asset. Chromium scales a monitor capture to the capturing window and requires a secure context, so /mirror detects an insecure origin and prints the three ways out rather than failing on a button click. LLM-Generated: true
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
# mirror — browser-only screen mirroring.
|
||||
#
|
||||
# podman build -t mirror .
|
||||
# podman run --rm -p 8055:8055 mirror
|
||||
#
|
||||
# The image serves the app; it does not capture anything. Capture happens in the
|
||||
# viewer's and sharer's own browsers, so there is no display, D-Bus, or PipeWire
|
||||
# socket to pass in.
|
||||
|
||||
FROM docker.io/library/python:3.13-slim AS builder
|
||||
|
||||
ENV PIP_DISABLE_PIP_VERSION_CHECK=1 UV_LINK_MODE=copy
|
||||
RUN pip install --no-cache-dir uv
|
||||
|
||||
WORKDIR /app
|
||||
COPY pyproject.toml README.md ./
|
||||
COPY src ./src
|
||||
RUN uv venv /opt/venv \
|
||||
&& uv pip install --python /opt/venv/bin/python --no-cache .
|
||||
|
||||
|
||||
FROM docker.io/library/python:3.13-slim
|
||||
|
||||
LABEL org.opencontainers.image.title="mirror" \
|
||||
org.opencontainers.image.description="Browser-only screen mirroring for the local network" \
|
||||
org.opencontainers.image.source="https://example.invalid/mirror"
|
||||
|
||||
# curl is for the HEALTHCHECK only; nothing else in the runtime image reaches out.
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=builder /opt/venv /opt/venv
|
||||
ENV PATH="/opt/venv/bin:${PATH}" \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
MIRROR_HOST=0.0.0.0 \
|
||||
MIRROR_PORT=8055
|
||||
|
||||
# Never run the web process as root.
|
||||
RUN useradd --create-home --shell /usr/sbin/nologin mirror
|
||||
USER mirror
|
||||
WORKDIR /home/mirror
|
||||
|
||||
EXPOSE 8055
|
||||
HEALTHCHECK --interval=20s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD curl -fsS http://127.0.0.1:8055/healthz || exit 1
|
||||
|
||||
ENTRYPOINT ["mirror"]
|
||||
CMD ["serve"]
|
||||
Reference in New Issue
Block a user