Skip to content

feat(notifications): Play On Media Server in notification#2392

Open
JackW6809 wants to merge 8 commits intoseerr-team:developfrom
JackW6809:notification-media-server-links
Open

feat(notifications): Play On Media Server in notification#2392
JackW6809 wants to merge 8 commits intoseerr-team:developfrom
JackW6809:notification-media-server-links

Conversation

@JackW6809
Copy link
Contributor

@JackW6809 JackW6809 commented Feb 8, 2026

In the email, Telegram, and Slack notification users receive when their media request is now available, I have added a Play on media server (e.g. Play on Plex) button that takes them directly to the media on their media server.

AI Was used to help understand parts of existing codebase so I could re-use parts in my new work.

Description

In the email notification I have added an extra button to the bottom, in my example I use Plex so for me the button is dynamically called Play on Plex. This takes you directly to the media in the users media stack. The same as the button if you were to view the media in Seerr and click Play on Plex.

It is not "required" but more a quality of life feature, it allows the user to go directly to the media in their chosen media server, eliminates an extra step of having to find it manually in the media server or in Seerr.

How Has This Been Tested?

  • I have tested the change on all platforms by removing existing media, requesting it, running a full library scan so Seerr picks it back up from Plex, then send an email, slack, and telegram notification to me. I click on the link in each notification individually and it successfully sends me to the media in Plex.

  • Ran from my Mac from a fresh Seerr dev instance, added my Plex Media Server as the Media Server and ran a full library scan so Seerr has all the latest data.

  • It affects Notifications but it doesn't remove any features but instead adds more useful features.

Screenshots / Logs (if applicable)

Screenshot 2026-02-08 at 7 33 49 pm Screenshot 2026-02-08 at 7 34 05 pm image

Checklist:

  • I have read and followed the contribution guidelines.
  • Disclosed any use of AI (see our policy)
  • I have updated the documentation accordingly.
  • All new and existing tests passed.
  • Successful build pnpm build
  • Translation keys pnpm i18n:extract
  • Database migration (if required)

Summary by CodeRabbit

  • New Features
    • Notifications now include direct action links to play content on your media server (Plex, Emby, or Jellyfin) in email, Slack, and Telegram messages.

@JackW6809 JackW6809 requested a review from a team as a code owner February 8, 2026 19:52
@JackW6809 JackW6809 force-pushed the notification-media-server-links branch 4 times, most recently from 6b7b647 to d90632b Compare February 13, 2026 22:05
@JackW6809 JackW6809 changed the title feat(notifications): Play On Media Server in email notification feat(notifications): Play On Media Server in notification Feb 14, 2026
@JackW6809 JackW6809 force-pushed the notification-media-server-links branch 2 times, most recently from d4691f9 to c3db226 Compare February 15, 2026 11:29
@coderabbitai
Copy link

coderabbitai bot commented Feb 15, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The changes extend notification agents (Email, Slack, Telegram) with media server integration. A new utility module provides helpers to resolve media server names and URLs. Notification payloads are enriched with media server context, and conditional action buttons or links are added to templates when media server URLs are available.

Changes

Cohort / File(s) Summary
Media Server Utilities
server/utils/mediaServerHelper.ts
New module exporting getAvailableMediaServerName() and getAvailableMediaServerUrl() helpers that resolve media server type to display name (Emby, Plex, Jellyfin) and compute media URLs with 4K-first preference when available.
Notification Agents
server/lib/notifications/agents/email.ts, server/lib/notifications/agents/slack.ts, server/lib/notifications/agents/telegram.ts
All three agents now import and use media server helpers; added shouldSend() methods to determine notification eligibility; enriched payloads and templates with mediaServerName and mediaServerActionUrl/mediaServerUrl context; Slack adds dynamic action buttons for media server playback; Telegram appends "Play on" links; Email uses template conditionals.
Email Templates
server/templates/email/media-request/html.pug
Adds conditional rendering of a "Play on {mediaServerName}" button when mediaServerActionUrl is provided, matching styling of existing action buttons.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A media server here, a media server there,
I've scattered them 'cross every notification with care,
Slack buttons now dance, emails glow bright,
Telegram links leap—'tis a glorious sight!
Users can play now, with one hopeful click. 🎬

🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: adding 'Play on Media Server' buttons to notifications across email, Slack, and Telegram.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into develop

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

@JackW6809 JackW6809 force-pushed the notification-media-server-links branch from adaed40 to b64fde1 Compare February 15, 2026 13:22
@JackW6809
Copy link
Contributor Author

@coderabbitai help

@coderabbitai
Copy link

coderabbitai bot commented Feb 15, 2026

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

