aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wells <chris@mathematicaster.org>2024-09-03 12:13:30 -0500
committerChris Wells <chris@mathematicaster.org>2024-09-03 12:13:30 -0500
commit849bdb056feb8e064396970f79c8962b20b0c07f (patch)
tree03c220b6f90ad1f68a45bb55cfba377c11260cf9
parentd7483ed8505710033384d7fabad34470818bc760 (diff)
downloadkobo-manager-849bdb056feb8e064396970f79c8962b20b0c07f.tar
kobo-manager-849bdb056feb8e064396970f79c8962b20b0c07f.tar.gz
kobo-manager-849bdb056feb8e064396970f79c8962b20b0c07f.tar.bz2
kobo-manager-849bdb056feb8e064396970f79c8962b20b0c07f.tar.lz
kobo-manager-849bdb056feb8e064396970f79c8962b20b0c07f.tar.xz
kobo-manager-849bdb056feb8e064396970f79c8962b20b0c07f.tar.zst
kobo-manager-849bdb056feb8e064396970f79c8962b20b0c07f.zip
Re-doing a bunch of this
-rw-r--r--flake.nix7
-rw-r--r--modules/firmware/default.nix27
-rw-r--r--modules/kfmon/default.nix59
-rw-r--r--modules/koreader/default.nix57
-rw-r--r--modules/lib/file-type.nix42
-rw-r--r--modules/lib/merge-files.nix10
-rw-r--r--modules/nickel/default.nix153
-rw-r--r--modules/plato/default.nix362
-rw-r--r--overlays/default.nix16
-rw-r--r--pkgs/firmware/default.nix33
-rw-r--r--pkgs/kfmon/default.nix29
-rw-r--r--pkgs/kobo-patch/default.nix29
-rw-r--r--pkgs/kobo-utils/default.nix23
-rw-r--r--pkgs/koreader/default.nix27
-rw-r--r--pkgs/nickel-menu/default.nix26
-rw-r--r--pkgs/plato/default.nix27
16 files changed, 927 insertions, 0 deletions
diff --git a/flake.nix b/flake.nix
index a79a9e7..9649bc3 100644
--- a/flake.nix
+++ b/flake.nix
@@ -24,6 +24,13 @@
in {
packages = {
+ inherit (pkgs)
+ kfmon
+ kobo-koreader
+ kobo-utils
+ nickel-menu
+ plato
+ ;
default = myKobo.config.build.src;
# installer = myKobo.config.installer.package;
};
diff --git a/modules/firmware/default.nix b/modules/firmware/default.nix
new file mode 100644
index 0000000..609212a
--- /dev/null
+++ b/modules/firmware/default.nix
@@ -0,0 +1,27 @@
+{ config, pkgs, lib, ... }:
+with builtins // lib;
+let
+ cfg = config.firmware;
+in {
+ options.firmware = {
+ hardware = mkOption {
+ type = types.str;
+ };
+ date = mkOption {
+ type = types.str;
+ };
+ version = mkOption {
+ type = types.str;
+ };
+ hash = mkOption {
+ type = types.str;
+ };
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.kobo-firmware {
+ inherit (cfg) hardware date version hash;
+ };
+ };
+ };
+}
diff --git a/modules/kfmon/default.nix b/modules/kfmon/default.nix
new file mode 100644
index 0000000..8557a3e
--- /dev/null
+++ b/modules/kfmon/default.nix
@@ -0,0 +1,59 @@
+{ config, pkgs, lib, ... }:
+with builtins // lib;
+let
+ cfg = config.kfmon;
+ ini = pkgs.formats.ini {};
+in {
+ options.kfmon = {
+ enable = mkEnableOption "KFMon";
+
+ package = mkPackageOption pkgs "kfmon" {};
+
+ path = mkOption {
+ type = types.str;
+ readOnly = true;
+ internal = true;
+ default = ".adds/kfmon";
+ };
+
+ devicePath = mkOption {
+ type = types.str;
+ readOnly = true;
+ internal = true;
+ default = "/mnt/onboard/${cfg.path}";
+ };
+
+ file = mkOption {
+ default = {};
+ type = types.attrsOf (types.submodule (pkgs.callPackage ../lib/file-type.nix {}));
+ };
+
+ _allFiles = mkOption {
+ type = types.package;
+ internal = true;
+ readOnly = true;
+ default = (pkgs.callPackage ../lib/merge-files.nix {}) (attrValues file);
+ };
+
+ configs = mkOption {
+ type = types.attrsOf ini.type;
+ default = {};
+ description = ''
+ KFMon .ini config files. Do not touch this unless you know what you're doing!
+ '';
+ };
+ };
+
+ config = {
+ kfmon.file = mapAttrs' (n: v: {
+ name = "kfmon-config-${n}";
+ value = {
+ text = generators.toINI {} v;
+ target =
+ let
+ fixedN = if isSuffix ".ini" n then n else "${n}.ini";
+ in "config/${fixedN}";
+ };
+ });
+ };
+};
diff --git a/modules/koreader/default.nix b/modules/koreader/default.nix
new file mode 100644
index 0000000..db12219
--- /dev/null
+++ b/modules/koreader/default.nix
@@ -0,0 +1,57 @@
+{ config, pkgs, lib, ... }:
+with builtins // lib;
+let
+ cfg = config.koreader;
+in {
+ options.koreader = {
+ enable = mkEnableOption "KOReader";
+
+ package = mkPackageOption pkgs "kobo-koreader" {};
+
+ _allFiles = mkOption {
+ type = types.package;
+ readOnly = true;
+ internal = true;
+ default = (pkgs.callPackage ../lib/merge-files.nix {}) ([
+ cfg.package
+ ] ++ attrValues cfg.file);
+ };
+
+ path = mkOption {
+ type = types.str;
+ readOnly = true;
+ internal = true;
+ default = ".adds/koreader";
+ };
+
+ devicePath = mkOption {
+ type = types.str;
+ readOnly = true;
+ internal = true;
+ default = "/mnt/onboard/${cfg.path}";
+ };
+
+ file = mkOption {
+ default = {};
+ type = types.attrsOf (types.submodule (pkgs.callPackage ../lib/file-type.nix {}));
+ };
+
+ nickel = {
+ enable = mkEnableOption "Add NickelMenu entry" // { default = true; };
+ };
+ };
+
+ config = {
+ nickel.menu.item = mkIf (cfg.enable && cfg.nickel.enable) {
+ koreader = singleton {
+ location = "main";
+ label = "KOReader";
+ action = "cmd_spawn";
+ arg = [
+ "quiet"
+ "exec ${cfg.devicePath}/koreader.sh";
+ ];
+ };
+ };
+ };
+}
diff --git a/modules/lib/file-type.nix b/modules/lib/file-type.nix
new file mode 100644
index 0000000..c95c0d4
--- /dev/null
+++ b/modules/lib/file-type.nix
@@ -0,0 +1,42 @@
+{ writeTextFile, lib, ... }:
+{ name, config, ... }:
+with builtins // lib;
+let
+ sanitize = p:
+ let
+ safeChars = [ "+" "." "_" "?" "=" ] ++ lowerChars ++ upperChars ++ stringToCharacters "0123456789";
+ empties = l: genList (_: "") (length l);
+ unsafeInName = stringToCharacters (replaceStrings safeChars (empties safeChars) p;
+ in "kobo_" + replaceStrings unsafeInName (empties unsafeInName) p;
+in {
+ options = {
+ enable = mkEnableOption name // { default = true; };
+ name = mkOption {
+ type = types.str;
+ };
+ target = mkOption {
+ type = types.str;
+ default = name;
+ apply = x: if isPrefix "/" x then x else "/${x}";
+ };
+ executable = mkOption {
+ type = with types; nullOr bool;
+ default = null;
+ };
+ text = mkOption {
+ type = with types; nullOr lines;
+ default = null;
+ };
+ source = mkOption {
+ type = types.path;
+ };
+ };
+
+ config = {
+ source = mkIf (cfg.text != null) (mkDefault (writeTextFile {
+ inherit (config) text;
+ name = sanitieze name;
+ executable = config.executable == true;
+ }));
+ };
+}
diff --git a/modules/lib/merge-files.nix b/modules/lib/merge-files.nix
new file mode 100644
index 0000000..c024e0c
--- /dev/null
+++ b/modules/lib/merge-files.nix
@@ -0,0 +1,10 @@
+{ runCommandLocal, rsync, lib, ... }:
+files:
+let
+ cpFile = s: ''
+ ${lib.getExe rsync} -aL "${s.source}/" "$out${s.target}"
+ '';
+in runCommandLocal "merged-files" {} ''
+ mkdir $out
+ ${lib.concatMapStringsSep "\n" cpFile files}
+''
diff --git a/modules/nickel/default.nix b/modules/nickel/default.nix
new file mode 100644
index 0000000..c5736f0
--- /dev/null
+++ b/modules/nickel/default.nix
@@ -0,0 +1,153 @@
+{ config, pkgs, lib, options, ... }:
+with builtins // lib;
+let
+ cfg = config.nickel;
+ action = mkOption {
+ type = types.enum [
+ "cmd_spawn"
+ "cmd_output"
+ "dbg_syslog"
+ "dbg_error"
+ "dbg_msg"
+ "dbg_toast"
+ "kfmon"
+ "nickel_setting"
+ "nickel_extras"
+ "nickel_browser"
+ "nickel_misc"
+ "nickel_open"
+ "nickel_wifi"
+ "nickel_orientation"
+ "power"
+ "skip"
+ ];
+ };
+ location = mkOption {
+ type = types.enum [
+ "main"
+ "reader"
+ "browser"
+ "library"
+ "selection"
+ ];
+ };
+
+ createChainItem = { when, action, arg, ... }: concatStringsSep " : " ([ "chain_${when}" action ] ++ arg);
+ createMenuItem = { location, label, action, arg, chain, ... }: concatStringsSep "\n" (
+ singleton (
+ concatStringsSep " : " ([ "menu_item" location label action ] ++ arg)
+ ) ++ (map createChainItem chain)
+ );
+
+ createExperimental = k: v: "experimental : ${k} : ${v}";
+
+ createGenerator = { location, generator }: concatStringsSep " : " (
+ [ "generator" ] ++
+ (if isInt generator then [ "_test" (toString generator) ]
+ else splitString " " generator)
+ );
+
+in {
+ options.nickel = {
+ enable = mkEnableOption "nickelMenu";
+
+ package = mkPackageOption pkgs "nickel-menu" {};
+
+ _allFiles = mkOption {
+ type = types.package;
+ readOnly = true;
+ internal = true;
+ default = (pkgs.callPackage ../lib/merge-files.nix {}) (atrValues cfg.file);
+ };
+
+ path = mkOption {
+ type = types.str;
+ default = ".adds/nm";
+ readOnly = true;
+ internal = true;
+ # description = "Relative path to nickelMenu within src";
+ };
+
+ devicePath = mkOption {
+ type = types.str;
+ default = "/mnt/onboard/${cfg.path}";
+ readOnly = true;
+ internal = true;
+ };
+
+ file = mkOption {
+ default = {};
+ type = types.attrsOf (types.submodule (pkgs.callPackage ../lib/file-type.nix {});
+ };
+
+ menu = {
+ item = mkOption {
+ default = {};
+ description = "https://github.com/pgaskin/NickelMenu/blob/v0.5.4/res/doc";
+ type = with types; attrsOf (listOf (submodule {
+ options = {
+ inherit action location;
+ label = mkOption {
+ type = types.str;
+ };
+ arg = mkOption {
+ type = with types; nonEmptyListOf str;
+ };
+ chain = mkOption {
+ default = [];
+ type = with types; listOf (submodule {
+ options = {
+ when = mkOption {
+ type = types.enum [ "success" "failure" "always" ];
+ };
+ inherit action;
+ arg = mkOption {
+ type = with types; nonEmptyListOf str;
+ };
+ };
+ });
+ };
+ };
+ }));
+ };
+
+ experimental = mkOption {
+ default = {};
+ description = "https://github.com/pgaskin/NickelMenu/blob/v0.5.4/res/doc";
+ type = with types; attrsOf (attrsOf str);
+ };
+
+ generator = mkOption {
+ default = {};
+ description = "https://github.com/pgaskin/NickelMenu/blob/v0.5.4/res/doc";
+ type = with types; attrsOf (listOf (submodule {
+ options = {
+ inherit location;
+ generator = mkOption {
+ type = with types; either (enum [ "kfmon" "kfmon all" "kfmon gui" ]) (ints.between 0 10);
+ default = "kfmon";
+ };
+ };
+ }));
+ };
+ };
+ };
+
+ config = {
+ nickel = {
+ file = mkMerge [
+ (mapAttrs (_: v: {
+ text = concatMapStringsSep "\n" createGenerator v;
+ }) cfg.menu.generator)
+
+ (mapAttrs (_: v: {
+ text = concatStringsSep "\n" (mapAttrsToList createExperimental v);
+ }) cfg.menu.experimental)
+
+ (mapAttrs (_: v: {
+ text = concatMapStringsSep "\n" createMenuItem v;
+ }) cfg.menu.item)
+ ];
+ };
+ };
+}
diff --git a/modules/plato/default.nix b/modules/plato/default.nix
new file mode 100644
index 0000000..1886662
--- /dev/null
+++ b/modules/plato/default.nix
@@ -0,0 +1,362 @@
+{ config, pkgs, lib, options, ... }:
+with builtins // lib;
+let
+ cfg = config.plato;
+ toml = pkgs.formats.toml {};
+ # importOption = p: (import p { inherit pkgs lib; } cfg.path).option;
+in {
+ options.plato = {
+ enable = mkEnableOption "Plato";
+
+ package = mkPackageOption pkgs "plato" {};
+
+ path = mkOption {
+ type = types.str;
+ readOnly = true;
+ internal = true;
+ default = ".adds/plato";
+ };
+
+ devicePath = mkOption {
+ type = types.str;
+ readOnly = true;
+ internal = true;
+ default = "/mnt/onboard/${cfg.path}";
+ };
+
+ _allFiles = mkOption {
+ type = types.package;
+ readOnly = true;
+ internal = true;
+ default = (pkgs.callPackage ../lib/merge-files.nix {}) ([
+ cfg.package
+ ] ++ attrValues cfg.file);
+ };
+
+ file = mkOption {
+ default = {};
+ type = types.attrsOf (types.submodule (pkgs.callPackage ../lib/file-type.nix {}));
+ };
+
+ nickel = {
+ enable = mkEnableOption "Add NickelMenu option" // { default = true; };
+ };
+
+
+ settings = mkOption {
+ type = toml.type;
+ default = {};
+ description = ''
+ Contents of Settings.toml
+ '';
+ };
+
+ config = {
+ hyphenation = mkEnableOption "hyphenation" // { default = true; };
+ convertDictionaries = mkEnableOption "convert StartDict" // { default = true; };
+ setFramebufferDepth = mkEnableOption "set framebuffer's depth" // { default = true; };
+ extra = mkOption {
+ type = types.lines;
+ default = "";
+ };
+ };
+ # mkOption {
+ # type = types.lines;
+ # default = "";
+ # description = ''
+ # Contents of config.sh
+ # '';
+ # };
+
+ dictionaries = mkOption {
+ type = with types; listOf package;
+ default = [];
+ };
+
+ _dictionariesCombined = mkOption {
+ type = types.package;
+ readOnly = true;
+ internal = true;
+ default =
+ let
+ copyDicts = pkg: ''
+ find ${pkg}/share/dictd/ -type f -regex '.*\.\(dict\(\.dz\)?\|index\)' -exec cp -v {} $out/ \;
+ '';
+ in pkgs.runCommandLocal "plato-dictionaries" {} ''
+ mkdir $out
+ ${concatMapStringsSep "\n" copyDicts cfg.dictionaries}
+ '';
+ };
+
+ fonts = mkOption {
+ type = with types; listOf package;
+ default = [];
+ };
+
+ _fontsCombined = mkOption {
+ type = types.package;
+ readOnly = true;
+ internal = true;
+ default =
+ let
+ copyFonts = pkg: ''
+ find ${pkg}/share/fonts/truetype/ -type f -regex '.*\.\(ttf\|otf\)' -exec cp -v {} $out/ \;
+ '';
+ in pkgs.runCommandLocal {} ''
+ mkdir $out
+ ${concatMapStringsSep "\n" copyFonts cfg.fonts}
+ '';
+ };
+ };
+
+ config = mkMerge [
+ {
+ plato.file = {
+ "Settings.toml" = mkIf (cfg.settings != {}) {
+ source = toml.generate "Settings.toml" cfg.settings;
+ };
+
+ "config.sh" =
+ let
+ c = optional (!cfg.config.convertDictionaries) "unset PLATO_CONVERT_DICTIONARIES"
+ ++ optional (!cfg.config.setFramebufferDepth) "unset PLATO_SET_FRAMEBUFFER_DEPTH"
+ ++ optional (!cfg.config.hyphenation) "[ -d hyphenation-patters ] && rm -rf hyphenation-patterns"
+ ++ optional (cfg.config.extra != "") cfg.config.extra
+ ;
+ in mkIf (c != []) {
+ text = concatStringsSep "\n\n" c;
+ };
+
+ "_dictionaries" = {
+ target = "dictionaries";
+ source = cfg._dictionariesCombined;
+ };
+
+ "_fonts" = {
+ target = "fonts";
+ source = cfg._fontsCombined;
+ };
+ };
+
+ nickel.menu.item = mkIf (cfg.enable && cfg.nickel.enable) {
+ plato = singleton {
+ location = "main";
+ label = "Plato";
+ action = "cmd_spawn";
+ arg = [
+ "quiet"
+ "exec ${cfg.devicePath}/plato.sh"
+ ];
+ };
+ };
+ }
+ # (mkIf (cfg.enable && cfg.nickelEntry.enable {
+ # nickel.menu.item =
+ # })
+ ];
+}
+
+
+# imports = [
+# ./nickel.nix
+# ];
+
+# options.plato = {
+# enable = mkEnableOption "Plato";
+
+# path = mkOption {
+# type = types.str;
+# default = ".adds/plato";
+# description = "Relative path to Plato within src";
+# };
+
+# devPath = mkOption {
+# type = types.str;
+# default = "/mnt/onboard/${cfg.path}";
+# readOnly = true;
+# internal = true;
+# };
+
+# file = importOption ./lib/file.nix;
+# manifest = importOption ./lib/manifest.nix;
+
+# # file = mkOption {
+# # type = options.file.type;
+# # default = {};
+# # description = "Files relative to ${cfg.path}";
+# # };
+
+# # manifest = mkOption {
+# # type = options.manifest.type;
+# # default = {};
+# # description = "Manifest relative to ${cfg.path}";
+# # };
+
+# nickelEntry = mkEnableOption "Launch Plato directly from nickelMenu";
+
+# config = mkOption {
+# type = types.lines;
+# default = "";
+# description = "Plato config.sh";
+# };
+
+# hyphenation = mkEnableOption "hyphenation" // { default = true; };
+
+# convertDictionaries = mkEnableOption "convert StarDict" // { default = true; };
+
+# setFramebufferDepth = mkEnableOption "set framebuffer's depth" // { default = true; };
+
+# settings = mkOption {
+# type = toml.type;
+# default = {};
+# description = "Plato Settings.toml";
+# };
+
+# css = mkOption {
+# default = {};
+# type = with types; attrsOf lines;
+# description = ''
+# css style sheets.
+# Only use this for epub-user dictionary-user html-user
+# '';
+# };
+
+# scripts = mkOption {
+# default = {};
+# type = with types; attrsOf lines;
+# description = ''
+# Only use this for wifi-post-up wifi-post-down wifi-pre-up wifi-pre-down.
+# '';
+# # apply = mapAttrs (_: text: ''
+# # #!/bin/sh
+
+# # ${text}
+# # '')
+# };
+
+# dictionaries = mkOption {
+# type = with types; listOf package;
+# default = [];
+# };
+
+# allDictionaries = mkOption {
+# type = types.package;
+# readOnly = true;
+# internal = true;
+# default = pkgs.runCommand "PlatoDictionaries" {} (''
+# mkdir -p $out
+# '' + concatMapStringsSep "\n" (pkg: ''
+# find ${pkg}/share/dictd/ -type f -regex '.*\.\(dict\(\.dz\)?\|index\)' -exec cp -v {} $out/ \;
+# '') cfg.dictionaries
+# );
+
+# };
+
+# fonts = mkOption {
+# type = with types; listOf package;
+# default = [];
+# };
+
+# allFonts = mkOption {
+# type = types.package;
+# readOnly = true;
+# internal = true;
+# default = pkgs.runCommand "PlatoFonts" {} (''
+# mkdir -p $out
+# '' + concatMapStringsSep "\n" (pkg: ''
+# find ${pkg}/share/fonts/truetype/ -type f -regex '.*\.\(ttf\|otf\)' -exec cp -v {} $out/ \;
+# '') cfg.fonts
+# );
+
+# };
+# };
+
+# config = mkIf cfg.enable {
+# plato = {
+# config = concatStringsSep "\n\n" (
+# optional (!cfg.convertDictionaries) ''
+# unset PLATO_CONVERT_DICTIONARIES
+# ''
+# ++
+# optional (!cfg.setFramebufferDepth) ''
+# unset PLATO_SET_FRAMEBUFFER_DEPTH
+# ''
+# ++
+# optional (!cfg.hyphenation) ''
+# [ -d hyphenation-patterns ] && rm -rf hyphenation-patterns
+# ''
+# );
+# file = mkMerge [
+# (mkIf (cfg.settings != {}) {
+# "Settings.toml".source = toml.generate "Settings.toml" cfg.settings;
+# })
+
+# (mkIf (cfg.config != "") {
+# "config.sh".text = cfg.config;
+# })
+
+# (mapAttrs' (n: text:
+# let
+# n1 = if hasPrefix "css/" n then n else "css/${n}";
+# name = if hasSuffix ".css" n1 then n1 else "{n1}.css";
+# in {
+# inherit name;
+# value = { inherit text; };
+# }) cfg.css)
+
+# (mapAttrs' (n: t:
+# let
+# n1 = if hasPrefix "scripts/" n then n else "scripts/${n}";
+# name = if hasSuffix ".sh" n1 then n1 else "${n1}.sh";
+# text = if hasPrefix "#!/" t then t else "#!/bin/sh\n\n${t}";
+# in {
+# inherit name;
+# value = { inherit text; };
+# }) cfg.scripts)
+
+# {
+# dictionaries = {
+# # directory = true;
+# source = cfg.allDictionaries;
+# };
+# fonts = {
+# # directory = true;
+# source = cfg.allFonts;
+# };
+# }
+# ];
+
+# manifest = {
+# "config-sample.sh".mergeTool = _: _: "echo 'not copying config-sample.sh'";
+# "Settings-sample.toml".mergeTool = _: _: "echo 'not copying Settings-sample.toml'";
+# };
+# };
+
+# # file = mapAttrs' (n: v: {
+# # name = "plato-${n}";
+# # value = v // {
+# # target = "${cfg.path}/${v.target}";
+# # };
+# # }) cfg.file;
+
+# # manifest = mapAttrs' (n: v: {
+# # name = "plato-${n}";
+# # value = v // {
+# # targets = map (x: "${cfg.path}/${x}") v.targets;
+# # };
+# # }) cfg.manifest;
+
+# nickel.menu.item = mkIf cfg.nickelEntry {
+# plato = singleton {
+# location = "main";
+# label = "Plato";
+# action = "cmd_spawn";
+# arg = [
+# "quiet"
+# "exec ${cfg.devPath}/plato.sh"
+# ];
+# };
+# };
+
+# };
+# }
diff --git a/overlays/default.nix b/overlays/default.nix
index 561e8c2..8f47998 100644
--- a/overlays/default.nix
+++ b/overlays/default.nix
@@ -1,4 +1,20 @@
final: prev: {
+
+ kfmon = prev.callPackage ../pkgs/kfmon {};
+
+ kobo-firmware = prev.callPackage ../pkgs/firmware {};
+
+ kobo-koreader = prev.callPackage ../pkgs/koreader {};
+
+ kobo-patch = prev.callPackage ../pkgs/kobo-patch {};
+
+ kobo-utils = prev.callPackage ../pkgs/kobo-utils {};
+
+
+ nickel-menu = prev.callPackage ../pkgs/nickel-menu {};
+
+ plato = prev.callPackage ../pkgs/plato {};
+
kobo = {
src = prev.callPackage ../pkgs/source.nix {};
diff --git a/pkgs/firmware/default.nix b/pkgs/firmware/default.nix
new file mode 100644
index 0000000..813746a
--- /dev/null
+++ b/pkgs/firmware/default.nix
@@ -0,0 +1,33 @@
+{ stdenvNoCC, fetchzip, lib, ... }:
+{ hardware, date, version, hash ? "", sha256 ? "", ... }:
+stdenvNoCC.mkDerivation (finalAttrs: {
+ pname = "kobo-firmware";
+ inherit version hardware date;
+
+ src = fetchzip {
+ url = "https://ereaderfiles.kobo.com/firmwares/${finalAttrs.hardware}/${finalAttrs.date}/kobo-update-${finalAttrs.version}.zip";
+ inherit hash sha256;
+ };
+
+ phases = "installPhase";
+
+ installPhase = ''
+ runHook preInstall
+
+ cp -r $src $out
+
+ runHook postInstall
+ '';
+
+ passthru = {
+ inherit hardware date;
+ };
+
+ meta = with lib; {
+ homepage = "https://pgaskin.net/KoboStuff/kobofirmware.html";
+ description = ''
+ Kobo firmware files.
+ '';
+ platform = platforms.all;
+ };
+})
diff --git a/pkgs/kfmon/default.nix b/pkgs/kfmon/default.nix
new file mode 100644
index 0000000..6cb9c23
--- /dev/null
+++ b/pkgs/kfmon/default.nix
@@ -0,0 +1,29 @@
+{ stdenvNoCC, fetchzip, lib, ... }:
+stdenvNoCC.mkDerivation (finalAttrs: {
+ pname = "kfmon";
+ version = "1.4.6-89-g8daae26";
+
+ src = fetchzip {
+ url = "https://storage.gra.cloud.ovh.net/v1/AUTH_2ac4bfee353948ec8ea7fd1710574097/kfmon-pub/OCP-KFMon-${finalAttrs.version}.zip";
+ stripRoot = false;
+ hash = "sha256-yaFRNdnlzelLsdGdmBjeH1hx8anYFx6zpcaRpRzqDlY=";
+ };
+
+ phases = "installPhase";
+
+ installPhase = ''
+ runHook preInstall
+
+ cp -ra $src $out
+
+ chmod +x $out/.adds/kfmon/bin/*
+
+ runHook postInstall
+ '';
+
+ meta = with lib; {
+ homepage = "https://github.com/NiLuJe/kfmon";
+ platform = platforms.all;
+ license = licenses.gpl3Plus;
+ };
+})
diff --git a/pkgs/kobo-patch/default.nix b/pkgs/kobo-patch/default.nix
new file mode 100644
index 0000000..dc80f00
--- /dev/null
+++ b/pkgs/kobo-patch/default.nix
@@ -0,0 +1,29 @@
+{ stdenvNoCC, fetchzip, lib, ... }:
+{ version, hash ? "", sha256 ? "", ... }:
+stdenvNoCC.mkDerivation (finalAttrs: {
+ pname = "kobo-patch";
+ inherit version;
+
+ kobopatchVersion = "84";
+
+ src = fetchzip {
+ url = "https://github.com/pgaskin/kobopatch-patches/releases/download/v${finalAttrs.kobopatchVersion}/kobopatch_${finalAttrs.version}.zip";
+ inherit hash sha256;
+ };
+
+ phases = "installPhase";
+
+ installPhase = ''
+ runHook preInstall
+
+ cp -r $src $out
+
+ runHook postInstall
+ '';
+
+ meta = with lib; {
+ homepage = "https://github.com/pgaskin/kobopatch-patches";
+ platform = platforms.all;
+ };
+
+})
diff --git a/pkgs/kobo-utils/default.nix b/pkgs/kobo-utils/default.nix
new file mode 100644
index 0000000..9e00064
--- /dev/null
+++ b/pkgs/kobo-utils/default.nix
@@ -0,0 +1,23 @@
+{ buildGoModule, fetchFromGitHub, lib, util-linux, ... }:
+buildGoModule rec {
+ pname = "kobo-utils";
+ version = "2.2.0";
+
+ src = fetchFromGitHub {
+ owner = "pgaskin";
+ repo = "koboutils";
+ rev = "v${version}";
+ sha256 = "sha256-8w3kHj4wB2tEoZMRT5yE5sbXgnCr6dMhFN7BrJ48ouw=";
+ };
+
+ vendorHash = "sha256-0ju5ovqUXaCjv0tLSa+hDJPtaf0fdUQd5O0U5XN9AX8=";
+
+ buildInputs = [
+ util-linux
+ ];
+
+ meta = with lib; {
+ homepage = "https://github.com/pgaskin/koboutils";
+ license = licenses.mit;
+ };
+}
diff --git a/pkgs/koreader/default.nix b/pkgs/koreader/default.nix
new file mode 100644
index 0000000..fb81d71
--- /dev/null
+++ b/pkgs/koreader/default.nix
@@ -0,0 +1,27 @@
+{ stdenvNoCC, fetchzip, lib, ... }:
+stdenvNoCC.mkDerivation (finalAttrs: {
+ pname = "koreader";
+ version = "2024.07";
+
+ src = fetchzip {
+ url = "https://github.com/koreader/koreader/releases/download/v${finalAttrs.version}/koreader-kobo-v${finalAttrs.version}.zip";
+ stripRoot = false;
+ hash = "sha256-9Ga42XSCC5FUQmlAygPhhXlFs0TIdxAf3/sWBmZ5URU=";
+ };
+
+ phases = "installPhase";
+
+ installPhase = ''
+ runHook preInstall
+
+ cp -ra $src/koreader $out
+
+ runHook postInstall
+ '';
+
+ meta = with lib; {
+ homepage = "https://github.com/koreader/koreader";
+ platform = platforms.all;
+ license = licenses.agpl3Plus;
+ };
+})
diff --git a/pkgs/nickel-menu/default.nix b/pkgs/nickel-menu/default.nix
new file mode 100644
index 0000000..c151aaf
--- /dev/null
+++ b/pkgs/nickel-menu/default.nix
@@ -0,0 +1,26 @@
+{ stdenvNoCC, fetchzip, lib, ... }:
+stdenvNoCC.mkDerivation (finalAttrs: {
+ pname = "NickelMenu";
+ version = "0.5.4";
+
+ src = fetchzip {
+ url = "https://github.com/pgaskin/NickelMenu/releases/download/v${finalAttrs.version}/KoboRoot.tgz";
+ stripRoot = false;
+ hash = "sha256-BJC7zuvEHzI9zP9GR0K6psxumXcz5cDYhyCPxCsr8J0=";
+ };
+
+ phases = "installPhase";
+
+ installPhase = ''
+ runHook preInstall
+
+ cp -ra $src $out
+
+ runHook postInstall
+ '';
+
+ meta = with lib; {
+ homepage = "https://github.com/pgaskin/NickelMenu";
+ platform = platforms.all;
+ };
+})
diff --git a/pkgs/plato/default.nix b/pkgs/plato/default.nix
new file mode 100644
index 0000000..797044c
--- /dev/null
+++ b/pkgs/plato/default.nix
@@ -0,0 +1,27 @@
+{ stdenvNoCC, fetchzip, lib, ... }:
+stdenvNoCC.mkDerivation (finalAttrs: {
+ pname = "plato";
+ version = "0.9.43";
+
+ src = fetchzip {
+ url = "https://github.com/baskerville/plato/releases/download/${finalAttrs.version}/plato-${finalAttrs.version}.zip";
+ stripRoot = false;
+ hash = "sha256-1E9trfAF3w0+ix8JVDJwYjWQ/dfsLjLPmkCLJAYXkZU=";
+ };
+
+ phases = "installPhase";
+
+ installPhase = ''
+ runHook preInstall
+
+ cp -r $src $out
+
+ runHook postInstall
+ '';
+
+ meta = with lib; {
+ homepage = "https://github.com/baskerville/plato";
+ platform = platforms.all;
+ license = licenses.agpl3Plus;
+ };
+})