kodi: add module

Kodi is a media center software.
This commit is contained in:
Daniel Wagenknecht 2021-10-21 16:40:36 +02:00 committed by Robert Helgesson
parent 93b52ce0bd
commit cbc176010b
No known key found for this signature in database
GPG Key ID: 36BDAA14C2797E89
13 changed files with 372 additions and 0 deletions

3
.github/CODEOWNERS vendored
View File

@ -114,6 +114,9 @@
/modules/programs/keychain.nix @marsam
/modules/programs/kodi.nix @dwagenk
/tests/modules/programs/kodi @dwagenk
/modules/programs/lazygit.nix @kalhauge
/modules/programs/less.nix @pamplemousse

View File

@ -19,6 +19,12 @@
github = "CarlosLoboxyz";
githubId = 86011416;
};
dwagenk = {
email = "dwagenk@mailbox.org";
github = "dwagenk";
githubId = 32838899;
name = "Daniel Wagenknecht";
};
justinlovinger = {
name = "Justin Lovinger";
email = "git@justinlovinger.com";

View File

@ -2387,6 +2387,14 @@ in
A new module is available: 'programs.pandoc'.
'';
}
{
time = "2022-01-26T22:08:29+00:00";
condition = hostPlatform.isLinux;
message = ''
A new module is available: 'programs.kodi'.
'';
}
];
};
}

View File

@ -86,6 +86,7 @@ let
./programs/kakoune.nix
./programs/keychain.nix
./programs/kitty.nix
./programs/kodi.nix
./programs/lazygit.nix
./programs/less.nix
./programs/lesspipe.nix

255
modules/programs/kodi.nix Normal file
View File

