Skip to content

add a featured content bar to the top of the jellyfin homepage with very little setup required.. you can also add custom lists for specific seasons etc.

Notifications You must be signed in to change notification settings

BobHasNoSoul/jellyfin-featured

Repository files navigation

jellyfin-featured

what does this do? well it makes a featured banner that changes every 10 seconds to the next item defined by the admin, it takes a single link per item, text title and your website url and does the rest for you. when a user clicks the item it will open and just take them to the item that is on that banner at that time. this works on the clients and pc but has one issue at the moment with the tv clients that stops the banner being clicked on because the doesnt know what to do when it is inside an iframe.. if you know how to fix this send a pull request :)

Screenshot 2023-11-11 090503 Screenshot 2023-11-11 090444 Screenshot 2023-11-11 090420

REQUIREMENTS

  • a jellyfin install
  • a brain
  • the ability to read this guide. (maybe also grab my avatars pack that will be updated soon too)

Updates / Changelog:

please see the changelog.md for accurate updates of each change.

sudo Crontab example

okay so this assumes you already have the lists made i reccomend using lists/halloween.txt etc as a naming standard

so with that said we will be doing a simple keep your lists out of the dir then copy them over crontab so they auto update.

# christmas featured list (1st december)
0 1 1 12 * cp /path/to/lists/christmas.txt /usr/share/jellyfin/web/avatars/list.txt
#new year featured list (day after boxing day)
0 1 27 12 * cp /path/to/lists/newyears.txt /usr/share/jellyfin/web/avatars/list.txt
#Normal random list (2nd jan)
0 1 2 1 * rm /usr/share/jellyfin/web/avatars/list.txt
#Valentines Day (10th onwards)
0 1 10 2 * cp /path/to/lists/valentines.txt /usr/share/jellyfin/web/avatars/list.txt
#Normal list (15th feb)
0 1 15 2 * rm /usr/share/jellyfin/web/avatars/list.txt
#Easter (mar 15th onwards)
0 1 15 3 * cp /path/to/lists/easter.txt /usr/share/jellyfin/web/avatars/list.txt
#Normal list (15th april)
0 1 15 4 * rm /usr/share/jellyfin/web/avatars/list.txt
#Halloween (1st october onwards)
0 1 1 10 * cp /path/to/lists/halloween.txt /usr/share/jellyfin/web/avatars/list.txt
#Normal list (1nd nov)
0 1 1 11 * rm /usr/share/jellyfin/web/avatars/list.txt
#Stephenkings brithday 21st september
0 1 21 9 * cp /path/to/lists/stephenking.txt /usr/share/jellyfin/web/avatars/list.txt
#Normal list (1nd nov)
0 1 22 9 * rm /usr/share/jellyfin/web/avatars/list.txt

Installation

  • Windows Install
  1. download the files from this repo using the zip or gitclone, you pick.. its the same result
  2. install ubuntu from the windows store and use windows subsystem linux for the shell script (you could use cygwin but at this point there isnt a real reason to).
  3. open C:\Program Files\Jellyfin\Server\jellyfin-web\ and create a new folder called avatars this will be where the slideshow.html will be living.
  4. open ubuntu for windows via the start menu and enter the following commands
cd "/mnt/c/Program Files/Jellyfin/Server/jellyfin-web/"
ls | grep home-htm

copy the output line that is like this but the uuid changed home-html.YOURSWILLHAVENUMBERSHERE.chunk.js you will need to modify that file with the following.

find this part

data-backdroptype="movie,series,book"> and insert the following directly after the >

