These mods are working and tested on Jellyfin 10.9.x (mods for older versions can be found here: https://github.com/BobHasNoSoul/jellyfin-mods/blob/main/10.8.x.md) More will be added when I get the chance, or if you want please feel free to submit a pull request with your own mods to add to the collection.
If you are having issues with finding the web root, you may need to see the help.md to find help with your particular deployment.
Please note this method of Jellyfin modding is intended for those who do not want or are unable to compile the web client yourself... There are better ways of doing these mods, but if you insist, this is the way to do it. (Not preaching, it's your server after all :D )
- jellyfin-mods
- Use the media item's logo and hide plain text title when present
- Custom login page that looks similar to Netflix
- Avatar library for your users
- Change the title of the page
- Change the default iOS/Android "app" title and description
- Featured Content Bar
- Force backdrops for all users
- Force theme music for all users
- Change font to whatever you want
- Set limit on how long items should be in the next up section
- Add a custom logo at the top of the login page
- Add a custom link button under login page
- Add a custom logo to side bar
- Add a custom link to side bar
- Add requests tab
- Hide scrollbar on older Microsoft edge (Xbox clients)
- Pan and tilt the backdrops with fades in and out
- Default user page size
- Change the favicon
- CSS mods
- Seasonal themes
- Bugfixes / Workarounds
- Some extra tools to be used with Jellyfin
This mod takes the title text away when an item has a valid logo loaded, thus not showing you the logo of "Game of Thrones" for example, and then also saying "Game of Thrones" in plain text underneath... This is a small mod that is applied in the "Custom CSS Code" area in the General tab of your Jellyfin admin panel. Simply copy and paste the following:
/*If the logo is present on the details page of an item, hide the items' title*/
#itemDetailPage .itemName.infoText.parentNameLast > bdi:nth-child(1) {display: none;}
.hide+.detailPageWrapperContainer .itemName > bdi:nth-child(1) {display: block !important;}
/*Do the same for the single episodes link back title*/
#itemDetailPage .parentName > bdi:nth-child(1) {display: none;}
.hide+.parentName > bdi:nth-child(1) {display: block !important;}
Custom login page that looks similar to Netflix with a custom background and styling (Ignore the custom logo, that's a mod further down)
In your admin panel, under General, check 'Enable the splash screen' and click save. Then add the following to the custom CSS, click save again, then reload your login page.
/*Custom login page of awesome*/
#loginPage {
background-image: url('/Branding/Splashscreen?format=jpg&foregroundLayer=20.0');
background-position: top left;
background-size: 200%;
background-attachment: fixed;
animation: backgroundAnimation 150s infinite alternate;
z-index: 2;
}
@keyframes backgroundAnimation {
0% {
background-position: top left;
}
25% {
background-position: bottom right;
}
50% {
background-position: bottom left;
}
100% {
background-position: top left;
}
}
.skinHeader.semiTransparent.noHeaderRight {
background: transparent !important;
}
div#loginPage {
margin-top: 0 !important;
overflow: hidden scroll;
}
#loginPage h1::after {
content: "Sign In";
font-size: 32px;
}
#loginPage h1 {
font-weight: 700;
font-size: 0;
margin-bottom: 21.44px;
margin-top: 32px !important;
text-align: left;
}
.inputContainer {
margin-bottom: 1.8em;
margin-top: 1.8em;
}
#loginPage .padded-left.padded-right.padded-bottom-page {
background: #000000bf;
transform: translate(-50%, -50%);
top: 50%;
left: 50%;
margin: 21px;
position: absolute;
border-radius: 10px;
width: 100vw;
display: flex;
flex-direction: column;
flex-wrap: nowrap;
align-content: center;
justify-content: center;
align-items: center;
padding: 3em !important;
}
#loginPage .readOnlyContent {
padding: 0 !important;
width: 100% !important;
height: -webkit-fit-content;
height: -moz-fit-content;
height: fit-content;
}
.manualLoginForm {
height: 100%;
width: 100%;
}
#loginPage .inputContainer {
background: #333;
border-radius: var(--rounding);
height: 4em;
position: relative;
}
#loginPage .inputLabel.inputLabelFocused,
#loginPage .inputLabel:not(.inputLabel-float) {
font-size: 0.8em;
left: 4%;
top: 4%;
transform: none;
}
.visualLoginForm {
width: 100%;
position: relative;
overflow: hidden;
}
#divUsers {
flex-flow: revert;
overflow: scroll visible;
justify-content: flex-start;
}
#loginPage .emby-input {
height: 100%;
border: none;
background: transparent !important;
-webkit-backdrop-filter: none;
backdrop-filter: none;
box-shadow: none !important;
padding: 4% !important;
font-size: 1.1em;
border: none !important;
}
#loginPage .inputLabel {
position: absolute;
top: 50%;
left: 4%;
transform: translateY(-50%);
font-size: 1.5em;
font-weight: 300;
transition: 0.2s ease;
color: #8c8c8c;
}
#loginPage .inputContainer:focus,
#loginPage .inputContainer:focus-within {
background: #454545;
}
For full instructions, please visit the dedicated repo at: https://github.com/BobHasNoSoul/jellyfin-avatars
Effectively, this adds a button next to the user profile image that links straight to an avatar library that works with a simple click to download images, enabling your users to upload them and use them on the server.
To be clear, this mod changes the title that appears in browser tabs from "Jellyfin" to your own unique name like "My Awesome Server" or in the example code "YOUR TITLE HERE". You can use either method.
Go to your web root and run sudo nano index.html
Then, inside the tags, add the following:
<script>
document.addEventListener("DOMContentLoaded", function() {
// Change the document title to "YOUR TITLE HERE"
document.title = "YOUR TITLE HERE";
// Create a MutationObserver to prevent any changes to the title
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.type === 'childList') {
if (document.title !== "YOUR TITLE HERE") {
document.title = "YOUR TITLE HERE";
}
}
});
});
// Observe the document title for changes
observer.observe(document.querySelector('title'), { childList: true });
// Set up a fallback in case of attempts to change the title through direct assignment
Object.defineProperty(document, 'title', {
set: function() {
return "YOUR TITLE HERE";
},
get: function() {
return "YOUR TITLE HERE";
}
});
});
</script>
Obviously change the "YOUR TITLE HERE" parts to your personal custom title you want the server to have.
Save the file and reload the cache on your clients to see your changes.
Go to your web root and create a new file called title.sh
and inside that file add the following:
grep -rl 'document\.title="Jellyfin"' . | while read -r file; do
sed -i 's/document\.title="Jellyfin"/document\.title="YOUR TITLE HERE"/g' "$file"
done
grep -rl 'document.title=e||"Jellyfin"' . | while IFS= read -r file; do
sed -i 's/document.title=e||"Jellyfin"/document.title=e||"YOUR TITLE HERE"/g' "$file"
done
Obviously change the "YOUR TITLE HERE" parts to your personal custom title you want the server to have.
Save the file, then run sudo chmod +x title.sh sudo ./title.sh
Reload the cache on your clients to see your changes.
This mod changes the title that appears when adding the site to your homescreen as a webapp from "Jellyfin" to your own unique name like "My Awesome Server" or in the example code "YOUR TITLE HERE".
Go to your web root and run grep -oP '<link[^>]*rel="manifest"[^>]*href="[^"]*"' index.html | grep -oP '(?<=href=")[^"]*'
This command will output a JSON filename, copy it, then run sudo nano <YOUR_COPIED_FILENAME.json>
to edit the file.
{
"name": "YOUR TITLE HERE",
"description": "YOUR DESCRIPTION HERE",
"lang": "en-US",
"short_name": "YOUR TITLE HERE",
"start_url": "index.html#/home.html",
"theme_color": "#101010",
"background_color": "#101010",
"display": "standalone",
"icons": [
{
"sizes": "72x72",
"src": "touchicon72.png",
"type": "image/png"
},
{
"sizes": "114x114",
"src": "touchicon114.png",
"type": "image/png"
},
{
"sizes": "144x144",
"src": "touchicon144.png",
"type": "image/png"
},
{
"sizes": "512x512",
"src": "touchicon512.png",
"type": "image/png"
}
]
}
Obviously change the "YOUR TITLE HERE" and "YOUR DESCRIPTION HERE" parts to your personal custom title/description you want the homescreen shortcut to have, but leave everything else as is.
Save the file and reload the cache on your clients to see your changes.
This allows the user to add custom featured content to be pinned to the homepage. Please see the separate repo for this for more details.
Allows for the use of a specific account's favorites to promote content, as well as user-defined custom lists that are looped through via crontab.
In 'main.jellyfin.bundle.js' simply search for enableBackdrops:function(){return _}
and replace it with enableBackdrops:function(){return E}
Save the file and reload the cache on your clients to see your changes.
*** If you cannot find it (because of regex in search like in nano) try searching for enableBackdrops:function
. This should give you the ability to find the string above ***
In 'main.jellyfin.bundle.js' simply search for enableThemeSongs:function(){return j}
and replace it with enableThemeSongs:function(){return P}
Save the file and reload the cache on your clients to see your changes.
*** If you cannot find it (because of regex in search like in nano) try searching for enableThemeSongs:function
. This should give you the ability to find the string above ***
Pro tip: Use the theme songs plugin to grab multiple theme songs for TV shows in one go (https://github.com/danieladov/jellyfin-plugin-themesongs), or manually add a theme .mp3 at the root of each TV show folder (i.e. /tv/breaking bad/theme.mp3
). This mod also works for movies of course, but you will have to manually grab each theme song as the mentioned plugin does not work with movies.
First, get a font pack... there are many out there... so take your time looking for one you really like the look of and download it. You can get some free fonts from https://google-webfonts-helper.herokuapp.com/fonts/, but there are many other free sources. Once you've found a font, navigate to your Jellyfin web root and create a new folder called "fonts" (your font pack should contain .woff .woff2 .tff .eot and .svg files), and unzip the contents of your font archive into this folder. For this example, I used the Ubuntu font (don't judge me). You can get the same font from here https://google-webfonts-helper.herokuapp.com/api/fonts/ubuntu-mono?download=zip&subsets=latin&variants=regular
Extract the contents of your font archive into following directory:
/usr/share/jellyfin/web/fonts/
Then, simply add the following to your custom CSS (rename them for your files in turn unless you're using the linked Ubuntu font):
/* ubuntu-regular - latin */
@font-face {
font-family: 'Ubuntu';
font-style: normal;
font-weight: 400;
src: url('/web/fonts/ubuntu-v15-latin-regular.eot'); /* IE9 Compat Modes */
src: local(''),
url('/web/fonts/ubuntu-v15-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('/web/fonts/ubuntu-v15-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */
url('/web/fonts/ubuntu-v15-latin-regular.woff') format('woff'), /* Modern Browsers */
url('/web/fonts/ubuntu-v15-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */
url('/web/fonts/ubuntu-v15-latin-regular.svg#Ubuntu') format('svg'); /* Legacy iOS */
}
html { font-family: "Ubuntu" !important;}
(Alternative download method) Easy mode for Ubuntu font... (You can use this as a guide to do this for other fonts too if you prefer downloading through the terminal)
cd /usr/share/jellyfin/web/
sudo mkdir fonts
sudo wget https://google-webfonts-helper.herokuapp.com/api/fonts/ubuntu-mono?download=zip&subsets=latin&variants=regular
The 'wget' command might output what looks like an error [1] [2] but just ignore that and press Ctrl+C and go to the next command:
sudo mv ubuntu-mono* fonts/ubuntu.zip
sudo unzip fonts/ubuntu.zip
Now your font is where it should be, just modify the CSS in the General tab of your Jellyfin admin panel to suit different names of fonts.
The default time for this is one year (365 days).
To change this, simply go to your web root and run sudo nano main.jellyfin.bundle.js
Find t("maxDaysForNextUp",e.toString(),!1);var t=parseInt(this.get("maxDaysForNextUp",!1),10);return 0===t?0:t||365}}
and replace the 365 with whatever value you want in days.
Save the file and reload the cache on your clients to see your changes.
Simply go to your web root and edit the session-login-index-html.xxxxxxxxxxxxxxxxxxxxx.chunk.js file:
sudo nano session-login-index-html.*.bundle.js
Press Ctrl+W and find the following string:
<div class="padded-left padded-right padded-bottom-page margin-auto-y">
Now, directly after this string paste the following (but obviously amend for your own logo, it can even be a GIF if you want):
<img src="/web/logo.png" width=350px style="padding: 0px;display:block; margin-left: auto; margin-right: auto;">
In your web root run sudo nano session-login-index-html.*.chunk.js
then use find and replace ( Ctrl+\ )
Find <div class="loginDisclaimer
and replace it with <a href="https://www.example.com" class="emby-button raised block btnCUSTOMBUTTON">NEW LINK BUTTON TEST</a> <div class="loginDisclaimer
Save the file and reload the cache on your clients to see your changes.
In your web root run grep -r -l -n 'customMenuOptions' .
This command will output a filename, copy it, then run sudo nano <YOUR_COPIED_FILENAME>
to edit the file.
Find <div style="height:.5em;"></div>',n+='
and replace it with the following (obviously replace YOURLOGOURLHERE with your actual URL):
<div style="height:.5em;"></div>',n+='<img src="YOURLOGOURLHERE" width=250px style="padding: 5px;display:block; margin-left: auto; margin-right: auto;">
Save the file and reload the cache on your clients to see your changes.
Find the 'config.json' file in your web root. Change the "menuLinks" section to the following and adjust the properties to suit your needs (icons are from Material Design Icons).
"menuLinks": [
{
"name": "Custom Link",
"url": "https://jellyfin.org"
},
{
"name": "Custom Link w. Custom Icon",
"icon": "attach_money",
"url": "https://demo.jellyfin.org/stable"
}
],
If you only want one link, make sure to remove the comma after the closing bracket (}). If you want to add more links, add a comma for every entry except the last one.
- Before doing anything, remember to backup the files we are going to edit
- Go to your web root and edit the
index.html
file - Find
</body></html>
and paste the following right before it:
<script>const createRequestTab = () => {const title = document.createElement("div");title.classList.add("emby-button-foreground");title.innerText = "Requisições";const button = document.createElement("button");button.type = "button";button.is = "empty-button";button.classList.add("emby-tab-button", "emby-button", "lastFocused");button.setAttribute("data-index", "2");button.setAttribute("id", "requestTab");button.appendChild(title);(function e() {const tabb = document.querySelector(".emby-tabs-slider");tabb ? !document.querySelector("#requestTab") && tabb.appendChild(button) : setTimeout(e, 500)})();}</script>
- Save the file with your changes. This is the script that creates the tab.
- Now edit the
home-html.*.chunk.js
file - Find
data-backdroptype="movie,series,book">
and paste the following right after it:
<style>:root{--save-gut:max(env(safe-area-inset-left),3.3%)}.requestIframe{margin:0 .4em;padding:0 var(--save-gut);width:calc(100% - (.4em * 2) - (var(--save-gut) * 2));height:85vh;border:none;position:absolute;top:0}</style><script>setTimeout(() => {createRequestTab()}, 500)</script>
- This is what will make it look good and start the script that creates the tab.
- And now, find
id="favoritesTab" data-index="1"> <div class="sections"></div> </div>
and paste the following right after it:
<div class="tabContent pageTabContent" id="requestsTab" data-index="2"> <div class="sections"><iframe class="requestIframe" src="[YOUR_REQUEST_SERVICE_HERE]"></iframe></div> </div>
- This is what will make the service open in the correct tab.
For example, I'm using Jellyseerr as my request service, so, my last part would be <iframe class="requestIframe" src="[MY_LOCAL_IP]:5055"></iframe>
sudo sed -i -e '$abody { -ms-overflow-style: none !important; }' /usr/share/jellyfin/web/themes/dark/theme.css
This adds a line to make it hide the scrollbar while retaining scroll functionality... so yay no more invasive scrollbar from the early 00s!
Video of this in action: https://gfycat.com/sizzlingcavernousgalapagospenguin
This mod works really well with the forced backdrop mod!
It's simply custom CSS, and you can use and adjust any and all values you like. Personally, I like these values:
/*Pan the background for backdrops*/
@keyframes backgroundScroll {
0% { background-position: 99% 1%; opacity:0;}
33% { background-position: 50% 50%;opacity:1;}
40% { background-position: 99% 99%; opacity:0;}
66% { background-position: 50% 50%; }
75% { background-position: 1% 1%; }
100% { background-position: 50% 50%; }}
.backdropImage {background-size: 150% 150%; opacity:0 ;background-position: 99% 1%; animation: backgroundScroll 60s ease-in-out 1s;}
@keyframes backgroundScrollmob {
0% { background-position: 99% 1%; opacity:0;}
33% { background-position: 50% 50%;opacity:1;}
40% { background-position: 1% 99%; opacity:0}
66% { background-position: 99% 50%; }
75% { background-position: 99% 99%; }
100% { background-position: 50% 50%; }}
@media (max-width: 600px) {
.backdropImage {background-size: 150% 150% cover; opacity:0 ; background-position: 99% 1%; animation: backgroundScrollmob 60s ease-in-out 1s;}
}
/*Thanks to poiaman for the fix for mobile devices below*/
@Keyframes backgroundScroll {
0% { background-position: 99% 1%; opacity: 0; filter: blur(0px); }
5% { opacity: 1; filter: blur(0px); }
33% { background-position: 50% 50%; opacity: 1; filter: blur(0px); }
40% { background-position: 99% 99%; opacity: 0; filter: blur(0px); }
66% { background-position: 50% 50%; filter: blur(0px); }
75% { background-position: 1% 1%; filter: blur(0px); }
100% { background-position: 50% 50%; opacity: 0.5; filter: blur(5px); }
}
.backdropImage {
background-size: cover;
opacity: 0;
background-position: center center;
animation: backgroundScroll 60s ease-in-out 0s;
filter: blur(0px);
}
@Keyframes backgroundScrollmob {
0% { background-position: 99% 1%; opacity: 0; filter: blur(0px); }
5% { opacity: 1; filter: blur(0px); }
33% { background-position: 50% 50%; opacity: 1; filter: blur(0px); }
40% { background-position: 1% 99%; opacity: 0; filter: blur(0px); }
66% { background-position: 99% 50%; filter: blur(0px); }
75% { background-position: 99% 99%; filter: blur(0px); }
100% { background-position: 50% 50%; opacity: 0.5; filter: blur(5px); }
}
@media (max-width: 600px) {
.backdropImage {
background-size: cover;
opacity: 0;
background-position: center center;
animation: backgroundScrollmob 60s ease-in-out 0s;
filter: blur(0px);
}
}
Just paste that into your custom CSS in the General tab of your Jellyfin admin panel and click save.
In your web root, find and edit your 'main.xxxxxxxxxxxx.bundle.js' by running sudo nano main.*.bundle.js
Then, find this:
this.get("libraryPageSize",!1),10);return 0===t?0:t||100}
And change it to this (300 in this example):
this.get("libraryPageSize",!1),10);return 0===t?0:t||300}
You can modify the number from 100 to any number you want the user default to be.
Save the file and reload the cache on your clients to see your changes.
As of a recent update, the favicon now lives in the web root as a random string followed by .ico
Thankfully, it is the only (should be the only) .ico in there, so run the following command inside your web root to find it:
ls | grep .ico
Copy the output of this command, as this is what you will name your custom favicon file.
Now, simply grab your new favicon from wherever and save it to your web root named as the output of the previous grep command. This may require you to either use a volume to map that file to the new file, or simply just replace the file using a new volume that isn't web root in the Docker and mapped to a transfer folder on your server.
Example:
./transfer:/jellyfin/transfer
Then you would simply do the following inside the web root after you have created the .ico in the transfer folder on your host. (This only applies to Docker. If you installed without Docker, just replace the file like you would any other file.)
Run this command from within web root cp /jellyfin/transfer/*.ico ./
This will copy the .ico from your transfer folder to the web root without having to do any other weird fancy tricks.
Reload the cache on your clients to see your changes.
The following hides "please login" dialog and prevents the login going too far up top by adding a margin.
/*Hide "please login" text, margin is to prevent login form moving too far up*/
#loginPage h1 {display: none}
#loginPage .padded-left.padded-right.padded-bottom-page {margin-top: 10px}
Lighten the backdrop background using the following:
/*Lighten background*/
.backgroundContainer.withBackdrop {background-color: rgba(0, 0, 0, 0.34) !important;}
Transparent top bar using the following:
/*transparent top bar*/
.skinHeader-withBackground {background-color: #20202000 !important;}
Partially transparent side menu with the following:
/*Partially transparent side bar*/
div.mainDrawer {background-color: rgba(0,0,0,0.6) !important;}
Remove the title "My Media" with the following:
/* remove My Media title */
.section0 .sectionTitle {display: none;}
This is currently being revived so no auto scripts, yet... There may be bugs so please let me know and submit issues.
Installation:
First, in the web root you need to create a 'seasonal' folder and fill it with the contents of the 'seasonal' folder from this repo. Once you do that, to activate a theme just add the following to your 'index.html' just before the final </body></html>
tags
To apply the snowstorm theme simply add:
<script src="seasonal/snowstorm.js"></script>
To apply the snowflakes theme simply add:
<link rel="stylesheet" href="seasonal/snowflakes.css">
<snowflake><div class="snowflakes" aria-hidden="true"> <div class="snowflake"> ❅ </div> <div class="snowflake"> ❆ </div> <div class="snowflake"> ❅ </div> <div class="snowflake"> ❆ </div> <div class="snowflake"> ❅ </div> <div class="snowflake"> ❆ </div> <div class="snowflake"> ❅ </div> <div class="snowflake"> ❆ </div> <div class="snowflake"> ❅ </div> <div class="snowflake"> ❆ </div> <div class="snowflake"> ❅ </div> <div class="snowflake"> ❆ </div></div></snowflake>
To apply the fireworks theme simply add:
<snowflake><div class="pyro"> <div class="before"></div> <div class="after"></div></div></snowflake>
<link rel="stylesheet" href="seasonal/fireworks.css">
Note: A known bug with fireworks is they don't scroll with the user, they stay near the top of the page, and may cause infinite loading due to a JS bug... this does need fixing.
To apply the hearts theme simply add:
<link rel="stylesheet" href="seasonal/hearts.css"> <snowflake><div class="snowflakes" aria-hidden="true"><div class="snowflake"> ❤️ </div> <div class="snowflake"> ❤️ </div> <div class="snowflake"> ❤️ </div> <div class="snowflake"> ❤️ </div> <div class="snowflake"> ❤️ </div> <div class="snowflake"> ❤️ </div> <div class="snowflake"> ❤️ </div> <div class="snowflake"> ❤️ </div> <div class="snowflake"> ❤️ </div> <div class="snowflake"> ❤️ </div> <div class="snowflake"> ❤️ </div> <div class="snowflake"> ❤️ </div></div></snowflake>
To apply the Halloween theme simply add:
<link rel="stylesheet" href="/web/seasonal/halloween.css"> <snowflake><div class="snowflakes" aria-hidden="true"> <div class="snowflake"> <img src="/web/seasonal/ghost_20x20.png"> </div> <div class="snowflake"> <img src="/web/seasonal/bat_20x20.png"> </div> <div class="snowflake"> <img src="/web/seasonal/pumpkin_20x20.png"> </div> <div class="snowflake"> <img src="/web/seasonal/ghost_20x20.png"> </div> <div class="snowflake"> <img src="/web/seasonal/bat_20x20.png"> </div> <div class="snowflake"> <img src="/web/seasonal/pumpkin_20x20.png"> </div> <div class="snowflake"> <img src="/web/seasonal/ghost_20x20.png"> </div> <div class="snowflake"> <img src="/web/seasonal/bat_20x20.png"> </div> <div class="snowflake"> <img src="/web/seasonal/pumpkin_20x20.png"> </div> <div class="snowflake"> <img src="/web/seasonal/ghost_20x20.png"> </div> <div class="snowflake"> <img src="/web/seasonal/bat_20x20.png"> </div> <div class="snowflake"> <img src="/web/seasonal/pumpkin_20x20.png"> </div></div></snowflake>
TO DO: Automation scripts that crontab in and out these effects for holidays and seasons.
This bug is due to the Edge browser being identified incorrectly on the Jellyfin server. Jellyfin thinks it is Chromium (which is correct to an extent seeing as it is based on Chromium) but it is missing a few of the features it needs, such as functioning to surround sound. To fix this, you just need to set your audio channels
to stereo
in your profile > playback
settings in your Xbox's Edge browser. Hit save and it will play the files without any issues. (Note that you may still see a few hls issues reported in the log for FFmpeg, but that is just a warning, not an error, and can be ignored.)
Have you experienced HDHomeRun audio sync issues, or stutter on playback from IPTV even if its from a Gtmedia tuner on your own LAN? So did I until I saw that this is a known bug in the 10.9 version of Jellyfin that has the fmp4 container used for Live TV and found the fix was to disable fmp4 container for each user. However, you can set this by default by editing the playback config.
sudo nano user-playback.*.chunk.js
Then find e.querySelector(".chkPreferFmp4HlsContainer").checked=i.preferFmp4HlsContainer()
And replace it with e.querySelector(".chkPreferFmp4HlsContainer").checked==i.preferFmp4HlsContainer()
Save the file and reload the cache on your clients to see your changes.
These are some extremely helpful tools that can be used with Jellyfin to increase functionality.
This is a Jellyfin account management tool that can be used to generate links to invite people to your Jellyfin server and allow them to create their own username and passsword. It's written in Go and can be installed on most OS's. You can get it here: https://github.com/hrfee/jfa-go
A free and open source software application for managing requests for your media library. After adding a custom link in the side bar, when your friends or family want to request media, they can request it using Jellyseerr, which also integrates with Radarr, Sonarr, and other relevant services. You can get it here: https://github.com/Fallenbagel/jellyseerr
A legacy alternative to Jellyseerr, Ombi is a media requesting service that can be used with Jellyfin. You can get it here: https://github.com/Ombi-app/Ombi
ErsatzTV is a bit like PseudoTV for Kodi but more like a Live TV media server. You can get it here: https://github.com/jasongdove/ErsatzTV
Intro Skipper plugin analyzes the audio of television episodes to detect and skip over intros. You can get it here: https://github.com/intro-skipper/intro-skipper
This script sends a message to all currently active users that are watching media. (For example, I use this to inform users the server will be shutting down for maintenance in 60 mins, then 30 mins, then 10 mins, 5 min, 4 min, 3 min, and so on. This is easily setup with basic configuration.) You can get it here: https://github.com/BobHasNoSoul/Jellyfin-Announce