CodeRabbit commands

These commands are invoked using PR/Issue comments.

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai evaluate custom pre-merge check --instructions <custom-checks-instructions> --name <custom-checks-title> [--mode <error|warning>] to validate the custom pre-merge checks instructions. Defaults to error when --mode is omitted.
    • @coderabbitai ignore pre-merge checks to override pre-merge checks and get an approval on PR.
    • @coderabbitai run pre-merge checks to run pre-merge checks on the pull request.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve to resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai generate configuration to create a PR that adds the current resolved configuration as .coderabbit.yaml (or show it if already present).
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit configuration file (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, support, documentation and community

  • Visit our status page to check the current availability of CodeRabbit.
  • Create a ticket on our support page for assistance with any issues or questions.
  • Visit our documentation site for detailed information on how to use CodeRabbit.
  • Join our Discord community to connect with other users and get help from the community.
  • Follow us on X/Twitter for updates and announcements.

@JackW6809
Copy link
Contributor Author

@coderabbitai resume

@coderabbitai
Copy link

coderabbitai bot commented Feb 15, 2026

✅ Actions performed

Reviews resumed.

… media is available

In the email notification users receive when their media request is now available, I have added a
Play on media server (e.g. Play on Plex) button that takes them directly to the media on their media
server.

feat(notifications): play On Media Server in Discord & Slack Notifications

In the Discord & Slack notification users receive when their media request is now available, I have
added a Play on media server (e.g. Play on Plex) button that takes them directly to the media on
their media server.
…location

Created a helper file, this makes it easier to make changes to the function that multiple different
agents use in the same fashion.

BREAKING CHANGE: Adding extra content to notifications

closes seerr-team#2104
Removed some casts from the getAvailableMediaServerUrl as they were unnecessary

BREAKING CHANGE: Function updated

closes seerr-team#2104
In this commit, I updated the slack button behaviour based on the suggestion made by coderabbitai.
This means that now the View Media in Seerr and Play on Plex is on the same line and handled in one
variable.

BREAKING CHANGE: Changing the way buttons are sent in Slack notifications

Closes seerr-team#2104
@JackW6809 JackW6809 force-pushed the notification-media-server-links branch from db87bf7 to b2dc582 Compare February 15, 2026 14:53
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/lib/notifications/agents/telegram.ts (1)

44-57: ⚠️ Potential issue | 🟡 Minor

Minor typo in documentation.

Line 45 has a double space: "agent's notification" → "agent's notification"

📝 Proposed fix
   /**
-   * Returns this agent's  notification settings.
+   * Returns this agent's notification settings.
    * Uses a cached copy when available.
    * `@protected`
    */
🧹 Nitpick comments (1)
server/utils/mediaServerHelper.ts (1)

36-40: Consider documenting the cross-resolution fallback behavior.

The function falls back to the 4K URL when a non-4K request has no standard URL (and vice versa). This "show something rather than nothing" behavior is reasonable but not mentioned in the docstring. A brief note would help future maintainers understand this is intentional.

Additionally, the || undefined suffix is only necessary if URLs can be empty strings rather than just undefined. If mediaUrl and mediaUrl4k are always string | undefined, this is redundant.

@JackW6809
Copy link
Contributor Author

@coderabbitai generate docstrings

@coderabbitai
Copy link

coderabbitai bot commented Feb 15, 2026

✅ Actions performed

Initiated docstring generation; will generate only if new commits exist.

@coderabbitai
Copy link

coderabbitai bot commented Feb 15, 2026

Note

Docstrings generation - SUCCESS
Generated docstrings for this pull request at #2446

coderabbitai bot added a commit that referenced this pull request Feb 15, 2026
Docstrings generation was requested by @JackW6809.

* #2392 (comment)

The following files were modified:

* `server/utils/mediaServerHelper.ts`
Removed a double space from JSDoc, added more into to JSDoc
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@server/lib/notifications/agents/telegram.ts`:
- Around line 73-82: The escapeText method's character class is missing the
backtick and backslash; update the regex in private escapeText(text: string |
undefined): string to include ` and \ as characters to escape, making sure the
backslash is properly escaped in the regex literal (i.e., represent a single
backslash match with an escaped backslash in the pattern). Keep the rest of the
character class and behavior the same so replace still returns '' for undefined
input.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/lib/notifications/agents/telegram.ts (1)

101-205: ⚠️ Potential issue | 🔴 Critical

Remove local helper shadowing and fix argument mismatch (TS compile error).

Local helpers duplicate the imported getAvailableMediaServerName and getAvailableMediaServerUrl but declare them to take no parameters. Lines 200-201 invoke these local functions with arguments (mediaServerType and payload), causing a TypeScript error. Remove the local helper definitions and use the imported helpers instead, which properly accept these arguments.

🔧 Proposed fix
-    function getAvailableMediaServerName() {
-      if (mediaServerType === MediaServerType.EMBY) {
-        return 'Emby';
-      }
-
-      if (mediaServerType === MediaServerType.PLEX) {
-        return 'Plex';
-      }
-
-      return 'Jellyfin';
-    }
-
-    function getAvailableMediaServerUrl(): string | undefined {
-      const wants4k = payload.request?.is4k;
-      const url4k = (payload.media as any)?.mediaUrl4k as string | undefined;
-      const url = (payload.media as any)?.mediaUrl as string | undefined;
-
-      return (wants4k ? (url4k ?? url) : (url ?? url4k)) || undefined;
-    }
-
     /* eslint-disable no-useless-escape */
     let message = `\*${this.escapeText(
🤖 Fix all issues with AI agents
In `@server/lib/notifications/agents/email.ts`:
- Around line 78-106: The file defines mediaServerName and mediaServerUrl twice
and re-declares local helper functions that shadow imported helpers; remove the
duplicate const declarations and the local functions getAvailableMediaServerName
and getAvailableMediaServerUrl and instead call the existing imported helper
functions (use the already destructured mediaServerType and payload to call the
imported getAvailableMediaServerName/mediaServerUrl helpers or the single
imported helpers with the correct arguments), leaving only one const
mediaServerName and one const mediaServerUrl assigned via the imported helper
functions.

In `@server/lib/notifications/agents/slack.ts`:
- Around line 229-289: The second if (!payload.issue) block duplicates the "Play
on <MediaServer>" action already added to actionElements earlier; remove the
later duplicate block (the standalone if (!payload.issue) that calls
getAvailableMediaServerName() and getAvailableMediaServerUrl() with no args and
pushes another actions block) so the media server button is only created via
actionElements; keep the initial creation that uses mediaServerType and payload
and only render the actions block from actionElements when actionElements.length
> 0.
- Around line 85-108: Remove the local helper functions
getAvailableMediaServerName() and getAvailableMediaServerUrl() that shadow the
imported helpers; delete their definitions and use the imported
getAvailableMediaServerName and getAvailableMediaServerUrl instead, passing the
expected arguments (e.g., mediaServerType and payload) where they are called
(the places that currently pass mediaServerType and payload around lines that
generate the "Play on …" action), and ensure you only call them in one place to
avoid duplicating the "Play on …" action block; keep using existing symbols like
MediaServerType and payload and preserve embedPoster usage from
settings.notifications.agents.slack.
🧹 Nitpick comments (1)
server/migration/sqlite/1769971922216-CustomNotifyEmailMigration.ts (1)

7-17: user_push_subscription table is recreated three times in the up() method.

This is inefficient and makes the migration harder to understand:

  1. Lines 7-17: First recreation (removes unique constraint on endpoint+userId)
  2. Lines 90-99: Second recreation (same schema, appears redundant)
  3. Lines 162-171: Third recreation (adds back the unique constraint)

If the intent is to add/modify a unique constraint, this could be simplified to a single table recreation.

Also applies to: 90-99, 162-171

@JackW6809 JackW6809 force-pushed the notification-media-server-links branch from 34d66e1 to 6cb90a2 Compare February 15, 2026 16:21
@JackW6809
Copy link
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link

coderabbitai bot commented Feb 15, 2026

✅ Actions performed

Full review triggered.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@server/lib/notifications/agents/telegram.ts`:
- Around line 80-82: The escapeText function's MarkdownV2 regex is missing
backtick and backslash; update the regex used in escapeText(text: string |
undefined) to include both the backtick (`) and the backslash (\) in the
character class so all Telegram MarkdownV2-reserved characters are escaped,
ensuring you correctly escape the backslash in the string literal/regex syntax
for the language runtime.
🧹 Nitpick comments (1)
server/lib/notifications/agents/email.ts (1)

171-174: Consider simplifying the template literal.

The template literal wrapping is unnecessary since mediaServerUrl is already a string.

♻️ Suggested simplification
-          mediaServerActionUrl: mediaServerUrl
-            ? `${mediaServerUrl}`
-            : undefined,
+          mediaServerActionUrl: mediaServerUrl,

Telegram requires escaping of ` and \ characters, currently does not. Coderabbit found this and I am
implementing this change

BREAKING CHANGE: Changes the regex formula for escaping characters for telegram
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.

Link to Jellyfin/Emby/Plex in "Now available" mail notification

1 participant