Table of Contents#
Overview#
LizardByte has the full documentation hosted on Read the Docs.
About#
Themerr-kodi is an add-on for Kodi. The add-on plays theme music while browsing movies and tv shows in your library.
Integrations#
Downloads#
Installation#
The recommended method for running Themerr-kodi is to use the zip in the latest release.
Zip#
The zip is cross platform, meaning all Kodi clients are supported.
Download the
service.themerr.zip
from the latest releaseMove the
service.themerr.zip
to a location your Kodi client can access.Follow the steps in how to install from ZIP file.
Source#
Caution
Installing from source is not recommended most users.
Follow the steps in Build.
Move the compiled
service.themerr.zip
to a location your Kodi client can access.Follow the steps in how to install from ZIP file.
Usage#
Minimal setup is required to use Themerr-kodi. In addition to the installation, a couple of settings can be configured.
Preferences#
Dev mode#
- Description
When enabled, Themerr-kodi will use Kodi’s notification system to output log messages.
- Default
False
Theme timeout#
- Description
The amount of time, in seconds, that Themerr-kodi will wait before playing or stopping a theme.
- Default
3
Troubleshooting#
Plugin Fails to Install#
Try clearing the contents of the following locations, or restart Kodi:
.kodi/addons/temp
.kodi/temp/temp
.kodi/temp/archive_cache
See common errors for more information.
Logging#
Per Kodi Add-on guidelines, the add-on will only log when the user enables debug logging.
Log messages from the add-on will be prefixed with Themerr:
.
Changelog#
Contributing#
Read our contribution guide in our organization level docs.
Database#
The database of themes is held in our ThemerrDB repository. To contribute to the database, follow the documentation there.
Build#
Follow the steps below to build the add-on.
Clone#
Ensure git is installed and run the following:
git clone --recurse-submodules https://github.com/lizardbyte/themerr-kodi.git cd ./themerr-kodi
Setup venv#
It is recommended to setup and activate a venv.
Install Requirements#
- Install Requirements (Optional)
python -m pip install -r requirements.txt
- Development Requirements (Required)
python -m pip install -r requirements-dev.txt
Build Add-on#
python -m scripts.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
Testing#
Flake8#
Themerr-kodi uses Flake8 for enforcing consistent code styling. Flake8 is
included in the requirements-dev.txt
.
The config file for flake8 is .flake8
. This is already included in the root of the repo and should not be modified.
- Test with Flake8
python -m flake8
Sphinx#
Themerr-kodi uses Sphinx for documentation building. Sphinx is included
in the requirements-dev.txt
.
Themerr-kodi follows numpydoc styling and formatting in
docstrings. This will be tested when building the docs. numpydoc is included in the requirements-dev.txt
.
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 .
pytest#
Themerr-kodi uses pytest for unit testing. pytest is included in the
requirements-dev.txt
.
No config is required for pytest.
- Test with pytest
python -m pytest -rxXs --tb=native --verbose --cov=src tests
Additional Information#
References#
Kodi Built-in modules#
Kodi References#
Similar Add-ons#
Notes#
Kodistubs#
Kodistubs is a project that provides stubs for the Kodi built-in modules. It makes it very easy to develop Kodi add-ons
in an IDE like PyCharm. This is included in the requirements-dev.txt
.
Python Dependencies#
Python dependencies can be added in three different ways.
Kodi add-on modules
PyPI modules
Submodules
The preferred method is to use Kodi add-on modules. Using this method allows the dependency to be included without including extra bloat.
Add the dependency to the
addon.yaml
file in theaddon['requires']['import']
section.
If the dependency is not available as a Kodi add-on module, the next preferred method is to use PyPI modules. Using this method allows the dependency to be installed from PyPI when the add-on is built.
Add the dependency to the
requirements.txt
file, and hard pin the version. e.g.my_requirement==1.2.3
If the dependency is not available as a Kodi add-on module or a PyPI module, the last resort is to use submodules.
Add the dependency as a submodule in the
third-party
directory.git submodule add <git_url>
Checkout a stable version of the dependency.
git checkout <branch, commit, or tag>
Add the branch, that dependabot should track, to the
.gitmodules
file.[submodule "third-party/<submodule_name>"] path = third-party/<submodule_name> url = <git_url> branch = <branch>
IDE Configuration#
To allow your IDE to find dependencies which are provided by Kodi, you may be able to add the
third-party/repo-scripts/script.module.<module_name>/lib
directory to your IDE’s sources list. In PyCharm, you can
right click the lib
directory and select Mark Directory as
-> Sources Root
. In VSCode, you can add the
following to your .vscode/settings.json
file:
{
"python.analysis.extraPaths": [
"./third-party/repo-scripts/script.module.<module_name>/lib"
]
}
Source Code#
Our source code is documented using the numpydoc standard.
Source#
src.service#
Main entry point for the Themerr service.
src.themerr.gui#
- class src.themerr.gui.Window(player_instance=None)[source]#
Bases:
object
A class to represent the Kodi window.
This class watches for changes to the selected item in the Kodi window and starts/stops the theme accordingly.
- Parameters:
- player_instanceOptional[player.Player]
A player instance to use for testing purposes.
Examples
>>> window = Window() >>> window.window_watcher() ... >>> window = Window(player_instance=player.Player()) >>> window.window_watcher()
- Attributes:
- loglogger.Logger
The logger object.
- monitormonitor.ThemerrMonitor
The monitor object.
- playerplayer.Player
The player object.
- item_selected_forint
The number of seconds the current item has been selected for.
- playing_item_not_selected_forint
The number of seconds the playing item has not been selected for.
- current_selected_item_idOptional[int]
The current selected item ID.
- last_selected_item_idOptional[int]
The last selected item ID.
- uuid_mappingdict
A mapping of uuids to YouTube URLs. The UUID will be the database type and the database ID, separated by an underscore. e.g. tmdb_1 This is used to cache the YouTube URLs for faster lookups.
Methods
window_watcher()
The main method that watches for changes to the Kodi window.
pre_checks()
Perform pre-checks before starting/stopping the theme.
process_kodi_id(kodi_id: str)
Process the Kodi ID and return a YouTube URL.
process_movie(kodi_id: int)
Process the Kodi ID and return a dictionary of IDs.
find_youtube_url(kodi_id: str, db_type: str)
Find the YouTube URL from the IDs.
any_true(check: Optional[bool] = None, checks: Optional[Union[List[bool], Set[bool]]] = ())
Determine if the check is True or if any of the checks are True.
is_home()
Determine if the Kodi window is the home screen.
is_movies()
Determine if the Kodi window is a movies screen.
is_movie_set()
Determine if the Kodi window is a movie set screen.
is_tv_shows()
Determine if the Kodi window is a TV shows screen.
is_seasons()
Determine if the Kodi window is a seasons screen.
is_episodes()
Determine if the Kodi window is an episodes screen.
- static any_true(check: bool | None = None, checks: List[bool] | Set[bool] | None = ())[source]#
Determine if the check is True or if any of the checks are True.
This method can be used to determine if at least one condition is True out of a list of multiple conditions.
- Parameters:
- checkOptional[bool]
The check to perform.
- checksOptional[List[bool]]
The checks to perform.
- Returns:
- bool
True if any of the checks are True, otherwise False.
Examples
>>> Window().any_true(checks=[True, False, False]) True >>> Window().any_true(checks=[False, False, False]) False >>> Window().any_true(check=True) True >>> Window().any_true(check=False) False
- find_youtube_url(kodi_id: str, db_type: str) str | None [source]#
Find YouTube URL from the Dictionary of IDs.
Given a dictionary of IDs, this method will query the Themerr DB to find the YouTube URL.
- Parameters:
- kodi_idstr
The Kodi ID to process.
- db_typestr
The database type.
- Returns:
- Optional[str]
A YouTube URL if found, otherwise None.
Examples
>>> window = Window() >>> window.find_youtube_url(kodi_id='tmdb_1', db_type='movies')
- is_episodes() bool [source]#
Check if the Kodi window is an episodes screen.
This method uses
xbmc.getCondVisibility()
andxbmc.getInfoLabel()
to determine if the Kodi window is an episodes screen.- Returns:
- bool
True if the Kodi window is an episodes screen, otherwise False.
Examples
>>> Window().is_episodes()
- is_home() bool [source]#
Check if the Kodi window is the home screen.
This method uses
xbmc.getCondVisibility()
to determine if the Kodi window is the home screen.- Returns:
- bool
True if the Kodi window is the home screen, otherwise False.
Examples
>>> Window().is_home()
- is_movie_set() bool [source]#
Check if the Kodi window is a movie set screen.
This method uses
xbmc.getCondVisibility()
andxbmc.getInfoLabel()
to determine if the Kodi window is a movie set screen.- Returns:
- bool
True if the Kodi window is a movie set screen, otherwise False.
Examples
>>> Window().is_movie_set()
- is_movies() bool [source]#
Check if the Kodi window is a movies screen.
This method uses
xbmc.getCondVisibility()
andxbmc.getInfoLabel()
to determine if the Kodi window is a movies screen.- Returns:
- bool
True if the Kodi window is a movies screen, otherwise False.
Examples
>>> Window().is_movies()
- is_seasons() bool [source]#
Check if the Kodi window is a seasons screen.
This method uses
xbmc.getCondVisibility()
andxbmc.getInfoLabel()
to determine if the Kodi window is a seasons screen.- Returns:
- bool
True if the Kodi window is a seasons screen, otherwise False.
Examples
>>> Window().is_seasons()
- is_tv_shows() bool [source]#
Check if the Kodi window is a TV shows screen.
This method uses
xbmc.getCondVisibility()
andxbmc.getInfoLabel()
to determine if the Kodi window is a TV shows screen.- Returns:
- bool
True if the Kodi window is a TV shows screen, otherwise False.
Examples
>>> Window().is_tv_shows()
- pre_checks() bool [source]#
Perform pre-checks before starting/stopping the theme.
A series of checks are performed to determine if the theme should be played.
- Returns:
- bool
True if the theme should be played, otherwise False.
Examples
>>> window = Window() >>> window.pre_checks() True
- process_kodi_id(kodi_id: str) str | None [source]#
Generate YouTube URL from a given Kodi ID.
This method takes a Kodi ID and returns a YouTube URL.
- Parameters:
- kodi_idstr
The Kodi ID to process.
- Returns:
- Optional[str]
A YouTube URL if found, otherwise None.
Examples
>>> window = Window() >>> window.process_kodi_id(kodi_id='tmdb_1')
src.themerr.locale#
- class src.themerr.locale.Locale[source]#
Bases:
object
Locale class.
This class is used to handle the localization of strings. Currently, it used only to extract strings from the
settings.xml
file.Examples
>>> Locale.settings() {30001: '...', ...}
Methods
settings()
Get the strings used in the
settings.xml
file.- static addon() dict [source]#
Get the strings used in the addon.xml file.
This method uses the
pgettext
function to extract the strings needed for the addon.xml file. Usingpgettext
allows us to add the msgctxt to the po file, which is needed for Kodi to find the correct translation.- Returns:
- dict
Dictionary of strings used in the addon.xml file.
Examples
>>> Locale.addon() {"addon.extension.description": '...', ...}
- static settings() dict [source]#
Get the strings used in the
settings.xml
file.This method uses the
pgettext
function to extract the strings needed for thesettings.xml
file. Usingpgettext
allows us to add the msgctxt to the po file, which is needed for Kodi to find the correct translation.- Returns:
- dict
Dictionary of strings used in the
settings.xml
file.
Examples
>>> Locale.settings() {30001: '...', ...}
src.themerr.logger#
- class src.themerr.logger.Logger[source]#
Bases:
object
Themerr’s logger class.
Creates a new logger to log to the Kodi log.
Examples
>>> logger = Logger()
- Attributes:
- notifierNotifier
The notifier to use to display notifications to the user.
- iconsdict
A dictionary mapping log levels to notification icons.
- level_mapperdict
A dictionary mapping log levels to strings.
Methods
log(msg: str, level: int = xbmc.LOGDEBUG)
Log a message to the Kodi log.
debug(msg: str)
Log a debug message to the Kodi log.
info(msg: str)
Log an info message to the Kodi log.
warning(msg: str)
Log a warning message to the Kodi log.
error(msg: str)
Log an error message to the Kodi log.
fatal(msg: str)
Log a fatal message to the Kodi log.
- debug(msg: str)[source]#
Log a debug message to the Kodi log.
Passes the message to the log method with the debug log level.
- Parameters:
- msgstr
The message to log.
Examples
>>> logger = Logger() >>> logger.debug("This is a debug message")
- error(msg: str)[source]#
Log an error message to the Kodi log.
Passes the message to the log method with the error log level.
- Parameters:
- msgstr
The message to log.
Examples
>>> logger = Logger() >>> logger.error("This is an error message")
- fatal(msg: str)[source]#
Log a fatal message to the Kodi log.
Passes the message to the log method with the fatal log level.
- Parameters:
- msgstr
The message to log.
Examples
>>> logger = Logger() >>> logger.fatal("This is a fatal message")
- info(msg: str)[source]#
Log an info message to the Kodi log.
Passes the message to the log method with the info log level.
- Parameters:
- msgstr
The message to log.
Examples
>>> logger = Logger() >>> logger.info("This is an info message")
- log(msg: str, level: int = 0)[source]#
Log a message to the Kodi log.
This method will log a debug message to the Kodi log. The level parameter will be included in the log message. Additionally, a notification will be displayed to the user if the addon is in development mode.
- Parameters:
- msgstr
The message to log.
- levelint
The log level to log the message at.
Examples
>>> logger = Logger() >>> logger.log("This is a debug message", xbmc.LOGDEBUG)
src.themerr.monitor#
- class src.themerr.monitor.ThemerrMonitor[source]#
Bases:
Monitor
Kodi’s monitor class.
Creates a new monitor to notify addon about changes.
Examples
>>> monitor = ThemerrMonitor()
- Attributes:
- loglogging.Logger
The logger of the ThemerrMonitor class.
Methods
abortRequested() -> bool
Check if Kodi is requesting an abort.
onSettingsChanged()
Check if Kodi settings have been modified.
src.themerr.notifier#
- class src.themerr.notifier.Notifier(heading: str | None = 'Themerr', icon: str | None = 'info', time: int | None = 5000, sound: bool | None = True)[source]#
Bases:
object
A class to show notification dialogs.
A wrapper class for the
xbmcgui.Dialog.notification
method.- Parameters:
- headingOptional[str]
The heading of the notification dialog.
- iconOptional[str]
The icon of the notification dialog.
- timeOptional[int]
The time to show the notification dialog.
- soundOptional[bool]
Whether to play a sound when showing the notification dialog.
Examples
>>> notifier = Notifier()
- Attributes:
- dialogxbmcgui.Dialog
The notification dialog.
- headingOptional[str]
The heading of the notification dialog.
- iconOptional[str]
The icon of the notification dialog.
- timeOptional[int]
The time to show the notification dialog.
- soundOptional[bool]
Whether to play a sound when showing the notification dialog.
Methods
notify(
message: str, heading: Optional[str] = None, icon: Optional[str] = None, time: Optional[int] = None, sound: Optional[bool] = None,
)
Show a notification dialog.
- notify(message: str, heading: str | None = None, icon: str | None = None, time: int | None = None, sound: bool | None = None)[source]#
Show a notification dialog.
Use the
xbmcgui.Dialog.notification
method to show a notification dialog.- Parameters:
- messagestr
The message of the notification dialog.
- headingOptional[str]
The heading of the notification dialog.
- iconOptional[str]
The icon of the notification dialog.
- timeOptional[int]
The time to show the notification dialog.
- soundOptional[bool]
Whether to play a sound when showing the notification dialog.
Examples
>>> notifier = Notifier() >>> notifier.notify("Hello World!")
src.themerr.player#
- class src.themerr.player.Player[source]#
Bases:
Player
Kodi’s player class.
Creates a new player to control playback.
Examples
>>> player = Player()
- Attributes:
- loglogging.Logger
The logger for this class.
- theme_is_playingbool
True if a theme is currently playing, False otherwise.
- theme_is_playing_forint
The number of seconds the theme has been playing for.
- theme_playing_kodi_idOptional[str]
The Kodi ID of the theme currently playing.
- theme_playing_urlOptional[str]
The URL of the theme currently playing.
Methods
ytdl_extract_url(url: str) -> Optional[str]
Extract the audio URL from a YouTube URL.
play_url(url: str, kodi_id: str, windowed: bool = False)
Play a YouTube URL.
stop()
Stop playback.
reset()
Reset the player.
- play_url(url: str, kodi_id: str, windowed: bool = False)[source]#
Play a YouTube URL.
Given a user facing YouTube URL, extract the audio URL and play it.
- Parameters:
- urlstr
The url to play.
- kodi_idstr
The Kodi ID of the item.
- windowedbool
True to play in a window, False otherwise.
Examples
>>> player = Player() >>> player.play_url(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ", kodi_id='tmdb_1')
src.themerr.plugin#
- class src.themerr.plugin.Themerr[source]#
Bases:
object
The Themerr class is the main class for the Themerr addon.
This class is responsible for starting and terminating the addon.
Examples
>>> Themerr().start()
- Attributes:
- loglogger.Logger
The logger instance for the Themerr addon.
- monitormonitor.ThemerrMonitor
The monitor instance for the Themerr addon.
- settingssettings.Settings
The settings instance for the Themerr addon.
- guigui.Window
The gui instance for the Themerr addon.
- add_onxbmcaddon.Addon
The xbmcaddon.Addon instance for the Themerr addon.
- cwdstr
The current working directory for the Themerr addon.
- lib_dirstr
The lib directory for the Themerr addon.
- threadslist
A list of threads for the Themerr addon.
Methods
start()
Start the Themerr addon.
terminate()
Terminate the Themerr addon.
src.themerr.settings#
- class src.themerr.settings.Settings[source]#
Bases:
object
Settings class to access addon settings.
This class is used to access addon settings.
Examples
>>> addon_settings = Settings()
- Attributes:
- addonxbmcaddon.Addon
addon instance
Methods
dev_mode()
Get the dev mode setting.
theme_timeout()
Get the theme timeout setting.
src.themerr.youtube#
- src.themerr.youtube.process_youtube(url: str) str | None [source]#
Get URL using youtube_dl.
The function will try to get a playable URL from the YouTube video.
- Parameters:
- urlstr
The URL of the YouTube video.
- Returns:
- Optional[str]
The URL of the audio object.
Examples
>>> process_youtube(url='https://www.youtube.com/watch?v=dQw4w9WgXcQ') ...