# syntax=docker/dockerfile:1.7
#
# Multi-stage build with automatic signature discovery:
#   1. base    — PMS base image (source of the binary to analyze)
#   2. discover — auto-discover hook patterns from the PMS binary
#   3. builder  — cross-compile the .so with zig (musl) + generated patterns
#   4. runtime  — layer onto lscr.io/linuxserver/plex with LD_PRELOAD wrapper
#
# Based on https://github.com/authrequest/Freeloader (AGPL-3.0-or-later).

ARG PLEX_BASE_IMAGE=lscr.io/linuxserver/plex:latest

# ── Stage 1: base (PMS image, used as source for discovery) ──────────────
FROM ${PLEX_BASE_IMAGE} AS base

# ── Stage 2: discover hook patterns from the PMS binary ─────────────────
# Auto-discovers byte patterns by analyzing the PMS binary. If a pattern
# can't be found, the build fails here — before compiling or shipping.
FROM debian:bookworm-slim AS discover
RUN apt-get update \
 && apt-get install -y --no-install-recommends python3 python3-pip \
 && pip3 install --break-system-packages capstone \
 && rm -rf /var/lib/apt/lists/*
COPY scripts/discover_patterns.py /tmp/discover_patterns.py
COPY --from=base /usr/lib/plexmediaserver/ /tmp/plex/
RUN python3 /tmp/discover_patterns.py "/tmp/plex/Plex Media Server" \
        -o /tmp/patterns_generated.h \
 && cat /tmp/patterns_generated.h

# ── Stage 3: build the musl .so ───────────────────────────────────────────
FROM debian:bookworm-slim AS builder

ARG ZIG_VERSION=0.13.0
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
 && apt-get install -y --no-install-recommends \
        ca-certificates curl xz-utils \
 && rm -rf /var/lib/apt/lists/*

WORKDIR /src
RUN mkdir -p /src/toolchain \
 && curl -fsSL \
      "https://ziglang.org/download/${ZIG_VERSION}/zig-linux-x86_64-${ZIG_VERSION}.tar.xz" \
      -o /tmp/zig.tar.xz \
 && tar -C /src/toolchain --strip-components=1 -xf /tmp/zig.tar.xz \
 && rm /tmp/zig.tar.xz
ENV PATH="/src/toolchain:${PATH}"

COPY Freeloader/build.sh ./
COPY Freeloader/src ./src
COPY Freeloader/third_party ./third_party
COPY --from=discover /tmp/patterns_generated.h ./src/patterns_generated.h
RUN bash build.sh

# ── Stage 4: runtime -- patch lscr.io/linuxserver/plex ────────────────────
FROM ${PLEX_BASE_IMAGE} AS runtime

ARG PLEX_BASE_IMAGE
ARG PATCH_VERSION=dev
LABEL org.opencontainers.image.title="plexmediaserver-crack (linuxserver)" \
      org.opencontainers.image.source="https://github.com/authrequest/Freeloader" \
      org.opencontainers.image.licenses="AGPL-3.0-or-later" \
      plex_patch.base="${PLEX_BASE_IMAGE}" \
      plex_patch.version="${PATCH_VERSION}"

RUN set -eux; \
    PMS="/usr/lib/plexmediaserver/Plex Media Server"; \
    PMS_LIB="/usr/lib/plexmediaserver/lib"; \
    RUN_SCRIPT="/etc/s6-overlay/s6-rc.d/svc-plex/run"; \
    [ -x "${PMS}" ]        || { echo "patcher: missing ${PMS} in ${PLEX_BASE_IMAGE}"; exit 1; }; \
    [ -d "${PMS_LIB}" ]    || { echo "patcher: missing ${PMS_LIB}/ in ${PLEX_BASE_IMAGE}"; exit 1; }; \
    [ -f "${RUN_SCRIPT}" ] || { echo "patcher: missing ${RUN_SCRIPT} in ${PLEX_BASE_IMAGE}"; exit 1; }

COPY --from=builder /src/build/plexmediaserver_crack.so \
                    /usr/lib/plexmediaserver/lib/plexmediaserver_crack.so
RUN chmod 0644 /usr/lib/plexmediaserver/lib/plexmediaserver_crack.so
COPY wrapper.sh /usr/lib/plexmediaserver/plex-crack-wrapper.sh
RUN chmod 0755 /usr/lib/plexmediaserver/plex-crack-wrapper.sh

RUN set -eux; \
    RUN_SCRIPT="/etc/s6-overlay/s6-rc.d/svc-plex/run"; \
    cp "${RUN_SCRIPT}" "${RUN_SCRIPT}.orig"; \
    printf '#!/usr/bin/with-contenv bash\nexec s6-setuidgid abc /usr/lib/plexmediaserver/plex-crack-wrapper.sh\n' \
        > "${RUN_SCRIPT}"; \
    chmod 0755 "${RUN_SCRIPT}"
