A Plex DVR sidecar that records the live broadcast, not the repeat.
4.1K
A CouchElephant never forgets.
Plex's DVR records the wrong broadcast. Ask it to record your team and it will happily pick the repeat that airs two days later, on a channel you do not watch, and tell you nothing about it. CouchElephant reads the same guide, picks the live broadcast itself, and pins the recording to that exact channel and start time so Plex has nothing left to choose.
It sits beside Plex. It does not replace it, proxy it, or ask you to watch anything anywhere else. Recordings land in your Plex library exactly as they always did.
Version 1.0.1.
Plex's guide already flags the live airing as a premiere. Plex ignores that flag and breaks the tie on the lowest channel number. This is a known bug, reported in March 2025 and still open.
CouchElephant reads the flag, chooses the airing, and creates a one-shot
recording pinned with lineupChannel and startTimeslot. Every decision it
makes, including the ones it declines, is written down and shown to you.
It also does several things Plex cannot say at all:
A real two-axis guide. Channels down, time across, both loading more as you reach the edge. Amber means CouchElephant scheduled it, blue-grey means Plex did.
| Dark | Light |
|---|---|
![]() | ![]() |
Press record and you get Plex's own options, read from Plex rather than copied here, plus CouchElephant's. Each row is marked with whose feature it is, and a bar across the top says which of the two will end up owning the recording.

Opening a programme shows every airing of it, which one is live, and why it is being recorded if it already is.

What your Plex server will actually record, read from Plex's own grab list. Two views over the same data, and every entry says who booked it and why.
| Agenda | Calendar |
|---|---|
![]() | ![]() |
A pass keeps matching new airings on its own. Open one to see what it will record next and why it chose that broadcast. Plex's own rules are listed here too, in the other colour.

A pass can follow something the guide has not reached. Those show as plans rather than bookings, with the date at exactly the precision the source gave it: a kickoff if the league published one, only a month if that is all anyone has announced. None of them are booked. Each becomes a real recording the moment Plex carries an airing for it, and if the guide runs past the date with no match, you are told which one.
Follow a team, a programme, or a set of conditions. Leave the source limit alone on a team or a programme and it becomes an ordinary Plex rule.

A nested tree: every group matches all, any or none of what it holds, and groups nest as deep as you like. It counts what it would record, and shows the first matches, before you create it.

Plex's own settings are on every pass, padding included, with Plex's own explanation of each one a hover away.

CouchElephant can only record from the airings Plex offers it, so it checks that Plex is doing its own job. Every sync it asks Plex how often it intends to refresh the guide, when it last did, and how far ahead the guide now reaches. A problem badges the sync button, because a guide that has stopped moving is a sync problem. A notice says what is wrong and what to do, clears itself when the condition clears, and cannot be dismissed.
Sections down the left, sub-tabs inside each, and a search that reads all of them.
Under Plex there is a Sources tab for looking past the end of the guide. TVmaze covers announced series and needs no key and no account, so that works out of the box. Two optional free keys widen it: TheSportsDB for a team's published season, and TMDB for films. Neither is required, and you are only told about one if it would add something to what you already follow.
| Plex | Accounts | Channel artwork |
|---|---|---|
![]() | ![]() | ![]() |
Export them to a file, snapshot them on a schedule, or keep a live two-way copy in another database.
| Export and import | Backing store |
|---|---|
![]() | ![]() |
It asks for the one thing it needs, tests it before saving, and tells you what you can leave for later.

| Guide | Recordings |
|---|---|
![]() | ![]() |
You need a Plex Media Server with a DVR, and Docker.
docker run -d --name couchelephant --restart unless-stopped \
-p 8710:8710 \
-v /opt/couchelephant/data:/data \
-e TZ=UTC \
ghcr.io/datbird/couchelephant:latest
The same image is on Docker Hub as datbird/couchelephant, if you would
rather pull from there. There is a docker-compose.yml in the repository if
you would rather use that.
On Unraid, search for CouchElephant in Apps. The template fills in the port and the appdata path for you.
From source, if you would rather build it yourself: clone the repository
and run docker build -t couchelephant .
Open http://your-host:8710, and in Settings, Plex put in your server
address and token. The address has to work from inside the container, so
127.0.0.1 only works if Plex runs in it too.
Preview mode is on for a new install. Rules work out which airing they would choose and show it, but nothing is written to your DVR. Turn it off under Settings, Recording once the choices look right.
Nobody is asked to sign in on a new install, which suits a box on your own network. Turn on local accounts or Cloudflare Access under Settings, Accounts before this is reachable from anywhere else.
Full instructions are in docs/INSTALL.md.
./scripts/test.sh
410 checks: the airing choice, the pin, the smart filter compiler, the three-way merge behind the backing store, the Plex client against a fake server that reproduces the real one's quirks, every endpoint, and a browser suite that drives the guide, the record panel, the recordings page, the smart filter builder, backup and restore, settings, the phone layout and first run. It refuses to start unless every path it would write to is scratch. See docs/DEVELOPING.md.
Every picture above is made by scripts/test.sh --shots, from an invented
guide in tests/demo_guide.py. None of them shows anybody's real television,
and they can be remade whenever the interface changes.
| Install and configure | Docker, volumes, environment, the Plex token |
| How recording works | Choosing the airing, passes, source limits, who owns a rule |
| Architecture | Modules, the database, the sync loop |
| HTTP API | Every endpoint |
| Accounts | Off, local, or Cloudflare Access |
| Your data | Export and import, snapshots, and a two-way backing store |
| Developing | Running it locally, the test suite, the deploy script |
| Releasing | Tagging a version, the published image, Unraid Community Applications |
| Plex API notes | What the server really returns, and the traps in it |
MIT. See LICENSE. Third-party notices are in THIRD_PARTY.md.
Content type
Image
Digest
sha256:2227711e2…
Size
70.2 MB
Last updated
23 days ago
docker pull datbird/couchelephant