<script async src="/web/avatars/featuredscripts.js"></script><style>.featurediframe { width: 89vw; height: 300px; display: block; border: 1px solid #000; margin: 0 auto;}</style> <style>@import url("avatars/featuredstyles.css");</style><div class="featurediframe"><div id="slides-container" class="focuscontainer-x"></div>

okay now we have injected the javascript and css we are %80 of the way there.

  1. Okay so now we just need to edit the index.html in your webroot (/mnt/c/Program Files/Jellyfin/Server/jellyfin-web/index.html) so open it in your favorite text editor and find the following

</body></html>

replace with

<script>
// Function to save credentials to sessionStorage
function saveCredentialsToSessionStorage(credentials) {
  try {
    // Store the credentials in sessionStorage
    sessionStorage.setItem('json-credentials', JSON.stringify(credentials));
    console.log('Credentials saved to sessionStorage.');
  } catch (error) {
    console.error('Error saving credentials:', error);
  }
}

// Function to save the API key to sessionStorage
function saveApiKey(apiKey) {
  try {
    sessionStorage.setItem('api-key', apiKey);
    console.log('API key saved to sessionStorage.');
  } catch (error) {
    console.error('Error saving API key:', error);
  }
}

// Override the default console.log function
(function() {
  var originalConsoleLog = console.log;

  console.log = function(message) {
    // Call the original console.log method
    originalConsoleLog.apply(console, arguments);

    // Check if the message contains the JSON credentials
    if (typeof message === 'string' && message.startsWith('Stored JSON credentials:')) {
      try {
        // Extract the JSON credentials from the message
        var jsonString = message.substring('Stored JSON credentials: '.length);
        var credentials = JSON.parse(jsonString);

        // Save the credentials to sessionStorage
        saveCredentialsToSessionStorage(credentials);
      } catch (error) {
        console.error('Error parsing credentials:', error);
      }
    }

    // Check if the message contains the WebSocket URL with api_key
    if (typeof message === 'string' && message.startsWith('opening web socket with url:')) {
      try {
        // Extract the API key from the message
        var url = message.split('url:')[1].trim();
        var urlParams = new URL(url).searchParams;
        var apiKey = urlParams.get('api_key');

        if (apiKey) {
          saveApiKey(apiKey);
        }
      } catch (error) {
        console.error('Error extracting API key:', error);
      }
    }
  };
})();
</script>
</body></html>

  1. save the file and close the file

  2. simply reload the page after clearing the cache (incognito mode or ctrl+shift+r on some browsers)

7b (optional). make custom lists and crontab them for best effect


Docker

Instructions to be added at a later date


Linux

to install on linux it is super simple

your webroot is /usr/share/jellyfin/web (by default if it isnt just adjust this for your custom one you put in)

inside webroot make the avatars folder and then download the slideshow.html from this repo and put that inside the avatars folder inside of webroot (that should be /usr/share/jellyfin/web/avatars/slideshow.html)

when inside the webroot run the following

sudo nano index.html

find </body></html>

replace with

<script>
// Function to save credentials to sessionStorage
function saveCredentialsToSessionStorage(credentials) {
  try {
    // Store the credentials in sessionStorage
    sessionStorage.setItem('json-credentials', JSON.stringify(credentials));
    console.log('Credentials saved to sessionStorage.');
  } catch (error) {
    console.error('Error saving credentials:', error);
  }
}

// Function to save the API key to sessionStorage
function saveApiKey(apiKey) {
  try {
    sessionStorage.setItem('api-key', apiKey);
    console.log('API key saved to sessionStorage.');
  } catch (error) {
    console.error('Error saving API key:', error);
  }
}

// Override the default console.log function
(function() {
  var originalConsoleLog = console.log;

  console.log = function(message) {
    // Call the original console.log method
    originalConsoleLog.apply(console, arguments);

    // Check if the message contains the JSON credentials
    if (typeof message === 'string' && message.startsWith('Stored JSON credentials:')) {
      try {
        // Extract the JSON credentials from the message
        var jsonString = message.substring('Stored JSON credentials: '.length);
        var credentials = JSON.parse(jsonString);

        // Save the credentials to sessionStorage
        saveCredentialsToSessionStorage(credentials);
      } catch (error) {
        console.error('Error parsing credentials:', error);
      }
    }

    // Check if the message contains the WebSocket URL with api_key
    if (typeof message === 'string' && message.startsWith('opening web socket with url:')) {
      try {
        // Extract the API key from the message
        var url = message.split('url:')[1].trim();
        var urlParams = new URL(url).searchParams;
        var apiKey = urlParams.get('api_key');

        if (apiKey) {
          saveApiKey(apiKey);
        }
      } catch (error) {
        console.error('Error extracting API key:', error);
      }
    }
  };
})();
</script>
</body></html>

then run sudo nano home-html.*.chunk.js

find data-backdroptype="movie,series,book"> and insert the following directly after the >

<link rel="stylesheet" href="/web/avatars/slideshowpure.css"><div id="slides-container"></div><script async src="/web/avatars/slideshowpure.js"></script>

now save it and you should be good to go once you reload your browsers cache on the client side

optional make a list.txt inside /usr/share/jellyfin/web/avatars/list.txt using the following syntax

TITLE OF PLAYLIST HERE itemid itemid itemid


Bugfix on chrome

okay so when you reload the cache on chrome this can break on the first two reloads... to fix reload the cache.. then reload twice

for some reason i have only reproduced this on a limited childs account that could not access all age ranges.