← Back to All Bots
🐈

Purrl TV

Overview

Purrl TV is an adult, stations-only Discord Activity and website (purrl.tvkitty.com) forked from Tv Kitty. Members tune into always-on stations that play from a private Plex library on the NAS; there is no watch-party mode. Everything is gated by an 18+ Discord role, and the app itself never shows explicit content until someone deliberately enters a station.

📺

Stations from folders

Stations are scoped to Plex libraries and tags. Videos are auto-labeled with the folder they sit in, so a station named after a folder fills itself.

👁

Blurred featured station

The home screen shows a blurred poster with an Enter button, never a live preview.

❤

Likes and Top Rated

Anyone can like what a station is playing; the most-liked videos make the Top Rated page.

🔒

Two tiers

Everyone with the 18+ role watches stations. The owner and a chosen full-library role also browse, play, keep favorites and upload clips.

⬆

Clip uploads

Post a video in the clips channel and the bot asks which category it is (a dropdown under your post, no threads); pick one and it lands in that folder on the NAS, Plex rescans, and the Discord post is deleted (the bot needs Manage Messages there). Also from the app's upload page or /clip-upload.

💾

Always ready

The whole library is prepared ahead of time and nothing prepared is ever deleted; disk is the only limit.

How content flows

1. Download into a category folder

The NAS share purrl has Videos\<Category> and Clips\<Category> folders (Vintage, Ebony, Interracial, Amateur, ...). Two Desktop shortcuts open them. Plex's "Purrl (18+)" library covers the whole share.

2. Labels appear on their own

Every 30 minutes the backend re-reads the library, labels each video with its folder name (clips also get "Clips"), and queues anything unprepared for preparation at the lowest priority.

3. Stations pick by tag

A station scoped to tag Vintage plays everything labeled Vintage. Run /station-rebuild after adding content to rebuild today's schedules right away instead of waiting for the nightly build.

Commands

Everyone

CommandWhat it does
/stationsBrowse station schedules and vote to replace upcoming items.
/clip-upload full tierUpload a video attachment into a category. Age-restricted channels only.

Owner

CommandWhat it does
/connectLink the Plex account Purrl streams from (the owner's personal account, which owns the NAS server).
/station-addCreate a station: name, comma-separated library titles, comma-separated tags. Blank tags = everything in those libraries.
/station-edit / /station-remove / /station-listManage stations. Type - for a field to clear it.
/station-scope-optionsShow the libraries and tags a station can be scoped to.
/station-rebuildRebuild today's station schedules now.
/full-library-role (+ -clear, -show)The role that unlocks browsing, favorites, Play and uploads.
/clips-channel-setThe age-restricted clips channel. Any video posted there gets a category prompt (dropdowns, 15-minute timeout files it under Uncategorized) and is saved to the library; /clip-upload cards go there too. No threads.
/clip-channel-add #channel [category]Optionally watch another 18+ channel too, with its own default category. /clip-channel-remove, /clip-channel-list.
/now-playing-channelAge-restricted channel for station "now playing" cards.
/station-calendar-channelChannel for the daily station calendar post.
/favorite-save-roleRole whose favorites are kept prepared permanently (inherited from Tv Kitty).

In the app

  • Home: the blurred featured station with Enter, the other station tiles, and (full tier) a big "Purrl (18+)" library tile.
  • Menu: Join a Station, Top Rated, and for the full tier My Favorites (with Randomize) and Upload a Clip.
  • Station view: Like what's playing; full tier also gets Favorite.
  • Video page: Like for everyone; Play and Favorite for the full tier. Play prepares the file through the same pipeline the stations use, then plays it in the app.

Operations

Services

Three Windows services on the desktop, installed by scripts\install_services.ps1: PurrlTvBackend (port 8440, runs as the local tvkitty account so it can write to the NAS), PurrlTvBot (internal API 8441), PurrlTvVite (port 5174). purrl.tvkitty.com is an ingress rule in Tv Kitty's named Cloudflare tunnel; there is no tunnel service of its own.

Restart order

Stop-Service PurrlTvBot; Restart-Service PurrlTvBackend; Start-Sleep 8; Start-Service PurrlTvBot

Frontend changes need npm run build in activity\ followed by Restart-Service PurrlTvVite.

Configuration

.env in the repo root (never committed). Notable keys: PLEX_SERVER_NAMES=tvkitty-nas, PURRL_LIBRARY_PREFIX=Purrl, CLIPS_DIR, PREPARED_MEDIA_DIR, FFMPEG_BINARY (full path - the service account has no PATH to the per-user ffmpeg), PREPARE_WHOLE_LIBRARY, PREPARE_KEEP_EVERYTHING, AUTO_LABEL_BY_FOLDER.

Watch the disk

Prepared files are kept forever by design. The cache lives on D:\purrl-prepared for now; move it to a NAS share the way Tv Kitty's was moved when it grows.

Tech

Python 3.10, FastAPI + uvicorn, discord.py 2.7, plexapi, aiosqlite, ffmpeg; vanilla JS frontend built with Vite and served as a Discord Activity and a standalone site. Repo: oldcatlady12/purrl-tv (private).