Fix guest sign-in on Jellyfin 12 (#22)

The sign-in page stored the guest's server entry with LastConnectionMode 1
(Remote) but only a ManualAddress. jellyfin-web 12 builds its ApiClient from
that entry, gets no address, throws "Must supply a serverAddress" and never
leaves the splash screen. Store mode 2 (Manual), which is what jellyfin-web
itself writes after a normal sign-in.

Also hide the Modern layout header links, user menu and drawer toggle for
guests (Modern is the default in 12), and close the item action sheet on
desktop when ShareLink opens its popup. Escape only closes it in the TV
layout, a click on the dialog container works everywhere.

Bump to 1.0.6.0.
Cette révision appartient à :
Francois Coutau Bégarie
2026-09-18 11:55:48 +02:00
révisé par GitHub
Parent b48f977c22
révision 079a1de23e
5 fichiers modifiés avec 31 ajouts et 12 suppressions
+3 -3
Voir le fichier
@@ -6,9 +6,9 @@
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<RootNamespace>Jellyfin.Plugin.ShareLinks</RootNamespace> <RootNamespace>Jellyfin.Plugin.ShareLinks</RootNamespace>
<AssemblyName>Jellyfin.Plugin.ShareLinks</AssemblyName> <AssemblyName>Jellyfin.Plugin.ShareLinks</AssemblyName>
<Version>1.0.5.0</Version> <Version>1.0.6.0</Version>
<AssemblyVersion>1.0.5.0</AssemblyVersion> <AssemblyVersion>1.0.6.0</AssemblyVersion>
<FileVersion>1.0.5.0</FileVersion> <FileVersion>1.0.6.0</FileVersion>
<GenerateAssemblyInfo>true</GenerateAssemblyInfo> <GenerateAssemblyInfo>true</GenerateAssemblyInfo>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors> <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<ImplicitUsings>disable</ImplicitUsings> <ImplicitUsings>disable</ImplicitUsings>
+4 -1
Voir le fichier
@@ -280,6 +280,9 @@ public sealed class ShareLinkRedemptionService
var infoUrlJson = JsonSerializer.Serialize($"{pathBase}/System/Info/Public"); var infoUrlJson = JsonSerializer.Serialize($"{pathBase}/System/Info/Public");
var pathBaseJson = JsonSerializer.Serialize(pathBase); var pathBaseJson = JsonSerializer.Serialize(pathBase);
// jellyfin-web resolves the server address from LastConnectionMode; 2 (Manual) is
// what it stores after a normal sign-in. Jellyfin 12 builds its client straight from
// this entry, so Remote (1) with no RemoteAddress left the guest on the splash screen.
return $$""" return $$"""
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
@@ -319,7 +322,7 @@ public sealed class ShareLinkRedemptionService
manualAddressOnly: true, manualAddressOnly: true,
Name: info.ServerName || "Jellyfin", Name: info.ServerName || "Jellyfin",
Id: info.Id, Id: info.Id,
LastConnectionMode: 1, LastConnectionMode: 2,
AccessToken: accessToken, AccessToken: accessToken,
UserId: userId, UserId: userId,
DateLastAccessed: Date.now() DateLastAccessed: Date.now()
+17 -3
Voir le fichier
@@ -2,7 +2,7 @@
var pluginId = '68540b76-ee74-436d-85ff-2abc884bbea6'; var pluginId = '68540b76-ee74-436d-85ff-2abc884bbea6';
var copyLabel = 'Copy Stream URL'; var copyLabel = 'Copy Stream URL';
var actionLabel = 'ShareLink'; var actionLabel = 'ShareLink';
var clientVersion = '1.0.3-ui-2'; var clientVersion = '1.0.6-ui-1';
var allowedItemStorageKey = 'sharelinks.allowedItemId'; var allowedItemStorageKey = 'sharelinks.allowedItemId';
var guestClassName = 'sharelinks-guest'; var guestClassName = 'sharelinks-guest';
var hiddenAttr = 'data-sharelinks-hidden'; var hiddenAttr = 'data-sharelinks-hidden';
@@ -382,6 +382,11 @@
+ ' body.' + guestClassName + ' [data-action="addtoplaylist"],' + ' body.' + guestClassName + ' [data-action="addtoplaylist"],'
+ ' body.' + guestClassName + ' [data-action="addtocollection"],' + ' body.' + guestClassName + ' [data-action="addtocollection"],'
+ ' body.' + guestClassName + ' [data-id="playlist"],' + ' body.' + guestClassName + ' [data-id="playlist"],'
// The Modern layout (the default from Jellyfin 12) renders its own header
// instead of .skinHeader, so its controls need their own selectors here.
+ ' body.' + guestClassName + ' .MuiAppBar-root a[href^="#/"],'
+ ' body.' + guestClassName + ' .MuiAppBar-root [aria-controls="app-user-menu"],'
+ ' body.' + guestClassName + ' .MuiAppBar-root .MuiToolbar-root > button:first-child,'
+ ' body.' + guestClassName + ' [data-id="addtocollection"] { display: none !important; }' + ' body.' + guestClassName + ' [data-id="addtocollection"] { display: none !important; }'
// Cards stay clickable so guests can navigate season/episode cards on a shared series; // Cards stay clickable so guests can navigate season/episode cards on a shared series;
// checkAllowedLocation() verifies the destination server-side and redirects if disallowed. // checkAllowedLocation() verifies the destination server-side and redirects if disallowed.
@@ -841,8 +846,10 @@
/** /**
* Dismisses the native action sheet so our dialog is not stacked on top of it. * Dismisses the native action sheet so our dialog is not stacked on top of it.
* Clicking the sheet's own close button keeps Jellyfin's animation and state * The sheet's own close button exists only on TV layouts. On desktop, jellyfin-web
* handling; Escape is the fallback when the sheet renders without one. * closes a sheet when its dialog container gets a mousedown and a click aimed at
* the container itself (a click on the backdrop), and ignores Escape outside the
* TV layout. Escape stays as the last fallback.
*/ */
function closeActionSheet(container) { function closeActionSheet(container) {
var closeButton = container.querySelector('.btnCloseActionSheet'); var closeButton = container.querySelector('.btnCloseActionSheet');
@@ -851,6 +858,13 @@
return; return;
} }
var dialogContainer = container.closest && container.closest('.dialogContainer');
if (dialogContainer) {
dialogContainer.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, cancelable: true }));
dialogContainer.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));
return;
}
container.dispatchEvent(new KeyboardEvent('keydown', { container.dispatchEvent(new KeyboardEvent('keydown', {
key: 'Escape', key: 'Escape',
keyCode: 27, keyCode: 27,
+2 -2
Voir le fichier
@@ -1,12 +1,12 @@
{ {
"guid": "68540b76-ee74-436d-85ff-2abc884bbea6", "guid": "68540b76-ee74-436d-85ff-2abc884bbea6",
"name": "ShareLinks", "name": "ShareLinks",
"version": "1.0.5.0", "version": "1.0.6.0",
"targetAbi": "10.11.0.0", "targetAbi": "10.11.0.0",
"framework": "net9.0", "framework": "net9.0",
"owner": "Franciskid", "owner": "Franciskid",
"overview": "Secure expiring guest-share links for Jellyfin items.", "overview": "Secure expiring guest-share links for Jellyfin items.",
"description": "Adds secure, expiring share links for Jellyfin items with JSON-backed storage, token hashing, and cleanup scaffolding.", "description": "Adds secure, expiring share links for Jellyfin items with JSON-backed storage, token hashing, and cleanup scaffolding.",
"category": "General", "category": "General",
"timestamp": "2026-09-11T12:00:00.0000000Z" "timestamp": "2026-09-18T12:00:00.0000000Z"
} }
+5 -3
Voir le fichier
@@ -3,7 +3,7 @@
Share a movie, episode, season or series with a link. The person you send it to does not need Share a movie, episode, season or series with a link. The person you send it to does not need
an account and can only access what you shared. You choose when the link expires. an account and can only access what you shared. You choose when the link expires.
`Jellyfin 10.11` · `.NET 9` · `no account for the guest` · `access restricted on the server` · `automatic cleanup` `Jellyfin 10.11 and 12` · `.NET 9` · `no account for the guest` · `access restricted on the server` · `automatic cleanup`
ShareLinks adds a **ShareLink** entry to the context menu of any movie, series, season or episode. ShareLinks adds a **ShareLink** entry to the context menu of any movie, series, season or episode.
Choose an expiry date and copy the link. Whoever opens it goes straight to the shared title, Choose an expiry date and copy the link. Whoever opens it goes straight to the shared title,
@@ -181,8 +181,10 @@ it in `token-secret.key`.
## Compatibility ## Compatibility
Jellyfin **10.11** (`targetAbi 10.11.0.0`), .NET 9. Tested on 10.11.8 and 10.11.11. The web-client injection Jellyfin **10.11** and **12** from a single build (`targetAbi 10.11.0.0`, .NET 9, which Jellyfin 12's
targets the shipped client, in English and in French. .NET 10 runtime loads as is). Tested on 10.11.0, 10.11.5, 10.11.8, 10.11.9, 10.11.11, 12.0 and 12.1.
The web-client injection targets the shipped client, in the Legacy and Modern layouts, in English
and in French.
## Workflow ## Workflow