@ -0,0 +1,255 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.programs.kodi;
stylesheetCommonHeader = ''
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='1.0'>
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
'';
stylesheetCommonFooter = "</xsl:stylesheet>";
stylesheetNestedTags = ''
<xsl:template match="attr[attrs]">
<xsl:variable name="elementName" select="@name"/>
<xsl:element name="{$elementName}">
<xsl:apply-templates select="attrs" />
</xsl:element>
</xsl:template>
<xsl:template match="attr[list[attrs]]">
<xsl:variable name="elementName" select="@name"/>
<xsl:for-each select="list/attrs">
<xsl:element name="{$elementName}">
<xsl:apply-templates select="." />
</xsl:element>
</xsl:for-each>
</xsl:template>
<xsl:template match="attr[not(attrs|list)]">
<xsl:variable name="elementName" select="@name"/>
<xsl:element name="{$elementName}">
<xsl:if test="$elementName='path'">
<!-- needed in sources.xml but will be used for all "path" tags -->
<xsl:attribute name="pathversion">1</xsl:attribute>
</xsl:if>
<xsl:value-of select="*/@value" />
</xsl:element>
</xsl:template>
'';
stylesheetTagsAsSettingWithId = ''
<xsl:template match='attr'>
<setting>
<xsl:attribute name="id">
<xsl:value-of select="@name" />
</xsl:attribute>
<xsl:value-of select="*/@value" />
</setting>
</xsl:template>
'';
stylesheetAdvancedSettingsRootTag = ''
<xsl:template match='/'>
<xsl:comment> Generated by Home Manager. </xsl:comment>
<advancedsettings version="1.0">
<xsl:apply-templates/>
</advancedsettings>
</xsl:template>
'';
stylesheetSourcesRootTag = ''
<xsl:template match='/'>
<xsl:comment> Generated by Home Manager. </xsl:comment>
<sources>
<xsl:apply-templates/>
</sources>
</xsl:template>
'';
stylesheetAddonSettingsRootTag = ''
<xsl:template match='/'>
<xsl:comment> Generated by Home Manager. </xsl:comment>
<settings version="2">
<xsl:apply-templates/>
</settings>
</xsl:template>
'';
attrsetToXml = attrs: name: stylesheet:
pkgs.runCommand name {
# Package splicing for libxslt does not work correctly leading to errors
# when cross-compiling. Use the version from buildPackages explicitely to
# fix this.
nativeBuildInputs = [ pkgs.buildPackages.libxslt.bin ];
xml = builtins.toXML attrs;
passAsFile = [ "xml" ];
} ''
xsltproc ${stylesheet} - < "$xmlPath" > "$out"
'';
attrsetToAdvancedSettingsXml = attrs: name:
let
stylesheet = builtins.toFile "stylesheet.xsl" ''
${stylesheetCommonHeader}
${stylesheetAdvancedSettingsRootTag}
${stylesheetNestedTags}
${stylesheetCommonFooter}
'';
in attrsetToXml attrs name stylesheet;
attrsetToSourcesXml = attrs: name:
let
stylesheet = builtins.toFile "stylesheet.xsl" ''
${stylesheetCommonHeader}
${stylesheetSourcesRootTag}
${stylesheetNestedTags}
${stylesheetCommonFooter}
'';
in attrsetToXml attrs name stylesheet;
attrsetToAddonSettingsXml = attrs: name:
let
stylesheet = builtins.toFile "stylesheet.xsl" ''
${stylesheetCommonHeader}
${stylesheetAddonSettingsRootTag}
${stylesheetTagsAsSettingWithId}
${stylesheetCommonFooter}
'';
in attrsetToXml attrs name stylesheet;
in {
meta.maintainers = [ hm.maintainers.dwagenk ];
options.programs.kodi = {
enable = mkEnableOption "Kodi";
package = mkOption {
type = types.package;
default = pkgs.kodi;
defaultText = literalExpression "pkgs.kodi";
example = literalExpression ''
{ pkgs.kodi.withPackages (exts: [ exts.pvr-iptvsimple ]) }
'';
description = ''
The <literal>kodi</literal> package to use.
Can be used to specify extensions.
'';
};
datadir = mkOption {
type = types.path;
default = "${config.home.homeDirectory}/.kodi";
defaultText =
literalExpression ''"''${config.home.homeDirectory}/.kodi"'';
example = literalExpression ''"''${config.xdg.dataHome}/kodi"'';
description = "Directory to store configuration and metadata.";
};
settings = mkOption {
type = with types;
let
valueType = either str (attrsOf valueType) // {
description = "attribute sets of strings";
};
in nullOr valueType;
default = null;
example = literalExpression ''
{ videolibrary.showemptytvshows = "true"; }
'';
description = ''
Configuration to write to the <literal>advancedsettings.xml</literal>
file in kodis userdata directory. Settings specified here will be
immutable from inside kodi and be hidden from the GUI settings dialog.
</para><para>
See <link xlink:href="https://kodi.wiki/view/Advancedsettings.xml"/> as
reference for how settings need to be specified.
</para><para>
The innermost attributes must be of type str.
'';
};
sources = mkOption {
type = with types;
let
valueType = oneOf [ str (attrsOf valueType) (listOf valueType) ] // {
description = "attribute sets or lists of strings";
};
in nullOr valueType;
default = null;
example = literalExpression ''
{
video = {
default = "movies";
source = [
{ name = "videos"; path = "/path/to/videos"; allowsharing = "true"; }
{ name = "movies"; path = "/path/to/movies"; allowsharing = "true"; }
];
};
}
'';
description = ''
Contents to populate the file <literal>sources.xml</literal> in kodis
userdata directory.
</para><para>
See <link xlink:href="https://kodi.wiki/view/Sources.xml"/> as
reference for how sources need to be specified.
</para><para>
Kodi will still show the dialogs to modify sources in the GUI and they
appear to be mutable. This however is not the case and the sources will
stay as specified via Home Manager.
</para><para>
The innermost attributes must be of type str.
'';
};
addonSettings = mkOption {
type = with types; nullOr (attrsOf (attrsOf str));
default = null;
example = literalExpression ''
{ "service.xbmc.versioncheck".versioncheck_enable = "false"; }
'';
description = ''
Attribute set with the plugin namespace as toplevel key and the plugins
settings as lower level key/value pairs.
</para><para>
Kodi will still show the settings of plugins configured via this
mechanism in the GUI and they appear to be mutable. This however is
not the case and the settings will stay as specified via Home Manager.
'';
};
};
config = mkIf cfg.enable (mkMerge [
{
assertions = [
(lib.hm.assertions.assertPlatform "programs.kodi" pkgs
lib.platforms.linux)
];
home.packages = [ cfg.package ];
home.sessionVariables = { KODI_DATA = cfg.datadir; };
}
(mkIf (cfg.settings != null) {
home.file."${cfg.datadir}/userdata/advancedsettings.xml".source =
attrsetToAdvancedSettingsXml cfg.settings "kodi-advancedsettings.xml";
})
(mkIf (cfg.sources != null) {
home.file."${cfg.datadir}/userdata/sources.xml".source =
attrsetToSourcesXml cfg.sources "kodi-sources.xml";
})
(mkIf (cfg.addonSettings != null) {
home.file = mapAttrs' (k: v:
attrsets.nameValuePair
("${cfg.datadir}/userdata/addon_data/${k}/settings.xml") {
source = attrsetToAddonSettingsXml v "kodi-addon-${k}-settings.xml";
}) cfg.addonSettings;
})
]);
}

