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 à :
@@ -6,9 +6,9 @@
|
||||
<LangVersion>latest</LangVersion>
|
||||
<RootNamespace>Jellyfin.Plugin.ShareLinks</RootNamespace>
|
||||
<AssemblyName>Jellyfin.Plugin.ShareLinks</AssemblyName>
|
||||
<Version>1.0.5.0</Version>
|
||||
<AssemblyVersion>1.0.5.0</AssemblyVersion>
|
||||
<FileVersion>1.0.5.0</FileVersion>
|
||||
<Version>1.0.6.0</Version>
|
||||
<AssemblyVersion>1.0.6.0</AssemblyVersion>
|
||||
<FileVersion>1.0.6.0</FileVersion>
|
||||
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
|
||||
@@ -280,6 +280,9 @@ public sealed class ShareLinkRedemptionService
|
||||
var infoUrlJson = JsonSerializer.Serialize($"{pathBase}/System/Info/Public");
|
||||
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 $$"""
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
@@ -319,7 +322,7 @@ public sealed class ShareLinkRedemptionService
|
||||
manualAddressOnly: true,
|
||||
Name: info.ServerName || "Jellyfin",
|
||||
Id: info.Id,
|
||||
LastConnectionMode: 1,
|
||||
LastConnectionMode: 2,
|
||||
AccessToken: accessToken,
|
||||
UserId: userId,
|
||||
DateLastAccessed: Date.now()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
var pluginId = '68540b76-ee74-436d-85ff-2abc884bbea6';
|
||||
var copyLabel = 'Copy Stream URL';
|
||||
var actionLabel = 'ShareLink';
|
||||
var clientVersion = '1.0.3-ui-2';
|
||||
var clientVersion = '1.0.6-ui-1';
|
||||
var allowedItemStorageKey = 'sharelinks.allowedItemId';
|
||||
var guestClassName = 'sharelinks-guest';
|
||||
var hiddenAttr = 'data-sharelinks-hidden';
|
||||
@@ -382,6 +382,11 @@
|
||||
+ ' body.' + guestClassName + ' [data-action="addtoplaylist"],'
|
||||
+ ' body.' + guestClassName + ' [data-action="addtocollection"],'
|
||||
+ ' 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; }'
|
||||
// Cards stay clickable so guests can navigate season/episode cards on a shared series;
|
||||
// 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.
|
||||
* Clicking the sheet's own close button keeps Jellyfin's animation and state
|
||||
* handling; Escape is the fallback when the sheet renders without one.
|
||||
* The sheet's own close button exists only on TV layouts. On desktop, jellyfin-web
|
||||
* 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) {
|
||||
var closeButton = container.querySelector('.btnCloseActionSheet');
|
||||
@@ -851,6 +858,13 @@
|
||||
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', {
|
||||
key: 'Escape',
|
||||
keyCode: 27,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"guid": "68540b76-ee74-436d-85ff-2abc884bbea6",
|
||||
"name": "ShareLinks",
|
||||
"version": "1.0.5.0",
|
||||
"version": "1.0.6.0",
|
||||
"targetAbi": "10.11.0.0",
|
||||
"framework": "net9.0",
|
||||
"owner": "Franciskid",
|
||||
"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.",
|
||||
"category": "General",
|
||||
"timestamp": "2026-09-11T12:00:00.0000000Z"
|
||||
"timestamp": "2026-09-18T12:00:00.0000000Z"
|
||||
}
|
||||
|
||||
Référencer dans un nouveau ticket
Bloquer un utilisateur