Table of Contents#
Overview#
LizardByte has the full documentation hosted on Read the Docs.
About#
Themerr-jellyfin is a plugin for Jellyfin that adds theme songs to movies using ThemerrDB.
Integrations#
Downloads#
Installation#
The recommended method for running Themerr-jellyfin is to add the repository to Jellyfin.
Tip
See Jellyfin Plugins for more information about installing plugins.
Repository#
In Jellyfin, go to http://localhost:8096/web/index.html#!/repositories.html.
Add the repository
https://app.lizardbyte.dev/jellyfin-plugin-repo/manifest.json
Go to the
Catalog
and search for Themerr.Select and install the plugin.
Restart Jellyfin
Portable#
The portable archive is cross platform, meaning Linux, macOS, and Windows are supported.
Download the
themerr-jellyfin.zip
from the latest releaseExtract the contents to your Jellyfin plugins directory.
Restart Jellyfin
Docker#
Docker images are available on Dockerhub and ghcr.io.
See Docker for additional information.
Source#
Caution
Installing from source is not recommended most users.
Follow the steps in Build.
Extract the generated zip archive to your Jellyfin plugins directory.
Restart Jellyfin
Docker#
lizardbyte/themerr-jellyfin#
This is a docker-mod for jellyfin which adds Themerr-jellyfin to jellyfin as a plugin, to be downloaded/updated during container start.
This image extends the jellyfin image, and is not intended to be created as a separate container.
Installation#
In jellyfin docker arguments, set an environment variable DOCKER_MODS=lizardbyte/themerr-jellyfin:latest
or
DOCKER_MODS=ghcr.io/lizardbyte/themerr-jellyfin:latest
If adding multiple mods, enter them in an array separated by |
, such as
DOCKER_MODS=lizardbyte/themerr-jellyfin:latest|linuxserver/mods:other-jellyfin-mod
Supported Architectures#
Specifying lizardbyte/themerr-jellyfin:latest
or ghcr.io/lizardbyte/themerr-jellyfin:latest
should retrieve the correct
image for your architecture.
The architectures supported by this image are:
Architecture |
Available |
---|---|
x86-64 |
✅ |
arm64 |
✅ |
Usage#
Minimal setup is required to use Themerr-jellyfin. In addition to the installation, a few settings must be configured.
Enable Themes#
Navigate to your user settings page.
Select Display from the user section.
Within the Library section, ensure Theme songs is enabled.
Directory Structure#
Task Activation#
Scheduled#
Themerr will run automatically on a schedule. You can configure the schedule in the configuration page.
Manual#
To initialize a download task manually, follow these steps:
Navigate to configuration page.
Select Update Theme Songs.
Or alternatively:
Navigate to http://localhost:8096/web/index.html#!/scheduledtasks.html.
Select Update Theme Songs under the Themerr section.
Theme Updates#
Themerr will only add or update a theme song if the following conditions are met.
A user supplied
theme.mp3
is not present.The theme in ThemerrDB is different from the previously added theme by Themerr.
Troubleshooting#
Jellyfin Server Logs#
Unfortunately, Jellyfin does not separate the logs by plugin. You will need to review the server logs.
The log location varies, depending on your environment. See Jellyfin Server Logs for more information.
Attention
Before uploading logs, it would be wise to review the data in the log file. Themerr does not have control of the information that is logged by the Jellyfin server.
Changelog#
Database#
The database of themes is held in our ThemerrDB repository. To contribute to the database, follow the documentation there.
Build#
Compiling Themerr-jellyfin requires the following:
Clone#
Ensure git is installed and run the following:
git clone https://github.com/lizardbyte/themerr-jellyfin.git
cd ./themerr-jellyfin
Setup Python venv#
It is recommended to setup and activate a venv.
Install Requirements#
Install Requirements
python -m pip install -r ./requirements-dev.txt
Compile#
mkdir -p ./build
python -m jprm plugin build --output ./build
Remote Build#
It may be beneficial to build remotely in some cases. This will enable easier building on different operating systems.
Fork the project
Activate workflows
Trigger the CI workflow manually
Download the artifacts from the workflow run summary
Localization#
Themerr-jellyfin and related LizardByte projects are being localized into various languages. The default language is en (English).
CrowdIn#
The translations occur on CrowdIn. Anyone is free to contribute to localization there.
- Translations Basics
The brand names LizardByte and Themerr should never be translated.
Other brand names should never be translated. Examples:
Jellyfin
- CrowdIn Integration
How does it work?
When a change is made to the source locale file, those strings get pushed to CrowdIn automatically.
When translations are updated on CrowdIn, a push gets made to the l10n_master branch and a PR is made. Once PR is merged, all updated translations are part of the project and will be included in the next release.
Extraction#
Themerr-jellyfin uses a custom translation implementation for localizing the html config page. The implementation uses a JSON key-value pair to map the strings to their respective translations.
The following is a simple example of how to use it.
- Add the string to Locale/en.json, in English.
{ "hello": "Hello!" }
Note
The json keys should be sorted alphabetically. You can use jsonabc to sort the keys.
- Use the string in the config page.
<p data-localize="hello">Hello!</p>
Note
The data-localize attribute should be the same as the key in the JSON file.
The innerText of the element should be the default English string, incase the translations cannot be properly loaded.
The data-localize attribute can be added to any element that supports innerText.
Once the page is loaded, the innerText will be replaced with their respective translations.
If the translation is not found, there will be a fallback to the default English string.
- Use the string in javascript.
const hello = translate("hello");
Testing#
SonarAnalyzer.CSharp#
Themerr-jellyfin uses SonarAnalyzers.CSharp to spot Bugs, Vulnerabilities, and Code Smells in the project. This is run automatically as part of the build process.
The config file for SonarAnalyzers.CSharp is .editorconfig
.
StyleCop.Analyzers#
Themerr-jellyfin uses StyleCop.Analyzers to enforce consistent code styling. This is run automatically as part of the build process.
The config file for StyleCop.Analyzers is .editorconfig
.
Sphinx#
Themerr-jellyfin uses Sphinx for documentation building. Sphinx, along with other required python dependencies are included in the ./docs/requirements.txt file. Python is required to build sphinx docs. Installation and setup of python will not be covered here.
The config file for Sphinx is docs/source/conf.py
. This is already included in the root of the repo and should not
be modified.
- Test with Sphinx
cd docs make html
Alternatively
cd docs sphinx-build -b html source build
- Lint with rstcheck
rstcheck -r .
Unit Testing#
Themerr-jellyfin uses xUnit for unit testing.
- Test with xUnit
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover --logger "console;verbosity=detailed"
Source Code#
Our source code is documented using the standard documentation guidelines.
Source#
- class Jellyfin.Plugin.Themerr.Configuration.PluginConfiguration : BasePluginConfiguration#
Inheritence diagram for Jellyfin::Plugin::Themerr::Configuration::PluginConfiguration:
Collaboration diagram for Jellyfin::Plugin::Themerr::Configuration::PluginConfiguration:
Initializes a new instance of the PluginConfiguration class.
Public Functions
- PluginConfiguration ()#
Initializes a new instance of the PluginConfiguration class.
Properties
- int? UpdateInterval { get; set; }#
Gets or sets the time between scheduled updates, in minutes.
Minimum value of 15.
Private Members
- int _updateInterval#
- class Jellyfin.Plugin.Themerr.Api.ThemerrController : ControllerBase#
Inheritence diagram for Jellyfin::Plugin::Themerr::Api::ThemerrController:
Collaboration diagram for Jellyfin::Plugin::Themerr::Api::ThemerrController:
The Themerr api controller.
Public Functions
- List<string> GetCultureResource (string culture)#
Get the resources of the given culture.
- Param culture:
The culture to get the resource for.
- Return:
A list of file names.
- ActionResult GetProgress ()#
Get the data required to populate the progress dashboard.
Loop over all Jellyfin libraries and supported items, creating a json object with the following structure: { “items”: [BaseItems], “media_count”: BaseItems.Count, “media_percent_complete”: ThemedItems.Count / BaseItems.Count * 100, }
- Return:
JSON object containing progress data.
- ActionResult GetTranslations ()#
Get the localization strings from Locale/{selected_locale}.json.
- Return:
JSON object containing localization strings.
- ThemerrController (ILibraryManager libraryManager, ILogger<ThemerrController> logger, IServerConfigurationManager configurationManager, ILoggerFactory loggerFactory)#
Initializes a new instance of the ThemerrController class.
- Param libraryManager:
The library manager.
- Param logger:
The logger.
- Param configurationManager:
The configuration manager.
- Param loggerFactory:
The logger factory.
Private Members
- readonly IServerConfigurationManager _configurationManager#
- readonly ILogger<ThemerrController> _logger#
- readonly ThemerrManager _themerrManager#
- class Jellyfin.Plugin.Themerr.ThemerrManager : IServerEntryPoint#
Inheritence diagram for Jellyfin::Plugin::Themerr::ThemerrManager:
Collaboration diagram for Jellyfin::Plugin::Themerr::ThemerrManager:
The main entry point for the plugin.
Public Functions
- bool ContinueDownload (string themePath, string themerrDataPath)#
Check if the theme song should be downloaded.
Various checks are performed to determine if the theme song should be downloaded.
- Param themePath:
The path to the theme song.
- Param themerrDataPath:
The path to the themerr data file.
- Return:
True to continue with downloaded, false otherwise.
- string CreateThemerrDbLink (string tmdbId, string dbType)#
Create a link to the themerr database.
- Param tmdbId:
The tmdb id.
- Param dbType:
The database type.
- Return:
The themerr database link.
- void Dispose ()#
Cleanup.
- string GetExistingThemerrDataValue (string key, string themerrDataPath)#
Get a value from the themerr data file if it exists.
- Param key:
The key to search for.
- Param themerrDataPath:
The path to the themerr data file.
- Return:
The value of the key if it exists, null otherwise.
- string GetIssueUrl (BaseItem item)#
Get ThemerrDB issue url.
This url can be used to easily add/edit theme songs in ThemerrDB.
- Param item:
The Jellyfin media object.
- Return:
The ThemerrDB issue url.
- string GetMd5Hash (string filePath)#
Get the MD5 hash of a file.
- Param filePath:
The file path.
- Return:
The MD5 hash of the file.
- string GetThemePath (BaseItem item)#
Get the path to the theme song.
- Param item:
The Jellyfin media object.
- Return:
The path to the theme song.
- string GetThemeProvider (BaseItem item)#
Get the theme provider.
- Param item:
The Jellyfin media object.
- Return:
The theme provider.
- string GetThemerrDataPath (BaseItem item)#
Get the path to the themerr data file.
- Param item:
The Jellyfin media object.
- Return:
The path to the themerr data file.
- string GetTmdbId (BaseItem item)#
Get TMDB id from an item.
- Param item:
The Jellyfin media object.
- Return:
TMDB id.
- IEnumerable<BaseItem> GetTmdbItemsFromLibrary ()#
Get all supported items from the library that have a tmdb id.
- Return:
List of BaseItem objects.
- string GetYoutubeThemeUrl (string themerrDbUrl, BaseItem item)#
Get the YouTube theme url from the themerr database.
- Param themerrDbUrl:
The themerr database url.
- Param item:
The Jellyfin media object.
- Return:
The YouTube theme url.
- void ProcessItemTheme (BaseItem item)#
Download the theme song for a media item if it doesn’t already exist.
- Param item:
The Jellyfin media object.
- Task RunAsync ()#
Run the task, asynchronously.
- Return:
A Task representing the asynchronous operation.
- bool SaveMp3 (string destination, string videoUrl)#
Save a mp3 file from a youtube video url.
- Param destination:
The destination path.
- Param videoUrl:
The YouTube video url.
- Return:
True if the file was saved successfully, false otherwise.
- bool SaveThemerrData (string themePath, string themerrDataPath, string youtubeThemeUrl)#
Save the themerr data file.
- Param themePath:
The path to the theme song.
- Param themerrDataPath:
The path to the themerr data file.
- Param youtubeThemeUrl:
The YouTube theme url.
- Return:
True if the file was saved successfully, false otherwise.
- ThemerrManager (ILibraryManager libraryManager, ILogger<ThemerrManager> logger)#
Initializes a new instance of the ThemerrManager class.
- Param libraryManager:
The library manager.
- Param logger:
The logger.
- Task UpdateAll ()#
Enumerate through all supported items in the library and downloads their theme songs as required.
- Return:
A Task representing the asynchronous operation.
- bool WaitForFile (string filePath, int timeout)#
Wait for file to exist on disk and is not locked by another process.
- Param filePath:
The file path to check.
- Param timeout:
The maximum amount of time (in milliseconds) to wait.
- Return:
True if the file exists and is not locked, false otherwise.
Private Functions
- void OnTimerElapsed ()#
Called when the plugin is loaded.
- class Jellyfin.Plugin.Themerr.ThemerrPlugin : BasePlugin<PluginConfiguration>, IHasWebPages#
Inheritence diagram for Jellyfin::Plugin::Themerr::ThemerrPlugin:
Collaboration diagram for Jellyfin::Plugin::Themerr::ThemerrPlugin:
The Themerr plugin class.
Public Functions
- IEnumerable<PluginPageInfo> GetPages ()#
Get the plugin’s html config page.
- Return:
Instance of the PluginPageInfo configuration page.
- ThemerrPlugin (IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer)#
Initializes a new instance of the ThemerrPlugin class.
- Param applicationPaths:
Instance of the IApplicationPaths interface.
- Param xmlSerializer:
Instance of the IXmlSerializer interface.
Properties
- override string Description { get; set; }#
Gets the description of the plugin.
- ThemerrPlugin Instance { get; set; }#
Gets the plugin instance.
- override string Name { get; set; }#
Gets the name of the plugin.
- class Jellyfin.Plugin.Themerr.ScheduledTasks.ThemerrTasks : IScheduledTask#
Inheritence diagram for Jellyfin::Plugin::Themerr::ScheduledTasks::ThemerrTasks:
Collaboration diagram for Jellyfin::Plugin::Themerr::ScheduledTasks::ThemerrTasks:
The Themerr scheduled task.
Public Functions
- async Task ExecuteAsync (IProgress<double> progress, CancellationToken cancellationToken)#
Execute the task, asynchronously.
- Param progress:
The progress reporter.
- Param cancellationToken:
The cancellation token.
- Return:
A Task representing the asynchronous operation.
- IEnumerable<TaskTriggerInfo> GetDefaultTriggers ()#
Gets the default triggers.
- Return:
A list of TaskTriggerInfo.
- ThemerrTasks (ILibraryManager libraryManager, ILogger<ThemerrTasks> logger, ILoggerFactory loggerFactory)#
Initializes a new instance of the ThemerrTasks class.
- Param libraryManager:
The library manager.
- Param logger:
The logger.
- Param loggerFactory:
The logger factory.
- namespace Jellyfin#
- namespace Jellyfin.Data.Enums#
- namespace Jellyfin.Plugin#
- namespace Jellyfin.Plugin.Themerr#
- namespace Jellyfin.Plugin.Themerr.Api#
- namespace Jellyfin.Plugin.Themerr.Configuration#
- namespace Jellyfin.Plugin.Themerr.ScheduledTasks#
- namespace MediaBrowser.Common.Configuration#
- namespace MediaBrowser.Common.Plugins#
- namespace MediaBrowser.Controller.Configuration#
- namespace MediaBrowser.Controller.Entities#
- namespace MediaBrowser.Controller.Entities.Movies#
- namespace MediaBrowser.Controller.Entities.TV#
- namespace MediaBrowser.Controller.Library#
- namespace MediaBrowser.Controller.Plugins#
- namespace MediaBrowser.Model.Entities#
- namespace MediaBrowser.Model.Plugins#
- namespace MediaBrowser.Model.Serialization#
- namespace MediaBrowser.Model.Tasks#
- namespace Microsoft.AspNetCore.Authorization#
- namespace Microsoft.AspNetCore.Http#
- namespace Microsoft.AspNetCore.Mvc#
- namespace Microsoft.Extensions.Logging#
- namespace Newtonsoft.Json#
- namespace System#
- namespace System.Collections#
- namespace System.Collections.Generic#
- namespace System.IO#
- namespace System.Linq#
- namespace System.Net.Http#
- namespace System.Net.Mime#
- namespace System.Reflection#
- namespace System.Threading#
- namespace System.Threading.Tasks#
- namespace YoutubeExplode#
- namespace YoutubeExplode.Videos.Streams#
- file ThemerrController.cs
- file PluginConfiguration.cs
- file ThemerrTasks.cs
- file ThemerrManager.cs
- file ThemerrPlugin.cs
- dir Jellyfin.Plugin.Themerr/Api
- dir Jellyfin.Plugin.Themerr/Configuration
- dir Jellyfin.Plugin.Themerr
- dir Jellyfin.Plugin.Themerr/ScheduledTasks