Skip to content

Support for multiple Plex instances - #1155

Draft
oceanplexian wants to merge 3 commits into
Notifiarr:v1from
oceanplexian:feat/multi-plex-instances
Draft

Support for multiple Plex instances#1155
oceanplexian wants to merge 3 commits into
Notifiarr:v1from
oceanplexian:feat/multi-plex-instances

Conversation

@oceanplexian

@oceanplexian oceanplexian commented Jan 27, 2026

Copy link
Copy Markdown
Contributor

Support for multiple Plex instances

Adds support for configuring multiple Plex Media Servers, addressing use cases where users run backup Plex servers or have multiple independent Plex installations.

Fixes #790

Changes

  • Add PlexServer field to AppsConfig for additional servers (backward compatible)
  • Change Apps.Plex from single instance to slice internally
  • Update plexcron to collect sessions from all configured servers
  • Update empty trash trigger to work across all servers
  • Update service checks to monitor all servers
  • Update clientinfo to report all server versions
  • Add [[plex_server]] config template section

Backward Compatibility

  • The existing [plex] config section continues to work unchanged
  • Additional servers can be added via [[plex_server]] sections
  • Single server configurations work exactly as before
  • Webhook routing matches server by name, falls back to first server

Configuration Example

# Primary Plex server (existing config)
[plex]
url     = "http://plex1:32400/"
token   = "token1"
timeout = "1m"

# Additional Plex server
[[plex_server]]
url     = "http://plex2:32400/"
token   = "token2"
timeout = "1m"

Backend/Website Implications

The website will now receive:

  • Aggregated sessions from all Plex servers
  • Server name included with each session batch
  • Separate connection status reports for each server
  • Service checks for each configured server

The website may need minor updates to:

  • Display sessions grouped by server name
  • Show health status for multiple Plex instances
  • Handle the numPlex count being > 1 in app info

This adds support for configuring multiple Plex Media Servers.

Changes:
- Add PlexServer field to AppsConfig for additional servers
- Change Apps.Plex from single instance to slice
- Update plexcron to collect sessions from all servers
- Update empty trash to work across all servers
- Update service checks to monitor all servers
- Update clientinfo to report all server versions
- Add [[plex_server]] config template section

Backward Compatibility:
- The existing [plex] config section continues to work
- Additional servers can be added via [[plex_server]] sections
- Single server configs work exactly as before

Resolves Notifiarr#790

@davidnewhall davidnewhall left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's like you forgot there's a frontend. And Tautulli needs a "plex picker" per instance.

Comment thread pkg/triggers/plexcron/sessions.go Outdated
// The Lock ensures only one request to Plex happens at once.
// Because of the cache two requests may get the same answer.
func (c *cmd) getSessions(ctx context.Context, allowedAge time.Duration) (*plex.Sessions, error) {
func (c *cmd) getSessionsForServer(ctx context.Context, server *apps.Plex, allowedAge time.Duration) (*plex.Sessions, error) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this even need to be renamed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted - kept the original name getSessions since the server parameter makes it clear which server is being operated on.

Comment thread pkg/triggers/plexcron/sessions.go
Comment thread pkg/triggers/plexcron/finished.go Outdated
// Plex does not send a webhook or identify in any other way when an item is "finished".
func (c *cmd) checkForFinishedItems(ctx context.Context, _ *common.ActionInput) {
sessionCtx, cancel := context.WithTimeout(ctx, c.Plex.Timeout.Duration)
for idx := range c.Plex {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably make the http method take in an index, and pick the server based on the index. Otherwise, set it to 0 if one isn't provided and assume the first server.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added GetByIndex(index int) method that returns a Plex server by index (0-based), or nil if out of range. Also added Len() helper. The First() method now uses GetByIndex(0).

Comment thread pkg/triggers/plexcron/plexcron.go Outdated
mnd.Log.Printf("==> Plex Sessions Collection Started, URL: %s, interval:%s timeout:%s webhook_cooldown:%v delay:%v",
c.Plex.Server.URL, cfg.Interval, c.Plex.Timeout, cfg.Cooldown, cfg.Delay)

for idx := range c.Plex {

@davidnewhall davidnewhall Jan 27, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"session collection" is enabled and disabled on the website. That configuration is in the "client info" (see a few lines above this). We'll need a way to allow the website to continue to control this, but it needs to default to just controlling the first plex server for now. We can add another structure member to the "actions" struct if needed to keep backward compatibility. In other words, the website needs to be able to independently enable and disable this feature per server.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Session collection and finished items checking now only fire for the first server (website-controlled). Added comments explaining this. The getAllSessions() method remains available for API calls that need to aggregate from all servers, but the timer-based features only use c.Plex[0].

Comment thread pkg/triggers/plexcron/plexcron.go
Comment thread pkg/triggers/plexcron/sessions.go
- Revert unnecessary function renames (getSessions, plexSessionTracker)
- Add GetByIndex method for index-based server selection
- Fix session/finished collection to only fire for first server (website-controlled)
- Website config currently controls only the first server for backward compat
@oceanplexian

Copy link
Copy Markdown
Contributor Author

Addressed all review comments:

  1. Function renames reverted - Kept original names getSessions and plexSessionTracker since the server parameter makes it clear which server is being operated on.

  2. Added GetByIndex(index int) - Returns a Plex server by index (0-based), with Len() helper. First() now uses GetByIndex(0).

  3. Fixed timer-based features - Session collection (sendPlexSessions) and finished items checking (checkForFinishedItems) now only fire for the first server (website-controlled). Added comments explaining this limitation.

  4. getAllSessions() preserved - Still available for API calls that need to aggregate from all servers, but timer-based features use c.Plex[0] directly.

Re: frontend and Tautulli plex picker - acknowledged, those will need separate work.

now := time.Now()
info := clientinfo.Get()
cacheKey := "plexCurrentSessions_" + server.Server.Name()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should use the url not the name.

@davidnewhall

Copy link
Copy Markdown
Contributor

It's looking better. Move all the icons to another PR since they're not used here. They make this PR difficult to review.

Comment thread pkg/services/apps.go
Comment on lines +427 to +430
name := PlexServerName
if len(plexServers) > 1 {
name = fmt.Sprintf("%s %d", PlexServerName, idx+1)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may always have the instance number.

Suggested change
name := PlexServerName
if len(plexServers) > 1 {
name = fmt.Sprintf("%s %d", PlexServerName, idx+1)
}
name := fmt.Sprintf("%s %d", PlexServerName, idx+1)

(and then just move it below, don't set name)

if c.Apps.Plex.Enabled() {
numPlex = 1
}
numPlex := len(c.Apps.Plex)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to set this variable. Just put the len() below.

@davidnewhall
davidnewhall changed the base branch from main to v1 February 5, 2026 04:56
@davidnewhall
davidnewhall marked this pull request as draft February 24, 2026 05:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for multiple Plex instances

2 participants