View File

@ -123,6 +123,7 @@ import nmt {
./modules/programs/gnome-terminal
./modules/programs/hexchat
./modules/programs/i3status-rust
./modules/programs/kodi
./modules/programs/mangohud
./modules/programs/ncmpcpp-linux
./modules/programs/neovim # Broken package dependency on Darwin.

View File

@ -0,0 +1,5 @@
{
kodi-example-addon-settings = ./example-addon-settings.nix;
kodi-example-settings = ./example-settings.nix;
kodi-example-sources = ./example-sources.nix;
}

View File

@ -0,0 +1,4 @@
<!-- Generated by Home Manager. -->
<settings version="2">
<setting id="versioncheck_enable">false</setting>
</settings>

View File

@ -0,0 +1,18 @@
{ config, ... }:
{
programs.kodi = {
enable = true;
package = config.lib.test.mkStubPackage { };
addonSettings = {
"service.xbmc.versioncheck".versioncheck_enable = "false";
};
};
nmt.script = ''
assertFileContent \
home-files/.kodi/userdata/addon_data/service.xbmc.versioncheck/settings.xml \
${./example-addon-settings-expected.xml}
'';
}

View File

@ -0,0 +1,6 @@
<!-- Generated by Home Manager. -->
<advancedsettings version="1.0">
<videolibrary>
<showemptytvshows>true</showemptytvshows>
</videolibrary>
</advancedsettings>

View File

@ -0,0 +1,16 @@
{ config, ... }:
{
programs.kodi = {
enable = true;
package = config.lib.test.mkStubPackage { };
settings = { videolibrary.showemptytvshows = "true"; };
};
nmt.script = ''
assertFileContent \
home-files/.kodi/userdata/advancedsettings.xml \
${./example-settings-expected.xml}
'';
}

View File

@ -0,0 +1,16 @@
<!-- Generated by Home Manager. -->
<sources>
<video>
<default>movies</default>
<source>
<allowsharing>true</allowsharing>
<name>videos</name>
<path pathversion="1">/path/to/videos</path>
</source>
<source>
<allowsharing>true</allowsharing>
<name>movies</name>
<path pathversion="1">/path/to/movies</path>
</source>
</video>
</sources>

View File

@ -0,0 +1,33 @@
{ config, ... }:
{
programs.kodi = {
enable = true;
package = config.lib.test.mkStubPackage { };
sources = {
video = {
default = "movies";
source = [
{
name = "videos";
path = "/path/to/videos";
allowsharing = "true";
}
{
name = "movies";
path = "/path/to/movies";
allowsharing = "true";
}
];
};
};
};
nmt.script = ''
assertFileContent \
home-files/.kodi/userdata/sources.xml \
${./example-sources-expected.xml}
'';
}