Omahub
← All plugins
I

Plex

by Ian Swope

Plex streams in the Omarchy bar: who is watching what, whether the server is transcoding for them, and whether that transcode is keeping up.

Security review

No obvious issues detected

Deterministic scan — not a security guarantee

None
Risk level
None
Analyzed commit
e28ba0e
Scanned
3 weeks ago

No potentially dangerous behavior detected in the analyzed commit.

Automated analysis only — not a security guarantee.

AI advisory review

No obvious issues detected

Language-model assessment · ~deepseek/deepseek-v4-flash-latest — advisory only

Low
AI risk level
Low
Recommendation
install
Model
~deepseek/deepseek-v4-flash-latest
Analyzed commit
e28ba0e
Reviewed
3 weeks ago

The plugin is a well-engineered Plex status widget that reads server state and can stop streams with explicit user confirmation. It handles credentials carefully (token via stdin, absolute binary paths, -q for curl, bounded reads) and contains no obfuscated or destructive code. The only inherent risk is storing a Plex token in a local config file, which is standard for such integrations.

  • Stores a Plex server token in plaintext at ~/.config/omarchy-plex/config.json (mode 600), which is typical but means anyone with the user's account access could read it.
  • The plugin can terminate Plex streams, but only after explicit user confirmation and with a visible reason; no unexpected state changes were found.
How this check works

This review combines the deterministic scan (the rule-based results above) with an independent look at the plugin's code by a language model. The model reads a trimmed sample of the repository's files, the manifest, and the README, then gives a plain-language risk level and a recommendation: install (no notable danger), review (look closer first), or avoid (clearly dangerous).

It runs on the same analyzed commit as the deterministic scan and is strictly advisory — it is not a security guarantee and never blocks a plugin by itself. A human moderator still reviews plugins before they are listed.

AI advisory only — automated analysis, not a security guarantee.

Install
$ omarchy plugin add https://github.com/ianswope/omarchy-plex --enable
Widgets #bar #quickshell #media

Plex

Plex streams in the Omarchy bar: who is watching what, whether the server is transcoding for them, and whether that transcode is keeping up.

What it shows

One row per stream:

  • What is playing — series and episode code, or film and year — and how far in.
  • Who is watching it, and on which client.
  • How it is reaching them: LAN, WAN, or relayed.
  • The playback decision: Direct Play, Direct Stream, or Transcode with the codec change.
  • Bandwidth, and for a transcode, whether it is keeping up.

The bar carries the number of active streams and says nothing at all when nobody is watching. It turns urgent only when the server cannot be reached; a transcode losing ground gets a warmer tint, because the stream is still playing and may recover.

The two things it is careful about

A direct stream is not a transcode. Plex reports the decision in two places. Part.decision says what happened to the file, TranscodeSession.videoDecision says what happened to the video. A file marked transcode whose video is copy is a direct stream — only the container or the audio changed, the video was passed through untouched, and the server is barely working. Counting those as transcodes makes a quiet server look busy. This plugin separates them.

A throttled transcode is a healthy one. speed is a multiple of realtime, so anything under 1.0 is losing ground — except that a transcoder which has run far enough ahead deliberately idles, and reports a low speed precisely because everything is fine. The panel reads throttled and speed together, and only says "falling behind" when the transcoder is actually working and still losing.

That second one is the whole reason this exists in the bar rather than in a dashboard: "someone is about to buffer" is worth knowing in the second it becomes true.

Sign in

Press l in the panel, or run:

bash ~/.config/omarchy/plugins/ianswope.plex/bin/omarchy-plex-login

A browser opens on Plex's own sign-in page, you click Allow, and that is the whole configuration. Nothing is typed, no token is hunted for, and the script never sees your password — it is the same device-link flow Plex's TV and mobile apps use. It then lists the servers on your account, picks the LAN address in preference to a remote one and a remote one in preference to a relay, and writes the config itself.

Over ssh with no display, set OMARCHY_PLEX_NO_BROWSER=1 and it prints the URL to open somewhere else instead.

What it writes — ~/.config/omarchy-plex/config.json, mode 600:

