add raspberry stuff

This commit is contained in:
Patrick Neff 2025-01-08 00:00:32 +01:00
parent 036d6fdca8
commit bec0f66f0d
26 changed files with 758 additions and 564 deletions

View File

@ -349,6 +349,32 @@
"type": "github"
}
},
"gokosync": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"nixpkgs": [
"nixpkgs"
],
"systems": [
"systems"
]
},
"locked": {
"lastModified": 1736215102,
"narHash": "sha256-0aMz+9Tk/a5AxUSZLubJpuYfSdgJaCwIK/6CSwuoP2g=",
"ref": "refs/heads/master",
"rev": "ebb45e7fbbb88c16fdb9e8de0d167e6c55510600",
"revCount": 7,
"type": "git",
"url": "ssh://git@git.gaja-group.com/odie/gokosync.git"
},
"original": {
"type": "git",
"url": "ssh://git@git.gaja-group.com/odie/gokosync.git"
}
},
"guihua": {
"flake": false,
"locked": {
@ -451,6 +477,40 @@
"type": "github"
}
},
"libcamera-src": {
"flake": false,
"locked": {
"lastModified": 1725630279,
"narHash": "sha256-KH30jmHfxXq4j2CL7kv18DYECJRp9ECuWNPnqPZajPA=",
"owner": "raspberrypi",
"repo": "libcamera",
"rev": "69a894c4adad524d3063dd027f5c4774485cf9db",
"type": "github"
},
"original": {
"owner": "raspberrypi",
"repo": "libcamera",
"rev": "69a894c4adad524d3063dd027f5c4774485cf9db",
"type": "github"
}
},
"libpisp-src": {
"flake": false,
"locked": {
"lastModified": 1724944683,
"narHash": "sha256-Fo2UJmQHS855YSSKKmGrsQnJzXog1cdpkIOO72yYAM4=",
"owner": "raspberrypi",
"repo": "libpisp",
"rev": "28196ed6edcfeda88d23cc5f213d51aa6fa17bb3",
"type": "github"
},
"original": {
"owner": "raspberrypi",
"ref": "v1.0.7",
"repo": "libpisp",
"type": "github"
}
},
"luavit-meta": {
"flake": false,
"locked": {
@ -1110,6 +1170,35 @@
"url": "https://download.gaja-group.com/LuckPerms-Fabric-PlaceholderAPI-Hook.jar"
}
},
"raspberry-pi-nix": {
"inputs": {
"libcamera-src": "libcamera-src",
"libpisp-src": "libpisp-src",
"nixpkgs": [
"nixpkgs"
],
"rpi-bluez-firmware-src": "rpi-bluez-firmware-src",
"rpi-firmware-nonfree-src": "rpi-firmware-nonfree-src",
"rpi-firmware-src": "rpi-firmware-src",
"rpi-linux-6_10_12-src": "rpi-linux-6_10_12-src",
"rpi-linux-6_6_67-src": "rpi-linux-6_6_67-src",
"rpicam-apps-src": "rpicam-apps-src",
"u-boot-src": "u-boot-src"
},
"locked": {
"lastModified": 1736181271,
"narHash": "sha256-tCxJzhFxJmRlIKjLREntBYmoQr3db9P6eOE9q6dh/HA=",
"owner": "nix-community",
"repo": "raspberry-pi-nix",
"rev": "6b63ee98284cd68e86bcdb29feeb3009896f1a6b",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "raspberry-pi-nix",
"type": "github"
}
},
"root": {
"inputs": {
"catppuccin": "catppuccin",
@ -1117,6 +1206,7 @@
"flake-compat": "flake-compat",
"flake-parts": "flake-parts",
"flake-utils": "flake-utils",
"gokosync": "gokosync",
"guihua": "guihua",
"home-manager": "home-manager",
"lazydev": "lazydev",
@ -1140,11 +1230,114 @@
"nvim-spell-de-latin1-suggestions": "nvim-spell-de-latin1-suggestions",
"nvim-spell-de-utf8-dictionary": "nvim-spell-de-utf8-dictionary",
"nvim-spell-de-utf8-suggestions": "nvim-spell-de-utf8-suggestions",
"raspberry-pi-nix": "raspberry-pi-nix",
"sops-nix": "sops-nix",
"systems": "systems_2",
"vim-mcfunction": "vim-mcfunction"
}
},
"rpi-bluez-firmware-src": {
"flake": false,
"locked": {
"lastModified": 1708969706,
"narHash": "sha256-KakKnOBeWxh0exu44beZ7cbr5ni4RA9vkWYb9sGMb8Q=",
"owner": "RPi-Distro",
"repo": "bluez-firmware",
"rev": "78d6a07730e2d20c035899521ab67726dc028e1c",
"type": "github"
},
"original": {
"owner": "RPi-Distro",
"ref": "bookworm",
"repo": "bluez-firmware",
"type": "github"
}
},
"rpi-firmware-nonfree-src": {
"flake": false,
"locked": {
"lastModified": 1723266537,
"narHash": "sha256-T7eTKXqY9cxEMdab8Snda4CEOrEihy5uOhA6Fy+Mhnw=",
"owner": "RPi-Distro",
"repo": "firmware-nonfree",
"rev": "4b356e134e8333d073bd3802d767a825adec3807",
"type": "github"
},
"original": {
"owner": "RPi-Distro",
"ref": "bookworm",
"repo": "firmware-nonfree",
"type": "github"
}
},
"rpi-firmware-src": {
"flake": false,
"locked": {
"lastModified": 1727798811,
"narHash": "sha256-eavbshXGYmkYR33y9FLcQMJoAYdYTESVEy0g/RRXnb0=",
"owner": "raspberrypi",
"repo": "firmware",
"rev": "287e6a6c2d3b50eee3e2c5b2eacdd907e5cbe09a",
"type": "github"
},
"original": {
"owner": "raspberrypi",
"ref": "1.20241001",
"repo": "firmware",
"type": "github"
}
},
"rpi-linux-6_10_12-src": {
"flake": false,
"locked": {
"lastModified": 1728305462,
"narHash": "sha256-LtvNmGD1D5YYv+C9xxxddAeHw69o3OX/H9M7F663L74=",
"owner": "raspberrypi",
"repo": "linux",
"rev": "26ee50d56618c2d98100b1bc672fd201aed4d00f",
"type": "github"
},
"original": {
"owner": "raspberrypi",
"ref": "rpi-6.10.y",
"repo": "linux",
"type": "github"
}
},
"rpi-linux-6_6_67-src": {
"flake": false,
"locked": {
"lastModified": 1734790986,
"narHash": "sha256-q9swM2TmmuzbUuQnbLZk5PseKWD7/SNPwtth6bpGIqE=",
"owner": "raspberrypi",
"repo": "linux",
"rev": "811ff707533bcd67cdcd368bbd46223082009b12",
"type": "github"
},
"original": {
"owner": "raspberrypi",
"ref": "rpi-6.6.y",
"repo": "linux",
"type": "github"
}
},
"rpicam-apps-src": {
"flake": false,
"locked": {
"lastModified": 1727515047,
"narHash": "sha256-qCYGrcibOeGztxf+sd44lD6VAOGoUNwRqZDdAmcTa/U=",
"owner": "raspberrypi",
"repo": "rpicam-apps",
"rev": "a8ccf9f3cd9df49875dfb834a2b490d41d226031",
"type": "github"
},
"original": {
"owner": "raspberrypi",
"ref": "v1.5.2",
"repo": "rpicam-apps",
"type": "github"
}
},
"sops-nix": {
"inputs": {
"nixpkgs": [
@ -1258,6 +1451,19 @@
"type": "github"
}
},
"u-boot-src": {
"flake": false,
"locked": {
"lastModified": 1719857238,
"narHash": "sha256-mJ2TBy0Y5ZtcGFgtU5RKr0UDUp5FWzojbFb+o/ebRJU=",
"type": "tarball",
"url": "https://ftp.denx.de/pub/u-boot/u-boot-2024.07.tar.bz2"
},
"original": {
"type": "tarball",
"url": "https://ftp.denx.de/pub/u-boot/u-boot-2024.07.tar.bz2"
}
},
"vanillatweaks": {
"flake": false,
"locked": {

View File

@ -46,6 +46,7 @@
server = import ./modules/nixos/server;
games = import ./modules/nixos/games;
sops = import ./modules/nixos/sops;
raspberry-pi = import ./modules/nixos/raspberry-pi;
};
nixosConfigurations =
flakeLib.mkNixosConfiguration
@ -169,6 +170,13 @@
flake-compat.follows = "flake-compat";
};
};
raspberry-pi-nix = {
url = "github:nix-community/raspberry-pi-nix";
inputs = {
nixpkgs.follows = "nixpkgs";
};
};
nixgl = {
url = "github:nix-community/nixGL";
inputs.nixpkgs.follows = "nixpkgs";
@ -282,6 +290,15 @@
};
};
gokosync = {
url = "git+ssh://git@git.gaja-group.com/odie/gokosync.git";
inputs = {
nixpkgs.follows = "nixpkgs";
flake-utils.follows = "flake-utils";
systems.follows = "systems";
};
};
# Misc
csleeptimer = {
url = "git+ssh://gitea@git.niederkassel.neff-steindesign.de/odie/csleeptimer.git";

30
lib/genSslCert.nix Normal file
View File

@ -0,0 +1,30 @@
{ name, dataDir, user, domain, wantedBy ? [], Before ? [] }: { pkgs, ... }:
{
systemd.services."create-${name}-cert" = {
description = "Create a certificate for ${domain}";
script = ''
${pkgs.openssl}/bin/openssl req -x509 -newkey rsa:4096 -keyout ${domain}.key -out ${domain}.crt -nodes -subj '/CN=${domain}'
${pkgs.openssl}/bin/openssl pkcs12 -export -out ${domain}.pfx -inkey ${domain}.key -in ${domain}.crt -passout pass:
cat ${domain}.crt ${domain}.key > ${domain}.pem
chmod 644 ${domain}.crt
chmod 640 ${domain}.pfx
chmod 640 ${domain}.key
chmod 640 ${domain}.pem
'';
wantedBy = [ "multi-user.target" ] ++ wantedBy;
unitConfig = {
Before = [ "multi-user.target" ] ++ Before;
ConditionPathExists = "!${dataDir}/${domain}.pfx";
};
serviceConfig = {
User = user;
Type = "oneshot";
WorkingDirectory = dataDir;
RemainAfterExit = true;
};
};
}

View File

@ -1,3 +1,5 @@
{
nixpkgs.config.allowUnfree = true;
nixpkgs = {
config.allowUnfree = true;
};
}

View File

@ -1,74 +0,0 @@
{
vars,
mysql,
media,
...
}: let
inherit (vars) timeZone hostName domain;
datadirs = "smb://${media.host}/kodi/userdata";
in {
addons = {
unknownsources = "true";
};
services = {
devicename = "${hostName}.${domain}";
webserver = "true";
webserverauthentication = "false";
webserverusername = "kodi";
webserverpassword = "kodi";
webserverport = "8000";
webserverssl = "false";
zeroconf = "true";
wsdiscovery = "true";
upnp = "true";
upnpserver = "true";
airplay = "true";
airplayvideosupport = "true";
};
locale = {
language = "resource.language.de_de";
country = "Deutschland";
timezone = timeZone;
};
lookandfeed = {
enablerssfeeds = "false";
};
videodatabase = {
inherit (mysql) user pass host;
type = "mysql";
port = builtins.toString mysql.port;
};
musicdatabase = {
inherit (mysql) user pass host;
type = "mysql";
port = builtins.toString mysql.port;
};
videolibrary = {
importwatchedstate = "true";
importresumepoint = "true";
};
pathsubstitution = {
substitute = [
{
from = "special://profile/playlists/";
to = "${datadirs}/playlists/";
}
{
from = "special://profile/sources.xml";
to = "${datadirs}/sources.xml";
}
{
from = "special://profile/mediasources.xml";
to = "${datadirs}/mediasources.xml";
}
{
from = "special://profile/RssFeeds.xml";
to = "${datadirs}/RssFeeds.xml";
}
{
from = "special://profile/favourites.xml";
to = "${datadirs}/favourites.xml";
}
];
};
}

View File

@ -1,64 +0,0 @@
{
vars,
pkgs,
config,
lib,
...
}: let
cfg = config.mediacenter.kodi;
inherit (lib) types;
in
with lib; {
options.mediacenter.kodi = {
# enable = mkEnableOption "kodi";
media = {
host = mkOption {
type = types.str;
default = "media";
};
user = mkOption {
type = types.str;
default = "kodi";
};
pass = mkOption {
type = types.str;
default = "kodi";
};
};
mysql = {
host = mkOption {
type = types.str;
default = "localhost";
};
port = mkOption {
type = types.int;
default = 3306;
};
user = mkOption {
type = types.str;
default = "kodi";
};
pass = mkOption {
type = types.str;
default = "kodi";
};
};
};
imports = [./kodi.nix]; # import overridden kodi module
config = mkIf cfg.enable {
#programs.kodi = {
mediacenter.kodi = {
# enable = true;
package = pkgs.kodi-standalone;
settings = import ./advancedsettings.nix {inherit vars; inherit (cfg) mysql media;};
};
home.file = {
"kodi-passwords.xml" = {
target = ".kodi/userdata/passwords.xml";
text = import ./passwords.nix {
inherit (cfg) media;
};
};
};
};
}

View File

@ -1,262 +1,171 @@
{ pkgs, ... }:
{
config,
lib,
pkgs,
...
}:
with lib; let
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="*"/>
home.file = {
aelProfiles = {
text = ''
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<advanced_emulator_launcher version="1">
<control>
<update_timestamp>1659964681.6420453</update_timestamp>
</control>
<launcher>
<id>6bc2506af9af35bc7326d70b7356af51</id>
<m_name>retroarch</m_name>
<m_year />
<m_genre />
<m_developer />
<m_rating />
<m_plot />
<platform>Unknown</platform>
<categoryID>root_category</categoryID>
<application>${pkgs.retroarch}/bin/retroarch</application>
<args />
<rompath />
<romext />
<romextrapath />
<finished>False</finished>
<toggle_window>False</toggle_window>
<non_blocking>True</non_blocking>
<multidisc>True</multidisc>
<roms_base_noext />
<audit_state>Audit OFF</audit_state>
<audit_auto_dat_file />
<audit_custom_dat_file />
<audit_display_mode>All ROMs</audit_display_mode>
<launcher_display_mode>Flat mode</launcher_display_mode>
<num_roms>0</num_roms>
<num_parents>0</num_parents>
<num_clones>0</num_clones>
<num_have>0</num_have>
<num_miss>0</num_miss>
<num_unknown>0</num_unknown>
<num_extra>0</num_extra>
<timestamp_launcher>1659942644.8321931</timestamp_launcher>
<timestamp_report>0.0</timestamp_report>
<default_icon>s_icon</default_icon>
<default_fanart>s_fanart</default_fanart>
<default_banner>s_banner</default_banner>
<default_poster>s_poster</default_poster>
<default_clearlogo>s_clearlogo</default_clearlogo>
<default_controller>s_controller</default_controller>
<Asset_Prefix />
<s_icon />
<s_fanart />
<s_banner />
<s_poster />
<s_clearlogo />
<s_controller />
<s_trailer />
<roms_default_icon>s_boxfront</roms_default_icon>
<roms_default_fanart>s_fanart</roms_default_fanart>
<roms_default_banner>s_banner</roms_default_banner>
<roms_default_poster>s_flyer</roms_default_poster>
<roms_default_clearlogo>s_clearlogo</roms_default_clearlogo>
<ROM_asset_path />
<path_3dbox />
<path_title />
<path_snap />
<path_boxfront />
<path_boxback />
<path_cartridge />
<path_fanart />
<path_banner />
<path_clearlogo />
<path_flyer />
<path_map />
<path_manual />
<path_trailer />
</launcher>
</advanced_emulator_launcher>
'';
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>
target =
".kodi/userdata/addon_data/plugin.program.advanced.emulator.launcher/categories.xml";
};
germanIptv = {
text = ''
<settings version="2">
<xsl:apply-templates/>
<setting id="kodi_addon_instance_name">IPTV Deutsch</setting>
<setting id="kodi_addon_instance_enabled" default="true">true</setting>
<setting id="m3uPathType" default="true">1</setting>
<setting id="m3uPath" default="true" />
<setting id="m3uUrl">https://iptv-org.github.io/iptv/languages/deu.m3u</setting>
<setting id="m3uCache" default="true">true</setting>
<setting id="startNum" default="true">1</setting>
<setting id="numberByOrder" default="true">false</setting>
<setting id="m3uRefreshMode" default="true">0</setting>
<setting id="m3uRefreshIntervalMins" default="true">60</setting>
<setting id="m3uRefreshHour" default="true">4</setting>
<setting id="defaultProviderName" default="true" />
<setting id="enableProviderMappings" default="true">false</setting>
<setting id="providerMappingFile" default="true">special://userdata/addon_data/pvr.iptvsimple/providers/providerMappings.xml</setting>
<setting id="tvGroupMode" default="true">0</setting>
<setting id="numTvGroups" default="true">1</setting>
<setting id="oneTvGroup" default="true" />
<setting id="twoTvGroup" default="true" />
<setting id="threeTvGroup" default="true" />
<setting id="fourTvGroup" default="true" />
<setting id="fiveTvGroup" default="true" />
<setting id="customTvGroupsFile" default="true">special://userdata/addon_data/pvr.iptvsimple/channelGroups/customTVGroups-example.xml</setting>
<setting id="tvChannelGroupsOnly" default="true">false</setting>
<setting id="radioGroupMode" default="true">0</setting>
<setting id="numRadioGroups" default="true">1</setting>
<setting id="oneRadioGroup" default="true" />
<setting id="twoRadioGroup" default="true" />
<setting id="threeRadioGroup" default="true" />
<setting id="fourRadioGroup" default="true" />
<setting id="fiveRadioGroup" default="true" />
<setting id="customRadioGroupsFile" default="true">special://userdata/addon_data/pvr.iptvsimple/channelGroups/customRadioGroups-example.xml</setting>
<setting id="radioChannelGroupsOnly" default="true">false</setting>
<setting id="epgPathType" default="true">1</setting>
<setting id="epgPath" default="true" />
<setting id="epgUrl">http://10.0.20.10:3000/guide.xml</setting>
<setting id="epgCache" default="true">true</setting>
<setting id="epgTimeShift" default="true">0</setting>
<setting id="epgTSOverride" default="true">false</setting>
<setting id="epgIgnoreCaseForChannelIds" default="true">true</setting>
<setting id="useEpgGenreText" default="true">false</setting>
<setting id="genresPathType" default="true">0</setting>
<setting id="genresPath" default="true">special://userdata/addon_data/pvr.iptvsimple/genres/genreTextMappings/genres.xml</setting>
<setting id="genresUrl" default="true" />
<setting id="logoPathType" default="true">1</setting>
<setting id="logoPath" default="true" />
<setting id="logoBaseUrl" default="true" />
<setting id="useLogosLocalPathOnly" default="true">false</setting>
<setting id="logoFromEpg" default="true">1</setting>
<setting id="mediaEnabled" default="true">true</setting>
<setting id="mediaGroupByTitle" default="true">true</setting>
<setting id="mediaGroupBySeason" default="true">true</setting>
<setting id="mediaTitleSeasonEpisode" default="true">false</setting>
<setting id="mediaM3UGroupPath" default="true">0</setting>
<setting id="mediaForcePlaylist" default="true">false</setting>
<setting id="mediaVODAsRecordings" default="true">true</setting>
<setting id="timeshiftEnabled" default="true">false</setting>
<setting id="timeshiftEnabledAll" default="true">true</setting>
<setting id="timeshiftEnabledHttp" default="true">true</setting>
<setting id="timeshiftEnabledUdp" default="true">true</setting>
<setting id="timeshiftEnabledCustom" default="true">false</setting>
<setting id="catchupEnabled" default="true">false</setting>
<setting id="catchupQueryFormat" default="true" />
<setting id="catchupDays" default="true">5</setting>
<setting id="allChannelsCatchupMode" default="true">0</setting>
<setting id="catchupOverrideMode" default="true">0</setting>
<setting id="catchupCorrection" default="true">0</setting>
<setting id="catchupPlayEpgAsLive" default="true">false</setting>
<setting id="catchupWatchEpgBeginBufferMins" default="true">5</setting>
<setting id="catchupWatchEpgEndBufferMins" default="true">15</setting>
<setting id="catchupOnlyOnFinishedProgrammes" default="true">false</setting>
<setting id="transformMulticastStreamUrls" default="true">false</setting>
<setting id="udpxyHost" default="true">127.0.0.1</setting>
<setting id="udpxyPort" default="true">4022</setting>
<setting id="useFFmpegReconnect" default="true">true</setting>
<setting id="useInputstreamAdaptiveforHls" default="true">false</setting>
<setting id="defaultUserAgent" default="true" />
<setting id="defaultInputstream" default="true" />
<setting id="defaultMimeType" default="true" />
</settings>
</xsl:template>
'';
target = ".kodi/userdata/addon_data/pvr.iptvsimple/instance-settings-2.xml";
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 explicitly 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.mediacenter.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 `kodi` 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 =
oneOf [str (attrsOf valueType) (listOf valueType)]
// {
description = "attribute sets or lists of strings";
};
in
nullOr valueType;
default = null;
example = literalExpression ''
{ videolibrary.showemptytvshows = "true"; }
'';
description = ''
Configuration to write to the `advancedsettings.xml`
file in kodis userdata directory. Settings specified here will be
immutable from inside kodi and be hidden from the GUI settings dialog.
See <https://kodi.wiki/view/Advancedsettings.xml> as
reference for how settings need to be specified.
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 `sources.xml` in kodis
userdata directory.
See <https://kodi.wiki/view/Sources.xml> as
reference for how sources need to be specified.
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.
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.
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 = let
cfg = config.mediacenter.kodi;
in
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

@ -1,8 +0,0 @@
{media,...}: ''
<passwords>
<path>
<from>smb://${media.host}</from>
<to>smb://${media.user}:${media.pass}@${media.host}</to>
</path>
</passwords>
''

View File

@ -3,11 +3,9 @@
nix = {
settings = {
substituters = [
"http://nixcache.odie.home.arpa"
"https://nix-community.cachix.org"
];
trusted-public-keys = [
"nixcache.odie.home.arpa:2j5qAVmtBUSZMPWlIRS8Gn0Il9tbotJ9c2y43N0RLKU="
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
];
};

View File

@ -18,5 +18,34 @@
dates = "weekly";
options = "--delete-older-than 30d";
};
buildMachines = [
{
hostName = "nix-cache.gaja-group.intranet";
#system = "x86_64-linux";
protocol = "ssh-ng";
# if the builder supports building for multiple architectures,
# replace the previous line by, e.g.,
systems = [ "x86_64-linux" "aarch64-linux" ];
maxJobs = 4;
speedFactor = 1;
supportedFeatures = [ "nixos-test" "benchmark" "big-parallel" "kvm" ];
mandatoryFeatures = [ ];
}
];
distributedBuilds = true;
# optional, useful when the builder has a faster internet connection than yours
extraOptions = ''
builders-use-substitutes = true
'';
settings = {
substituters = [
"https://nix-community.cachix.org"
"http://nix-cache.gaja-group.intranet:5000"
];
trusted-public-keys = [
"nix-cache.gaja-group.intranet:EcUsafvI9NUrnab3DA71s2PGjAYMgct0FOvCwdYuStw="
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
];
};
};
}

