Skip to content

feat(messages): write messages your users can read in the app - #258

Open
bientavu wants to merge 10 commits into
Moonfin-Client:masterfrom
bientavu:feat/server-messages
Open

feat(messages): write messages your users can read in the app#258
bientavu wants to merge 10 commits into
Moonfin-Client:masterfrom
bientavu:feat/server-messages

Conversation

@bientavu

@bientavu bientavu commented Aug 25, 2026

Copy link
Copy Markdown

Pull Request

Summary

POST /Moonfin/Broadcast was the only way to tell users anything, and the message was not saved and only reached clients that were connected at that moment. This adds a Messages tab where an admin writes messages that are stored, scheduled and aimed at people they choose, plus the endpoints the app reads them from. Broadcast still works and is now saved too, so a message no longer disappears the moment it is sent.

Related Issues

Type of Change

  • Bug fix
  • New feature
  • Refactor
  • Performance improvement
  • API / endpoint change
  • Settings schema change
  • Documentation update
  • Build/CI change
  • Other (describe):

Area

  • Settings sync / profiles
  • Admin defaults / config page
  • Ratings (MDBList / TMDB)
  • Notifications / Push (FCM / relay)
  • Seerr integration
  • Games / Emulators
  • Custom home rows
  • Web Client (Go to Moonfin-Core repo)
  • Other / shared

What an admin can do

  • Write a message with a title and a body. The body takes Markdown, so headings, bold, italic, lists and links all work.
  • Pick a colour: white, green, blue, yellow or red.
  • Pick how it shows up: a count on the menu button, or the message window opening on its own once.
  • Pick who sees it: everyone, some selected users, or admins only.
  • Set a start date, so a message appears on its own, and an end date, so it goes away without anyone having to remember to delete it.
  • Add a button with a link at the end of a message.
  • Order the list with up and down arrows. The app shows them in the same order.
  • Edit or delete any saved message.

Changes Made

  • New ServerMessage in PluginConfiguration. It lives in the config next to UploadedThemes rather than in the data folder. Up to 50 are kept, and expired ones are dropped on the next save, so nothing has to run on a schedule.
  • New endpoints, following MoonfinThemesController: GET Moonfin/Messages for users, and GET, POST, DELETE under Moonfin/Admin/Messages behind RequiresElevation. POST Moonfin/Admin/Messages/Order saves the order, the same thing as Moonfin/Collections/{id}/Order.
  • Who sees what is decided on the server, in GET Moonfin/Messages. Sending everything and hiding it in the app would let any user read a message meant for someone else. Scheduled and expired messages are left out of the payload too.
  • Input is cleaned before it is stored: the body is capped, unknown colours fall back to white, and a link that is not http or https is dropped rather than passed to a client to open.
  • POST Moonfin/Broadcast keeps working and now saves what it sends, so users who were offline still find it.
  • Push already existed and is reused.
  • Ping gains messagesSupported, so an older plugin simply reads as false and the client hides the button.
  • New Messages tab in both config pages, and showServerMessagesButton in the Navigation part of the default user settings.
  • ⚠️ Mirrored on the Emby plugin but not tested at all as I don't have an Emby server.

Client Impact

Does this need matching changes in a client repo (Core, Smart-TV, Roku)?

  • No client changes needed
  • Companion client PR(s) required, linked here: Moonfin-Core feat/server-messages
  • New setting keys added. List each key and confirm it matches the client key exactly, including casing:
    • showServerMessagesButton matches the Dart SyncedField('showServerMessagesButton',) in lib/data/services/synced_fields.dart exactly, including casing.

Compatibility

  • Change to the settings profile is additive only, no renamed or removed properties
  • New properties use the same type the client sends (a client bool maps to bool?, an int to int?)
  • Migration added for any renamed or removed settings
  • Older clients still work, unknown fields are ignored and no keys were removed

MoonfinSettingsProfile only gains ShowServerMessagesButton as a bool?, so it is additive. No migration is needed: ServerMessage is new in this PR, so nothing has ever been stored under an older shape. Older clients never call the new endpoints and ignore messagesSupported.

One ordering dependency, which is why the last box is unticked. A message push carries route: "messages", and only a client with the matching Moongin-Core PR knows what to do with it.

Testing

  • Built the plugin and deployed to a Jellyfin server
  • Verified against a live client, Moonfin-Core on:
    • macOS (physical device)
    • Android TV (emulator)
    • Android phone (emulator)
    • Web
  • Manual testing completed
  • Not tested (explain why):

Test Steps

  1. With no messages on the server, the button is absent. Post one and it appears with a red cicle with 1 inside. ("Show messages button" setting needs to be enabled)
  2. Open a message: the count drops and the circle goes away.
  3. Post a message set to open the window, with the app closed. Open the app and the window comes up on its own, once.
  4. Write a message with a heading, bold text, a list and a link. The closed card shows a plain sentence, the open one shows the formatting.
  5. Kill the app and reopen it: the messages are still listed.
  6. Move a message in Moonbase with the arrows. The app follows the same order.
  7. On a TV, walk the list with the D-pad. Down from an open message reaches its link button, up goes back to the card, and the link shows a QR code.
  8. Sign in as another user. You only see the messages meant for you.

Screenshots (if applicable)

FireShot Capture 002 - bientavu-jellyfin -  jellyfin bientavu dev

Checklist

  • Code builds successfully
  • Code follows project style and conventions
  • No unnecessary commented-out code
  • No new warnings introduced
  • Any new setting keys match the client-side keys exactly

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.

1 participant