{
  "url": "http://<plex-host>:32400",
  "token": "<per-server access token>",
  "client_id": "<stable device id>",
  "stop_reason": "Stopped from the Omarchy bar"
}

The token stored is the server's access token, not the account token that authorised the sign-in. It reaches one server and nothing else — the account token is used once, in memory, to ask which servers exist, and is never written down. The config lives outside the plugin directory so it is never in the repo, and outside the bar's settings so it is never in shell.json.

stop_reason is the message a viewer sees when you stop their stream. It lives here, in a file, rather than in a settings row — the wording lands on someone else's screen mid-show and deserves to be written once, deliberately.

If you would rather not sign in at all, the two fields the plugin actually needs are url and token; any Plex token you already have works.

Stopping a stream

x on a selected row, or right-click it. The panel confirms first, naming what is playing and who is watching.

This ends playback server-side and puts your reason on their screen. It is deliberately the only action: Plex's remote-control protocol (play, pause, seek) only reaches clients that advertise themselves as controllable, and most of the ones people actually watch on do not. An action that works on half your devices is worse than one that always works.

Keys

Key Does
x Stop the selected stream, after confirming
r Refresh now
l Sign in to Plex
e Open the config
arrows Move the cursor
Escape Close

Right-click the bar icon to refresh without opening the panel.

Install

Requires Omarchy 4 ("Quattro", Quickshell bar), plus curl and jq.

# 1. Drop the plugin in place — the directory name must be the manifest id
mkdir -p ~/.config/omarchy/plugins
cp -r omarchy-plex ~/.config/omarchy/plugins/ianswope.plex

# 2. Sign in — opens a browser, click Allow, done
bash ~/.config/omarchy/plugins/ianswope.plex/bin/omarchy-plex-login

# 3. Prove the data layer before touching the bar
bash ~/.config/omarchy/plugins/ianswope.plex/bin/omarchy-plex-status

# 4. Add {"id": "ianswope.plex"} to bar.layout.right in ~/.config/omarchy/shell.json,
#    then restart the shell
omarchy-restart-shell

Step 3 is the one worth not skipping: it prints the same JSON the panel reads, so a bad token or an unreachable host is one line of output rather than a widget that silently shows nothing.

A bar widget goes in bar.layout.right, not the top-level plugins[] array — that array is for overlay plugins, and a bar widget listed there never appears and logs nothing. omarchy-restart-shell, not omarchy-refresh-shell: refresh re-reads config without reloading plugin QML.

Remove

# 1. Take the widget out of bar.layout.right in ~/.config/omarchy/shell.json
# 2. Delete the plugin and its config
rm -rf ~/.config/omarchy/plugins/ianswope.plex
rm -rf ~/.config/omarchy-plex
omarchy-restart-shell

Removing the config directory is what revokes this machine's access. The token it held reaches only your Plex server, but it stays valid until you also remove the device: plex.tv → Account → Authorized Devices → Omarchy Plex. Do that if the machine is leaving your hands.

Nothing else is written anywhere: no state directory, no cache, no files on the Plex server, and no change to any Plex setting.

What it never does

It does not start playback, change quality, alter your library, or write anything to the server. The only request that changes state is the session termination behind x, and it is confirmed first.

The token is passed to curl through stdin rather than on the command line, because arguments are visible in /proc to every user on the machine.

curl is given -q as its first option, so ~/.curlrc is never read. That file is writable by anything running as this user, and a line in it can add a second url = to the request — which the X-Plex-Token header written on stdin would then follow. A poll that runs every few seconds makes that a standing leak rather than a one-off.

Every binary on the credential path is an absolute /usr/bin path rather than a name resolved through PATH: a shadow curl planted ahead of the real one would receive the token, and a shadow dd reads the config it came from.

Tests

node test/model-test.js    # what the panel decides, on plain data
bash test/path-test.sh     # the helpers, under a hostile PATH

model-test.js covers the decision and throttle logic above, the formatting, the health policy, and the input handling for text and ids that arrive from the server. path-test.sh plants a shim for every binary the helpers use earlier in PATH and proves the status helper still runs and reaches none of them.

Licence

MIT.