KobayashiM 27 Posted January 9 Posted January 9 I was checking out Jellyfin and noticed they have a Custom Tabs plugin that can add new tabs to the Home/Favorites menu. So I added a "Requests" tab which launches Jellyseerr in an iframe and it was awesome. Unfortunately there's no such plugin for Emby that I could find. So I resorted to modifying web files and wrote a script I can run whenever the container needs to be re-built. Here's what it looks like un-selected: Selected: The only thing I have left to do is implement SSO so users don't have to login to Jellyseerr manually. Instructions in next post... 5 1
KobayashiM 27 Posted January 9 Author Posted January 9 (edited) Note: I run Emby and Jellyseerr containers on the same physical machine which is running Unraid OS. My reverse proxy setup is handled by Swag and domain is hosted with Cloudflare. Pre-requisites as of today: - Emby v4.9.1.90 - Jellyseerr v2.7.3 - Both containers can see each other on same custom network EMBY CHANGES Container directory: /app/emby/system/dashboard-ui/home/ Modified Files: home.html, home.js New Files: requests.js 1. Create a backup of home.html and home.js 2. Add a new option "Requests" to the Home/Favorites button (called embyTabs)... a) Add a new <div> element at the bottom of home.html and assign it data-index="2": <div class="view flex flex-direction-column withTabs"> <div class="tabContent tabContent-positioned flex flex-grow" data-index="0" data-swapnode="sectionstab"> </div> <div class="tabContent tabContent-positioned flex flex-grow" data-index="1" data-swapnode="sectionstab"> </div> <div class="tabContent tabContent-positioned flex flex-grow" data-index="2" data-swapnode="sectionstab"> </div> </div> b) Edit home.js and search for "favorites". Copy the syntax and create a new entry for "Requests" (there are two spots): define(["exports", "./../modules/tabbedview/tabbedview.js", "./../modules/common/globalize.js", "./../modules/maintabsmanager.js", "./../modules/layoutmanager.js", "./../modules/common/usersettings/usersettings.js", "./../modules/emby-elements/emby-scroller/emby-scroller.js", "./../modules/emby-elements/emby-button/emby-button.js"], function(_exports, _tabbedview, _globalize, _maintabsmanager, _layoutmanager, _usersettings, _embyScroller, _embyButton) { function HomeView(view, params) { _tabbedview.default.apply(this, arguments), this.enableBackMenu = !0 } Object.defineProperty(_exports, "__esModule", { value: !0 }), _exports.default = void 0, Object.assign(HomeView.prototype, _tabbedview.default.prototype), HomeView.prototype.getTabs = function() { return [{ name: _globalize.default.translate("Home"), id: "home" }, { name: _globalize.default.translate("Favorites"), id: "favorites" }, { name: _globalize.default.translate("Requests"), id: "requests" }] }, HomeView.prototype.getAutoBackdropItemTypes = function() { return ["Movie", "Series", "Game", "Book"] }, HomeView.prototype.setTitle = function() {}, HomeView.prototype.supportsHorizontalTabScroll = function() { return !0 }, HomeView.prototype.tabScrollDirection = function() { return this.supportsHorizontalTabScroll() && _layoutmanager.default.tv && "horizontal" === _usersettings.default.tvHome() ? "x" : "y" }, HomeView.prototype.onPause = function() { _tabbedview.default.prototype.onPause.call(this) }, HomeView.prototype.destroy = function() { _tabbedview.default.prototype.destroy.apply(this, arguments) }, HomeView.prototype.loadTabController = function(id) { switch (id) { case "home": return Emby.importModule("./home/hometab.js"); case "favorites": return Emby.importModule("./home/favorites.js"); case "requests": return Emby.importModule("./home/requests.js"); default: throw new Error("tab not found: " + id) } }, HomeView.prototype.onWindowInputCommand = function(e) { "home" === e.detail.command ? (_maintabsmanager.default.selectedTabIndex(0), e.preventDefault()) : _tabbedview.default.prototype.onWindowInputCommand.apply(this, arguments) }; _exports.default = HomeView }); c) Create a new file requests.js which will contain an iframe that can be pointed to Jellyseerr. This file is called by home.js. Note: the 'padding-top' parameter pushes the page down a bit so that Emby's menu doesn't overlap with Jellyseer's. define([], function () { return function RequestsTab(view) { view.innerHTML = ` <div style=" width:100%; height:100%; box-sizing:border-box; padding-top:60px; "> <iframe src="https://requests.example.net" style="width:100%; height:100%; border:0;" allowfullscreen > </iframe> </div> `; }; }); 3. Upload home.html, home.js and requests.js to the container dir: /app/emby/system/dashboard-ui/home/ 4. Create Unraid user script to backup original Emby files and upload custom files to the container. Note: I keep my custom files in the appdata folder '/emby/custom-files' which is mapped in the container as '/config/custom-files'. #!/bin/bash # # CURRENT AS OF Emby v4.9.1.90 # # This script should be run any time the Emby container has been re-built. # In the event that a newer release of Emby breaks this script due to changing file paths, # locate the files manually and update this script accordingly. # # Use "docker exec emby" at the start of each command to run it in the Emby container # Backup and replace home.html with edited version that displays custom link at the top of the home page. This may require clearing image cache in browser. docker exec emby cp /app/emby/system/dashboard-ui/home/home.html /app/emby/system/dashboard-ui/home/home.html.bak docker exec emby cp /config/custom-files/dashboard-ui/home/home.html /app/emby/system/dashboard-ui/home/ # Backup and replace home.js with modified version that adds a 'Requests' tab to the main page (next to favorites) docker exec emby cp /app/emby/system/dashboard-ui/home/home.js /app/emby/system/dashboard-ui/home/home.js.bak docker exec emby cp /config/custom-files/dashboard-ui/home/home.js /app/emby/system/dashboard-ui/home/ # Copy new file requests.js to Emby container. This file contains an <iframe> with contents referencing https://requests.example.net docker exec emby cp /config/custom-files/dashboard-ui/home/requests.js /app/emby/system/dashboard-ui/home/ Next, we need to mess with networking a bit because Jellyseerr does not work properly in an iFrame due to cross-site cookie handling being set to 'SameSite=Lax'. To be honest, I'm not fully clear which of these changes made it work because the cookie is still 'SameSite=Lax' when I check the developer console in Chrome. There was some trial and error required to get this working. JELLYSEERR 1. Add the following variables to the container template: Name: AUTH_COOKIE_SAMESITE Key: AUTH_COOKIE_SAMESITE Value: None Name: AUTH_COOKIE_SECURE Key: AUTH_COOKIE_SECURE Value: true 2. Enabled in UI: Settings> Network> Enable Proxy Support NETWORKING SWAG 1. Added the following lines in the Location block within proxy-confs file jellyseerr.subdomain.conf: # Not all (or any) of these may be necessary--further testing needed proxy_cookie_path / "/;Secure; SameSite=None"; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; CLOUDFLARE 1. Disabled Cloudflare Proxy Status for root DNS record as well as subdomain record I'm using for Jellyseerr 2. Set Caching Level: No query string (might not be necessary) 3. Set Browser Cache TTL: Respect Existing Headers (might not be necessary) Done. Clear your browser cache/cookies and re-load Emby. I had some trouble with javascript files not refreshing right away so I thought it wasn't working. If you open the developer console in Chrome you can disable cache under the Network tab. Enjoy Edited January 9 by KobayashiM
KobayashiM 27 Posted January 15 Author Posted January 15 (edited) I can't edit my last post for some reason so just want to add a custom css which reduces the size of the top header so it doesn't block Jellyseerr's search bar. Also made it transparent. Figuring out as I go... /* ------------------------ TRANSPARENT TOP BAR -------------------------------- */ div.skinHeader.skinHeader-withBackground { background: transparent !important; height: 60px; } @AdminCould we move this to the Web App CSS forum if you agree it's more appropriate there? Thanks Edited January 15 by KobayashiM
ttgapers 98 Posted January 22 Posted January 22 Thumbs up for this @KobayashiM Will keep following with keen interest.
KobayashiM 27 Posted January 26 Author Posted January 26 define([], function () { return function RequestsTab(view) { view.innerHTML = ` <div style=" width:100%; height:100%; box-sizing:border-box; padding-top:65px; overflow-y: hidden; "> <iframe src="https://requests.example.net" style="width:100%; height:100%; border:0;" allowfullscreen > </iframe> </div> `; }; }); Updated requests.js to slightly increase top padding because the entire iframe scrolls up into the top header about 5 pixels when you reach the bottom of the page but the scroll wheel keeps going. Tried to hide the parent scrollbar but was only half successful as an empty vertical scrollbar is still visible.
KobayashiM 27 Posted February 5 Author Posted February 5 I've decided to try modding the android app just as a learning experience. I kind of got this to work there but can't loging to Jellyseerr. Probably the same issue with cross-site cookies but I'm not sure what more I can do to solve that on the client end. I'll keep messing with it...
Babatom 6 Posted February 12 Posted February 12 @LukeThat would be a killer feature if it come's to Apple TV/Android TV clients. 1 1
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now