View File

@ -1,13 +1,13 @@
{
config,
lib,
pkgs,
vars,
...
}: let
inherit (vars) username name sshKeys extraGroups;
{ config
, lib
, pkgs
, vars
, ...
}:
let
inherit (vars) username name sshKeys;
baseGroups = [
extraGroups = vars.extraGroups ++ [
"users"
"wheel"
"audio"
@ -16,19 +16,14 @@
"power"
"adm"
"plugdev"
];
rpiGroups =
if config.hardware.raspberry-pi.enable
then [
] ++ lib.optionals config.hardware.raspberry-pi.enable [
"i2c"
"spi"
]
else [];
allExtraGroups = baseGroups ++ rpiGroups ++ extraGroups;
];
basePackages = with pkgs; [ home-manager ];
wslPackages =
if config.wsl.enable
if ((builtins.hasAttr "wsl" config) && config.wsl.enable)
then
with pkgs; [
wslu
@ -36,7 +31,8 @@
]
else [ ];
packages = basePackages ++ wslPackages;
in {
in
{
options = {
hardware.raspberry-pi.enable = lib.mkEnableOption "raspberry pi features";
};
@ -45,8 +41,7 @@ in {
groups.${username} = { };
users = {
${username} = {
inherit packages ;
extraGroups = allExtraGroups;
inherit packages extraGroups;
name = username;
uid = 1000;
isNormalUser = true;

View File

@ -1,13 +1,14 @@
{
flakeLib,
inputs,
outputs,
vars,
...
}: let
{ flakeLib
, inputs
, outputs
, vars
, ...
}:
let
inherit (vars) username hostName;
profile = "${username}@${hostName}";
in {
in
{
imports = [
inputs.home-manager.nixosModules.home-manager
];
@ -24,5 +25,6 @@ in {
../../../profiles/home-manager/${profile}/home.nix
];
};
backupFileExtension = "backup";
};
}

View File

@ -3,5 +3,6 @@ _:
imports = [
./kodi
./jellyfin
./gokosync
];
}

View File

@ -0,0 +1,4 @@
{ inputs, ... }: {
nixpkgs.overlays = [ inputs.gokosync.overlays.default ];
imports = [ inputs.gokosync.nixosModules.default ];
}

View File

@ -1,7 +1,47 @@
{ pkgs, lib, config, ... }:
with lib;
let
cfg = config.services.jellyfin;
extraGroups = [
"users"
"audio"
"video"
"disk"
"power"
"plugdev"
] ++ lib.optionals config.hardware.raspberry-pi.enable [
"i2c"
"spi"
];
in
{
imports = [
(import ../../../../lib/genSslCert.nix {
name = "jellyfin";
inherit (cfg) dataDir user;
domain = "pi0.odie.home.arpa";
wantedBy = [ "jellyfin.service" ];
Before = [ "jellyfin.service" ];
})
];
options = {
services.jellyfin.domain = mkOption {
type = types.str;
default = "localhost";
};
};
config = {
services.jellyfin = {
enable = true;
openFirewall = true;
};
users.users.jellyfin = {
inherit extraGroups;
};
networking.firewall = {
allowedUDPPorts = [ 1900 ];
allowedTCPPorts = [ 8920 ];
};
};
}

View File

@ -1,38 +1,29 @@
{ pkgs, ... }:
{ pkgs, lib, config, ... }:
let
user = "kodi";
kodi-standalone = pkgs.kodi-wayland.withPackages
(kodiPkgs: with pkgs.kodiPackages; [
youtube
pvr-iptvsimple
keymap
inputstream-adaptive
inputstream-ffmpegdirect
requests-cache
inputstreamhelper
advanced-emulator-launcher
jellyfin
]);
extraGroups = [
"users"
"audio"
"video"
"disk"
"power"
"plugdev"
] ++ lib.optionals config.hardware.raspberry-pi.enable [
"i2c"
"spi"
];
in
{
services.cage = {
inherit user;
enable = true;
program = "${kodi-standalone}/bin/kodi-standalone";
program = "${pkgs.kodi-standalone}/bin/kodi-standalone";
};
users.users.kodi = {
inherit extraGroups;
name = user;
isNormalUser = true;
extraGroups = [
"audio"
"video"
"disk"
"plugdev"
"i2c"
"spi"
"power"
];
};
sops.secrets = {
@ -65,6 +56,7 @@ in
environment.systemPackages = with pkgs; [
#kodi-standalone
alsa-utils
/*
(retroarch.override {
cores = with libretro; [
snes9x
@ -72,5 +64,6 @@ in
nestopia
];
})
*/
];
}

View File

@ -1,5 +1,5 @@
{
"data": "ENC[AES256_GCM,data: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,iv:nFT/yFOmF81VwjM5ab5dJQYrlkDeb9Ov9dzTkMxcUqY=,tag:t2UzVTh0cbuFOZm/RWyu9A==,type:str]",
"data": "ENC[AES256_GCM,data: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,iv:OFKpx7VTY03kM9Dgf/LFkhweMwJabQ/Rf6IVdIWOAVI=,tag:WMQvgxLCmIbrDCuEyyyUOQ==,type:str]",
"sops": {
"kms": null,
"gcp_kms": null,
@ -15,10 +15,10 @@
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0cGZFU3FrZTVsNFE2ZGVn\nKzRabVo4Y2tLWEZrbW1aY1oydkZWbWFxV1FFClE5dkR2N1RFaWRvYlNwaUh0VGNx\nakVnbW84T3pGc1lGNzlLNmRMdHNzN2sKLS0tIEhZbENEUTdLQ0laL1B5Tmd3UW5h\nTWtlZFp2bXFHQ0tYK1pSV2xPSHhJeGMKV2WF/21OkoIUBSViIzX5pXZX+8OIwkuP\nb/4owrDej1otYCczA7upnO8d7r9HgdzV0PohZ9ghY+L7xMDtE2Pb0A==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-01-05T05:36:06Z",
"mac": "ENC[AES256_GCM,data:Xm8OaOdmS+XIP1vIA1XUAzM0rvoSXtVmVa3TnyCL5d0hHtJ0WHgCadiEmdngNWaizZ/HyqUipMOR5dRbZSa2KErqvtMXABT5NeoTGQOf11Ug7E+cShfMkEedFXNJ45/qntgpqcd8JqfVHHtcbSb7ccnUapMOFRygtudDb/lHADA=,iv:bVEgaFam+OC5+iGOTA4tH8vU1RRcmuc5tAT03snYgXg=,tag:VMTJjmfH7Qf1/xyQWJFEhA==,type:str]",
"lastmodified": "2025-01-06T09:21:00Z",
"mac": "ENC[AES256_GCM,data:fQZoXecKTIqGjah5sxkylLRE4xgj7wKKBUR4Vk5lf2PvSFyxlC1WUinjPl8ltqm/NTiHY+XeL0mkD0ODlo8LN/QOjz++coWeNHyx5Y8+pSjb6hC/RA3GVfmSeMi6oTJryMbJeZ0fpurXBT3CFlCX2iYdfFOymJcfi92mNYupENQ=,iv:431aHv9TrhPPa7PAEAcgZcyLkM4YMWw+QM8mYr1T4mo=,tag:OUbGZDEfxU9rEGD33L70Jg==,type:str]",
"pgp": null,
"unencrypted_suffix": "_unencrypted",
"version": "3.9.0"
"version": "3.9.1"
}
}

View File

@ -0,0 +1,8 @@
{inputs, ...}: {
imports = [
inputs.raspberry-pi-nix.nixosModules.raspberry-pi
];
nixpkgs.overlays = [
inputs.raspberry-pi-nix.overlays.core
];
}

18
overlays/jellyfin.nix Normal file
View File

@ -0,0 +1,18 @@
{
jellyfin-web = final: prev:
{
jellyfin-web = prev.jellyfin-web.overrideAttrs (finalAttrs: previousAttrs: {
installPhase = ''
runHook preInstall
# this is the important line
sed -i "s#</head>#<script src=\"configurationpage?name=skip-intro-button.js\"></script></head>#" dist/index.html
mkdir -p $out/share
cp -a dist $out/share/jellyfin-web
runHook postInstall
'';
});
};
}

View File

@ -1,14 +1,6 @@
_: final: prev: {
kodi-standalone =
final.kodi-wayland.withPackages
(kodiPkgs:
with kodiPkgs; [
youtube
pvr-iptvsimple
keymap
inputstream-adaptive
inputstream-ffmpegdirect
requests-cache
inputstreamhelper
]);
kodiPackages = prev.kodiPackages // {
advanced-emulator-launcher = final.callPackage ../pkgs/kodiPackages/advanced-emulator-launcher {};
};
kodi-standalone = final.callPackage ../pkgs/kodi {};
}

14
pkgs/kodi/default.nix Normal file
View File

@ -0,0 +1,14 @@
{ callPackage, kodi-wayland, ... }:
kodi-wayland.withPackages
(kodiPkgs: with kodiPkgs; [
youtube
pvr-iptvsimple
keymap
inputstream-adaptive
inputstream-ffmpegdirect
requests-cache
inputstreamhelper
(callPackage ../../pkgs/kodiPackages/advanced-emulator-launcher { })
jellyfin
jellycon
])

View File

@ -0,0 +1,14 @@
{ pkgs, fetchFromGitHub, ... }:
pkgs.kodiPackages.buildKodiAddon {
pname = "advanced-emulator-launcher";
namespace = "plugin.program.advanced.emulator.launcher";
version = "0.10.1";
src = fetchFromGitHub {
owner = "Wintermute0110";
repo = "plugin.program.AEL.dev";
rev = "20b082d58518883384735efbd5e9123e7c6d17d8";
hash = "sha256-+9bZ2m8qSLp+ZyhQnvZUEhYXiDQZUBuG3eJwAyLJg5k=";
};
}

View File

@ -0,0 +1,11 @@
{ outputs
, ...
}:
{
imports = [
outputs.homeManagerModules.base
outputs.homeManagerModules.shell
];
home.stateVersion = "24.11";
}

View File

@ -1,61 +1,45 @@
/*
{
outputs,
flakeLib,
vars,
...
}: {
imports = [
outputs.nixosModules.base
outputs.nixosModules.home-manager
./hardware-configuration.nix
];
networking = {
inherit (vars) hostName domain;
};
home-manager.users = flakeLib.mkNixosHomeConfiguration {inherit vars;};
}
*/
{ inputs
, pkgs
, outputs
, vars
, config
, lib
, ...
}: {
}:
let
haproxy = rec {
dataDir = "/var/lib/haproxy";
certDir = "${dataDir}/crt";
domains = [
"pi0.odie.home.arpa"
"jellyfin.odie.home.arpa"
"gokosync.odie.home.arpa"
];
};
in
{
imports = [
inputs.nixos-hardware.nixosModules.raspberry-pi-4
outputs.nixosModules.base
outputs.nixosModules.home-manager
outputs.nixosModules.mediacenter
];
outputs.nixosModules.sops
outputs.nixosModules.raspberry-pi
./hardware-configuration.nix
] ++ map (name: (import ../../../lib/genSslCert.nix {
inherit name;
inherit (config.services.haproxy) user;
dataDir = haproxy.certDir;
domain = name;
wantedBy = [ "haproxy.service" ];
Before = [ "haproxy.service" ];
})) haproxy.domains;
networking = {
inherit (vars) hostName domain;
};
boot = {
kernelPackages = pkgs.linuxPackages_rpi4;
kernelParams = [ "snd_bcm2835.enable_headphones=1" "snd_bcm2835.enable_hdmi=1" ];
initrd.availableKernelModules = [
# Allows early (earlier) modesetting for the Raspberry Pi
"vc4"
"bcm2835_dma"
"i2c_bcm2835"
"xhci_pci"
"usbhid"
"usb_storage"
];
};
fileSystems = {
"/" = {
device = "/dev/disk/by-label/NIXOS_SD";
fsType = "ext4";
options = [ "noatime" ];
};
"/media/net/hel_Public" = {
device = "hel.odie.home.arpa:/nfs/Public";
fsType = "nfs";
@ -70,28 +54,9 @@
};
};
swapDevices = [{
device = "/var/lib/swapfile";
size = 4 * 1024;
}];
hardware = {
raspberry-pi."4" = {
apply-overlays-dtmerge.enable = true;
fkms-3d.enable = true;
};
enableRedistributableFirmware = true;
};
home-manager = {
extraSpecialArgs = {
inherit inputs outputs;
};
useGlobalPkgs = true;
useUserPackages = true;
users = {
kodi = import ../../home-manager/kodi/pi0;
odie = import ../../home-manager/odie/pi0;
kodi = let profile = "kodi@pi0"; in import ../../home-manager/${profile}/home.nix;
};
};
@ -107,19 +72,62 @@
programs.zsh.enable = true;
services.udev.extraRules = ''
networking.firewall.allowedTCPPorts = [ 80 443 ];
services = {
gokosync.enable = true;
haproxy = {
enable = true;
config =
let
certs = lib.strings.concatMapStrings (d: "crt ${haproxy.certDir}/${d}.pem ") haproxy.domains;
in
''
global
maxconn 256
defaults
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend http
bind *:80
bind *:443 ssl ${certs} default-crt ${haproxy.certDir}/pi0.odie.home.arpa.pem
redirect scheme https code 301 if !{ ssl_fc }
use_backend be_jellyfin if { ssl_fc_sni jellyfin.odie.home.arpa }
use_backend be_gokosync if { ssl_fc_sni gokosync.odie.home.arpa }
default_backend be_null
backend be_null
http-request return status 204
backend be_jellyfin
option httpchk
option forwardfor
http-check send meth GET uri /health
http-check expect string Healthy
server server1 127.0.0.1:8920 maxconn 32 ssl verify none
server server2 127.0.0.1:8096 maxconn 32
backend be_gokosync
server server1 ${config.services.gokosync.addr}:${builtins.toString config.services.gokosync.port} maxconn 32
'';
};
udev.extraRules = ''
# allow access to raspi cec device for video group (and optionally register it as a systemd device, used below)
KERNEL=="vchiq", GROUP="video", MODE="0660", TAG+="systemd", ENV{SYSTEMD_ALIAS}="/dev/vchiq"
'';
system = {
stateVersion = "23.05";
};
systemd.tmpfiles.rules = [
"d ${haproxy.certDir} 0770 ${config.users.users.haproxy.name} ${config.users.groups.haproxy.name} -"
];
nixpkgs = {
hostPlatform.system = "aarch64-linux";
# Fix missing modules
# https://github.com/NixOS/nixpkgs/issues/154163
overlays = [
(final: prev: {
makeModulesClosure = x: prev.makeModulesClosure (x // { allowMissing = true; });

View File

@ -1,9 +1,13 @@
{ lib, pkgs, ... }: {
boot = {
loader.grub.enable = false;
loader.generic-extlinux-compatible.enable = true;
loader = {
grub.enable = false;
systemd-boot.enable = false;
generic-extlinux-compatible.enable = false;
};
/*
kernelPackages = pkgs.linuxPackages_rpi4;
kernelParams = [ "snd_bcm2835.enable_headphones=1" "snd_bcm2835.enable_hdmi=1" ];
kernelParams = [ "snd_bcm2835.enable_headphones=1" "snd_bcm2835.enable_hdmi=1" "gpu_mem=128" ];
initrd.availableKernelModules = lib.mkDefault [
"vc4"
"bcm2835_dma"
@ -13,6 +17,7 @@
"usbhid"
"usb_storage"
];
*/
};
swapDevices = [{
@ -28,15 +33,59 @@
};
};
raspberry-pi-nix.board = "bcm2711";
hardware = {
raspberry-pi = {
enable = true;
cec.enable = true;
"4" = {
apply-overlays-dtmerge.enable = true;
fkms-3d.enable = true;
config = {
pi4 = {
options = {
arm_boost = {
enable = true;
value = true;
};
gpu_mem = {
enable = true;
value = "256";
};
};
dt-overlays = {
vc4-kms-v3d = {
enable = true;
params = { cma-256 = { enable = true; }; };
};
};
};
all = {
options = {
arm_64bit = {
enable = true;
value = true;
};
};
base-dt-params = {
BOOT_UART = {
value = 1;
enable = true;
};
uart_2ndstage = {
value = 1;
enable = true;
};
};
dt-overlays = {
disable-bt = {
enable = true;
params = { };
};
vc4-kms-v3d = {
enable = true;
params = { };
};
};
};
};
enableRedistributableFirmware = true;
};
};
system.stateVersion = "23.11";

View File

@ -5,6 +5,6 @@ set -e
HOSTNAME=$1
nix build -L ".#nixosConfigurations.${HOSTNAME}.config.system.build.toplevel"
#nix copy --no-check-sigs --to "ssh-ng://root@${HOSTNAME}" "./result"
#ssh "root@${HOSTNAME}" nix-env -p /nix/var/nix/profiles/system --set "$(readlink ./result)"
#ssh "root@${HOSTNAME}" /nix/var/nix/profiles/system/bin/switch-to-configuration switch
nix copy --no-check-sigs --to "ssh-ng://root@${HOSTNAME}" "./result"
ssh "root@${HOSTNAME}" nix-env -p /nix/var/nix/profiles/system --set "$(readlink ./result)"
ssh "root@${HOSTNAME}" /nix/var/nix/profiles/system/bin/switch-to-configuration switch