diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 69534372..2a046f88 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -32,12 +32,11 @@ on:
workflow_dispatch:
env:
- # Canonical Docker Hub image name. The deprecated mirror below keeps
- # publishing alongside this one until 2026-10-29 so users on the old
- # name keep getting updates while they migrate.
+ # Canonical Docker Hub image name. The old mirror
+ # (stevezzau/plex_generate_vid_previews) was retired — a one-shot tombstone
+ # (retire-deprecated-image.yml) now sits on its tags telling users to switch.
# Change DOCKER_IMAGE for forks; see CONTRIBUTING.md.
DOCKER_IMAGE: stevezzau/media_preview_generator
- DOCKER_IMAGE_DEPRECATED: stevezzau/plex_generate_vid_previews
concurrency:
# Cancel superseded PR runs; never cancel in-flight pushes to main/dev/tags
@@ -366,7 +365,6 @@ jobs:
head_sha: ${{ steps.ctx.outputs.head_sha }}
is_tag: ${{ steps.ctx.outputs.is_tag }}
docker_tags_canonical: ${{ steps.ctx.outputs.docker_tags_canonical }}
- docker_tags_deprecated: ${{ steps.ctx.outputs.docker_tags_deprecated }}
steps:
- name: Compute build context
id: ctx
@@ -380,12 +378,10 @@ jobs:
if [[ "$REF_TYPE" == "tag" ]]; then
echo "is_tag=true" >> "$GITHUB_OUTPUT"
echo "docker_tags_canonical=-t ${{ env.DOCKER_IMAGE }}:$HEAD_BRANCH -t ${{ env.DOCKER_IMAGE }}:latest" >> "$GITHUB_OUTPUT"
- echo "docker_tags_deprecated=-t ${{ env.DOCKER_IMAGE_DEPRECATED }}:$HEAD_BRANCH -t ${{ env.DOCKER_IMAGE_DEPRECATED }}:latest" >> "$GITHUB_OUTPUT"
else
# dev branch push or manual workflow_dispatch
echo "is_tag=false" >> "$GITHUB_OUTPUT"
echo "docker_tags_canonical=-t ${{ env.DOCKER_IMAGE }}:dev" >> "$GITHUB_OUTPUT"
- echo "docker_tags_deprecated=-t ${{ env.DOCKER_IMAGE_DEPRECATED }}:dev" >> "$GITHUB_OUTPUT"
fi
build:
@@ -394,24 +390,16 @@ jobs:
fail-fast: true
matrix:
include:
- # 4 jobs total: 2 platforms × 2 image flavours. The deprecated
- # mirror and the canonical image differ only in the published
- # name + the DOCKER_IMAGE_NAME build-arg baked in (drives the
- # in-app deprecation banner). Layer cache is shared across
- # flavours via cache-scope so the second flavour's build is
- # near-instant.
+ # 2 jobs: amd64 + arm64 of the canonical image. The deprecated
+ # mirror (stevezzau/plex_generate_vid_previews) was retired — a
+ # one-shot tombstone image (see retire-deprecated-image.yml) now
+ # sits on its tags telling users to switch to the canonical name.
- platform: linux/amd64
runner: ubuntu-latest
image_flavour: canonical
- - platform: linux/amd64
- runner: ubuntu-latest
- image_flavour: deprecated
- platform: linux/arm64
runner: ubuntu-24.04-arm
image_flavour: canonical
- - platform: linux/arm64
- runner: ubuntu-24.04-arm
- image_flavour: deprecated
runs-on: ${{ matrix.runner }}
steps:
@@ -437,14 +425,9 @@ jobs:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- - name: Resolve image name for this flavour
+ - name: Resolve image name
id: image
- run: |
- if [[ "${{ matrix.image_flavour }}" == "canonical" ]]; then
- echo "name=${{ env.DOCKER_IMAGE }}" >> "$GITHUB_OUTPUT"
- else
- echo "name=${{ env.DOCKER_IMAGE_DEPRECATED }}" >> "$GITHUB_OUTPUT"
- fi
+ run: echo "name=${{ env.DOCKER_IMAGE }}" >> "$GITHUB_OUTPUT"
- name: Generate bundled release notes
# Fetches GitHub Releases into media_preview_generator/release_notes.json
@@ -512,13 +495,6 @@ jobs:
pattern: digest-*-canonical
merge-multiple: true
- - name: Download deprecated digests
- uses: actions/download-artifact@v4
- with:
- path: /tmp/digests/deprecated
- pattern: digest-*-deprecated
- merge-multiple: true
-
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
@@ -535,13 +511,6 @@ jobs:
${{ needs.context.outputs.docker_tags_canonical }} \
$(printf '${{ env.DOCKER_IMAGE }}@sha256:%s ' *)
- - name: Create deprecated mirror manifest list and push
- working-directory: /tmp/digests/deprecated
- run: |
- docker buildx imagetools create \
- ${{ needs.context.outputs.docker_tags_deprecated }} \
- $(printf '${{ env.DOCKER_IMAGE_DEPRECATED }}@sha256:%s ' *)
-
update-dockerhub-description:
runs-on: ubuntu-latest
needs: context
@@ -558,11 +527,3 @@ jobs:
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: stevezzau/media_preview_generator
readme-filepath: ./DOCKERHUB_README.md
-
- - name: Update deprecated mirror Docker Hub description
- uses: peter-evans/dockerhub-description@v5
- with:
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKERHUB_TOKEN }}
- repository: stevezzau/plex_generate_vid_previews
- readme-filepath: ./DOCKERHUB_DEPRECATED_README.md
diff --git a/.github/workflows/retire-deprecated-image.yml b/.github/workflows/retire-deprecated-image.yml
new file mode 100644
index 00000000..45c421fe
--- /dev/null
+++ b/.github/workflows/retire-deprecated-image.yml
@@ -0,0 +1,54 @@
+name: Retire deprecated Docker image
+
+# One-shot, manually triggered. Builds the tombstone image (a static "this
+# image moved" page) and pushes it OVER the deprecated repo's :latest and :dev
+# tags, so anyone still pulling stevezzau/plex_generate_vid_previews gets a
+# clear "switch to stevezzau/media_preview_generator" notice. Run this ONCE,
+# then the deprecated build is already removed from ci.yml.
+on:
+ workflow_dispatch:
+ inputs:
+ confirm:
+ description: 'Type "retire" to confirm pushing the tombstone over the old image'
+ required: true
+ default: ''
+
+env:
+ DEPRECATED_IMAGE: stevezzau/plex_generate_vid_previews
+
+jobs:
+ tombstone:
+ runs-on: ubuntu-latest
+ if: ${{ github.event.inputs.confirm == 'retire' }}
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Validate Docker secrets
+ run: |
+ if [ -z "${{ secrets.DOCKER_USERNAME }}" ] || [ -z "${{ secrets.DOCKER_PASSWORD }}" ]; then
+ echo "::error::DOCKER_USERNAME and DOCKER_PASSWORD must be set in repository secrets"
+ exit 1
+ fi
+
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v3
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Log in to Docker Hub
+ uses: docker/login-action@v3
+ with:
+ username: ${{ secrets.DOCKER_USERNAME }}
+ password: ${{ secrets.DOCKER_PASSWORD }}
+
+ - name: Build & push tombstone (multi-arch) over :latest and :dev
+ uses: docker/build-push-action@v6
+ with:
+ context: ./tombstone
+ platforms: linux/amd64,linux/arm64
+ push: true
+ tags: |
+ ${{ env.DEPRECATED_IMAGE }}:latest
+ ${{ env.DEPRECATED_IMAGE }}:dev
diff --git a/DOCKERHUB_DEPRECATED_README.md b/DOCKERHUB_DEPRECATED_README.md
deleted file mode 100644
index f76be7a4..00000000
--- a/DOCKERHUB_DEPRECATED_README.md
+++ /dev/null
@@ -1,43 +0,0 @@
-
-
-# ⚠️ This image has been renamed
-
-This Docker Hub repository — `stevezzau/plex_generate_vid_previews` — is now a **mirror** of the canonical image:
-
-> **➡ [`stevezzau/media_preview_generator`](https://hub.docker.com/r/stevezzau/media_preview_generator)**
-
-The project supports **Plex, Emby, and Jellyfin** today, so the old "Plex" name is misleading. We renamed the image (and the upstream repository) to match the broader scope.
-
-## What you need to do
-
-Update your `docker-compose.yml` (or `docker run` script):
-
-```diff
- services:
- media-preview-generator:
-- image: stevezzau/plex_generate_vid_previews:latest
-+ image: stevezzau/media_preview_generator:latest
- # ... everything else stays the same
-```
-
-Then `docker compose pull && docker compose up -d`. Existing volumes, settings, jobs, schedules, and configuration are unchanged — only the image name moves.
-
-## Timeline
-
-- **Now → 2026-10-29**: Both image names mirror the same builds. Watchtower / `:latest` users on the old name keep getting updates automatically.
-- **After 2026-10-29**: Only `stevezzau/media_preview_generator` receives updates. The old name stops being published.
-
-## Why the rename?
-
-The app started life as a Plex-only tool. Phases 0–L of the multi-server refactor (PR #225) added Emby and Jellyfin adapters with full per-server libraries, path mappings, exclude paths, webhooks, and dispatch fan-out. The "Plex Generate Previews" name no longer reflected what the project does.
-
-## Where to read more
-
-- Canonical Docker Hub: You're running the Docker image "
- f" Both image names mirror the same builds until "
- f"{DEPRECATED_IMAGE_SUNSET_DATE}; after that, only "
- f"{DEPRECATED_IMAGE_NAME}, which has been renamed to "
- f"{CANONICAL_IMAGE_NAME} to reflect that this app now "
- f"supports Plex, Emby, and Jellyfin.{CANONICAL_IMAGE_NAME} receives updates. Update your "
- f"compose file's image: line and pull "
- f"the new image to keep getting updates.{DEPRECATED_IMAGE_NAME}, which has been retired "
+ f"and renamed to {CANONICAL_IMAGE_NAME} (this app now supports "
+ f"Plex, Emby, and Jellyfin).
The old image name no longer receives updates. "
+ f"Update your compose file's image: line to "
+ f"{CANONICAL_IMAGE_NAME} and run "
+ f"docker compose pull && docker compose up -d to keep "
+ f"getting updates.
Existing volumes, settings, and " f"configuration are unchanged — only the image name moves.
" ) return { "id": DEPRECATED_IMAGE_ID, "severity": "warning", - "title": "Update your Docker image", + "title": "Your Docker image has been retired", "body_html": body, "dismissable": True, "source": "image_deprecation", diff --git a/tests/test_notifications_api.py b/tests/test_notifications_api.py index 45a7e8dc..04a0f8f9 100644 --- a/tests/test_notifications_api.py +++ b/tests/test_notifications_api.py @@ -311,8 +311,9 @@ def test_fires_when_running_deprecated_image(self, monkeypatch): # The body names both the old and the new image so users can copy-paste. assert "stevezzau/plex_generate_vid_previews" in deprecated["body_html"] assert "stevezzau/media_preview_generator" in deprecated["body_html"] - # And carries the sunset date. - assert "2026-10-29" in deprecated["body_html"] + # And makes clear the old image is retired (no longer updated). + assert "retired" in deprecated["body_html"].lower() + assert deprecated["title"] == "Your Docker image has been retired" class TestSettingsManagerDismissedNotifications: diff --git a/tombstone/Dockerfile b/tombstone/Dockerfile new file mode 100644 index 00000000..d467df10 --- /dev/null +++ b/tombstone/Dockerfile @@ -0,0 +1,10 @@ +# Minimal "this image was retired" tombstone for the old Docker Hub repo +# (stevezzau/plex_generate_vid_previews). Built + pushed ONCE by +# .github/workflows/retire-deprecated-image.yml, then the deprecated build is +# removed from ci.yml. Anyone who pulls the old image after that gets a page +# telling them to switch to stevezzau/media_preview_generator. +FROM nginx:1.27-alpine +COPY index.html /usr/share/nginx/html/index.html +COPY default.conf /etc/nginx/conf.d/default.conf +EXPOSE 8080 +HEALTHCHECK CMD wget -qO- http://127.0.0.1:8080/ >/dev/null 2>&1 || exit 1 diff --git a/tombstone/default.conf b/tombstone/default.conf new file mode 100644 index 00000000..1b8a21be --- /dev/null +++ b/tombstone/default.conf @@ -0,0 +1,8 @@ +# Tombstone server: every request returns the "this image moved" page on the +# app's normal port (8080) so existing compose port-maps still hit it. +server { + listen 8080 default_server; + server_name _; + root /usr/share/nginx/html; + location / { try_files /index.html =404; } +} diff --git a/tombstone/index.html b/tombstone/index.html new file mode 100644 index 00000000..514b3433 --- /dev/null +++ b/tombstone/index.html @@ -0,0 +1,36 @@ + + + + + +stevezzau/plex_generate_vid_previews is no longer published.
+ The project was renamed (it now supports Plex, Emby & Jellyfin).
Switch your image: line to the new name — your config, volumes and settings carry over unchanged:
Then docker compose pull && docker compose up -d. Same app, same data — just the new image name.
+ Docs: github.com/stevezau/media_preview_generator