Add beta media endpoint
Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
@@ -121,6 +121,8 @@ in
|
|||||||
"||*^"
|
"||*^"
|
||||||
# Personal
|
# Personal
|
||||||
"@@||karaolidis.com^$important"
|
"@@||karaolidis.com^$important"
|
||||||
|
"@@||media.karaolidis.com^$important"
|
||||||
|
"@@||beta.media.karaolidis.com^$important"
|
||||||
# Connectivity Check
|
# Connectivity Check
|
||||||
"@@||clients3.google.com^"
|
"@@||clients3.google.com^"
|
||||||
"@@||clients.l.google.com^"
|
"@@||clients.l.google.com^"
|
||||||
|
@@ -47,7 +47,7 @@ in
|
|||||||
client_id = autheliaClientId;
|
client_id = autheliaClientId;
|
||||||
client_name = "Jellyfin";
|
client_name = "Jellyfin";
|
||||||
client_secret = hmConfig.sops.placeholder."jellyfin/authelia/digest";
|
client_secret = hmConfig.sops.placeholder."jellyfin/authelia/digest";
|
||||||
redirect_uris = [ "https://media.karaolidis.com/sso/OID/redirect/authelia" ];
|
redirect_uris = [ "https://beta.media.karaolidis.com/sso/OID/redirect/authelia" ];
|
||||||
authorization_policy = "jellyfin";
|
authorization_policy = "jellyfin";
|
||||||
require_pkce = true;
|
require_pkce = true;
|
||||||
pkce_challenge_method = "S256";
|
pkce_challenge_method = "S256";
|
||||||
@@ -97,6 +97,8 @@ in
|
|||||||
[
|
[
|
||||||
"/mnt/storage/private/storm/containers/storage/volumes/media/_data:/var/lib/media"
|
"/mnt/storage/private/storm/containers/storage/volumes/media/_data:/var/lib/media"
|
||||||
"${setup}:/etc/jellyfin/setup.sh:ro"
|
"${setup}:/etc/jellyfin/setup.sh:ro"
|
||||||
|
# FIXME: https://github.com/9p4/jellyfin-plugin-sso/issues/189#issuecomment-3262794524
|
||||||
|
"${./sso-button.js}:/etc/jellyfin/sso-button.js:ro"
|
||||||
"${./libraries}:/etc/jellyfin/libraries:ro"
|
"${./libraries}:/etc/jellyfin/libraries:ro"
|
||||||
"${volumes.jellyfin-config.ref}:/etc/jellyfin"
|
"${volumes.jellyfin-config.ref}:/etc/jellyfin"
|
||||||
"${volumes.jellyfin-data.ref}:/var/lib/jellyfin/data"
|
"${volumes.jellyfin-data.ref}:/var/lib/jellyfin/data"
|
||||||
@@ -109,7 +111,7 @@ in
|
|||||||
environmentFiles = [ hmConfig.sops.templates.jellyfin-env.path ];
|
environmentFiles = [ hmConfig.sops.templates.jellyfin-env.path ];
|
||||||
labels = [
|
labels = [
|
||||||
"traefik.enable=true"
|
"traefik.enable=true"
|
||||||
"traefik.http.routers.jellyfin.rule=Host(`media.karaolidis.com`)"
|
"traefik.http.routers.jellyfin.rule=Host(`beta.media.karaolidis.com`)"
|
||||||
];
|
];
|
||||||
podmanArgs = [ "--cdi-spec-dir=/run/cdi" ];
|
podmanArgs = [ "--cdi-spec-dir=/run/cdi" ];
|
||||||
devices = [ "nvidia.com/gpu=all" ];
|
devices = [ "nvidia.com/gpu=all" ];
|
||||||
@@ -123,18 +125,18 @@ in
|
|||||||
mediaConfig = (pkgs.formats.yaml { }).generate "media.yaml" {
|
mediaConfig = (pkgs.formats.yaml { }).generate "media.yaml" {
|
||||||
access_control.rules = [
|
access_control.rules = [
|
||||||
{
|
{
|
||||||
domain = "media.karaolidis.com";
|
domain = "beta.media.karaolidis.com";
|
||||||
policy = "one_factor";
|
policy = "one_factor";
|
||||||
resources = [ "^/manage([/?].*)?$" ];
|
resources = [ "^/manage([/?].*)?$" ];
|
||||||
subject = [ "group:media" ];
|
subject = [ "group:media" ];
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
domain = "media.karaolidis.com";
|
domain = "beta.media.karaolidis.com";
|
||||||
policy = "deny";
|
policy = "deny";
|
||||||
resources = [ "^/manage([/?].*)?$" ];
|
resources = [ "^/manage([/?].*)?$" ];
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
domain = "media.karaolidis.com";
|
domain = "beta.media.karaolidis.com";
|
||||||
policy = "bypass";
|
policy = "bypass";
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
@@ -173,26 +173,34 @@ a.raised.emby-button,
|
|||||||
EOF
|
EOF
|
||||||
)
|
)
|
||||||
|
|
||||||
login_disclaimer=$(cat <<EOF
|
|
||||||
<form action="https://media.karaolidis.com/sso/OID/start/authelia">
|
|
||||||
<button class="raised block emby-button button-submit">
|
|
||||||
Sign in with Authelia
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
curl -sf "$JELLYFIN_HOST/System/Configuration/branding" \
|
curl -sf "$JELLYFIN_HOST/System/Configuration/branding" \
|
||||||
-H "Authorization: MediaBrowser Token=$token" |
|
-H "Authorization: MediaBrowser Token=$token" |
|
||||||
jq --arg custom_css "$custom_css" \
|
jq --arg custom_css "$custom_css" \
|
||||||
--arg login_disclaimer "$login_disclaimer" \
|
'.CustomCss = $custom_css' |
|
||||||
'.CustomCss = $custom_css | .LoginDisclaimer = $login_disclaimer' |
|
|
||||||
curl -sf "$JELLYFIN_HOST/System/Configuration/branding" \
|
curl -sf "$JELLYFIN_HOST/System/Configuration/branding" \
|
||||||
-X POST \
|
-X POST \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \
|
||||||
-H "Authorization: MediaBrowser Token=$token" \
|
-H "Authorization: MediaBrowser Token=$token" \
|
||||||
--data-binary @-
|
--data-binary @-
|
||||||
|
|
||||||
|
jq -Rn --rawfile script /etc/jellyfin/sso-button.js '
|
||||||
|
{
|
||||||
|
CustomJavaScripts: [
|
||||||
|
{
|
||||||
|
Name: "SSO Button",
|
||||||
|
Script: $script,
|
||||||
|
Enabled: true,
|
||||||
|
RequiresAuthentication: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
' \
|
||||||
|
| curl -sf "$JELLYFIN_HOST/Plugins/f5a34f7b-2e8a-4e6a-a722-3a216a81b374/Configuration" \
|
||||||
|
-X POST \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-H 'Authorization: MediaBrowser Token="'"$token"'"' \
|
||||||
|
--data-binary @-
|
||||||
|
|
||||||
existing_libraries="$(curl -sf "$JELLYFIN_HOST/Library/VirtualFolders" \
|
existing_libraries="$(curl -sf "$JELLYFIN_HOST/Library/VirtualFolders" \
|
||||||
-H 'Authorization: MediaBrowser Token="'"$token"'"')"
|
-H 'Authorization: MediaBrowser Token="'"$token"'"')"
|
||||||
|
|
||||||
|
@@ -0,0 +1,180 @@
|
|||||||
|
const SSO_AUTH_URL = "https://beta.media.karaolidis.com/sso/OID/start/authelia";
|
||||||
|
|
||||||
|
// SSO provider customization. Available options are:
|
||||||
|
// generic, authentik, authelia, keycloak, zitadel
|
||||||
|
const PROVIDER = "authelia";
|
||||||
|
|
||||||
|
// Self-executing function that waits for the document body to be available
|
||||||
|
(function waitForBody() {
|
||||||
|
// If document.body doesn't exist yet, retry in 100ms
|
||||||
|
if (!document.body) {
|
||||||
|
return setTimeout(waitForBody, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the current page is a login page by checking multiple indicators
|
||||||
|
* @returns {boolean} True if this appears to be a login page
|
||||||
|
*/
|
||||||
|
function isLoginPage() {
|
||||||
|
const hash = location.hash.toLowerCase();
|
||||||
|
const pathname = location.pathname.toLowerCase();
|
||||||
|
// Check for URL patterns that typically indicate login pages
|
||||||
|
const hasLoginUrl =
|
||||||
|
hash === "" ||
|
||||||
|
hash === "#/" ||
|
||||||
|
hash === "#/home" ||
|
||||||
|
hash === "#/login" ||
|
||||||
|
hash.startsWith("#/login") ||
|
||||||
|
pathname.includes("/login");
|
||||||
|
|
||||||
|
// Check for DOM elements that indicate a login form is present
|
||||||
|
const hasLoginElements =
|
||||||
|
document.querySelector('input[type="password"]') !== null ||
|
||||||
|
document.querySelector(".loginPage") !== null ||
|
||||||
|
document.querySelector("#txtUserName") !== null;
|
||||||
|
|
||||||
|
return hasLoginUrl || hasLoginElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the current page should be excluded from SSO button insertion
|
||||||
|
* These are typically pages where users are already authenticated
|
||||||
|
* @returns {boolean} True if this page should be excluded
|
||||||
|
*/
|
||||||
|
function shouldExcludePage() {
|
||||||
|
const hash = location.hash.toLowerCase();
|
||||||
|
// List of page patterns where we don't want to show the SSO button
|
||||||
|
const excludePatterns = [
|
||||||
|
"#/dashboard",
|
||||||
|
"#/home.html",
|
||||||
|
"#/movies",
|
||||||
|
"#/tv",
|
||||||
|
"#/music",
|
||||||
|
"#/livetv",
|
||||||
|
"#/search",
|
||||||
|
"#/settings",
|
||||||
|
"#/wizardstart",
|
||||||
|
"#/wizardfinish",
|
||||||
|
"#/mypreferencesmenu",
|
||||||
|
"#/userprofile",
|
||||||
|
];
|
||||||
|
|
||||||
|
return excludePatterns.some((pattern) => hash.startsWith(pattern));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the OAuth device ID in localStorage if it doesn't exist
|
||||||
|
* This is required for Jellyfin native apps to maintain device identification
|
||||||
|
*/
|
||||||
|
function oAuthInitDeviceId() {
|
||||||
|
// Only set device ID if it's not already set and we're in a native shell environment
|
||||||
|
if (
|
||||||
|
!localStorage.getItem("_deviceId2") &&
|
||||||
|
window.NativeShell?.AppHost?.deviceId
|
||||||
|
) {
|
||||||
|
localStorage.setItem("_deviceId2", window.NativeShell.AppHost.deviceId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and inserts the SSO login button into the login page
|
||||||
|
* Only runs if we're on a valid login page and the button doesn't already exist
|
||||||
|
*/
|
||||||
|
function insertSSOButton() {
|
||||||
|
// Safety check: ensure we're on the right page before proceeding
|
||||||
|
if (!isLoginPage() || shouldExcludePage()) return;
|
||||||
|
|
||||||
|
// Try to find a suitable container for the SSO button
|
||||||
|
const loginContainer =
|
||||||
|
document.querySelector(".readOnlyContent") ||
|
||||||
|
document.querySelector("form")?.parentNode ||
|
||||||
|
document.querySelector(".loginPage") ||
|
||||||
|
document.querySelector("#loginPage");
|
||||||
|
|
||||||
|
// Exit if no container found or button already exists
|
||||||
|
if (!loginContainer || document.querySelector("#custom-sso-button")) return;
|
||||||
|
|
||||||
|
switch (PROVIDER.toLowerCase()) {
|
||||||
|
case "authentik":
|
||||||
|
SSO_BUTTON_HTML =
|
||||||
|
'<img src="https://cdn.jsdelivr.net/gh/selfhst/icons/svg/authentik.svg" width="21em"><span>Login with Authentik</span>';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "authelia":
|
||||||
|
SSO_BUTTON_HTML =
|
||||||
|
'<img src="https://cdn.jsdelivr.net/gh/selfhst/icons/svg/authelia-light.svg" width="21em"><span>Login with Authelia</span>';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "keycloak":
|
||||||
|
SSO_BUTTON_HTML =
|
||||||
|
'<img src="https://cdn.jsdelivr.net/gh/selfhst/icons/svg/keycloak.svg" width="21em"><span>Login with Keycloak</span>';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "zitadel":
|
||||||
|
SSO_BUTTON_HTML =
|
||||||
|
'<img src="https://cdn.jsdelivr.net/gh/selfhst/icons/svg/zitadel.svg" width="21em"><span>Login with Zitadel</span>';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
SSO_BUTTON_HTML =
|
||||||
|
'<span class="material-icons">shield</span><span>Login with SSO</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip insertion for Jellyfin Media Player (JMP) as it may have different auth handling
|
||||||
|
const isJMP = navigator.userAgent.includes("JellyfinMediaPlayer");
|
||||||
|
if (isJMP) return;
|
||||||
|
|
||||||
|
// Create the SSO button element
|
||||||
|
const button = document.createElement("button");
|
||||||
|
button.id = "custom-sso-button";
|
||||||
|
button.className = "raised block emby-button button-submit";
|
||||||
|
// Style the button to match Jellyfin's design while being visually distinct
|
||||||
|
button.style =
|
||||||
|
"display: flex; align-items: center; justify-content: center; gap: 10px; padding: 12px 20px; font-size: 16px; background-color: #3949ab; color: white; margin-top: 16px;";
|
||||||
|
// Add icon and text content
|
||||||
|
button.innerHTML = SSO_BUTTON_HTML;
|
||||||
|
// Handle button click - prevent form submission and redirect to SSO
|
||||||
|
button.onclick = function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
oAuthInitDeviceId(); // Ensure device ID is set before SSO redirect
|
||||||
|
window.location.href = SSO_AUTH_URL;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add the button to the login container
|
||||||
|
loginContainer.appendChild(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initial setup: Check if we should insert the SSO button when script first loads
|
||||||
|
if (isLoginPage() && !shouldExcludePage()) {
|
||||||
|
// Delay insertion slightly to ensure all page elements are fully loaded
|
||||||
|
setTimeout(insertSSOButton, 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up a MutationObserver to watch for dynamic page changes
|
||||||
|
// This handles cases where Jellyfin loads content dynamically via JavaScript
|
||||||
|
const observer = new MutationObserver(() => {
|
||||||
|
if (isLoginPage() && !shouldExcludePage()) {
|
||||||
|
// Check if login elements are ready and button hasn't been inserted yet
|
||||||
|
const ready =
|
||||||
|
document.querySelector(".readOnlyContent") ||
|
||||||
|
document.querySelector("form") ||
|
||||||
|
document.querySelector(".loginPage");
|
||||||
|
if (ready && !document.querySelector("#custom-sso-button")) {
|
||||||
|
insertSSOButton();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start observing changes to the entire document body and its children
|
||||||
|
observer.observe(document.body, { childList: true, subtree: true });
|
||||||
|
|
||||||
|
// Listen for hash changes (when navigating between pages in Jellyfin's SPA)
|
||||||
|
window.addEventListener("hashchange", () => {
|
||||||
|
// Small delay to allow page transition to complete
|
||||||
|
setTimeout(() => {
|
||||||
|
if (isLoginPage() && !shouldExcludePage()) {
|
||||||
|
insertSSOButton();
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
});
|
||||||
|
})();
|
@@ -54,7 +54,7 @@ in
|
|||||||
name = "jupiter";
|
name = "jupiter";
|
||||||
ip = "jellyfin";
|
ip = "jellyfin";
|
||||||
port = 8096;
|
port = 8096;
|
||||||
externalHostname = "https://media.karaolidis.com";
|
externalHostname = "https://beta.media.karaolidis.com";
|
||||||
jellyfinForgotPasswordUrl = "https://id.karaolidis.com/reset-password/step1";
|
jellyfinForgotPasswordUrl = "https://id.karaolidis.com/reset-password/step1";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -78,7 +78,7 @@ in
|
|||||||
environmentFiles = [ hmConfig.sops.templates.prowlarr-env.path ];
|
environmentFiles = [ hmConfig.sops.templates.prowlarr-env.path ];
|
||||||
labels = [
|
labels = [
|
||||||
"traefik.enable=true"
|
"traefik.enable=true"
|
||||||
"traefik.http.routers.prowlarr.rule=Host(`media.karaolidis.com`) && PathPrefix(`/manage/indexers`)"
|
"traefik.http.routers.prowlarr.rule=Host(`beta.media.karaolidis.com`) && PathPrefix(`/manage/indexers`)"
|
||||||
"traefik.http.routers.prowlarr.middlewares=authelia@docker"
|
"traefik.http.routers.prowlarr.middlewares=authelia@docker"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
@@ -83,7 +83,7 @@ rec {
|
|||||||
activeDirectory = "/var/lib/media/libraries${mediaFolderBase}";
|
activeDirectory = "/var/lib/media/libraries${mediaFolderBase}";
|
||||||
minimumAvailability = "released";
|
minimumAvailability = "released";
|
||||||
isDefault = !isAnime;
|
isDefault = !isAnime;
|
||||||
externalUrl = "https://media.karaolidis.com${urlBase}";
|
externalUrl = "https://beta.media.karaolidis.com${urlBase}";
|
||||||
syncEnabled = true;
|
syncEnabled = true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -82,7 +82,7 @@ in
|
|||||||
environmentFiles = [ hmConfig.sops.templates."${radarr.hostName}-env".path ];
|
environmentFiles = [ hmConfig.sops.templates."${radarr.hostName}-env".path ];
|
||||||
labels = [
|
labels = [
|
||||||
"traefik.enable=true"
|
"traefik.enable=true"
|
||||||
"traefik.http.routers.${radarr.hostName}.rule=Host(`media.karaolidis.com`) && PathPrefix(`${radarr.urlBase}`)"
|
"traefik.http.routers.${radarr.hostName}.rule=Host(`beta.media.karaolidis.com`) && PathPrefix(`${radarr.urlBase}`)"
|
||||||
"traefik.http.routers.${radarr.hostName}.middlewares=authelia@docker"
|
"traefik.http.routers.${radarr.hostName}.middlewares=authelia@docker"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
@@ -85,7 +85,7 @@ rec {
|
|||||||
activeAnimeDirectory = "/var/lib/media/libraries${mediaFolderBase}";
|
activeAnimeDirectory = "/var/lib/media/libraries${mediaFolderBase}";
|
||||||
isDefault = !isAnime;
|
isDefault = !isAnime;
|
||||||
enableSeasonFolders = true;
|
enableSeasonFolders = true;
|
||||||
externalUrl = "https://media.karaolidis.com${urlBase}";
|
externalUrl = "https://beta.media.karaolidis.com${urlBase}";
|
||||||
syncEnabled = true;
|
syncEnabled = true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -82,7 +82,7 @@ in
|
|||||||
environmentFiles = [ hmConfig.sops.templates."${sonarr.hostName}-env".path ];
|
environmentFiles = [ hmConfig.sops.templates."${sonarr.hostName}-env".path ];
|
||||||
labels = [
|
labels = [
|
||||||
"traefik.enable=true"
|
"traefik.enable=true"
|
||||||
"traefik.http.routers.${sonarr.hostName}.rule=Host(`media.karaolidis.com`) && PathPrefix(`${sonarr.urlBase}`)"
|
"traefik.http.routers.${sonarr.hostName}.rule=Host(`beta.media.karaolidis.com`) && PathPrefix(`${sonarr.urlBase}`)"
|
||||||
"traefik.http.routers.${sonarr.hostName}.middlewares=authelia@docker"
|
"traefik.http.routers.${sonarr.hostName}.middlewares=authelia@docker"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
@@ -55,7 +55,7 @@ in
|
|||||||
};
|
};
|
||||||
labels = [
|
labels = [
|
||||||
"traefik.enable=true"
|
"traefik.enable=true"
|
||||||
"traefik.http.routers.transmission.rule=Host(`media.karaolidis.com`) && PathPrefix(`/manage/torrents`)"
|
"traefik.http.routers.transmission.rule=Host(`beta.media.karaolidis.com`) && PathPrefix(`/manage/torrents`)"
|
||||||
"traefik.http.routers.transmission.middlewares=authelia@docker"
|
"traefik.http.routers.transmission.middlewares=authelia@docker"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
@@ -70,7 +70,7 @@ in
|
|||||||
"--entrypoints.https.http.tls=true"
|
"--entrypoints.https.http.tls=true"
|
||||||
"--entrypoints.https.http.tls.certResolver=letsencrypt"
|
"--entrypoints.https.http.tls.certResolver=letsencrypt"
|
||||||
"--entrypoints.https.http.tls.domains[0].main=karaolidis.com"
|
"--entrypoints.https.http.tls.domains[0].main=karaolidis.com"
|
||||||
"--entrypoints.https.http.tls.domains[0].sans=*.karaolidis.com,*.tunnel.karaolidis.com,*.gaming.karaolidis.com"
|
"--entrypoints.https.http.tls.domains[0].sans=*.karaolidis.com,*.tunnel.karaolidis.com,*.gaming.karaolidis.com,beta.media.karaolidis.com"
|
||||||
"--entrypoints.https.http.tls.domains[1].main=krlds.com"
|
"--entrypoints.https.http.tls.domains[1].main=krlds.com"
|
||||||
"--entrypoints.https.http.tls.domains[1].sans=*.krlds.com"
|
"--entrypoints.https.http.tls.domains[1].sans=*.krlds.com"
|
||||||
"--entryPoints.https.http3"
|
"--entryPoints.https.http3"
|
||||||
@@ -110,7 +110,7 @@ in
|
|||||||
"traefik.http.middlewares.security-headers.headers.stsIncludeSubdomains=true"
|
"traefik.http.middlewares.security-headers.headers.stsIncludeSubdomains=true"
|
||||||
"traefik.http.middlewares.security-headers.headers.stsPreload=true"
|
"traefik.http.middlewares.security-headers.headers.stsPreload=true"
|
||||||
"traefik.http.middlewares.security-headers.headers.contentTypeNosniff=true"
|
"traefik.http.middlewares.security-headers.headers.contentTypeNosniff=true"
|
||||||
"traefik.http.middlewares.security-headers.headers.frameDeny=true"
|
"traefik.http.middlewares.security-headers.headers.customFrameOptionsValue=SAMEORIGIN"
|
||||||
];
|
];
|
||||||
environmentFiles = [ hmConfig.sops.templates.traefik-env.path ];
|
environmentFiles = [ hmConfig.sops.templates.traefik-env.path ];
|
||||||
};
|
};
|
||||||
|
@@ -57,6 +57,7 @@ final: prev:
|
|||||||
jellyfinPlugins = prev.jellyfinPlugins or { } // {
|
jellyfinPlugins = prev.jellyfinPlugins or { } // {
|
||||||
bookshelf = final.jellyfin-plugin-bookshelf-bin;
|
bookshelf = final.jellyfin-plugin-bookshelf-bin;
|
||||||
intro-skipper = final.jellyfin-plugin-intro-skipper-bin;
|
intro-skipper = final.jellyfin-plugin-intro-skipper-bin;
|
||||||
|
javascript-injector = final.jellyfin-plugin-javascript-injector-bin;
|
||||||
opensubtitles = final.jellyfin-plugin-opensubtitles-bin;
|
opensubtitles = final.jellyfin-plugin-opensubtitles-bin;
|
||||||
playbackreporting = final.jellyfin-plugin-playbackreporting-bin;
|
playbackreporting = final.jellyfin-plugin-playbackreporting-bin;
|
||||||
reports = final.jellyfin-plugin-reports-bin;
|
reports = final.jellyfin-plugin-reports-bin;
|
||||||
|
@@ -54,6 +54,9 @@
|
|||||||
|
|
||||||
jellyfin-plugin-bookshelf-bin = import ./jellyfin/plugins/bookshelf { inherit pkgs; };
|
jellyfin-plugin-bookshelf-bin = import ./jellyfin/plugins/bookshelf { inherit pkgs; };
|
||||||
jellyfin-plugin-intro-skipper-bin = import ./jellyfin/plugins/intro-skipper { inherit pkgs; };
|
jellyfin-plugin-intro-skipper-bin = import ./jellyfin/plugins/intro-skipper { inherit pkgs; };
|
||||||
|
jellyfin-plugin-javascript-injector-bin = import ./jellyfin/plugins/javascript-injector {
|
||||||
|
inherit pkgs;
|
||||||
|
};
|
||||||
jellyfin-plugin-opensubtitles-bin = import ./jellyfin/plugins/opensubtitles { inherit pkgs; };
|
jellyfin-plugin-opensubtitles-bin = import ./jellyfin/plugins/opensubtitles { inherit pkgs; };
|
||||||
jellyfin-plugin-playbackreporting-bin = import ./jellyfin/plugins/playbackreporting {
|
jellyfin-plugin-playbackreporting-bin = import ./jellyfin/plugins/playbackreporting {
|
||||||
inherit pkgs;
|
inherit pkgs;
|
||||||
|
@@ -38,6 +38,7 @@ pkgs.dockerTools.buildImage {
|
|||||||
++ (with jellyfinPlugins; [
|
++ (with jellyfinPlugins; [
|
||||||
bookshelf
|
bookshelf
|
||||||
intro-skipper
|
intro-skipper
|
||||||
|
javascript-injector
|
||||||
opensubtitles
|
opensubtitles
|
||||||
playbackreporting
|
playbackreporting
|
||||||
reports
|
reports
|
||||||
|
17
packages/jellyfin/plugins/javascript-injector/default.nix
Normal file
17
packages/jellyfin/plugins/javascript-injector/default.nix
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
# AUTO-UPDATE: nix-update --flake jellyfin-plugin-javascript-injector-bin
|
||||||
|
pkgs.stdenv.mkDerivation (finalAttrs: {
|
||||||
|
pname = "javascript-injector";
|
||||||
|
version = "2.0.0.0";
|
||||||
|
|
||||||
|
src = pkgs.fetchzip {
|
||||||
|
url = "https://github.com/n00bcodr/Jellyfin-JavaScript-Injector/releases/download/${finalAttrs.version}/javascript-injector-${finalAttrs.version}.zip";
|
||||||
|
sha256 = "sha256-BzT4Hk4ulHsnkV9eKyy2oK6su98Am0x6rydfjAY/AWY=";
|
||||||
|
stripRoot = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p $out/var/lib/jellyfin/plugins
|
||||||
|
cp -r $src $out/var/lib/jellyfin/plugins/javascript-injector
|
||||||
|
'';
|
||||||
|
})
|
Reference in New Issue
Block a user