Display remains capped
Only the three newest episode rows appear on the card.
A richer walkthrough for installing, testing, scheduling, backing up, and safely operating PlexWeekly beside a containerized Tautulli instance—without installing anything inside Tautulli.
$ ./plexweekly.sh verify [OK] Docker daemon available [OK] Compose command detected [OK] Tautulli API connected [OK] Persistent data writable [OK] Six preview states supported [OK] Weekly schedule syntax valid NEXT: ./plexweekly.sh preview-all No real Plex user email will be sent. $ |
ZIP and TAR.GZ contain the same application.
Keep both as backups if useful, but install only one into the final QNAP folder. They are two archive formats—not two editions.
Best when extracting on Windows or with a graphical archive utility. After copying to QNAP, mark the shell scripts executable.
PlexWeekly-NAS-Portable-v1.0.3-QNAP-Docker.zip
Best when extracting directly on QNAP/Linux over SSH. It is the more native Unix format and better preserves executable permissions.
PlexWeekly-NAS-Portable-v1.0.3-QNAP-Docker.tar.gz
| Workflow | Use | Extra step |
|---|---|---|
| Extract on Windows, then copy to QNAP | ZIP | chmod +x qnap-install.sh plexweekly.sh |
| Extract directly on QNAP over SSH | TAR.GZ | Permission repair usually unnecessary, but safe to run |
mkdir -p /share/Container/plexweekly tar -xzf PlexWeekly-NAS-Portable-v1.0.3-QNAP-Docker.tar.gz \ --strip-components=1 \ -C /share/Container/plexweekly
PlexWeekly communicates through APIs and network access.
Tautulli upgrades cannot remove PlexWeekly files.
./data keeps configuration, state, logs, and previews.
Microsoft’s cross-platform runtime powers the newsletter engine.
No Windows Task Scheduler or permanent QNAP cron edits.
Installing PlexWeekly inside Tautulli couples upgrades, backups, and troubleshooting. A dedicated container is safer and easier to restore.
The installer checks most requirements automatically.
/share/Container/plexweekly| Port | Purpose |
|---|---|
| 8181 | Tautulli host port |
| 8787 | LAN preview server |
| 587 | Typical SMTP STARTTLS |
Every risky action stays behind preview and TestEmail checkpoints.
Confirm Docker is available before beginning.
/share/Container/plexweekly
cd /share/Container/plexweekly chmod +x qnap-install.sh plexweekly.sh
./qnap-install.sh
The installer creates .env, builds the image, starts the service, runs setup, restarts, and verifies.
For Arizona, use TZ=America/Phoenix. Confirm PREVIEW_BASE_URL contains the NAS LAN IP.
./plexweekly.sh verify ./plexweekly.sh list-users ./plexweekly.sh preview-all ./plexweekly.sh send-test-all ./plexweekly.sh schedule-status
./plexweekly.sh schedule-enable
The container can run, preview, and send to TestEmail without being authorized to email all Plex users.
The application image is already Linux/Docker compatible. Unraid mainly changes the host paths, ownership defaults, and deployment workflow.
There is no separate Unraid engine. Deploy the included compose.yaml through Compose Manager or the Docker Compose CLI, and keep PlexWeekly in its own appdata folder.
qnap-install.sh on Unraid.That wrapper is tailored to QNAP path detection and onboarding. On Unraid, create .env, launch Compose, then use ./plexweekly.sh setup and verify.
mkdir -p /mnt/user/appdata/plexweekly cd /mnt/user/appdata/plexweekly
Extract either archive here so compose.yaml, Dockerfile, plexweekly.sh, app/, and data/ are all in this directory.
cp .env.example .env chmod +x plexweekly.sh nano .env
COMPOSE_PROJECT_NAME=plexweekly TZ=America/Phoenix PUID=99 PGID=100 UMASK=077 PREVIEW_BIND=0.0.0.0 PREVIEW_PORT=8787 PREVIEW_BASE_URL=http://UNRAID_SERVER_IP:8787
America/Phoenix is an example. Replace it with the correct timezone and replace UNRAID_SERVER_IP with the LAN address of the Unraid host.
Compose Manager Point the stack/project at /mnt/user/appdata/plexweekly/compose.yaml, review the environment values, then bring the stack up.
docker compose build --pull docker compose up -d
./plexweekly.sh setup ./plexweekly.sh verify ./plexweekly.sh status
The simplest route is the Unraid host LAN IP and Tautulli’s published host port:
"TautulliUrl": "http://UNRAID_SERVER_IP:8181"
When both services share the same custom Docker network, the Tautulli container name can be used instead:
"TautulliUrl": "http://tautulli:8181"
./plexweekly.sh list-users ./plexweekly.sh preview-all ./plexweekly.sh send-test-all ./plexweekly.sh schedule-status
Open the preview index at http://UNRAID_SERVER_IP:8787/preview-all/preview-all-00-INDEX.html.
./plexweekly.sh schedule-enable
The included relative volume ./data:/data resolves to /mnt/user/appdata/plexweekly/data when the Compose project lives in the recommended folder.
Use http://[IP]:[PORT:8787]/preview-all/preview-all-00-INDEX.html as the container WebUI URL when creating a custom Unraid template later.
The supported Unraid route for this package is Docker Compose. A future Unraid-specific release could add a one-click CA template without changing the newsletter engine.
Avoid the most common container networking mistake.
Inside PlexWeekly, localhost means PlexWeekly—not the QNAP host or the separate Tautulli container.
Use the same host address another LAN device uses to open Tautulli.
"TautulliUrl": "http://192.168.1.50:8181"
Attach both containers to a user-defined network and resolve Tautulli by service name.
"TautulliUrl": "http://tautulli:8181"
PlexServerUrl and PlexToken improve clearLogo support. Tautulli and text-title fallbacks remain available.
The wizard writes live settings into persistent storage.
URL, API key, history window, watched thresholds, and exclusions.
Sender, Reply-To, SMTP host/port, authentication, and TestEmail.
Server label, footer name, Plex web link, and optional direct Plex metadata.
Day, local time, grace period, polling, and enabled state.
Ten-second production recipient delay and shorter test delay.
Excluded users/emails and recent-access classification window.
{
"TautulliUrl": "http://192.168.1.50:8181",
"ApiKey": "PASTE_YOUR_TAUTULLI_API_KEY_HERE",
"FooterServerName": "My Plex",
"FromName": "My Plex Newsletter",
"SmtpHost": "smtp.example.com",
"SmtpPort": 587,
"SmtpEnableSsl": true,
"TestEmail": "you@example.com",
"ScheduleDay": "Friday",
"ScheduleTime": "09:30",
"SendDelaySeconds": 10,
"ScheduleEnabled": false
}The live config is stored under data/, receives restrictive permissions, and is not included in either distributed archive.
Every routine action is exposed through ./plexweekly.sh.
| Command | What it does | Risk |
|---|---|---|
verify | Checks runtime, assets, config, Tautulli, SMTP reachability, and schedule syntax. | Safe |
list-users | Lists selectable Plex/Tautulli users. | Safe |
preview [user] | Creates one browser preview. | No email |
preview-all [user] | Creates six HTML states and an index. | No email |
send-test [user] | Sends one message only to TestEmail. | TestEmail |
send-test-all [user] | Sends all six only to TestEmail. | TestEmail |
welcome [user] | Sends a real welcome and records state. | Real recipient |
send-all | Sends to every eligible Plex user after confirmation. | Bulk send |
roster | Displays access/welcome state. | Safe |
repair-assets | Repairs email-safe assets. | Safe |
logs / status | Shows logs or service state. | Safe |
restart / update | Restarts or rebuilds without deleting data. | Service change |
backup | Archives persistent data. | Safe |
shell | Opens a container shell. | Advanced |
All states use the production renderer and MIME/CID pipeline.
One-off onboarding without weekly stats, quiet copy, or warm-up copy.
WELCOMEONLY = TRUEFirst scheduled delivery with onboarding replacing empty statistics.
RECENTACCESS + ZERO STATSFirst scheduled delivery with populated statistics.
RECENTACCESS + ACTIVITYPopulated established newsletter; sample stats only when needed for layout testing.
NORMAL ACTIVITYZero activity after warm-up, showing QUIET IN THIS SECTOR.
WARMINGUP = FALSEZero activity during the initial window, showing STATS ARE WARMING UP.
WARMINGUP = TRUE./plexweekly.sh preview-all
http://QNAP_LAN_IP:8787/preview-all/preview-all-00-INDEX.html
send-test-all sends six real SMTP messages, but every message goes exclusively to TestEmail.
The same card renderer is used by browser previews, TestEmail, welcomes, normal newsletters, and quiet-week Latest Releases.
TV cards show the three newest episode rows. Totals above three add a gold footer at the bottom: 1 additional episode recently added for four total, or X additional episodes recently added for five or more. Totals from one through three show no footer.
Movie cards show up to two genres directly below the title. More than two becomes Genre One, Genre Two, and more. The 13px / 500-weight line uses the same muted color as the description and disappears entirely when no genre metadata is available.
Movie content height was expanded for the genre row, while TV details reserve room for three episode lines and a bottom-aligned overflow footer.
The scheduler records attempts to avoid duplicates.
ScheduleEnabled=false until explicitly enabled.
Day and time follow TZ in .env.
A short restart after send time can still be handled.
The attempt is recorded before delivery starts.
./plexweekly.sh schedule-status ./plexweekly.sh schedule-enable ./plexweekly.sh schedule-disable ./plexweekly.sh schedule-reset
It clears today’s attempt guard. A later scheduler poll may permit another real SendAll on the same day.
The data folder is the installation’s durable identity.
config.json: API, SMTP, branding, schedulestate.json: warm-up trackingaccess-state.json: new-user and welcome historyscheduler-state.json: same-day send guard./plexweekly.sh backup
./plexweekly.sh update
The backup includes config.json. Treat the generated archive as a private credential-bearing file.
The package minimizes exposure; the administrator controls LAN and credentials.
UMASK=077 restricts new files.env or config.jsonStart with verification and logs.
./plexweekly.sh status and ./plexweekly.sh logs. Confirm port 8787 and PREVIEW_BASE_URL use the current NAS LAN IP.chmod +x qnap-install.sh plexweekly.sh. This is common after Windows ZIP extraction.The shortest safe path from extraction to scheduled delivery.
cd /share/Container/plexweekly chmod +x qnap-install.sh plexweekly.sh ./qnap-install.sh ./plexweekly.sh verify ./plexweekly.sh list-users ./plexweekly.sh preview-all ./plexweekly.sh send-test-all ./plexweekly.sh schedule-status # Enable only after approving all six TestEmail messages: ./plexweekly.sh schedule-enable
Archive integrity, shell syntax, Compose structure, Linux-safe paths, non-root startup, and six-state wiring.
Your QNAP, Docker daemon, Tautulli, Plex metadata, LAN, SMTP provider, and mail clients still require acceptance testing.
Enabling the schedule authorizes confirmation-free weekly SendAll at the configured local time.
Do not enable the schedule until the browser preview index and all six TestEmail messages are approved on desktop and mobile clients.
When Tautulli reports one show or season row, PlexWeekly inspects child episode timestamps inside the newsletter window and calculates the true remainder beyond the three visible rows.
Only the three newest episode rows appear on the card.
Four total produces 1 additional episode recently added; five or more uses the exact remaining count.
A wrapped title or IMDb row no longer pushes the gold overflow line outside the visible card.
The muted 13px, weight-500 line stays directly under the movie title with the first two genres and “, and more” when applicable.
Movie genres now appear immediately beneath the title identity on regular cards and every movie-based hero layout.
The title and genre use normal flow, eliminating the large blank gap caused by fixed-height table distribution.
The genre appears below either the clearLogo or the normal fallback title.
The genre appears below the normal title while the mobile banner remains clearLogo-free.
13px, weight 500, muted description color, first two genres plus “, and more,” and no blank row when genre metadata is missing.