diff --git a/flake-old.nix b/flake-old.nix new file mode 100644 index 0000000..4865558 --- /dev/null +++ b/flake-old.nix @@ -0,0 +1,264 @@ +{ + description = "Nixos config flake"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11"; + nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable"; + nixos-hardware.url = "github:NixOS/nixos-hardware/master"; + home-manager = { + url = "github:nix-community/home-manager/release-25.11"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + sops-nix = { + url = "github:Mic92/sops-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + disko.url = "github:nix-community/disko"; + disko.inputs.nixpkgs.follows = "nixpkgs"; + plasma-manager = { + url = "github:pjones/plasma-manager"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.home-manager.follows = "home-manager"; + }; + firefox-addons = { + url = "gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + hyprland = { + url = "github:hyprwm/Hyprland"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + hyprland-plugins = { + url = "github:hyprwm/hyprland-plugins"; + inputs.hyprland.follows = "hyprland"; + }; + nixos-cosmic = { + url = "github:lilyinstarlight/nixos-cosmic"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + dzgui-nix = { + url = "github:lelgenio/dzgui-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + audio = { + url = "github:polygon/audio.nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + nix-minecraft.url = "github:Infinidoge/nix-minecraft"; + nix-minecraft.inputs.nixpkgs.follows = "nixpkgs"; + }; + + outputs = { + self, + nixpkgs, + nixpkgs-unstable, + nixos-hardware, + home-manager, + nixos-cosmic, + audio, + ... + } @ inputs: let + system = "x86_64-linux"; + overlay-unstable = final: prev: { + unstable = import nixpkgs-unstable { + system = prev.system; + config.allowUnfree = true; + }; + }; + in { + nixosConfigurations = { + comfy-station = nixpkgs.lib.nixosSystem { + inherit system; + specialArgs = { + inherit inputs; + isHM = false; + }; + modules = [ + ({...}: {nixpkgs.overlays = [overlay-unstable self.overlays.default audio.overlays.default];}) + ({...}: {nixpkgs.config.allowUnfree = true;}) + nixos-hardware.nixosModules.msi-b550-a-pro + inputs.sops-nix.nixosModules.sops + inputs.nix-minecraft.overlay + inputs.nix-minecraft.nixosModules.minecraft-servers + ./modules + ./hosts/comfy-station/configuration.nix + ]; + }; + monolith = nixpkgs.lib.nixosSystem { + inherit system; + specialArgs = { + inherit inputs; + isHM = false; + }; + modules = [ + ({...}: { + nixpkgs.overlays = [ + overlay-unstable + self.overlays.default + audio.overlays.default + inputs.nix-minecraft.overlay + ]; + }) + ({...}: { + nixpkgs.config.allowUnfree = true; + nixpkgs.config.nvidia.acceptLicense = true; + }) + { + nix.settings = { + substituters = ["https://cosmic.cachix.org/"]; + trusted-public-keys = ["cosmic.cachix.org-1:Dya9IyXD4xdBehWjrkPv6rtxpmMdRel02smYzA85dPE="]; + }; + } + nixos-hardware.nixosModules.lenovo-thinkpad-t14-amd-gen1 + inputs.sops-nix.nixosModules.sops + nixos-cosmic.nixosModules.default + inputs.nix-minecraft.nixosModules.minecraft-servers + ./fixes/plasma-fix.nix + ./modules + ./hosts/monolith/configuration.nix + ]; + }; + harbor = nixpkgs.lib.nixosSystem { + inherit system; + specialArgs = { + inherit inputs; + isHM = false; + }; + modules = [ + ({...}: { + nixpkgs.overlays = [ + overlay-unstable + self.overlays.default + audio.overlays.default + inputs.nix-minecraft.overlay + ]; + }) + ({...}: {nixpkgs.config.allowUnfree = true;}) + inputs.sops-nix.nixosModules.sops + inputs.disko.nixosModules.disko + inputs.nix-minecraft.nixosModules.minecraft-servers + ./modules + ./hosts/harbor/configuration.nix + ]; + }; + vm = nixpkgs.lib.nixosSystem { + inherit system; + specialArgs = { + inherit inputs; + }; + modules = [ + ./hosts/vm/configuration.nix + ]; + }; + }; + homeConfigurations."jonas@comfy-station" = home-manager.lib.homeManagerConfiguration { + pkgs = nixpkgs.legacyPackages.${system}; + + # Specify your home configuration modules here, for example, + # the path to your home.nix. + modules = [ + ({...}: {nixpkgs.overlays = [overlay-unstable self.overlays.default audio.overlays.default];}) + ({...}: {nixpkgs.config.allowUnfree = true;}) + inputs.plasma-manager.homeManagerModules.plasma-manager + inputs.sops-nix.homeManagerModules.sops + ./modules + (./home + "/jonas@comfy-station.nix") + ]; + + # Optionally use extraSpecialArgs + # to pass through arguments to home.nix + extraSpecialArgs = { + inherit inputs; + isHM = true; + }; + }; + homeConfigurations."jonas@harbor" = home-manager.lib.homeManagerConfiguration { + pkgs = nixpkgs.legacyPackages.${system}; + + # Specify your home configuration modules here, for example, + # the path to your home.nix. + modules = [ + ({...}: {nixpkgs.overlays = [overlay-unstable self.overlays.default audio.overlays.default];}) + ({...}: {nixpkgs.config.allowUnfree = true;}) + inputs.plasma-manager.homeManagerModules.plasma-manager + inputs.sops-nix.homeManagerModules.sops + ./modules + (./home + "/jonas@harbor.nix") + ]; + + # Optionally use extraSpecialArgs + # to pass through arguments to home.nix + extraSpecialArgs = { + inherit inputs; + isHM = true; + }; + }; + homeConfigurations."jonas@monolith" = home-manager.lib.homeManagerConfiguration { + pkgs = nixpkgs.legacyPackages.${system}; + + # Specify your home configuration modules here, for example, + # the path to your home.nix. + modules = [ + ({...}: {nixpkgs.overlays = [overlay-unstable self.overlays.default audio.overlays.default];}) + ({...}: {nixpkgs.config.allowUnfree = true;}) + inputs.plasma-manager.homeManagerModules.plasma-manager + inputs.sops-nix.homeManagerModules.sops + ./modules + (./home + "/jonas@monolith.nix") + ]; + + # Optionally use extraSpecialArgs + # to pass through arguments to home.nix + extraSpecialArgs = { + inherit inputs; + isHM = true; + }; + }; + homeConfigurations."admin-jroeger" = home-manager.lib.homeManagerConfiguration { + pkgs = nixpkgs.legacyPackages.${system}; + + # Specify your home configuration modules here, for example, + # the path to your home.nix. + modules = [ + ({...}: {nixpkgs.overlays = [overlay-unstable self.overlays.default audio.overlays.default];}) + ({...}: {nixpkgs.config.allowUnfree = true;}) + inputs.plasma-manager.homeManagerModules.plasma-manager + inputs.sops-nix.homeManagerModules.sops + ./modules + ./home/admin-jroeger.nix + ]; + + # Optionally use extraSpecialArgs + # to pass through arguments to home.nix + extraSpecialArgs = { + inherit inputs; + isHM = true; + }; + }; + + devShells.${system} = { + bulk-transcode = (import ./pkgs/bulk-transcode/shell.nix) {pkgs = nixpkgs.legacyPackages.${system};}; + spotify-shortcuts = (import ./pkgs/spotify-shortcuts/shell.nix) {pkgs = nixpkgs.legacyPackages.${system};}; + }; + + overlays.default = import ./pkgs; + + templates = { + rust = { + path = ./templates/rust; + description = "A simple rust binary template"; + welcomeText = '' + # Rust template + This is a simple rust binary template. + To build the project run `cargo build`. + To run the project run `cargo run`. + Before running nix build, make sure to run `cargo generate-lockfile` first. + ''; + }; + cmake-c = { + path = ./templates/cmake-c; + description = "A simple cmake c project."; + }; + }; + }; +} diff --git a/flake.lock b/flake.lock index 7b2a0a5..9ed091a 100644 --- a/flake.lock +++ b/flake.lock @@ -1,38 +1,5 @@ { "nodes": { - "aquamarine": { - "inputs": { - "hyprutils": [ - "hyprland", - "hyprutils" - ], - "hyprwayland-scanner": [ - "hyprland", - "hyprwayland-scanner" - ], - "nixpkgs": [ - "hyprland", - "nixpkgs" - ], - "systems": [ - "hyprland", - "systems" - ] - }, - "locked": { - "lastModified": 1773436376, - "narHash": "sha256-OUPRrprbgN27BXHuWkMAPSCfLLQ/uwpWghEfKYN2iAg=", - "owner": "hyprwm", - "repo": "aquamarine", - "rev": "43f10d24391692bba3d762931ee35e7f17f8e8b8", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "aquamarine", - "type": "github" - } - }, "audio": { "inputs": { "mucap": "mucap", @@ -142,22 +109,6 @@ } }, "flake-compat": { - "flake": false, - "locked": { - "lastModified": 1767039857, - "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", - "owner": "NixOS", - "repo": "flake-compat", - "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", - "type": "github" - }, - "original": { - "owner": "NixOS", - "repo": "flake-compat", - "type": "github" - } - }, - "flake-compat_2": { "flake": false, "locked": { "lastModified": 1747046372, @@ -173,41 +124,21 @@ "type": "github" } }, - "flake-compat_3": { - "flake": false, - "locked": { - "lastModified": 1746162366, - "narHash": "sha256-5SSSZ/oQkwfcAz/o/6TlejlVGqeK08wyREBQ5qFFPhM=", - "owner": "nix-community", - "repo": "flake-compat", - "rev": "0f158086a2ecdbb138cd0429410e44994f1b7e4b", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "flake-compat", - "type": "github" - } - }, - "gitignore": { + "flake-parts": { "inputs": { - "nixpkgs": [ - "hyprland", - "pre-commit-hooks", - "nixpkgs" - ] + "nixpkgs-lib": "nixpkgs-lib" }, "locked": { - "lastModified": 1709087332, - "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "lastModified": 1772408722, + "narHash": "sha256-rHuJtdcOjK7rAHpHphUb1iCvgkU3GpfvicLMwwnfMT0=", "owner": "hercules-ci", - "repo": "gitignore.nix", - "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "repo": "flake-parts", + "rev": "f20dc5d9b8027381c474144ecabc9034d6a839a3", "type": "github" }, "original": { "owner": "hercules-ci", - "repo": "gitignore.nix", + "repo": "flake-parts", "type": "github" } }, @@ -232,354 +163,18 @@ "type": "github" } }, - "hyprcursor": { - "inputs": { - "hyprlang": [ - "hyprland", - "hyprlang" - ], - "nixpkgs": [ - "hyprland", - "nixpkgs" - ], - "systems": [ - "hyprland", - "systems" - ] - }, + "import-tree": { "locked": { - "lastModified": 1772461003, - "narHash": "sha256-pVICsV7FtcEeVwg5y/LFh3XFUkVJninm/P1j/JHzEbM=", - "owner": "hyprwm", - "repo": "hyprcursor", - "rev": "b62396457b9cfe2ebf24fe05404b09d2a40f8ed7", + "lastModified": 1773693634, + "narHash": "sha256-BtZ2dtkBdSUnFPPFc+n0kcMbgaTxzFNPv2iaO326Ffg=", + "owner": "vic", + "repo": "import-tree", + "rev": "c41e7d58045f9057880b0d85e1152d6a4430dbf1", "type": "github" }, "original": { - "owner": "hyprwm", - "repo": "hyprcursor", - "type": "github" - } - }, - "hyprgraphics": { - "inputs": { - "hyprutils": [ - "hyprland", - "hyprutils" - ], - "nixpkgs": [ - "hyprland", - "nixpkgs" - ], - "systems": [ - "hyprland", - "systems" - ] - }, - "locked": { - "lastModified": 1772461523, - "narHash": "sha256-mI6A51do+hEUzeJKk9YSWfVHdI/SEEIBi2tp5Whq5mI=", - "owner": "hyprwm", - "repo": "hyprgraphics", - "rev": "7d63c04b4a2dd5e59ef943b4b143f46e713df804", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "hyprgraphics", - "type": "github" - } - }, - "hyprland": { - "inputs": { - "aquamarine": "aquamarine", - "hyprcursor": "hyprcursor", - "hyprgraphics": "hyprgraphics", - "hyprland-guiutils": "hyprland-guiutils", - "hyprland-protocols": "hyprland-protocols", - "hyprlang": "hyprlang", - "hyprutils": "hyprutils", - "hyprwayland-scanner": "hyprwayland-scanner", - "hyprwire": "hyprwire", - "nixpkgs": [ - "nixpkgs" - ], - "pre-commit-hooks": "pre-commit-hooks", - "systems": "systems", - "xdph": "xdph" - }, - "locked": { - "lastModified": 1773926276, - "narHash": "sha256-dasCo1RATJvJWjPaVkbXPvjbWE+4f69bnRNGwtsh7Ao=", - "owner": "hyprwm", - "repo": "Hyprland", - "rev": "ad46ff635bcf7b4877b03e97d8e85468f025f4a1", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "Hyprland", - "type": "github" - } - }, - "hyprland-guiutils": { - "inputs": { - "aquamarine": [ - "hyprland", - "aquamarine" - ], - "hyprgraphics": [ - "hyprland", - "hyprgraphics" - ], - "hyprlang": [ - "hyprland", - "hyprlang" - ], - "hyprtoolkit": "hyprtoolkit", - "hyprutils": [ - "hyprland", - "hyprutils" - ], - "hyprwayland-scanner": [ - "hyprland", - "hyprwayland-scanner" - ], - "nixpkgs": [ - "hyprland", - "nixpkgs" - ], - "systems": [ - "hyprland", - "systems" - ] - }, - "locked": { - "lastModified": 1772467975, - "narHash": "sha256-kipyuDBxrZq+beYpZqWzGvFWm4QbayW9agAvi94vDXY=", - "owner": "hyprwm", - "repo": "hyprland-guiutils", - "rev": "5e1c6b9025aaf4d578f3eff7c0eb1f0c197a9507", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "hyprland-guiutils", - "type": "github" - } - }, - "hyprland-plugins": { - "inputs": { - "hyprland": [ - "hyprland" - ], - "nixpkgs": [ - "hyprland-plugins", - "hyprland", - "nixpkgs" - ], - "systems": [ - "hyprland-plugins", - "hyprland", - "systems" - ] - }, - "locked": { - "lastModified": 1771865848, - "narHash": "sha256-xwNa+1D8WPsDnJtUofDrtyDCZKZotbUymzV/R5s+M0I=", - "owner": "hyprwm", - "repo": "hyprland-plugins", - "rev": "b85a56b9531013c79f2f3846fd6ee2ff014b8960", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "hyprland-plugins", - "type": "github" - } - }, - "hyprland-protocols": { - "inputs": { - "nixpkgs": [ - "hyprland", - "nixpkgs" - ], - "systems": [ - "hyprland", - "systems" - ] - }, - "locked": { - "lastModified": 1772460177, - "narHash": "sha256-/6G/MsPvtn7bc4Y32pserBT/Z4SUUdBd4XYJpOEKVR4=", - "owner": "hyprwm", - "repo": "hyprland-protocols", - "rev": "1cb6db5fd6bb8aee419f4457402fa18293ace917", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "hyprland-protocols", - "type": "github" - } - }, - "hyprlang": { - "inputs": { - "hyprutils": [ - "hyprland", - "hyprutils" - ], - "nixpkgs": [ - "hyprland", - "nixpkgs" - ], - "systems": [ - "hyprland", - "systems" - ] - }, - "locked": { - "lastModified": 1772459629, - "narHash": "sha256-/iwvNUYShmmnwmz/czEUh6+0eF5vCMv0xtDW0STPIuM=", - "owner": "hyprwm", - "repo": "hyprlang", - "rev": "7615ee388de18239a4ab1400946f3d0e498a8186", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "hyprlang", - "type": "github" - } - }, - "hyprtoolkit": { - "inputs": { - "aquamarine": [ - "hyprland", - "hyprland-guiutils", - "aquamarine" - ], - "hyprgraphics": [ - "hyprland", - "hyprland-guiutils", - "hyprgraphics" - ], - "hyprlang": [ - "hyprland", - "hyprland-guiutils", - "hyprlang" - ], - "hyprutils": [ - "hyprland", - "hyprland-guiutils", - "hyprutils" - ], - "hyprwayland-scanner": [ - "hyprland", - "hyprland-guiutils", - "hyprwayland-scanner" - ], - "nixpkgs": [ - "hyprland", - "hyprland-guiutils", - "nixpkgs" - ], - "systems": [ - "hyprland", - "hyprland-guiutils", - "systems" - ] - }, - "locked": { - "lastModified": 1772462885, - "narHash": "sha256-5pHXrQK9zasMnIo6yME6EOXmWGFMSnCITcfKshhKJ9I=", - "owner": "hyprwm", - "repo": "hyprtoolkit", - "rev": "9af245a69fa6b286b88ddfc340afd288e00a6998", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "hyprtoolkit", - "type": "github" - } - }, - "hyprutils": { - "inputs": { - "nixpkgs": [ - "hyprland", - "nixpkgs" - ], - "systems": [ - "hyprland", - "systems" - ] - }, - "locked": { - "lastModified": 1773436263, - "narHash": "sha256-n+2xFJngUkBqUJD5FsbVnYEHBTyDFSqtBIwQIGPXWWo=", - "owner": "hyprwm", - "repo": "hyprutils", - "rev": "5e228db6821380a5875d5643176c5c46a47b8134", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "hyprutils", - "type": "github" - } - }, - "hyprwayland-scanner": { - "inputs": { - "nixpkgs": [ - "hyprland", - "nixpkgs" - ], - "systems": [ - "hyprland", - "systems" - ] - }, - "locked": { - "lastModified": 1772459835, - "narHash": "sha256-978jRz/y/9TKmZb/qD4lEYHCQGHpEXGqy+8X2lFZsak=", - "owner": "hyprwm", - "repo": "hyprwayland-scanner", - "rev": "0a692d4a645165eebd65f109146b8861e3a925e7", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "hyprwayland-scanner", - "type": "github" - } - }, - "hyprwire": { - "inputs": { - "hyprutils": [ - "hyprland", - "hyprutils" - ], - "nixpkgs": [ - "hyprland", - "nixpkgs" - ], - "systems": [ - "hyprland", - "systems" - ] - }, - "locked": { - "lastModified": 1773074819, - "narHash": "sha256-qRqYnXiKoJLRTcfaRukn7EifmST2IVBUMZOeZMAc5UA=", - "owner": "hyprwm", - "repo": "hyprwire", - "rev": "f68afd0e73687598cc2774804fedad76693046f0", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "hyprwire", + "owner": "vic", + "repo": "import-tree", "type": "github" } }, @@ -653,11 +248,11 @@ }, "nix-minecraft": { "inputs": { - "flake-compat": "flake-compat_2", + "flake-compat": "flake-compat", "nixpkgs": [ "nixpkgs" ], - "systems": "systems_2" + "systems": "systems" }, "locked": { "lastModified": 1774407052, @@ -673,29 +268,6 @@ "type": "github" } }, - "nixos-cosmic": { - "inputs": { - "flake-compat": "flake-compat_3", - "nixpkgs": [ - "nixpkgs" - ], - "nixpkgs-stable": "nixpkgs-stable", - "rust-overlay": "rust-overlay_2" - }, - "locked": { - "lastModified": 1751591814, - "narHash": "sha256-A4lgvuj4v+Pr8MniXz1FBG0DXOygi8tTECR+j53FMhM=", - "owner": "lilyinstarlight", - "repo": "nixos-cosmic", - "rev": "fef2d0c78c4e4d6c600a88795af193131ff51bdc", - "type": "github" - }, - "original": { - "owner": "lilyinstarlight", - "repo": "nixos-cosmic", - "type": "github" - } - }, "nixos-hardware": { "locked": { "lastModified": 1773533765, @@ -728,19 +300,18 @@ "type": "github" } }, - "nixpkgs-stable": { + "nixpkgs-lib": { "locked": { - "lastModified": 1751048012, - "narHash": "sha256-MYbotu4UjWpTsq01wglhN5xDRfZYLFtNk7SBY0BcjkU=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "a684c58d46ebbede49f280b653b9e56100aa3877", + "lastModified": 1772328832, + "narHash": "sha256-e+/T/pmEkLP6BHhYjx6GmwP5ivonQQn0bJdH9YrRB+Q=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "c185c7a5e5dd8f9add5b2f8ebeff00888b070742", "type": "github" }, "original": { - "owner": "NixOS", - "ref": "nixos-24.11", - "repo": "nixpkgs", + "owner": "nix-community", + "repo": "nixpkgs.lib", "type": "github" } }, @@ -760,67 +331,19 @@ "type": "github" } }, - "plasma-manager": { - "inputs": { - "home-manager": [ - "home-manager" - ], - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1772361940, - "narHash": "sha256-B1Cz+ydL1iaOnGlwOFld/C8lBECPtzhiy/pP93/CuyY=", - "owner": "pjones", - "repo": "plasma-manager", - "rev": "a4b33606111c9c5dcd10009042bb710307174f51", - "type": "github" - }, - "original": { - "owner": "pjones", - "repo": "plasma-manager", - "type": "github" - } - }, - "pre-commit-hooks": { - "inputs": { - "flake-compat": "flake-compat", - "gitignore": "gitignore", - "nixpkgs": [ - "hyprland", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1772893680, - "narHash": "sha256-JDqZMgxUTCq85ObSaFw0HhE+lvdOre1lx9iI6vYyOEs=", - "owner": "cachix", - "repo": "git-hooks.nix", - "rev": "8baab586afc9c9b57645a734c820e4ac0a604af9", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "git-hooks.nix", - "type": "github" - } - }, "root": { "inputs": { "audio": "audio", "disko": "disko", "dzgui-nix": "dzgui-nix", "firefox-addons": "firefox-addons", + "flake-parts": "flake-parts", "home-manager": "home-manager", - "hyprland": "hyprland", - "hyprland-plugins": "hyprland-plugins", + "import-tree": "import-tree", "nix-minecraft": "nix-minecraft", - "nixos-cosmic": "nixos-cosmic", "nixos-hardware": "nixos-hardware", "nixpkgs": "nixpkgs", "nixpkgs-unstable": "nixpkgs-unstable", - "plasma-manager": "plasma-manager", "sops-nix": "sops-nix" } }, @@ -863,27 +386,6 @@ "type": "github" } }, - "rust-overlay_2": { - "inputs": { - "nixpkgs": [ - "nixos-cosmic", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1751251399, - "narHash": "sha256-y+viCuy/eKKpkX1K2gDvXIJI/yzvy6zA3HObapz9XZ0=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "b22d5ee8c60ed1291521f2dde48784edd6bf695b", - "type": "github" - }, - "original": { - "owner": "oxalica", - "repo": "rust-overlay", - "type": "github" - } - }, "sops-nix": { "inputs": { "nixpkgs": [ @@ -905,21 +407,6 @@ } }, "systems": { - "locked": { - "lastModified": 1689347949, - "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", - "owner": "nix-systems", - "repo": "default-linux", - "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default-linux", - "type": "github" - } - }, - "systems_2": { "locked": { "lastModified": 1681028828, "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", @@ -933,47 +420,6 @@ "repo": "default", "type": "github" } - }, - "xdph": { - "inputs": { - "hyprland-protocols": [ - "hyprland", - "hyprland-protocols" - ], - "hyprlang": [ - "hyprland", - "hyprlang" - ], - "hyprutils": [ - "hyprland", - "hyprutils" - ], - "hyprwayland-scanner": [ - "hyprland", - "hyprwayland-scanner" - ], - "nixpkgs": [ - "hyprland", - "nixpkgs" - ], - "systems": [ - "hyprland", - "systems" - ] - }, - "locked": { - "lastModified": 1772669058, - "narHash": "sha256-XhnY0aRuDo5LT8pmJVPofPOgO2hAR7T+XRoaQxtNPzQ=", - "owner": "hyprwm", - "repo": "xdg-desktop-portal-hyprland", - "rev": "906d0ac159803a7df2dc1f948df9327670380f69", - "type": "github" - }, - "original": { - "owner": "hyprwm", - "repo": "xdg-desktop-portal-hyprland", - "type": "github" - } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 4865558..54c368c 100644 --- a/flake.nix +++ b/flake.nix @@ -4,6 +4,8 @@ inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11"; nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable"; + flake-parts.url = "github:hercules-ci/flake-parts"; + import-tree.url = "github:vic/import-tree"; nixos-hardware.url = "github:NixOS/nixos-hardware/master"; home-manager = { url = "github:nix-community/home-manager/release-25.11"; @@ -15,27 +17,10 @@ }; disko.url = "github:nix-community/disko"; disko.inputs.nixpkgs.follows = "nixpkgs"; - plasma-manager = { - url = "github:pjones/plasma-manager"; - inputs.nixpkgs.follows = "nixpkgs"; - inputs.home-manager.follows = "home-manager"; - }; firefox-addons = { url = "gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons"; inputs.nixpkgs.follows = "nixpkgs"; }; - hyprland = { - url = "github:hyprwm/Hyprland"; - inputs.nixpkgs.follows = "nixpkgs"; - }; - hyprland-plugins = { - url = "github:hyprwm/hyprland-plugins"; - inputs.hyprland.follows = "hyprland"; - }; - nixos-cosmic = { - url = "github:lilyinstarlight/nixos-cosmic"; - inputs.nixpkgs.follows = "nixpkgs"; - }; dzgui-nix = { url = "github:lelgenio/dzgui-nix"; inputs.nixpkgs.follows = "nixpkgs"; @@ -48,217 +33,16 @@ nix-minecraft.inputs.nixpkgs.follows = "nixpkgs"; }; - outputs = { - self, - nixpkgs, - nixpkgs-unstable, - nixos-hardware, - home-manager, - nixos-cosmic, - audio, + outputs = inputs @ { + flake-parts, + import-tree, ... - } @ inputs: let - system = "x86_64-linux"; - overlay-unstable = final: prev: { - unstable = import nixpkgs-unstable { - system = prev.system; - config.allowUnfree = true; - }; - }; - in { - nixosConfigurations = { - comfy-station = nixpkgs.lib.nixosSystem { - inherit system; - specialArgs = { - inherit inputs; - isHM = false; - }; - modules = [ - ({...}: {nixpkgs.overlays = [overlay-unstable self.overlays.default audio.overlays.default];}) - ({...}: {nixpkgs.config.allowUnfree = true;}) - nixos-hardware.nixosModules.msi-b550-a-pro - inputs.sops-nix.nixosModules.sops - inputs.nix-minecraft.overlay - inputs.nix-minecraft.nixosModules.minecraft-servers - ./modules - ./hosts/comfy-station/configuration.nix - ]; - }; - monolith = nixpkgs.lib.nixosSystem { - inherit system; - specialArgs = { - inherit inputs; - isHM = false; - }; - modules = [ - ({...}: { - nixpkgs.overlays = [ - overlay-unstable - self.overlays.default - audio.overlays.default - inputs.nix-minecraft.overlay - ]; - }) - ({...}: { - nixpkgs.config.allowUnfree = true; - nixpkgs.config.nvidia.acceptLicense = true; - }) - { - nix.settings = { - substituters = ["https://cosmic.cachix.org/"]; - trusted-public-keys = ["cosmic.cachix.org-1:Dya9IyXD4xdBehWjrkPv6rtxpmMdRel02smYzA85dPE="]; - }; - } - nixos-hardware.nixosModules.lenovo-thinkpad-t14-amd-gen1 - inputs.sops-nix.nixosModules.sops - nixos-cosmic.nixosModules.default - inputs.nix-minecraft.nixosModules.minecraft-servers - ./fixes/plasma-fix.nix - ./modules - ./hosts/monolith/configuration.nix - ]; - }; - harbor = nixpkgs.lib.nixosSystem { - inherit system; - specialArgs = { - inherit inputs; - isHM = false; - }; - modules = [ - ({...}: { - nixpkgs.overlays = [ - overlay-unstable - self.overlays.default - audio.overlays.default - inputs.nix-minecraft.overlay - ]; - }) - ({...}: {nixpkgs.config.allowUnfree = true;}) - inputs.sops-nix.nixosModules.sops - inputs.disko.nixosModules.disko - inputs.nix-minecraft.nixosModules.minecraft-servers - ./modules - ./hosts/harbor/configuration.nix - ]; - }; - vm = nixpkgs.lib.nixosSystem { - inherit system; - specialArgs = { - inherit inputs; - }; - modules = [ - ./hosts/vm/configuration.nix - ]; - }; - }; - homeConfigurations."jonas@comfy-station" = home-manager.lib.homeManagerConfiguration { - pkgs = nixpkgs.legacyPackages.${system}; - - # Specify your home configuration modules here, for example, - # the path to your home.nix. - modules = [ - ({...}: {nixpkgs.overlays = [overlay-unstable self.overlays.default audio.overlays.default];}) - ({...}: {nixpkgs.config.allowUnfree = true;}) - inputs.plasma-manager.homeManagerModules.plasma-manager - inputs.sops-nix.homeManagerModules.sops - ./modules - (./home + "/jonas@comfy-station.nix") + }: + flake-parts.lib.mkFlake {inherit inputs;} { + systems = ["x86_64-linux"]; + imports = [ + ./hosts/comfy-station + (import-tree ./modules) ]; - - # Optionally use extraSpecialArgs - # to pass through arguments to home.nix - extraSpecialArgs = { - inherit inputs; - isHM = true; - }; }; - homeConfigurations."jonas@harbor" = home-manager.lib.homeManagerConfiguration { - pkgs = nixpkgs.legacyPackages.${system}; - - # Specify your home configuration modules here, for example, - # the path to your home.nix. - modules = [ - ({...}: {nixpkgs.overlays = [overlay-unstable self.overlays.default audio.overlays.default];}) - ({...}: {nixpkgs.config.allowUnfree = true;}) - inputs.plasma-manager.homeManagerModules.plasma-manager - inputs.sops-nix.homeManagerModules.sops - ./modules - (./home + "/jonas@harbor.nix") - ]; - - # Optionally use extraSpecialArgs - # to pass through arguments to home.nix - extraSpecialArgs = { - inherit inputs; - isHM = true; - }; - }; - homeConfigurations."jonas@monolith" = home-manager.lib.homeManagerConfiguration { - pkgs = nixpkgs.legacyPackages.${system}; - - # Specify your home configuration modules here, for example, - # the path to your home.nix. - modules = [ - ({...}: {nixpkgs.overlays = [overlay-unstable self.overlays.default audio.overlays.default];}) - ({...}: {nixpkgs.config.allowUnfree = true;}) - inputs.plasma-manager.homeManagerModules.plasma-manager - inputs.sops-nix.homeManagerModules.sops - ./modules - (./home + "/jonas@monolith.nix") - ]; - - # Optionally use extraSpecialArgs - # to pass through arguments to home.nix - extraSpecialArgs = { - inherit inputs; - isHM = true; - }; - }; - homeConfigurations."admin-jroeger" = home-manager.lib.homeManagerConfiguration { - pkgs = nixpkgs.legacyPackages.${system}; - - # Specify your home configuration modules here, for example, - # the path to your home.nix. - modules = [ - ({...}: {nixpkgs.overlays = [overlay-unstable self.overlays.default audio.overlays.default];}) - ({...}: {nixpkgs.config.allowUnfree = true;}) - inputs.plasma-manager.homeManagerModules.plasma-manager - inputs.sops-nix.homeManagerModules.sops - ./modules - ./home/admin-jroeger.nix - ]; - - # Optionally use extraSpecialArgs - # to pass through arguments to home.nix - extraSpecialArgs = { - inherit inputs; - isHM = true; - }; - }; - - devShells.${system} = { - bulk-transcode = (import ./pkgs/bulk-transcode/shell.nix) {pkgs = nixpkgs.legacyPackages.${system};}; - spotify-shortcuts = (import ./pkgs/spotify-shortcuts/shell.nix) {pkgs = nixpkgs.legacyPackages.${system};}; - }; - - overlays.default = import ./pkgs; - - templates = { - rust = { - path = ./templates/rust; - description = "A simple rust binary template"; - welcomeText = '' - # Rust template - This is a simple rust binary template. - To build the project run `cargo build`. - To run the project run `cargo run`. - Before running nix build, make sure to run `cargo generate-lockfile` first. - ''; - }; - cmake-c = { - path = ./templates/cmake-c; - description = "A simple cmake c project."; - }; - }; - }; } diff --git a/hosts/comfy-station/configuration.nix b/hosts/comfy-station/configuration.nix index 9b3435c..58bc27d 100644 --- a/hosts/comfy-station/configuration.nix +++ b/hosts/comfy-station/configuration.nix @@ -28,23 +28,13 @@ programs.zsh.enable = true; # hive modules - hive.nix-scripts.enable = true; - hive.displayManager.name = "sddm"; - hive.hyprland.enable = true; - hive.kwallet.enable = true; hive.kwallet.forUsers = ["jonas"]; hive.virt-manager.enable = true; hive.virt-manager.forUsers = ["jonas"]; - hive.bluetooth.enable = true; - hive.sound.enable = true; - hive.yubikey.enable = true; - hive.wg.client.enable = true; hive.wg.client.privateKeyFile = config.sops.secrets.wg-priv.path; hive.wg.client.peer = "comfy-station"; - hive.programs.games.enable = true; hive.programs.games.steam = true; hive.programs.creative = { - enable = true; image-management = true; image-raw-processing = true; video-editing-light = true; diff --git a/hosts/comfy-station/default.nix b/hosts/comfy-station/default.nix new file mode 100644 index 0000000..75a7dd0 --- /dev/null +++ b/hosts/comfy-station/default.nix @@ -0,0 +1,29 @@ +{ + inputs, + self, + ... +}: { + flake.nixosConfigurations.comfy-station = inputs.nixpkgs.lib.nixosSystem { + modules = [ + ({...}: { + nixpkgs.config.allowUnfree = true; + nixpkgs.overlays = [self.overlays.unstable self.overlays.bulk-transcode]; + }) + + ./configuration.nix + + inputs.nixos-hardware.nixosModules.lenovo-thinkpad-t14-amd-gen1 + inputs.sops-nix.nixosModules.sops + self.nixosModules.nix-scripts + self.nixosModules.hyprland + self.nixosModules.kwallet + self.nixosModules.virt-manager + self.nixosModules.bluetooth + self.nixosModules.sound + self.nixosModules.yubikey + self.nixosModules.wireguard-client + self.nixosModules.games + self.nixosModules.creative + ]; + }; +} diff --git a/modules/bin/nix-scripts.nix b/modules/bin/nix-scripts.nix index 61c97b7..b12e69e 100644 --- a/modules/bin/nix-scripts.nix +++ b/modules/bin/nix-scripts.nix @@ -1,12 +1,5 @@ -{ - config, - lib, - pkgs, - isHM, - ... -}: let - cfg = config.hive.nix-scripts; - home-rebuild = +{...}: let + home-rebuild = pkgs: pkgs.writeShellScriptBin ".home-rebuild" '' set -e @@ -20,7 +13,7 @@ ${pkgs.git}/bin/git commit --no-gpg-sign -am "Home $gen by $by" popd ''; - rebuild = + rebuild = pkgs: pkgs.writeShellScriptBin ".nixos-rebuild" '' set -e @@ -34,7 +27,7 @@ ${pkgs.git}/bin/git commit --no-gpg-sign -am "System $gen by $by" popd ''; - upgrade = + upgrade = pkgs: pkgs.writeShellScriptBin ".nixos-upgrade" '' set -e @@ -63,7 +56,7 @@ ${pkgs.git}/bin/git branch -D "$branch_staging" popd ''; - update = + update = pkgs: pkgs.writeShellScriptBin ".nixos-update" '' set -e @@ -94,25 +87,16 @@ popd ''; in { - options = { - hive.nix-scripts.enable = lib.mkEnableOption "Enable the nix build/update scripts"; + flake.nixosModules.nix-scripts = {pkgs, ...}: { + environment.systemPackages = [ + (rebuild pkgs) + (upgrade pkgs) + (update pkgs) + ]; + }; + flake.homeModules.nix-scripts = {pkgs, ...}: { + home.packages = [ + (home-rebuild pkgs) + ]; }; - - config = - lib.mkIf cfg.enable - ( - if isHM - then { - home.packages = [ - home-rebuild - ]; - } - else { - environment.systemPackages = [ - rebuild - upgrade - update - ]; - } - ); } diff --git a/modules/desktop/de/kwallet.nix b/modules/desktop/de/kwallet.nix deleted file mode 100644 index 36613df..0000000 --- a/modules/desktop/de/kwallet.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: let - cfg = config.hive.kwallet; -in { - options.hive.kwallet = { - enable = lib.mkEnableOption "Enable kwallet"; - forUsers = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = []; - description = '' - List of users that should unlock kwallet via pam. - ''; - }; - }; - - config = lib.mkIf cfg.enable { - environment.systemPackages = with pkgs.kdePackages; [ - kwallet - kwalletmanager - ]; - security.pam.services = builtins.listToAttrs (map (user: { - name = user; - value = { - kwallet.enable = true; - kwallet.forceRun = true; - kwallet.package = pkgs.kdePackages.kwallet-pam; - }; - }) - cfg.forUsers); - }; -} diff --git a/modules/desktop/hyprland.nix b/modules/desktop/hyprland.nix new file mode 100644 index 0000000..93cae48 --- /dev/null +++ b/modules/desktop/hyprland.nix @@ -0,0 +1,56 @@ +{ + flake.nixosModules.hyprland = { + config, + lib, + pkgs, + ... + }: let + cfg = config.hive.displayManager; + in { + options.hive.displayManager = with lib; { + autologin = mkOption { + type = types.nullOr types.str; + default = null; + description = "The autologin username or null for no autologin."; + }; + }; + config = { + services.xserver.enable = true; + services.xserver = { + xkb.layout = "de"; + xkb.variant = ""; + xkb.options = "caps:ctrl_modifier"; + }; + services.displayManager.autoLogin.enable = cfg.autologin != null; + services.displayManager.autoLogin.user = cfg.autologin; + + services.libinput.enable = true; + services.dbus.enable = true; + services.displayManager.sddm = { + enable = true; + wayland.enable = true; + }; + + xdg.portal = { + enable = true; + extraPortals = with pkgs; [ + xdg-desktop-portal-wlr + xdg-desktop-portal-hyprland + kdePackages.xdg-desktop-portal-kde + ]; + }; + + environment.systemPackages = with pkgs; [spaceFM]; + + services.udisks2.enable = true; + + programs.hyprland = { + enable = true; + withUWSM = true; + xwayland.enable = true; + }; + programs.hyprlock.enable = true; + security.pam.services.hyprlock = {}; + }; + }; +} diff --git a/modules/desktop/kwallet.nix b/modules/desktop/kwallet.nix new file mode 100644 index 0000000..c87edeb --- /dev/null +++ b/modules/desktop/kwallet.nix @@ -0,0 +1,36 @@ +{ + flake.nixosModules.kwallet = { + config, + lib, + pkgs, + ... + }: let + cfg = config.hive.kwallet; + in { + options.hive.kwallet = { + forUsers = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = []; + description = '' + List of users that should unlock kwallet via pam. + ''; + }; + }; + + config = { + environment.systemPackages = with pkgs.kdePackages; [ + kwallet + kwalletmanager + ]; + security.pam.services = builtins.listToAttrs (map (user: { + name = user; + value = { + kwallet.enable = true; + kwallet.forceRun = true; + kwallet.package = pkgs.kdePackages.kwallet-pam; + }; + }) + cfg.forUsers); + }; + }; +} diff --git a/modules/hardware/bluetooth.nix b/modules/hardware/bluetooth.nix index 9de9074..ec42a32 100644 --- a/modules/hardware/bluetooth.nix +++ b/modules/hardware/bluetooth.nix @@ -1,20 +1,5 @@ { - config, - lib, - ... -}: let - cfg = config.hive.bluetooth; -in { - options = { - hive.bluetooth.enable = lib.mkOption { - type = lib.types.bool; - default = false; - description = "Enable Bluetooth"; - }; - }; - - config = lib.mkIf cfg.enable { - # Enable Bluetooth + flake.nixosModules.bluetooth = { hardware.bluetooth.enable = true; }; } diff --git a/modules/hardware/sound.nix b/modules/hardware/sound.nix index 95bc5d4..c21adc1 100644 --- a/modules/hardware/sound.nix +++ b/modules/hardware/sound.nix @@ -1,75 +1,72 @@ { - config, - lib, - pkgs, - ... -}: let - cfg = config.hive.sound; -in { - options = { - hive.sound = { - enable = lib.mkOption { - type = lib.types.bool; - default = false; - description = "Enable sound with pipewire."; - }; - noisetorch = lib.mkOption { - type = lib.types.bool; - default = false; - description = "Enable Noisetorch for noise cancellation."; - }; - noisetorch-threshold = lib.mkOption { - type = lib.types.int; - default = -1; - description = "Set the noise cancellation threshold for Noisetorch."; + flake.nixosModules.sound = { + config, + lib, + pkgs, + ... + }: let + cfg = config.hive.sound; + in { + options = { + hive.sound = { + noisetorch = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable Noisetorch for noise cancellation."; + }; + noisetorch-threshold = lib.mkOption { + type = lib.types.int; + default = -1; + description = "Set the noise cancellation threshold for Noisetorch."; + }; }; }; - }; - config = lib.mkIf cfg.enable { - # Enable sound with pipewire. - services.pulseaudio.enable = false; - security.rtkit.enable = true; - services.pipewire = { - enable = true; - alsa.enable = true; - alsa.support32Bit = true; - pulse.enable = true; - # If you want to use JACK applications, uncomment this - #jack.enable = true; + config = { + # Enable sound with pipewire. + services.pulseaudio.enable = false; + security.rtkit.enable = true; + services.pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + # If you want to use JACK applications, uncomment this + #jack.enable = true; - # use the example session manager (no others are packaged yet so this is enabled by default, - # no need to redefine it in your config for now) - #media-session.enable = true; - }; - programs.noisetorch.enable = cfg.noisetorch; - systemd.user.services.noisetorch-autoload = lib.mkIf cfg.noisetorch { - description = "Automatically load Noisetorch on user login"; - after = ["pipewire.service"]; - requires = ["pipewire.service"]; - serviceConfig = { - Type = "oneshot"; - ExecStart = "${pkgs.writeShellScript "load-noisetorch" '' - set -euo pipefail - NOISETORCH="${pkgs.noisetorch}/bin/noisetorch" - WPCTL="${pkgs.wireplumber}/bin/wpctl" - GREP="${pkgs.gnugrep}/bin/grep" - AWK="${pkgs.gawk}/bin/awk" - HEAD="${pkgs.coreutils}/bin/head" - - sleep 2 - $NOISETORCH -i -t ${toString cfg.noisetorch-threshold}; - sleep 2 - FILTER_ID=$($WPCTL status | $GREP NoiseTorch | $AWK 'match($0, /[0-9]+(\.[0-9]+)?/) { print substr($0, RSTART, RLENGTH) }' | head -n1) - if [ -n "$FILTER_ID" ]; then - $WPCTL set-default $FILTER_ID - else - echo "Noisetorch filter not found, skipping setting default source." - fi - ''}"; - ExecStop = "${pkgs.noisetorch}/bin/noisetorch -u"; - RemainAfterExit = true; + # use the example session manager (no others are packaged yet so this is enabled by default, + # no need to redefine it in your config for now) + #media-session.enable = true; + }; + programs.noisetorch.enable = cfg.noisetorch; + systemd.user.services.noisetorch-autoload = lib.mkIf cfg.noisetorch { + description = "Automatically load Noisetorch on user login"; + after = ["pipewire.service"]; + requires = ["pipewire.service"]; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${pkgs.writeShellScript "load-noisetorch" '' + set -euo pipefail + NOISETORCH="${pkgs.noisetorch}/bin/noisetorch" + WPCTL="${pkgs.wireplumber}/bin/wpctl" + GREP="${pkgs.gnugrep}/bin/grep" + AWK="${pkgs.gawk}/bin/awk" + HEAD="${pkgs.coreutils}/bin/head" + + sleep 2 + $NOISETORCH -i -t ${toString cfg.noisetorch-threshold}; + sleep 2 + FILTER_ID=$($WPCTL status | $GREP NoiseTorch | $AWK 'match($0, /[0-9]+(\.[0-9]+)?/) { print substr($0, RSTART, RLENGTH) }' | head -n1) + if [ -n "$FILTER_ID" ]; then + $WPCTL set-default $FILTER_ID + else + echo "Noisetorch filter not found, skipping setting default source." + fi + ''}"; + ExecStop = "${pkgs.noisetorch}/bin/noisetorch -u"; + RemainAfterExit = true; + }; + wantedBy = ["default.target"]; }; - wantedBy = ["default.target"]; }; }; } diff --git a/modules/hardware/yubikey.nix b/modules/hardware/yubikey.nix index c09c764..f372c13 100644 --- a/modules/hardware/yubikey.nix +++ b/modules/hardware/yubikey.nix @@ -1,20 +1,5 @@ { - config, - lib, - pkgs, - ... -}: let - cfg = config.hive.yubikey; -in { - options = { - hive.yubikey.enable = lib.mkOption { - type = lib.types.bool; - default = false; - description = "Enable Yubikey support."; - }; - }; - - config = lib.mkIf cfg.enable { + flake.nixosModules.yubikey = {pkgs, ...}: { services.udev.packages = with pkgs; [ yubikey-personalization ]; diff --git a/modules/networking/wireguard/peers.nix b/modules/networking/wireguard/_peers.nix similarity index 100% rename from modules/networking/wireguard/peers.nix rename to modules/networking/wireguard/_peers.nix diff --git a/modules/networking/wireguard/client.nix b/modules/networking/wireguard/client.nix index ca46e5f..76e7fe2 100644 --- a/modules/networking/wireguard/client.nix +++ b/modules/networking/wireguard/client.nix @@ -1,35 +1,36 @@ { - config, - lib, - ... -}: let - cfg = config.hive.wg.client; - peers = import ./peers.nix {inherit lib;}; -in { - options.hive.wg.client = { - enable = lib.mkEnableOption "Enable WireGuard client"; - autoConnect = lib.mkOption { - type = lib.types.bool; - default = false; - description = "Automatically connect to the WireGuard server with systemd"; + flake.nixosModules.wireguard-client = { + config, + lib, + ... + }: let + cfg = config.hive.wg.client; + peers = import ./_peers.nix {inherit lib;}; + in { + options.hive.wg.client = { + autoConnect = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Automatically connect to the WireGuard server with systemd"; + }; + peer = lib.mkOption { + type = lib.types.singleLineStr; + example = "comfy-station"; + description = "The name of the peer defined in peers.nix to incarnate"; + }; + privateKeyFile = lib.mkOption { + type = lib.types.path; + description = "Path to the private key file for the WireGuard client"; + }; }; - peer = lib.mkOption { - type = lib.types.singleLineStr; - example = "comfy-station"; - description = "The name of the peer defined in peers.nix to incarnate"; - }; - privateKeyFile = lib.mkOption { - type = lib.types.path; - description = "Path to the private key file for the WireGuard client"; - }; - }; - config = lib.mkIf cfg.enable { - networking.wg-quick.interfaces.wg0 = { - address = peers.clientAddress cfg.peer; - inherit (cfg) privateKeyFile; - autostart = cfg.autoConnect; - peers = peers.forClient cfg.peer; + config = { + networking.wg-quick.interfaces.wg0 = { + address = peers.clientAddress cfg.peer; + inherit (cfg) privateKeyFile; + autostart = cfg.autoConnect; + peers = peers.forClient cfg.peer; + }; }; }; } diff --git a/modules/networking/wireguard/default.nix b/modules/networking/wireguard/default.nix deleted file mode 100644 index a27c069..0000000 --- a/modules/networking/wireguard/default.nix +++ /dev/null @@ -1,3 +0,0 @@ -{...}: { - imports = [./client.nix ./server.nix]; -} diff --git a/modules/networking/wireguard/server.nix b/modules/networking/wireguard/server.nix index c31245e..10b2a88 100644 --- a/modules/networking/wireguard/server.nix +++ b/modules/networking/wireguard/server.nix @@ -1,46 +1,47 @@ { - config, - lib, - pkgs, - ... -}: let - cfg = config.hive.wg.server; - peers = import ./peers.nix {inherit lib;}; -in { - options.hive.wg.server = { - enable = lib.mkEnableOption "Enable WireGuard server"; - port = lib.mkOption { - type = lib.types.port; - default = 51820; - description = "Port for WireGuard server"; + flake.nixosModules.wireguard-server = { + config, + lib, + pkgs, + ... + }: let + cfg = config.hive.wg.server; + peers = import ./peers.nix {inherit lib;}; + in { + options.hive.wg.server = { + port = lib.mkOption { + type = lib.types.port; + default = 51820; + description = "Port for WireGuard server"; + }; + privateKeyFile = lib.mkOption { + type = lib.types.path; + description = "Path to the private key file for the WireGuard server"; + }; }; - privateKeyFile = lib.mkOption { - type = lib.types.path; - description = "Path to the private key file for the WireGuard server"; - }; - }; - config = lib.mkIf cfg.enable { - # Firewall rule - networking.firewall.allowedUDPPorts = [cfg.port]; + config = { + # Firewall rule + networking.firewall.allowedUDPPorts = [cfg.port]; - # Interface without internet routing - networking.wireguard.interfaces."wg0" = { - ips = ["10.10.10.1/24"]; - listenPort = cfg.port; - inherit (cfg) privateKeyFile; + # Interface without internet routing + networking.wireguard.interfaces."wg0" = { + ips = ["10.10.10.1/24"]; + listenPort = cfg.port; + inherit (cfg) privateKeyFile; - peers = peers.forServer; + peers = peers.forServer; - # Allow p2p traffic - postSetup = '' - ${pkgs.iptables}/bin/iptables -A FORWARD -i wg0 -o wg0 -j ACCEPT - ''; + # Allow p2p traffic + postSetup = '' + ${pkgs.iptables}/bin/iptables -A FORWARD -i wg0 -o wg0 -j ACCEPT + ''; - # Undo the above - postShutdown = '' - ${pkgs.iptables}/bin/iptables -D FORWARD -i wg0 -o wg0 -j ACCEPT - ''; + # Undo the above + postShutdown = '' + ${pkgs.iptables}/bin/iptables -D FORWARD -i wg0 -o wg0 -j ACCEPT + ''; + }; }; }; } diff --git a/modules/overlays/unstable.nix b/modules/overlays/unstable.nix new file mode 100644 index 0000000..3cb2730 --- /dev/null +++ b/modules/overlays/unstable.nix @@ -0,0 +1,8 @@ +{inputs, ...}: { + flake.overlays.unstable = final: prev: { + unstable = import inputs.nixpkgs-unstable { + system = prev.system; + config.allowUnfree = true; + }; + }; +} diff --git a/modules/packages/bulk-transcode/.envrc b/modules/packages/bulk-transcode/.envrc new file mode 100644 index 0000000..7ee6560 --- /dev/null +++ b/modules/packages/bulk-transcode/.envrc @@ -0,0 +1 @@ +use flake ../../#bulk-transcode --show-trace diff --git a/modules/packages/bulk-transcode/_derivation.nix b/modules/packages/bulk-transcode/_derivation.nix new file mode 100644 index 0000000..1e1d8c0 --- /dev/null +++ b/modules/packages/bulk-transcode/_derivation.nix @@ -0,0 +1,35 @@ +{ + bash, + coreutils, + ffmpeg, + findutils, + fzf, + gum, + lib, + makeWrapper, + stdenv, + tree, + ... +}: +stdenv.mkDerivation (finalAttrs: { + name = "bulk-transcode"; + src = ./.; + + buildInputs = [ + bash + coreutils + ffmpeg + findutils + fzf + gum + makeWrapper + tree + ]; + + installPhase = '' + install -Dm755 bulk-transcode.sh $out/bin/bulk-transcode + + wrapProgram $out/bin/bulk-transcode \ + --set PATH "${lib.makeBinPath finalAttrs.buildInputs}" + ''; +}) diff --git a/modules/packages/bulk-transcode/_shell.nix b/modules/packages/bulk-transcode/_shell.nix new file mode 100644 index 0000000..d1ee79e --- /dev/null +++ b/modules/packages/bulk-transcode/_shell.nix @@ -0,0 +1,7 @@ +{pkgs ? import {}}: let + bin = pkgs.callPackage ./derivation.nix {}; +in + pkgs.mkShell { + name = "bulk-transcode"; + inputsFrom = [bin]; + } diff --git a/modules/packages/bulk-transcode/bulk-transcode.sh b/modules/packages/bulk-transcode/bulk-transcode.sh new file mode 100644 index 0000000..b8c6d5b --- /dev/null +++ b/modules/packages/bulk-transcode/bulk-transcode.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash + +declare -rA presets=( + [davinci-resolve]="-c:v dnxhd -profile:v dnxhr_hq -pix_fmt yuv422p -c:a pcm_s16le" + [instagram]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)':flags=lanczos -r 30 -c:v libx264 -profile:v high -level 4.1 -pix_fmt yuv420p -preset slow -crf 18 -bf 2 -g 15 -keyint_min 15 -x264-params \"open-gop=0:cabac=1:b-pyramid=none\" -movflags +faststart -c:a aac -b:a 96k" + [insta-4k]="-r 30 -c:v libx264 -profile:v high -level 4.1 -pix_fmt yuv420p -preset slow -crf 18 -bf 2 -g 15 -keyint_min 15 -x264-params \"open-gop=0:cabac=1:b-pyramid=none\" -movflags +faststart -c:a aac -b:a 96k" + [storage-hevc]="-c:v libx265 -preset slower -crf 18 -pix_fmt yuv420p10le -x265-params aq-mode=3:aq-strength=1.0:psy-rd=1.8:psy-rdoq=1.0 -c:a copy" + [storage-av1]="-c:v libsvtav1 -preset 6 -crf 28 -pix_fmt yuv420p -g 240 -svtav1-params tune=0:aq-mode=2 -c:a copy" + [storage-av1-1080p]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)' -c:v libsvtav1 -preset 6 -crf 28 -pix_fmt yuv420p -g 240 -svtav1-params tune=0:aq-mode=2 -c:a copy" + [storage-av1-nvenc]="-c:v av1_nvenc -cq 28 -preset slow -pix_fmt yuv420p10le -c:a copy" + [network]="-c:v libx264 -preset slow -crf 22 -pix_fmt yuv420p -c:a aac -b:a 128k" + [network-1080p]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)' -c:v libx264 -preset slow -crf 22 -pix_fmt yuv420p -c:a aac -b:a 128k" + [whatsapp]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)' -c:v libx264 -preset slow -crf 30 -profile:v baseline -level 3.0 -pix_fmt yuv420p -r 25 -g 50 -c:a aac -b:a 160k -r:a 44100" +) + +declare -rA containers=( + [davinci-resolve]="mov" + [instagram]="mp4" + [insta-4k]="mp4" + [storage-hevc]="mkv" + [storage-av1]="mkv" + [storage-av1-1080p]="mkv" + [storage-av1-nvenc]="mkv" + [network]="mp4" + [network-1080p]="mp4" + [whatsapp]="mp4" +) + +where="${1:-.}" +dest="${2:-$where}" + +selection=$(find "$where" -type f | fzf --multi --preview 'ffprobe -v error -show_format -show_streams {}' --preview-window=up:wrap) + +preset=$( + printf '%s\n' "${!presets[@]}" | \ + fzf --multi --prompt "Select a preset" +) +flags="${presets[$preset]}" +container="${containers[$preset]}" + +output_dir=$(find "$dest" -type d ! -name '.*' ! -path '*/.*/*' | fzf --preview 'tree -C {}' --preview-window=up:wrap --prompt "Select output directory: ") + +if gum confirm "Flatten the directory structure?"; +then + flatten=true +else + flatten=false +fi + + +function transcode_job { + local ifile="$1" + local output_dir="$2" + local flatten="$3" + local where="$4" + local flags="$5" + local container="$6" + local fname=$(basename "$ifile") + local segment=$(realpath --relative-to="$where" "$ifile") + + + if [ "$flatten" = true ]; then + output_file="$output_dir/$fname.$container" + else + output_file="$output_dir/$segment.$container" + fi + + tmp_file=$(mktemp) + + echo "Running Command: ffmpeg -y -i $ifile $flags $output_file" >> "$tmp_file" + + mkdir -p "$(dirname "$output_file")" + + if ffmpeg -y -i "$ifile" $(echo -n "$flags") "$output_file" 2>> "$tmp_file"; + then + rm -f "$tmp_file" + else + # gum log "Failed to transcode $ifile. Check ./error.log for details." + cat "$tmp_file" >> error.log + rm -f "$tmp_file" + + fi +} +export -f transcode_job + +mapfile -t files <<< "$selection" +len=${#files[@]} +i=1 +for file in "${files[@]}"; do + if [[ -f "$file" ]]; then + gum spin --spinner dot --title "[$i/$len] Transcoding $file" -- bash -c "source <(declare -f transcode_job); transcode_job \"$file\" \"$output_dir\" \"$flatten\" \"$where\" \"$flags\" \"$container\"" + else + echo "Skipping invalid file: $file" >&2 + fi + ((i++)) +done diff --git a/modules/packages/bulk-transcode/default.nix b/modules/packages/bulk-transcode/default.nix new file mode 100644 index 0000000..d6106da --- /dev/null +++ b/modules/packages/bulk-transcode/default.nix @@ -0,0 +1,9 @@ +{ + flake.overlays.bulk-transcode = final: prev: { + bulk-transcode = final.callPackage ./_derivation.nix {}; + }; + perSystem = {pkgs, ...}: { + packages.bulk-transcode = pkgs.callPackage ./_derivation.nix {}; + devShells.bulk-transcode = import ./_shell.nix {inherit pkgs;}; + }; +} diff --git a/modules/packages/crossover/_derivation.nix b/modules/packages/crossover/_derivation.nix new file mode 100644 index 0000000..d9185d0 --- /dev/null +++ b/modules/packages/crossover/_derivation.nix @@ -0,0 +1,40 @@ +{ + appimageTools, + fetchurl, + makeWrapper, + ... +}: let + pname = "crossover"; + version = "3.1.5"; + src = fetchurl { + url = "https://github.com/lacymorrow/crossover/releases/download/v${version}/CrossOver-${version}-x86_64.AppImage"; + sha256 = "sha256-64RPal8n1PJh1LB+CTyNFt04Pw1lVgcsyc63S8yQ/DA="; + }; + appimageContents = appimageTools.extract { + inherit pname version src; + }; +in + appimageTools.wrapType2 { + inherit pname version src; + + nativeBuildInputs = [makeWrapper]; + extraInstallCommands = '' + wrapProgram $out/bin/${pname} --add-flags "--no-sandbox" + + # Create a minimal .desktop file manually + mkdir -p $out/share/applications + cat > $out/share/applications/${pname}.desktop < {}}: let + drv = pkgs.callPackage ./derivation.nix {}; +in + pkgs.mkShell { + packages = [ + pkgs.pyright + pkgs.black + ]; + + inputsFrom = [drv]; + + shellHook = '' + export PYTHONPATH="$PYTHONPATH:$(pwd)" + ''; + } diff --git a/modules/packages/spotify-shortcuts/default.nix b/modules/packages/spotify-shortcuts/default.nix new file mode 100644 index 0000000..651f31d --- /dev/null +++ b/modules/packages/spotify-shortcuts/default.nix @@ -0,0 +1,9 @@ +{ + flake.overlays.spotify-shortcuts = final: prev: { + bulk-transcode = final.callPackage ./_derivation.nix {}; + }; + perSystem = {pkgs, ...}: { + packages.spotify-shortcuts = pkgs.callPackage ./_derivation.nix {}; + devShells.spotify-shortcuts = import ./_shell.nix {inherit pkgs;}; + }; +} diff --git a/modules/packages/spotify-shortcuts/setup.py b/modules/packages/spotify-shortcuts/setup.py new file mode 100644 index 0000000..474c0fe --- /dev/null +++ b/modules/packages/spotify-shortcuts/setup.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +from setuptools import setup, find_packages + +setup( + name="spotify_shortcuts", + version="1.0", + packages=find_packages(), + entry_points={ + "console_scripts": [ + "spotisc=spotify_shortcuts.run:main", + "spotify-like=spotify_shortcuts.spotify_like:main", + "spotify-pl-add=spotify_shortcuts.spotify_pl_add:main", + ], + }, +) diff --git a/modules/packages/spotify-shortcuts/spotify_shortcuts/__init__.py b/modules/packages/spotify-shortcuts/spotify_shortcuts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/packages/spotify-shortcuts/spotify_shortcuts/__main__.py b/modules/packages/spotify-shortcuts/spotify_shortcuts/__main__.py new file mode 100644 index 0000000..8f3c09e --- /dev/null +++ b/modules/packages/spotify-shortcuts/spotify_shortcuts/__main__.py @@ -0,0 +1,4 @@ +from spotify_shortcuts.run import main + +if __name__ == "__main__": + main() diff --git a/modules/packages/spotify-shortcuts/spotify_shortcuts/config.py b/modules/packages/spotify-shortcuts/spotify_shortcuts/config.py new file mode 100644 index 0000000..69901e1 --- /dev/null +++ b/modules/packages/spotify-shortcuts/spotify_shortcuts/config.py @@ -0,0 +1,74 @@ +from pathlib import Path +from dataclasses import dataclass +from argparse import ArgumentParser +from typing import List +from os import getenv +from sys import argv +from xdg.BaseDirectory import xdg_cache_home +from json import loads + + +@dataclass +class Config: + cache_file: Path = Path(xdg_cache_home) / Path("spotify-shortcuts.json") + client_id: str | None = None + client_secret: str | None = None + notifications: bool = True + + @staticmethod + def from_file(path: Path): + if not path.exists(): + raise FileNotFoundError(f"Configuration file {path} does not exist.") + with open(path, "r") as f: + data = loads(f.read()) + + return Config( + cache_file=Path(data.get("cacheFile", Config.cache_file)), + client_id=data.get("clientId", Config.client_id), + client_secret=data.get("clientSecret", Config.client_secret), + ) + + +def load_config(args: List[str] = argv[1:]) -> Config: + parser = ArgumentParser(description="Spotify CLI Tool") + parser.add_argument( + "--cache-file", + type=Path, + default=Config.cache_file, + help="Path to the cache file for Spotify authentication", + ) + parser.add_argument( + "--client-id", + type=str, + default=Config.client_id, + help="Spotify API Client ID", + ) + parser.add_argument( + "--client-secret", + type=str, + default=Config.client_secret, + help="Spotify API Client Secret", + ) + parser.add_argument( + "--config-file", + type=str, + help="Path to a json configuration file with keys clientId and clientSecret", + ) + parser.add_argument( + "--no-notifications", + action="store_true", + help="Disable desktop notifications", + ) + + ns = parser.parse_args(args) + + cfg = Config() + if (cfg_file := ns.config_file or getenv("SPOTIFY_SHORTCUTS_CONFIG", None)) != None: + cfg = Config.from_file(Path(cfg_file)) + + return Config( + cache_file=ns.cache_file or cfg.cache_file, + client_id=ns.client_id or cfg.client_id, + client_secret=ns.client_secret or cfg.client_secret, + notifications=not ns.no_notifications or cfg.notifications, + ) diff --git a/modules/packages/spotify-shortcuts/spotify_shortcuts/registry.py b/modules/packages/spotify-shortcuts/spotify_shortcuts/registry.py new file mode 100644 index 0000000..7e6f694 --- /dev/null +++ b/modules/packages/spotify-shortcuts/spotify_shortcuts/registry.py @@ -0,0 +1,7 @@ +from spotify_shortcuts.spotify_like import SpotifyLike +from spotify_shortcuts.spotify_pl_add import SpotifyPlAdd + +SHORTCUT_REGISTRY = { + "like": SpotifyLike(), + "pl_add": SpotifyPlAdd(), +} diff --git a/modules/packages/spotify-shortcuts/spotify_shortcuts/run.py b/modules/packages/spotify-shortcuts/spotify_shortcuts/run.py new file mode 100644 index 0000000..423ff6a --- /dev/null +++ b/modules/packages/spotify-shortcuts/spotify_shortcuts/run.py @@ -0,0 +1,47 @@ +from spotify_shortcuts.config import Config, load_config +from spotify_shortcuts.shortcut import Shortcut +from spotify_shortcuts.spotify_auth import authenticated_session +from itertools import chain + + +def all_scopes() -> list[str]: + from spotify_shortcuts.registry import SHORTCUT_REGISTRY + + return list( + set( + chain.from_iterable( + shortcut.get_scopes() for shortcut in SHORTCUT_REGISTRY.values() + ) + ) + ) + + +def run_shortcut(shortcut: Shortcut, config: Config): + client = authenticated_session( + config, scopes=all_scopes() # use all scopes to avoid re-authentication + ) + + shortcut.execute(client, config) + + +def main(): + from spotify_shortcuts.registry import SHORTCUT_REGISTRY + import sys + + if len(sys.argv) < 2: + print(f"Usage: {sys.argv[0]} ") + sys.exit(1) + + shortcut_name = sys.argv[1] + if shortcut_name not in SHORTCUT_REGISTRY: + print(f"Shortcut '{shortcut_name}' not found.") + sys.exit(1) + + shortcut = SHORTCUT_REGISTRY[shortcut_name] + config = load_config(args=sys.argv[2:]) + + run_shortcut(shortcut, config) + + +if __name__ == "__main__": + main() diff --git a/modules/packages/spotify-shortcuts/spotify_shortcuts/shortcut.py b/modules/packages/spotify-shortcuts/spotify_shortcuts/shortcut.py new file mode 100644 index 0000000..e8d871b --- /dev/null +++ b/modules/packages/spotify-shortcuts/spotify_shortcuts/shortcut.py @@ -0,0 +1,21 @@ +from abc import ABC, abstractmethod + +from spotify_shortcuts.config import Config +from spotipy import Spotify + + +class Shortcut(ABC): + @abstractmethod + def execute(self, client: Spotify, config: Config): + """Execute the shortcut action.""" + pass + + @abstractmethod + def get_help(self) -> str: + """Return a description of the shortcut.""" + pass + + @abstractmethod + def get_scopes(self) -> list[str]: + """Return the spotify API scopes required for the shortcut.""" + pass diff --git a/modules/packages/spotify-shortcuts/spotify_shortcuts/spotify_auth.py b/modules/packages/spotify-shortcuts/spotify_shortcuts/spotify_auth.py new file mode 100644 index 0000000..f4f6574 --- /dev/null +++ b/modules/packages/spotify-shortcuts/spotify_shortcuts/spotify_auth.py @@ -0,0 +1,20 @@ +from spotipy.oauth2 import SpotifyOAuth +from spotipy import Spotify +from spotify_shortcuts.config import Config + +CALLBACK_URI = "http://127.0.0.1:45632/callback" + + +def authenticated_session(cfg: Config, scopes: list[str]) -> Spotify: + assert cfg.client_id, "Spotify client ID is required" + assert cfg.client_secret, "Spotify client secret is required" + + return Spotify( + auth_manager=SpotifyOAuth( + client_id=cfg.client_id, + client_secret=cfg.client_secret, + redirect_uri=CALLBACK_URI, + scope=" ".join(scopes), + cache_path=cfg.cache_file, + ) + ) diff --git a/modules/packages/spotify-shortcuts/spotify_shortcuts/spotify_like.py b/modules/packages/spotify-shortcuts/spotify_shortcuts/spotify_like.py new file mode 100644 index 0000000..32787ce --- /dev/null +++ b/modules/packages/spotify-shortcuts/spotify_shortcuts/spotify_like.py @@ -0,0 +1,46 @@ +from spotify_shortcuts.run import run_shortcut +from spotify_shortcuts.shortcut import Shortcut +from spotify_shortcuts.config import load_config +from desktop_notifier import DesktopNotifierSync + +SCOPES = [ + "user-library-read", + "user-library-modify", + "user-read-playback-state", +] + + +class SpotifyLike(Shortcut): + def execute(self, client, config): + if (playback := client.current_playback()) is None: + print("No current playback found.") + return + + if (uri := playback.get("item", {}).get("uri", None)) is None: + print("No track URI found in current playback.") + return + + client.current_user_saved_tracks_add(tracks=[uri]) + + if config.notifications: + dn = DesktopNotifierSync() + dn.send( + title="Track Liked", + message=f"Track \"{playback.get('item', {}).get('name', '')}\" by \"{ + ", ".join(a.get('name', '') for a in playback.get('item', {}).get('artists', [])) + }\" has been liked.", + ) + + def get_help(self) -> str: + return "Like the currently playing track." + + def get_scopes(self) -> list[str]: + return SCOPES + + +def main(): + run_shortcut(SpotifyLike(), load_config()) + + +if __name__ == "__main__": + main() diff --git a/modules/packages/spotify-shortcuts/spotify_shortcuts/spotify_pl_add.py b/modules/packages/spotify-shortcuts/spotify_shortcuts/spotify_pl_add.py new file mode 100644 index 0000000..63d5426 --- /dev/null +++ b/modules/packages/spotify-shortcuts/spotify_shortcuts/spotify_pl_add.py @@ -0,0 +1,57 @@ +from spotify_shortcuts.shortcut import Shortcut +from spotify_shortcuts.config import load_config +from desktop_notifier import DesktopNotifierSync +from spotify_shortcuts.run import run_shortcut + +SCOPES = [ + "playlist-modify-public", + "playlist-modify-private", + "user-read-playback-state", +] + + +class SpotifyPlAdd(Shortcut): + def execute(self, client, config): + if (playback := client.current_playback()) is None: + print("No current playback found.") + return + + if (track_uri := playback.get("item", {}).get("uri", None)) is None: + print("No track URI found in current playback.") + return + + if (context_uri := playback.get("context", {}).get("uri", None)) is None: + print("No context URI found in current playback.") + return + + client.playlist_add_items(context_uri, items=[track_uri]) + + if config.notifications: + track_name = playback.get("item", {}).get("name", "") + artists = ", ".join( + a.get("name", "") + for a in playback.get("item", {}).get("artists", []) + ) + playlist_name = (client.playlist(context_uri) or {}).get( + "name", "" + ) + + dn = DesktopNotifierSync() + dn.send( + title="Track Added to Playlist", + message=f'Track "{track_name}" by "{artists}" has been added to {playlist_name}.', + ) + + def get_help(self) -> str: + return "Add the currently playing track to the current playlist." + + def get_scopes(self) -> list[str]: + return SCOPES + + +def main(): + run_shortcut(SpotifyPlAdd(), load_config()) + + +if __name__ == "__main__": + main() diff --git a/modules/programs/creative.nix b/modules/programs/creative.nix index 1becd41..57dc315 100644 --- a/modules/programs/creative.nix +++ b/modules/programs/creative.nix @@ -1,89 +1,90 @@ { - config, - lib, - pkgs, - ... -}: let - cfg = config.hive.programs.creative; - avidemux-wayland-fix = pkgs.avidemux.overrideAttrs (prev: { - installPhase = - (prev.installPhase or "") - + '' - wrapProgram $out/bin/avidemux3_qt5 \ - --add-flags "--platform" \ - --add-flags "xcb" - ''; - }); -in { - options.hive.programs.creative = { - enable = lib.mkEnableOption "Enable creative programs (video/image editing, etc.)"; - image-management = lib.mkOption { - type = lib.types.bool; - default = true; - description = '' - Enable image management tools. - ''; + flake.nixosModules.creative = { + config, + lib, + pkgs, + ... + }: let + cfg = config.hive.programs.creative; + avidemux-wayland-fix = pkgs.avidemux.overrideAttrs (prev: { + installPhase = + (prev.installPhase or "") + + '' + wrapProgram $out/bin/avidemux3_qt5 \ + --add-flags "--platform" \ + --add-flags "xcb" + ''; + }); + in { + options.hive.programs.creative = { + image-management = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Enable image management tools. + ''; + }; + image-editing = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Enable image editing tools. + ''; + }; + image-raw-processing = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Enable raw processing programs. + ''; + }; + video-editing-light = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Enable light video editing tools. + ''; + }; + video-editing-heavy = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Enable heavy video editing tools. + ''; + }; + daws = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Enable DAWs (currently bitwig beta) + ''; + }; }; - image-editing = lib.mkOption { - type = lib.types.bool; - default = false; - description = '' - Enable image editing tools. - ''; - }; - image-raw-processing = lib.mkOption { - type = lib.types.bool; - default = false; - description = '' - Enable raw processing programs. - ''; - }; - video-editing-light = lib.mkOption { - type = lib.types.bool; - default = false; - description = '' - Enable light video editing tools. - ''; - }; - video-editing-heavy = lib.mkOption { - type = lib.types.bool; - default = false; - description = '' - Enable heavy video editing tools. - ''; - }; - daws = lib.mkOption { - type = lib.types.bool; - default = false; - description = '' - Enable DAWs (currently bitwig beta) - ''; - }; - }; - config = lib.mkIf cfg.enable { - environment.systemPackages = with pkgs; - lib.optionals cfg.image-editing [gimp krita drawio] - ++ lib.optional cfg.image-management digikam - ++ lib.optionals cfg.image-raw-processing [ - enblend-enfuse - hdrmerge - hugin - rawtherapee - unstable.darktable - unstable.rapidraw - ] - ++ lib.optionals cfg.video-editing-light [ - avidemux-wayland-fix - ffmpeg - hive.bulk-transcode - losslesscut-bin - ] - ++ lib.optionals cfg.video-editing-heavy [ - davinci-resolve - kdePackages.kdenlive - obs-studio - ] - ++ lib.optional cfg.daws bitwig-studio-latest; + config = { + environment.systemPackages = with pkgs; + lib.optionals cfg.image-editing [gimp krita drawio] + ++ lib.optional cfg.image-management digikam + ++ lib.optionals cfg.image-raw-processing [ + enblend-enfuse + hdrmerge + hugin + rawtherapee + unstable.darktable + unstable.rapidraw + ] + ++ lib.optionals cfg.video-editing-light [ + avidemux-wayland-fix + ffmpeg + bulk-transcode + losslesscut-bin + ] + ++ lib.optionals cfg.video-editing-heavy [ + davinci-resolve + kdePackages.kdenlive + obs-studio + ] + ++ lib.optional cfg.daws bitwig-studio-latest; + }; }; } diff --git a/modules/programs/games.nix b/modules/programs/games.nix index 0452b6e..db48b01 100644 --- a/modules/programs/games.nix +++ b/modules/programs/games.nix @@ -1,73 +1,74 @@ { - config, - inputs, - lib, - pkgs, - ... -}: let - cfg = config.hive.programs.games; -in { - options.hive.programs.games = { - enable = lib.mkEnableOption "Enable the games module"; - steam = lib.mkOption { - type = lib.types.bool; - default = false; - description = '' - Enable Steam support. - ''; + flake.nixosModules.games = { + config, + inputs, + lib, + pkgs, + ... + }: let + cfg = config.hive.programs.games; + in { + options.hive.programs.games = { + steam = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Enable Steam support. + ''; + }; + dayz = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Enable DayZ tools. + ''; + }; + lutris = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Enable Lutris support. + ''; + }; + r2modman = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Enable R2ModMan support. + ''; + }; + wine = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Enable Wine support. + ''; + }; }; - dayz = lib.mkOption { - type = lib.types.bool; - default = false; - description = '' - Enable DayZ tools. - ''; - }; - lutris = lib.mkOption { - type = lib.types.bool; - default = false; - description = '' - Enable Lutris support. - ''; - }; - r2modman = lib.mkOption { - type = lib.types.bool; - default = false; - description = '' - Enable R2ModMan support. - ''; - }; - wine = lib.mkOption { - type = lib.types.bool; - default = false; - description = '' - Enable Wine support. - ''; - }; - }; - config = lib.mkIf cfg.enable { - environment.systemPackages = - lib.optional cfg.lutris - (pkgs.lutris.override { - extraPkgs = pkgs: [ - pkgs.libnghttp2 + config = { + environment.systemPackages = + lib.optional cfg.lutris + (pkgs.lutris.override { + extraPkgs = pkgs: [ + pkgs.libnghttp2 + pkgs.winetricks + ]; + }) + ++ lib.optional cfg.r2modman pkgs.r2modman + ++ lib.optionals cfg.dayz [ + pkgs.hive.crossover + inputs.dzgui-nix.packages.${pkgs.stdenv.system}.default + ] + ++ lib.optionals cfg.wine [ + pkgs.wine pkgs.winetricks ]; - }) - ++ lib.optional cfg.r2modman pkgs.r2modman - ++ lib.optionals cfg.dayz [ - pkgs.hive.crossover - inputs.dzgui-nix.packages.${pkgs.stdenv.system}.default - ] - ++ lib.optionals cfg.wine [ - pkgs.wine - pkgs.winetricks - ]; - programs.steam = lib.mkIf cfg.steam { - enable = true; - gamescopeSession.enable = true; + programs.steam = lib.mkIf cfg.steam { + enable = true; + gamescopeSession.enable = true; + }; }; }; } diff --git a/modules/services/virt-manager.nix b/modules/services/virt-manager.nix index f2b4af3..6e7bed8 100644 --- a/modules/services/virt-manager.nix +++ b/modules/services/virt-manager.nix @@ -1,31 +1,33 @@ -{ - lib, - config, - ... -}: let - cfg = config.hive.virt-manager; -in { - options.hive.virt-manager = { - enable = lib.mkOption { - type = lib.types.bool; - default = false; - description = '' - Enable the qemu-kvm + libvirt stack. - ''; +{...}: { + flake.nixosModules.virt-manager = { + lib, + config, + ... + }: let + cfg = config.hive.virt-manager; + in { + options.hive.virt-manager = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Enable the qemu-kvm + libvirt stack. + ''; + }; + forUsers = lib.mkOption { + type = lib.types.listOf lib.types.singleLineStr; + default = []; + description = '' + List of users that should be added to the libvirt group. + ''; + }; }; - forUsers = lib.mkOption { - type = lib.types.listOf lib.types.singleLineStr; - default = []; - description = '' - List of users that should be added to the libvirt group. - ''; - }; - }; - config = lib.mkIf cfg.enable { - programs.virt-manager.enable = true; - users.groups.libvirtd.members = cfg.forUsers; - virtualisation.libvirtd.enable = true; - virtualisation.spiceUSBRedirection.enable = true; + config = lib.mkIf cfg.enable { + programs.virt-manager.enable = true; + users.groups.libvirtd.members = cfg.forUsers; + virtualisation.libvirtd.enable = true; + virtualisation.spiceUSBRedirection.enable = true; + }; }; } diff --git a/old/fixes/plasma-fix.nix b/old/fixes/plasma-fix.nix new file mode 100644 index 0000000..35e95f9 --- /dev/null +++ b/old/fixes/plasma-fix.nix @@ -0,0 +1,57 @@ +# https://github.com/NixOS/nixpkgs/issues/126590#issuecomment-3194531220 +{ + config, + pkgs, + lib, + ... +}: { + nixpkgs.overlays = lib.singleton (final: prev: { + kdePackages = + prev.kdePackages + // { + plasma-workspace = let + # the package we want to override + basePkg = prev.kdePackages.plasma-workspace; + + # a helper package that merges all the XDG_DATA_DIRS into a single directory + xdgdataPkg = pkgs.stdenv.mkDerivation { + name = "${basePkg.name}-xdgdata"; + buildInputs = [basePkg]; + dontUnpack = true; + dontFixup = true; + dontWrapQtApps = true; + installPhase = '' + mkdir -p $out/share + ( IFS=: + for DIR in $XDG_DATA_DIRS; do + if [[ -d "$DIR" ]]; then + cp -r $DIR/. $out/share/ + chmod -R u+w $out/share + fi + done + ) + ''; + }; + + # undo the XDG_DATA_DIRS injection that is usually done in the qt wrapper + # script and instead inject the path of the above helper package + derivedPkg = basePkg.overrideAttrs { + preFixup = '' + for index in "''${!qtWrapperArgs[@]}"; do + if [[ ''${qtWrapperArgs[$((index+0))]} == "--prefix" ]] && [[ ''${qtWrapperArgs[$((index+1))]} == "XDG_DATA_DIRS" ]]; then + unset -v "qtWrapperArgs[$((index+0))]" + unset -v "qtWrapperArgs[$((index+1))]" + unset -v "qtWrapperArgs[$((index+2))]" + unset -v "qtWrapperArgs[$((index+3))]" + fi + done + qtWrapperArgs=("''${qtWrapperArgs[@]}") + qtWrapperArgs+=(--prefix XDG_DATA_DIRS : "${xdgdataPkg}/share") + qtWrapperArgs+=(--prefix XDG_DATA_DIRS : "$out/share") + ''; + }; + in + derivedPkg; + }; + }); +} diff --git a/old/home/admin-jroeger.nix b/old/home/admin-jroeger.nix new file mode 100644 index 0000000..6dc6d51 --- /dev/null +++ b/old/home/admin-jroeger.nix @@ -0,0 +1,51 @@ +{lib, ...}: { + # Home Manager needs a bit of information about you and the paths it should + # manage. + home.username = "admin-jroeger"; + home.homeDirectory = "/home/admin-jroeger"; + + # hive modules + hive.kitty.enable = true; + hive.ranger.enable = true; + hive.yubikey.enable = true; + hive.yubikey.pinentry = "gnome3"; + hive.nix-scripts.enable = true; + hive.zsh.enable = true; + hive.doom.enable = true; + hive.doom.asDefaultEditor = true; + hive.doom.enableCopilot = true; + hive.doom.withNixPkgs = true; + hive.doom.withShellPkgs = true; + hive.doom.withCXXPkgs = true; + hive.doom.withPythonPkgs = true; + hive.jj.enable = true; + + # This value determines the Home Manager release that your configuration is + # compatible with. This helps avoid breakage when a new Home Manager release + # introduces backwards incompatible changes. + # + # You should not change this value, even if you update Home Manager. If you do + # want to update the value, then make sure to first check the Home Manager + # release notes. + home.stateVersion = "24.11"; # Please read the comment before changing. + + home.sessionVariables = { + EDITOR = lib.mkDefault "vim"; + }; + + # Let Home Manager install and manage itself. + programs.home-manager.enable = true; + + # Git + programs.difftastic.enable = true; + programs.difftastic.git.enable = true; + programs.git = { + enable = true; + settings.user.name = "Jonas Röger"; + settings.user.email = "jonas.kieran.roeger@iml.fraunhofer.de"; + signing = { + signByDefault = true; + key = "4000EB35E1AE0F07"; + }; + }; +} diff --git a/old/home/jonas@comfy-station.nix b/old/home/jonas@comfy-station.nix new file mode 100644 index 0000000..e983cc9 --- /dev/null +++ b/old/home/jonas@comfy-station.nix @@ -0,0 +1,105 @@ +{ + config, + lib, + ... +}: { + imports = [ + (./. + "/jonas@comfy-station/" + /borg.nix) + ]; + + # Home Manager needs a bit of information about you and the paths it should + # manage. + home.username = "jonas"; + home.homeDirectory = "/home/jonas"; + + sops = { + age.keyFile = "${config.home.homeDirectory}/.config/sops/age/keys.txt"; + }; + + # hive modules + hive.themes.layan.enable = true; + hive.themes.layan.pkgsInHome = true; + hive.hyprland.enable = true; + hive.swaync.enable = true; + hive.waybar.enable = true; + hive.wlogout.enable = true; + hive.wofi.enable = true; + hive.kitty.enable = true; + hive.nextcloud.enable = true; + hive.firefox = { + enable = true; + plasmaIntegration = true; + passFF = true; + }; + hive.kdeconnect.enable = true; + hive.ranger.enable = true; + hive.ssh = { + enable = true; + sopsFile = ../secrets/jonas/ssh.yaml; + keys = ["borg" "passgit"]; + }; + hive.yubikey.enable = true; + hive.yubikey.withCCID = false; + hive.zsh.enable = true; + hive.nix-scripts.enable = true; + hive.doom.enable = true; + hive.doom.asDefaultEditor = true; + hive.doom.enableCopilot = true; + hive.doom.withNixPkgs = true; + hive.doom.withShellPkgs = true; + hive.doom.withPythonPkgs = true; + hive.jj.enable = true; + + # Make session variables available in systemd units + # SEE: https://github.com/nix-community/home-manager/pull/5543 + # systemd.user.settings.Manager.DefaultEnvironment = + # lib.mapAttrs (_: lib.mkDefault) config.home.sessionVariables; + + xdg.mimeApps = { + enable = true; + + defaultApplications = { + "text/html" = "firefox.desktop"; + "x-scheme-handler/http" = "firefox.desktop"; + "x-scheme-handler/https" = "firefox.desktop"; + "x-scheme-handler/about" = "firefox.desktop"; + "x-scheme-handler/unknown" = "firefox.desktop"; + }; + }; + xdg.userDirs.enable = true; + xdg.userDirs.createDirectories = true; + xdg.userDirs.extraConfig = { + XDG_WORKSPACES_DIR = "${config.home.homeDirectory}/Workspaces"; + XDG_NEXTCLOUD_DIR = "${config.home.homeDirectory}/Nextcloud"; + XDG_NOTES_DIR = "${config.home.homeDirectory}/Notes"; + }; + + # This value determines the Home Manager release that your configuration is + # compatible with. This helps avoid breakage when a new Home Manager release + # introduces backwards incompatible changes. + # + # You should not change this value, even if you update Home Manager. If you do + # want to update the value, then make sure to first check the Home Manager + # release notes. + home.stateVersion = "24.11"; # Please read the comment before changing. + + home.sessionVariables = { + EDITOR = lib.mkDefault "vim"; + }; + + # Let Home Manager install and manage itself. + programs.home-manager.enable = true; + + # Git + programs.difftastic.enable = true; + programs.difftastic.git.enable = true; + programs.git = { + enable = true; + settings.user.name = "Jonas Röger"; + settings.user.email = "jonas.roeger@tu-dortmund.de"; + signing = { + signByDefault = true; + key = "4000EB35E1AE0F07"; + }; + }; +} diff --git a/old/home/jonas@comfy-station/borg.nix b/old/home/jonas@comfy-station/borg.nix new file mode 100644 index 0000000..fb1fcfa --- /dev/null +++ b/old/home/jonas@comfy-station/borg.nix @@ -0,0 +1,131 @@ +{config, ...}: let + defaultChecks = [ + { + name = "repository"; + frequency = "2 weeks"; + } + { + name = "archives"; + frequency = "4 weeks"; + } + { + name = "data"; + frequency = "6 weeks"; + } + { + name = "extract"; + frequency = "6 weeks"; + } + ]; + passwordFile = "${config.home.homeDirectory}/.config/borg/password"; + encCmd = ''cat ${passwordFile}''; + repo = "ssh://borg.jroeger.de/./comfy-station"; +in { + sops.secrets = { + "borg/password" = { + sopsFile = ../../secrets/jonas/borg.yaml; + key = "password"; + path = passwordFile; + }; + }; + + services.borgmatic.enable = true; + services.borgmatic.frequency = "hourly"; + + programs.borgmatic.enable = true; + programs.borgmatic.backups = { + workspaces = { + location = { + sourceDirectories = ["${config.xdg.userDirs.extraConfig.XDG_WORKSPACES_DIR}"]; + repositories = [repo]; + excludeHomeManagerSymlinks = true; + extraConfig = { + archive_name_format = "{hostname}-workspaces-{now}"; + exclude_patterns = [ + "*/.venv" + "__pycache__" + ]; + }; + }; + retention = { + keepDaily = 7; + keepHourly = 12; + keepWeekly = 4; + keepMonthly = 6; + }; + storage = { + encryptionPasscommand = encCmd; + }; + consistency.checks = defaultChecks; + }; + media = { + location = { + sourceDirectories = [ + "${config.xdg.userDirs.documents}" + "${config.xdg.userDirs.music}" + "${config.home.homeDirectory}/org" + "${config.home.homeDirectory}/Obsidian" + "${config.home.homeDirectory}/Zotero" + ]; + repositories = [repo]; + excludeHomeManagerSymlinks = true; + extraConfig = { + archive_name_format = "{hostname}-media-{now}"; + }; + }; + retention = { + keepDaily = 7; + keepWeekly = 2; + keepMonthly = 6; + }; + storage = { + encryptionPasscommand = encCmd; + }; + consistency.checks = defaultChecks; + }; + sec = { + location = { + sourceDirectories = [ + "${config.xdg.configHome}/sops" + "${config.home.homeDirectory}/Stuff/sec" + "${config.home.homeDirectory}/.password-store" + ]; + repositories = [repo]; + excludeHomeManagerSymlinks = true; + extraConfig = { + archive_name_format = "{hostname}-sec-{now}"; + }; + }; + retention = { + keepDaily = 7; + keepWeekly = 2; + keepMonthly = 6; + }; + storage = { + encryptionPasscommand = encCmd; + }; + consistency.checks = defaultChecks; + }; + var = { + location = { + sourceDirectories = [ + "${config.xdg.userDirs.desktop}" + ]; + repositories = [repo]; + excludeHomeManagerSymlinks = true; + extraConfig = { + archive_name_format = "{hostname}-var-{now}"; + }; + }; + retention = { + keepDaily = 7; + keepWeekly = 2; + keepMonthly = 6; + }; + storage = { + encryptionPasscommand = encCmd; + }; + consistency.checks = defaultChecks; + }; + }; +} diff --git a/old/home/jonas@harbor.nix b/old/home/jonas@harbor.nix new file mode 100644 index 0000000..ce0b482 --- /dev/null +++ b/old/home/jonas@harbor.nix @@ -0,0 +1,44 @@ +{lib, ...}: { + # Home Manager needs a bit of information about you and the paths it should + # manage. + home.username = "jonas"; + home.homeDirectory = "/home/jonas"; + + # hive modules + hive.zsh.enable = true; + hive.nix-scripts.enable = true; + hive.ranger.enable = true; + hive.doom.enable = true; + hive.doom.asDefaultEditor = true; + hive.doom.withNixPkgs = true; + hive.doom.withShellPkgs = true; + + # This value determines the Home Manager release that your configuration is + # compatible with. This helps avoid breakage when a new Home Manager release + # introduces backwards incompatible changes. + # + # You should not change this value, even if you update Home Manager. If you do + # want to update the value, then make sure to first check the Home Manager + # release notes. + home.stateVersion = "24.11"; # Please read the comment before changing. + + home.sessionVariables = { + EDITOR = lib.mkDefault "vim"; + }; + + # Let Home Manager install and manage itself. + programs.home-manager.enable = true; + + # Git + programs.difftastic.enable = true; + programs.difftastic.git.enable = true; + programs.git = { + enable = true; + settings.user.name = "Jonas Röger"; + settings.user.email = "jonas.roeger@tu-dortmund.de"; + signing = { + signByDefault = true; + key = "4000EB35E1AE0F07"; + }; + }; +} diff --git a/old/home/jonas@monolith.nix b/old/home/jonas@monolith.nix new file mode 100644 index 0000000..0b2863a --- /dev/null +++ b/old/home/jonas@monolith.nix @@ -0,0 +1,105 @@ +{ + config, + lib, + ... +}: rec { + # Home Manager needs a bit of information about you and the paths it should + # manage. + home.username = "jonas"; + home.homeDirectory = "/home/jonas"; + + sops = { + age.keyFile = "${home.homeDirectory}/.config/sops/age/keys.txt"; + }; + sops.secrets.gotifyDaemonToken = { + sopsFile = ../secrets/jonas/gotify.yaml; + key = "monolithDesktopToken"; + }; + sops.secrets.gotifyCLIToken = { + sopsFile = ../secrets/jonas/gotify.yaml; + key = "cliToken"; + }; + + # hive moduless + hive.doom.enable = true; + hive.doom.asDefaultEditor = true; + hive.doom.enableCopilot = false; + hive.doom.enableTidal = false; + hive.doom.withNixPkgs = true; + hive.doom.withShellPkgs = true; + hive.doom.withPythonPkgs = true; + hive.firefox = { + enable = true; + plasmaIntegration = false; + passFF = true; + }; + hive.kdeconnect.enable = false; + hive.kdeconnect.indicatorOnly = false; + hive.nextcloud.enable = false; # kwallet bug + hive.nix-scripts.enable = true; + hive.ranger.enable = true; + hive.themes.layan.enable = true; + hive.yubikey.enable = true; + hive.zsh.enable = true; + hive.jj.enable = true; + hive.gotify = { + cli.enable = true; + daemon.enable = true; + cli.tokenSopsKey = config.sops.secrets.gotifyCLIToken.name; + daemon.tokenSopsKey = config.sops.secrets.gotifyDaemonToken.name; + host = "gotify.jroeger.de"; + }; + + # Make session variables available in systemd units + # SEE: https://github.com/nix-community/home-manager/pull/5543 + # systemd.user.settings.Manager.DefaultEnvironment = + # lib.mapAttrs (_: lib.mkDefault) config.home.sessionVariables; + + xdg.mimeApps = { + enable = true; + + defaultApplications = { + "text/html" = "firefox.desktop"; + "x-scheme-handler/http" = "firefox.desktop"; + "x-scheme-handler/https" = "firefox.desktop"; + "x-scheme-handler/about" = "firefox.desktop"; + "x-scheme-handler/unknown" = "firefox.desktop"; + }; + }; + xdg.userDirs.enable = true; + xdg.userDirs.createDirectories = true; + xdg.userDirs.extraConfig = { + XDG_WORKSPACES_DIR = "${config.home.homeDirectory}/Workspaces"; + XDG_NEXTCLOUD_DIR = "${config.home.homeDirectory}/Nextcloud"; + XDG_NOTES_DIR = "${config.home.homeDirectory}/Notes"; + }; + + # This value determines the Home Manager release that your configuration is + # compatible with. This helps avoid breakage when a new Home Manager release + # introduces backwards incompatible changes. + # + # You should not change this value, even if you update Home Manager. If you do + # want to update the value, then make sure to first check the Home Manager + # release notes. + home.stateVersion = "24.11"; # Please read the comment before changing. + + home.sessionVariables = { + EDITOR = lib.mkDefault "vim"; + }; + + # Let Home Manager install and manage itself. + programs.home-manager.enable = true; + + # Git + programs.difftastic.enable = true; + programs.difftastic.git.enable = true; + programs.git = { + enable = true; + settings.user.name = "Jonas Röger"; + settings.user.email = "jonas.roeger@tu-dortmund.de"; + signing = { + signByDefault = true; + key = "4000EB35E1AE0F07"; + }; + }; +} diff --git a/old/hosts/comfy-station/configuration.nix b/old/hosts/comfy-station/configuration.nix new file mode 100644 index 0000000..9b3435c --- /dev/null +++ b/old/hosts/comfy-station/configuration.nix @@ -0,0 +1,177 @@ +# Edit this configuration file to define what should be installed on +# your system. Help is available in the configuration.nix(5) man page +# and in the NixOS manual (accessible by running ‘nixos-help’). +{ + config, + pkgs, + ... +}: { + imports = [ + # Include the results of the hardware scan. + ./hardware-configuration.nix + ]; + + # Secret management + sops.age.keyFile = "/var/lib/sops-nix/key.txt"; + sops.secrets.wg-priv = { + sopsFile = ../../secrets/comfy-station/wg.yaml; + key = "privateKey"; + }; + + # Users + users.users.jonas = { + isNormalUser = true; + description = "Jonas"; + extraGroups = ["networkmanager" "wheel" "docker" "dialout"]; + }; + users.defaultUserShell = pkgs.zsh; + programs.zsh.enable = true; + + # hive modules + hive.nix-scripts.enable = true; + hive.displayManager.name = "sddm"; + hive.hyprland.enable = true; + hive.kwallet.enable = true; + hive.kwallet.forUsers = ["jonas"]; + hive.virt-manager.enable = true; + hive.virt-manager.forUsers = ["jonas"]; + hive.bluetooth.enable = true; + hive.sound.enable = true; + hive.yubikey.enable = true; + hive.wg.client.enable = true; + hive.wg.client.privateKeyFile = config.sops.secrets.wg-priv.path; + hive.wg.client.peer = "comfy-station"; + hive.programs.games.enable = true; + hive.programs.games.steam = true; + hive.programs.creative = { + enable = true; + image-management = true; + image-raw-processing = true; + video-editing-light = true; + }; + + # system packages + environment.systemPackages = with pkgs; [ + age + alejandra + arduino + borgbackup + borgmatic + chromium + digikam + discord + docker + docker-compose + drawio + feh + ffmpeg + firefox + gimp + git + (gnome-network-displays.overrideAttrs (final: prev: {buildInputs = prev.buildInputs ++ [glib-networking];})) + insomnia + krita + libreoffice + mosquitto + mpv + mupdf + nh + nix-index + nix-output-monitor + obsidian + openhantek6022 + qalculate-qt + qtpass + ranger + sops + spotify + vim + vlc + vscode + wget + zoom + zotero + ]; + nixpkgs.config.permittedInsecurePackages = [ + "electron-25.9.0" # required by obsidian + ]; + services.avahi.enable = true; + services.udev.packages = [pkgs.openhantek6022]; + virtualisation.docker.enable = true; + + # This value determines the NixOS release from which the default + # settings for stateful data, like file locations and database versions + # on your system were taken. It‘s perfectly fine and recommended to leave + # this value at the release version of the first install of this system. + # Before changing this value read the documentation for this option + # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). + system.stateVersion = "24.11"; # Did you read the comment? + + # gc settings and binary caches + nix = { + settings = { + substituters = [ + "https://aseipp-nix-cache.freetls.fastly.net" + "https://nix-community.cachix.org" + "https://cache.nixos.org/" + ]; + experimental-features = ["nix-command" "flakes"]; + auto-optimise-store = true; + trusted-users = [ + "@wheel" + ]; + max-jobs = 2; + cores = 8; + }; + gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 30d"; + }; + }; + + # boot + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + boot.plymouth.enable = true; + boot.initrd.systemd.enable = true; + boot.supportedFilesystems = ["ntfs"]; + + # Configure console keymap + console.keyMap = "de"; + + # Set your time zone. + time.timeZone = "Europe/Berlin"; + + # Select internationalisation properties. + i18n.defaultLocale = "en_US.UTF-8"; + i18n.extraLocaleSettings = { + LC_ADDRESS = "de_DE.UTF-8"; + LC_IDENTIFICATION = "de_DE.UTF-8"; + LC_MEASUREMENT = "de_DE.UTF-8"; + LC_MONETARY = "de_DE.UTF-8"; + LC_NAME = "de_DE.UTF-8"; + LC_NUMERIC = "de_DE.UTF-8"; + LC_PAPER = "de_DE.UTF-8"; + LC_TELEPHONE = "de_DE.UTF-8"; + LC_TIME = "de_DE.UTF-8"; + }; + + networking.hostName = "comfy-station"; # Define your hostname. + + # Enable networking + networking.networkmanager.enable = true; + + # printing + services.printing.enable = true; + + # touchpad + services.libinput.touchpad.naturalScrolling = true; + + # ld-fix + programs.nix-ld.enable = true; + programs.nix-ld.libraries = [ + # Add any missing dynamic libraries for unpackaged programs + # here, NOT in environment.systemPackages + ]; +} diff --git a/old/hosts/comfy-station/hardware-configuration.nix b/old/hosts/comfy-station/hardware-configuration.nix new file mode 100644 index 0000000..ea64137 --- /dev/null +++ b/old/hosts/comfy-station/hardware-configuration.nix @@ -0,0 +1,47 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ + config, + lib, + pkgs, + modulesPath, + ... +}: { + imports = [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = ["nvme" "ehci_pci" "xhci_pci" "usb_storage" "sd_mod" "rtsx_pci_sdmmc"]; + boot.initrd.kernelModules = ["dm-snapshot"]; + boot.kernelModules = ["kvm-amd"]; + boot.extraModulePackages = []; + + boot.initrd.luks.devices."lvm-root".device = "/dev/disk/by-uuid/0b55681d-5c7b-4045-b895-d1eb7e306ffb"; + + fileSystems."/" = { + device = "/dev/disk/by-uuid/88f53721-1c3f-43fd-8875-59e597aacb10"; + fsType = "ext4"; + }; + + fileSystems."/boot" = { + device = "/dev/disk/by-uuid/583D-114B"; + fsType = "vfat"; + }; + + swapDevices = [ + {device = "/dev/disk/by-uuid/f81521e7-4c09-4e91-8914-3dcd9febdfff";} + ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.enp2s0f0.useDHCP = lib.mkDefault true; + # networking.interfaces.enp5s0.useDHCP = lib.mkDefault true; + # networking.interfaces.wlp3s0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/harbor/configuration.nix b/old/hosts/harbor/configuration.nix similarity index 100% rename from hosts/harbor/configuration.nix rename to old/hosts/harbor/configuration.nix diff --git a/hosts/harbor/disko.nix b/old/hosts/harbor/disko.nix similarity index 100% rename from hosts/harbor/disko.nix rename to old/hosts/harbor/disko.nix diff --git a/hosts/harbor/hardware-configuration.nix b/old/hosts/harbor/hardware-configuration.nix similarity index 100% rename from hosts/harbor/hardware-configuration.nix rename to old/hosts/harbor/hardware-configuration.nix diff --git a/hosts/monolith/configuration.nix b/old/hosts/monolith/configuration.nix similarity index 100% rename from hosts/monolith/configuration.nix rename to old/hosts/monolith/configuration.nix diff --git a/hosts/monolith/hardware-configuration.nix b/old/hosts/monolith/hardware-configuration.nix similarity index 100% rename from hosts/monolith/hardware-configuration.nix rename to old/hosts/monolith/hardware-configuration.nix diff --git a/hosts/vm/configuration.nix b/old/hosts/vm/configuration.nix similarity index 100% rename from hosts/vm/configuration.nix rename to old/hosts/vm/configuration.nix diff --git a/hosts/vm/hardware-configuration.nix b/old/hosts/vm/hardware-configuration.nix similarity index 100% rename from hosts/vm/hardware-configuration.nix rename to old/hosts/vm/hardware-configuration.nix diff --git a/hosts/wsl/configuration.nix b/old/hosts/wsl/configuration.nix similarity index 100% rename from hosts/wsl/configuration.nix rename to old/hosts/wsl/configuration.nix diff --git a/old/modules/bin/nix-scripts.nix b/old/modules/bin/nix-scripts.nix new file mode 100644 index 0000000..61c97b7 --- /dev/null +++ b/old/modules/bin/nix-scripts.nix @@ -0,0 +1,118 @@ +{ + config, + lib, + pkgs, + isHM, + ... +}: let + cfg = config.hive.nix-scripts; + home-rebuild = + pkgs.writeShellScriptBin ".home-rebuild" + '' + set -e + pushd ~/.hive/ + ${pkgs.alejandra}/bin/alejandra . &>/dev/null + ${pkgs.git}/bin/git diff -U0 + echo "NixOS Rebuilding..." + home-manager switch --flake ~/.hive -b backup --log-format internal-json |& ${pkgs.nix-output-monitor}/bin/nom --json + gen=$(home-manager generations | head -n1 | ${pkgs.gawk}/bin/awk '{print "Gen" $5 " @ " $1 "-" $2}') + by="$(${pkgs.coreutils-full}/bin/whoami)@$(${pkgs.nettools}/bin/hostname)" + ${pkgs.git}/bin/git commit --no-gpg-sign -am "Home $gen by $by" + popd + ''; + rebuild = + pkgs.writeShellScriptBin ".nixos-rebuild" + '' + set -e + pushd ~/.hive/ + ${pkgs.alejandra}/bin/alejandra . &>/dev/null + ${pkgs.git}/bin/git diff -U0 + echo "NixOS Rebuilding..." + ${pkgs.nh}/bin/nh os switch ~/.hive + gen=$(sudo nix-env --list-generations --profile /nix/var/nix/profiles/system | ${pkgs.gnugrep}/bin/grep current | ${pkgs.gawk}/bin/awk '{print "Gen" $1 " @ " $2 "-" $3}') + by="$(${pkgs.coreutils-full}/bin/whoami)@$(${pkgs.nettools}/bin/hostname)" + ${pkgs.git}/bin/git commit --no-gpg-sign -am "System $gen by $by" + popd + ''; + upgrade = + pkgs.writeShellScriptBin ".nixos-upgrade" + '' + set -e + pushd ~/.hive/ + if [ -n "$(${pkgs.git}/bin/git status --porcelain)" ]; then + echo ".hive is unclean!" + exit 1 + fi + branch_staging="staging-update" + + if ${pkgs.git}/bin/git rev-parse --verify "$branch_staging" >/dev/null 2>&1; then + echo "Using staging update branch." + else + echo "No staging update branch found." + exit 1 + fi + + ${pkgs.git}/bin/git checkout "$branch_staging" flake.lock + echo "Updating nix-flake..." + nix flake update --flake . + echo "NixOS Rebuilding..." + ${pkgs.nh}/bin/nh os switch ~/.hive + gen=$(sudo nix-env --list-generations --profile /nix/var/nix/profiles/system | ${pkgs.gnugrep}/bin/grep current | ${pkgs.gawk}/bin/awk '{print "Gen" $1 " @ " $2 "-" $3}') + by="$(${pkgs.coreutils-full}/bin/whoami)@$(${pkgs.nettools}/bin/hostname)" + ${pkgs.git}/bin/git commit --no-gpg-sign -am "Upgrade $gen by $by" + ${pkgs.git}/bin/git branch -D "$branch_staging" + popd + ''; + update = + pkgs.writeShellScriptBin ".nixos-update" + '' + set -e + pushd ~/.hive/ + if [ -n "$(${pkgs.git}/bin/git status --porcelain)" ]; then + echo ".hive is unclean!" + exit 1 + fi + branch_staging="staging-update" + branch_current="$(${pkgs.git}/bin/git branch --show-current)" + + if ${pkgs.git}/bin/git rev-parse --verify "$branch_staging" >/dev/null 2>&1; then + echo "There is already a staging update branch." + else + echo "Creating a new staging update branch." + ${pkgs.git}/bin/git switch -c "$branch_staging" + nix flake update --verbose --flake . + ${pkgs.git}/bin/git add flake.lock + ${pkgs.git}/bin/git commit --no-gpg-sign -m "staging update" + ${pkgs.git}/bin/git switch "$branch_current" + fi + + nix store --log-format internal-json -v diff-closures \ + '.?ref='"$branch_current"'#nixosConfigurations.'"$(${pkgs.hostname}/bin/hostname)"'.config.system.build.toplevel' \ + '.?ref='"$branch_staging"'#nixosConfigurations.'"$(${pkgs.hostname}/bin/hostname)"'.config.system.build.toplevel' \ + |& ${pkgs.nix-output-monitor}/bin/nom --json + + popd + ''; +in { + options = { + hive.nix-scripts.enable = lib.mkEnableOption "Enable the nix build/update scripts"; + }; + + config = + lib.mkIf cfg.enable + ( + if isHM + then { + home.packages = [ + home-rebuild + ]; + } + else { + environment.systemPackages = [ + rebuild + upgrade + update + ]; + } + ); +} diff --git a/modules/default.nix b/old/modules/default.nix similarity index 100% rename from modules/default.nix rename to old/modules/default.nix diff --git a/modules/desktop/de/default.nix b/old/modules/desktop/de/default.nix similarity index 100% rename from modules/desktop/de/default.nix rename to old/modules/desktop/de/default.nix diff --git a/modules/desktop/de/hyprland.nix b/old/modules/desktop/de/hyprland.nix similarity index 100% rename from modules/desktop/de/hyprland.nix rename to old/modules/desktop/de/hyprland.nix diff --git a/modules/desktop/de/plasma.nix b/old/modules/desktop/de/plasma.nix similarity index 100% rename from modules/desktop/de/plasma.nix rename to old/modules/desktop/de/plasma.nix diff --git a/modules/desktop/dm/default.nix b/old/modules/desktop/dm/default.nix similarity index 100% rename from modules/desktop/dm/default.nix rename to old/modules/desktop/dm/default.nix diff --git a/modules/desktop/dm/gdm.nix b/old/modules/desktop/dm/gdm.nix similarity index 100% rename from modules/desktop/dm/gdm.nix rename to old/modules/desktop/dm/gdm.nix diff --git a/modules/desktop/dm/sddm.nix b/old/modules/desktop/dm/sddm.nix similarity index 100% rename from modules/desktop/dm/sddm.nix rename to old/modules/desktop/dm/sddm.nix diff --git a/modules/desktop/themes/default.nix b/old/modules/desktop/themes/default.nix similarity index 100% rename from modules/desktop/themes/default.nix rename to old/modules/desktop/themes/default.nix diff --git a/modules/desktop/themes/layan.nix b/old/modules/desktop/themes/layan.nix similarity index 100% rename from modules/desktop/themes/layan.nix rename to old/modules/desktop/themes/layan.nix diff --git a/modules/home/doom/default.nix b/old/modules/home/doom/default.nix similarity index 100% rename from modules/home/doom/default.nix rename to old/modules/home/doom/default.nix diff --git a/modules/home/doom/doom.nix b/old/modules/home/doom/doom.nix similarity index 100% rename from modules/home/doom/doom.nix rename to old/modules/home/doom/doom.nix diff --git a/modules/home/doom/static/config.d/copilot.el b/old/modules/home/doom/static/config.d/copilot.el similarity index 100% rename from modules/home/doom/static/config.d/copilot.el rename to old/modules/home/doom/static/config.d/copilot.el diff --git a/modules/home/doom/static/config.el b/old/modules/home/doom/static/config.el similarity index 100% rename from modules/home/doom/static/config.el rename to old/modules/home/doom/static/config.el diff --git a/modules/home/doom/static/icon.png b/old/modules/home/doom/static/icon.png similarity index 100% rename from modules/home/doom/static/icon.png rename to old/modules/home/doom/static/icon.png diff --git a/modules/home/doom/static/init.el b/old/modules/home/doom/static/init.el similarity index 100% rename from modules/home/doom/static/init.el rename to old/modules/home/doom/static/init.el diff --git a/modules/home/doom/static/packages.d/copilot.el b/old/modules/home/doom/static/packages.d/copilot.el similarity index 100% rename from modules/home/doom/static/packages.d/copilot.el rename to old/modules/home/doom/static/packages.d/copilot.el diff --git a/modules/home/doom/static/packages.d/tidal.el b/old/modules/home/doom/static/packages.d/tidal.el similarity index 100% rename from modules/home/doom/static/packages.d/tidal.el rename to old/modules/home/doom/static/packages.d/tidal.el diff --git a/modules/home/doom/static/packages.el b/old/modules/home/doom/static/packages.el similarity index 100% rename from modules/home/doom/static/packages.el rename to old/modules/home/doom/static/packages.el diff --git a/modules/home/doom/static/packages/treesit-docgen.el b/old/modules/home/doom/static/packages/treesit-docgen.el similarity index 100% rename from modules/home/doom/static/packages/treesit-docgen.el rename to old/modules/home/doom/static/packages/treesit-docgen.el diff --git a/modules/home/doom/static/splash.png b/old/modules/home/doom/static/splash.png similarity index 100% rename from modules/home/doom/static/splash.png rename to old/modules/home/doom/static/splash.png diff --git a/modules/home/firefox.nix b/old/modules/home/firefox.nix similarity index 100% rename from modules/home/firefox.nix rename to old/modules/home/firefox.nix diff --git a/modules/home/flameshot.nix b/old/modules/home/flameshot.nix similarity index 100% rename from modules/home/flameshot.nix rename to old/modules/home/flameshot.nix diff --git a/modules/home/gotify.nix b/old/modules/home/gotify.nix similarity index 100% rename from modules/home/gotify.nix rename to old/modules/home/gotify.nix diff --git a/modules/home/hyprland/config.nix b/old/modules/home/hyprland/config.nix similarity index 100% rename from modules/home/hyprland/config.nix rename to old/modules/home/hyprland/config.nix diff --git a/modules/home/hyprland/default.nix b/old/modules/home/hyprland/default.nix similarity index 100% rename from modules/home/hyprland/default.nix rename to old/modules/home/hyprland/default.nix diff --git a/modules/home/hyprland/hyprland.nix b/old/modules/home/hyprland/hyprland.nix similarity index 100% rename from modules/home/hyprland/hyprland.nix rename to old/modules/home/hyprland/hyprland.nix diff --git a/modules/home/jj.nix b/old/modules/home/jj.nix similarity index 100% rename from modules/home/jj.nix rename to old/modules/home/jj.nix diff --git a/modules/home/kdeconnect.nix b/old/modules/home/kdeconnect.nix similarity index 100% rename from modules/home/kdeconnect.nix rename to old/modules/home/kdeconnect.nix diff --git a/modules/home/kitty/default.nix b/old/modules/home/kitty/default.nix similarity index 100% rename from modules/home/kitty/default.nix rename to old/modules/home/kitty/default.nix diff --git a/modules/home/nextcloud/default.nix b/old/modules/home/nextcloud/default.nix similarity index 100% rename from modules/home/nextcloud/default.nix rename to old/modules/home/nextcloud/default.nix diff --git a/modules/home/plasma.nix b/old/modules/home/plasma.nix similarity index 100% rename from modules/home/plasma.nix rename to old/modules/home/plasma.nix diff --git a/modules/home/ranger/default.nix b/old/modules/home/ranger/default.nix similarity index 100% rename from modules/home/ranger/default.nix rename to old/modules/home/ranger/default.nix diff --git a/modules/home/ssh.nix b/old/modules/home/ssh.nix similarity index 100% rename from modules/home/ssh.nix rename to old/modules/home/ssh.nix diff --git a/modules/home/swaync/default.nix b/old/modules/home/swaync/default.nix similarity index 100% rename from modules/home/swaync/default.nix rename to old/modules/home/swaync/default.nix diff --git a/modules/home/swaync/icons/bolt.png b/old/modules/home/swaync/icons/bolt.png similarity index 100% rename from modules/home/swaync/icons/bolt.png rename to old/modules/home/swaync/icons/bolt.png diff --git a/modules/home/swaync/icons/brightness-100.png b/old/modules/home/swaync/icons/brightness-100.png similarity index 100% rename from modules/home/swaync/icons/brightness-100.png rename to old/modules/home/swaync/icons/brightness-100.png diff --git a/modules/home/swaync/icons/brightness-20.png b/old/modules/home/swaync/icons/brightness-20.png similarity index 100% rename from modules/home/swaync/icons/brightness-20.png rename to old/modules/home/swaync/icons/brightness-20.png diff --git a/modules/home/swaync/icons/brightness-40.png b/old/modules/home/swaync/icons/brightness-40.png similarity index 100% rename from modules/home/swaync/icons/brightness-40.png rename to old/modules/home/swaync/icons/brightness-40.png diff --git a/modules/home/swaync/icons/brightness-60.png b/old/modules/home/swaync/icons/brightness-60.png similarity index 100% rename from modules/home/swaync/icons/brightness-60.png rename to old/modules/home/swaync/icons/brightness-60.png diff --git a/modules/home/swaync/icons/brightness-80.png b/old/modules/home/swaync/icons/brightness-80.png similarity index 100% rename from modules/home/swaync/icons/brightness-80.png rename to old/modules/home/swaync/icons/brightness-80.png diff --git a/modules/home/swaync/icons/gamemode.png b/old/modules/home/swaync/icons/gamemode.png similarity index 100% rename from modules/home/swaync/icons/gamemode.png rename to old/modules/home/swaync/icons/gamemode.png diff --git a/modules/home/swaync/icons/microphone-mute.png b/old/modules/home/swaync/icons/microphone-mute.png similarity index 100% rename from modules/home/swaync/icons/microphone-mute.png rename to old/modules/home/swaync/icons/microphone-mute.png diff --git a/modules/home/swaync/icons/microphone.png b/old/modules/home/swaync/icons/microphone.png similarity index 100% rename from modules/home/swaync/icons/microphone.png rename to old/modules/home/swaync/icons/microphone.png diff --git a/modules/home/swaync/icons/music.png b/old/modules/home/swaync/icons/music.png similarity index 100% rename from modules/home/swaync/icons/music.png rename to old/modules/home/swaync/icons/music.png diff --git a/modules/home/swaync/icons/palette.png b/old/modules/home/swaync/icons/palette.png similarity index 100% rename from modules/home/swaync/icons/palette.png rename to old/modules/home/swaync/icons/palette.png diff --git a/modules/home/swaync/icons/picture.png b/old/modules/home/swaync/icons/picture.png similarity index 100% rename from modules/home/swaync/icons/picture.png rename to old/modules/home/swaync/icons/picture.png diff --git a/modules/home/swaync/icons/play.png b/old/modules/home/swaync/icons/play.png similarity index 100% rename from modules/home/swaync/icons/play.png rename to old/modules/home/swaync/icons/play.png diff --git a/modules/home/swaync/icons/timer.png b/old/modules/home/swaync/icons/timer.png similarity index 100% rename from modules/home/swaync/icons/timer.png rename to old/modules/home/swaync/icons/timer.png diff --git a/modules/home/swaync/icons/volume-high.png b/old/modules/home/swaync/icons/volume-high.png similarity index 100% rename from modules/home/swaync/icons/volume-high.png rename to old/modules/home/swaync/icons/volume-high.png diff --git a/modules/home/swaync/icons/volume-low.png b/old/modules/home/swaync/icons/volume-low.png similarity index 100% rename from modules/home/swaync/icons/volume-low.png rename to old/modules/home/swaync/icons/volume-low.png diff --git a/modules/home/swaync/icons/volume-mid.png b/old/modules/home/swaync/icons/volume-mid.png similarity index 100% rename from modules/home/swaync/icons/volume-mid.png rename to old/modules/home/swaync/icons/volume-mid.png diff --git a/modules/home/swaync/icons/volume-mute.png b/old/modules/home/swaync/icons/volume-mute.png similarity index 100% rename from modules/home/swaync/icons/volume-mute.png rename to old/modules/home/swaync/icons/volume-mute.png diff --git a/modules/home/swaync/icons/wand.png b/old/modules/home/swaync/icons/wand.png similarity index 100% rename from modules/home/swaync/icons/wand.png rename to old/modules/home/swaync/icons/wand.png diff --git a/modules/home/swaync/themes/nova-dark/central_control.css b/old/modules/home/swaync/themes/nova-dark/central_control.css similarity index 100% rename from modules/home/swaync/themes/nova-dark/central_control.css rename to old/modules/home/swaync/themes/nova-dark/central_control.css diff --git a/modules/home/swaync/themes/nova-dark/notifications.css b/old/modules/home/swaync/themes/nova-dark/notifications.css similarity index 100% rename from modules/home/swaync/themes/nova-dark/notifications.css rename to old/modules/home/swaync/themes/nova-dark/notifications.css diff --git a/modules/home/themes/layan.nix b/old/modules/home/themes/layan.nix similarity index 100% rename from modules/home/themes/layan.nix rename to old/modules/home/themes/layan.nix diff --git a/modules/home/waybar/default.nix b/old/modules/home/waybar/default.nix similarity index 100% rename from modules/home/waybar/default.nix rename to old/modules/home/waybar/default.nix diff --git a/modules/home/wlogout/default.nix b/old/modules/home/wlogout/default.nix similarity index 100% rename from modules/home/wlogout/default.nix rename to old/modules/home/wlogout/default.nix diff --git a/modules/home/wlogout/icons/hibernate-hover.png b/old/modules/home/wlogout/icons/hibernate-hover.png similarity index 100% rename from modules/home/wlogout/icons/hibernate-hover.png rename to old/modules/home/wlogout/icons/hibernate-hover.png diff --git a/modules/home/wlogout/icons/hibernate.png b/old/modules/home/wlogout/icons/hibernate.png similarity index 100% rename from modules/home/wlogout/icons/hibernate.png rename to old/modules/home/wlogout/icons/hibernate.png diff --git a/modules/home/wlogout/icons/lock-hover.png b/old/modules/home/wlogout/icons/lock-hover.png similarity index 100% rename from modules/home/wlogout/icons/lock-hover.png rename to old/modules/home/wlogout/icons/lock-hover.png diff --git a/modules/home/wlogout/icons/lock.png b/old/modules/home/wlogout/icons/lock.png similarity index 100% rename from modules/home/wlogout/icons/lock.png rename to old/modules/home/wlogout/icons/lock.png diff --git a/modules/home/wlogout/icons/logout-hover.png b/old/modules/home/wlogout/icons/logout-hover.png similarity index 100% rename from modules/home/wlogout/icons/logout-hover.png rename to old/modules/home/wlogout/icons/logout-hover.png diff --git a/modules/home/wlogout/icons/logout.png b/old/modules/home/wlogout/icons/logout.png similarity index 100% rename from modules/home/wlogout/icons/logout.png rename to old/modules/home/wlogout/icons/logout.png diff --git a/modules/home/wlogout/icons/power-hover.png b/old/modules/home/wlogout/icons/power-hover.png similarity index 100% rename from modules/home/wlogout/icons/power-hover.png rename to old/modules/home/wlogout/icons/power-hover.png diff --git a/modules/home/wlogout/icons/power.png b/old/modules/home/wlogout/icons/power.png similarity index 100% rename from modules/home/wlogout/icons/power.png rename to old/modules/home/wlogout/icons/power.png diff --git a/modules/home/wlogout/icons/restart-hover.png b/old/modules/home/wlogout/icons/restart-hover.png similarity index 100% rename from modules/home/wlogout/icons/restart-hover.png rename to old/modules/home/wlogout/icons/restart-hover.png diff --git a/modules/home/wlogout/icons/restart.png b/old/modules/home/wlogout/icons/restart.png similarity index 100% rename from modules/home/wlogout/icons/restart.png rename to old/modules/home/wlogout/icons/restart.png diff --git a/modules/home/wlogout/icons/sleep-hover.png b/old/modules/home/wlogout/icons/sleep-hover.png similarity index 100% rename from modules/home/wlogout/icons/sleep-hover.png rename to old/modules/home/wlogout/icons/sleep-hover.png diff --git a/modules/home/wlogout/icons/sleep.png b/old/modules/home/wlogout/icons/sleep.png similarity index 100% rename from modules/home/wlogout/icons/sleep.png rename to old/modules/home/wlogout/icons/sleep.png diff --git a/modules/home/wlogout/style.css b/old/modules/home/wlogout/style.css similarity index 100% rename from modules/home/wlogout/style.css rename to old/modules/home/wlogout/style.css diff --git a/modules/home/wofi/default.nix b/old/modules/home/wofi/default.nix similarity index 100% rename from modules/home/wofi/default.nix rename to old/modules/home/wofi/default.nix diff --git a/modules/home/yubikey.nix b/old/modules/home/yubikey.nix similarity index 100% rename from modules/home/yubikey.nix rename to old/modules/home/yubikey.nix diff --git a/modules/home/zsh/default.nix b/old/modules/home/zsh/default.nix similarity index 100% rename from modules/home/zsh/default.nix rename to old/modules/home/zsh/default.nix diff --git a/modules/home/zsh/static/omz_custom/themes/my_bureau.zsh-theme b/old/modules/home/zsh/static/omz_custom/themes/my_bureau.zsh-theme similarity index 100% rename from modules/home/zsh/static/omz_custom/themes/my_bureau.zsh-theme rename to old/modules/home/zsh/static/omz_custom/themes/my_bureau.zsh-theme diff --git a/old/modules/programs/creative.nix b/old/modules/programs/creative.nix new file mode 100644 index 0000000..1becd41 --- /dev/null +++ b/old/modules/programs/creative.nix @@ -0,0 +1,89 @@ +{ + config, + lib, + pkgs, + ... +}: let + cfg = config.hive.programs.creative; + avidemux-wayland-fix = pkgs.avidemux.overrideAttrs (prev: { + installPhase = + (prev.installPhase or "") + + '' + wrapProgram $out/bin/avidemux3_qt5 \ + --add-flags "--platform" \ + --add-flags "xcb" + ''; + }); +in { + options.hive.programs.creative = { + enable = lib.mkEnableOption "Enable creative programs (video/image editing, etc.)"; + image-management = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Enable image management tools. + ''; + }; + image-editing = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Enable image editing tools. + ''; + }; + image-raw-processing = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Enable raw processing programs. + ''; + }; + video-editing-light = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Enable light video editing tools. + ''; + }; + video-editing-heavy = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Enable heavy video editing tools. + ''; + }; + daws = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Enable DAWs (currently bitwig beta) + ''; + }; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = with pkgs; + lib.optionals cfg.image-editing [gimp krita drawio] + ++ lib.optional cfg.image-management digikam + ++ lib.optionals cfg.image-raw-processing [ + enblend-enfuse + hdrmerge + hugin + rawtherapee + unstable.darktable + unstable.rapidraw + ] + ++ lib.optionals cfg.video-editing-light [ + avidemux-wayland-fix + ffmpeg + hive.bulk-transcode + losslesscut-bin + ] + ++ lib.optionals cfg.video-editing-heavy [ + davinci-resolve + kdePackages.kdenlive + obs-studio + ] + ++ lib.optional cfg.daws bitwig-studio-latest; + }; +} diff --git a/modules/programs/spotify-shortcuts.nix b/old/modules/programs/spotify-shortcuts.nix similarity index 100% rename from modules/programs/spotify-shortcuts.nix rename to old/modules/programs/spotify-shortcuts.nix diff --git a/modules/programs/utils.nix b/old/modules/programs/utils.nix similarity index 100% rename from modules/programs/utils.nix rename to old/modules/programs/utils.nix diff --git a/modules/services/borg-server.nix b/old/modules/services/borg-server.nix similarity index 100% rename from modules/services/borg-server.nix rename to old/modules/services/borg-server.nix diff --git a/modules/services/gitea-instance.nix b/old/modules/services/gitea-instance.nix similarity index 100% rename from modules/services/gitea-instance.nix rename to old/modules/services/gitea-instance.nix diff --git a/modules/services/gotify-instance.nix b/old/modules/services/gotify-instance.nix similarity index 100% rename from modules/services/gotify-instance.nix rename to old/modules/services/gotify-instance.nix diff --git a/modules/services/kdeconnect.nix b/old/modules/services/kdeconnect.nix similarity index 100% rename from modules/services/kdeconnect.nix rename to old/modules/services/kdeconnect.nix diff --git a/modules/services/minecraft-server/default.nix b/old/modules/services/minecraft-server/default.nix similarity index 100% rename from modules/services/minecraft-server/default.nix rename to old/modules/services/minecraft-server/default.nix diff --git a/modules/services/minecraft-server/loadCurseForge.nix b/old/modules/services/minecraft-server/loadCurseForge.nix similarity index 100% rename from modules/services/minecraft-server/loadCurseForge.nix rename to old/modules/services/minecraft-server/loadCurseForge.nix diff --git a/modules/services/nextcloud-instance.nix b/old/modules/services/nextcloud-instance.nix similarity index 100% rename from modules/services/nextcloud-instance.nix rename to old/modules/services/nextcloud-instance.nix diff --git a/old/pkgs/bulk-transcode/.envrc b/old/pkgs/bulk-transcode/.envrc new file mode 100644 index 0000000..7ee6560 --- /dev/null +++ b/old/pkgs/bulk-transcode/.envrc @@ -0,0 +1 @@ +use flake ../../#bulk-transcode --show-trace diff --git a/old/pkgs/bulk-transcode/bulk-transcode.sh b/old/pkgs/bulk-transcode/bulk-transcode.sh new file mode 100644 index 0000000..b8c6d5b --- /dev/null +++ b/old/pkgs/bulk-transcode/bulk-transcode.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash + +declare -rA presets=( + [davinci-resolve]="-c:v dnxhd -profile:v dnxhr_hq -pix_fmt yuv422p -c:a pcm_s16le" + [instagram]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)':flags=lanczos -r 30 -c:v libx264 -profile:v high -level 4.1 -pix_fmt yuv420p -preset slow -crf 18 -bf 2 -g 15 -keyint_min 15 -x264-params \"open-gop=0:cabac=1:b-pyramid=none\" -movflags +faststart -c:a aac -b:a 96k" + [insta-4k]="-r 30 -c:v libx264 -profile:v high -level 4.1 -pix_fmt yuv420p -preset slow -crf 18 -bf 2 -g 15 -keyint_min 15 -x264-params \"open-gop=0:cabac=1:b-pyramid=none\" -movflags +faststart -c:a aac -b:a 96k" + [storage-hevc]="-c:v libx265 -preset slower -crf 18 -pix_fmt yuv420p10le -x265-params aq-mode=3:aq-strength=1.0:psy-rd=1.8:psy-rdoq=1.0 -c:a copy" + [storage-av1]="-c:v libsvtav1 -preset 6 -crf 28 -pix_fmt yuv420p -g 240 -svtav1-params tune=0:aq-mode=2 -c:a copy" + [storage-av1-1080p]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)' -c:v libsvtav1 -preset 6 -crf 28 -pix_fmt yuv420p -g 240 -svtav1-params tune=0:aq-mode=2 -c:a copy" + [storage-av1-nvenc]="-c:v av1_nvenc -cq 28 -preset slow -pix_fmt yuv420p10le -c:a copy" + [network]="-c:v libx264 -preset slow -crf 22 -pix_fmt yuv420p -c:a aac -b:a 128k" + [network-1080p]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)' -c:v libx264 -preset slow -crf 22 -pix_fmt yuv420p -c:a aac -b:a 128k" + [whatsapp]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)' -c:v libx264 -preset slow -crf 30 -profile:v baseline -level 3.0 -pix_fmt yuv420p -r 25 -g 50 -c:a aac -b:a 160k -r:a 44100" +) + +declare -rA containers=( + [davinci-resolve]="mov" + [instagram]="mp4" + [insta-4k]="mp4" + [storage-hevc]="mkv" + [storage-av1]="mkv" + [storage-av1-1080p]="mkv" + [storage-av1-nvenc]="mkv" + [network]="mp4" + [network-1080p]="mp4" + [whatsapp]="mp4" +) + +where="${1:-.}" +dest="${2:-$where}" + +selection=$(find "$where" -type f | fzf --multi --preview 'ffprobe -v error -show_format -show_streams {}' --preview-window=up:wrap) + +preset=$( + printf '%s\n' "${!presets[@]}" | \ + fzf --multi --prompt "Select a preset" +) +flags="${presets[$preset]}" +container="${containers[$preset]}" + +output_dir=$(find "$dest" -type d ! -name '.*' ! -path '*/.*/*' | fzf --preview 'tree -C {}' --preview-window=up:wrap --prompt "Select output directory: ") + +if gum confirm "Flatten the directory structure?"; +then + flatten=true +else + flatten=false +fi + + +function transcode_job { + local ifile="$1" + local output_dir="$2" + local flatten="$3" + local where="$4" + local flags="$5" + local container="$6" + local fname=$(basename "$ifile") + local segment=$(realpath --relative-to="$where" "$ifile") + + + if [ "$flatten" = true ]; then + output_file="$output_dir/$fname.$container" + else + output_file="$output_dir/$segment.$container" + fi + + tmp_file=$(mktemp) + + echo "Running Command: ffmpeg -y -i $ifile $flags $output_file" >> "$tmp_file" + + mkdir -p "$(dirname "$output_file")" + + if ffmpeg -y -i "$ifile" $(echo -n "$flags") "$output_file" 2>> "$tmp_file"; + then + rm -f "$tmp_file" + else + # gum log "Failed to transcode $ifile. Check ./error.log for details." + cat "$tmp_file" >> error.log + rm -f "$tmp_file" + + fi +} +export -f transcode_job + +mapfile -t files <<< "$selection" +len=${#files[@]} +i=1 +for file in "${files[@]}"; do + if [[ -f "$file" ]]; then + gum spin --spinner dot --title "[$i/$len] Transcoding $file" -- bash -c "source <(declare -f transcode_job); transcode_job \"$file\" \"$output_dir\" \"$flatten\" \"$where\" \"$flags\" \"$container\"" + else + echo "Skipping invalid file: $file" >&2 + fi + ((i++)) +done diff --git a/old/pkgs/bulk-transcode/default.nix b/old/pkgs/bulk-transcode/default.nix new file mode 100644 index 0000000..1e1d8c0 --- /dev/null +++ b/old/pkgs/bulk-transcode/default.nix @@ -0,0 +1,35 @@ +{ + bash, + coreutils, + ffmpeg, + findutils, + fzf, + gum, + lib, + makeWrapper, + stdenv, + tree, + ... +}: +stdenv.mkDerivation (finalAttrs: { + name = "bulk-transcode"; + src = ./.; + + buildInputs = [ + bash + coreutils + ffmpeg + findutils + fzf + gum + makeWrapper + tree + ]; + + installPhase = '' + install -Dm755 bulk-transcode.sh $out/bin/bulk-transcode + + wrapProgram $out/bin/bulk-transcode \ + --set PATH "${lib.makeBinPath finalAttrs.buildInputs}" + ''; +}) diff --git a/old/pkgs/bulk-transcode/shell.nix b/old/pkgs/bulk-transcode/shell.nix new file mode 100644 index 0000000..327a200 --- /dev/null +++ b/old/pkgs/bulk-transcode/shell.nix @@ -0,0 +1,7 @@ +{pkgs ? import {}}: let + bin = pkgs.callPackage ./default.nix {}; +in + pkgs.mkShell { + name = "bulk-transcode"; + inputsFrom = [bin]; + } diff --git a/old/pkgs/crossover.nix b/old/pkgs/crossover.nix new file mode 100644 index 0000000..d9185d0 --- /dev/null +++ b/old/pkgs/crossover.nix @@ -0,0 +1,40 @@ +{ + appimageTools, + fetchurl, + makeWrapper, + ... +}: let + pname = "crossover"; + version = "3.1.5"; + src = fetchurl { + url = "https://github.com/lacymorrow/crossover/releases/download/v${version}/CrossOver-${version}-x86_64.AppImage"; + sha256 = "sha256-64RPal8n1PJh1LB+CTyNFt04Pw1lVgcsyc63S8yQ/DA="; + }; + appimageContents = appimageTools.extract { + inherit pname version src; + }; +in + appimageTools.wrapType2 { + inherit pname version src; + + nativeBuildInputs = [makeWrapper]; + extraInstallCommands = '' + wrapProgram $out/bin/${pname} --add-flags "--no-sandbox" + + # Create a minimal .desktop file manually + mkdir -p $out/share/applications + cat > $out/share/applications/${pname}.desktop < {}}: +pkgs.callPackage ./derivation.nix {} diff --git a/old/pkgs/spotify-shortcuts/derivation.nix b/old/pkgs/spotify-shortcuts/derivation.nix new file mode 100644 index 0000000..4bfa123 --- /dev/null +++ b/old/pkgs/spotify-shortcuts/derivation.nix @@ -0,0 +1,9 @@ +{python3Packages}: +with python3Packages; + buildPythonApplication { + name = "spotify-shortcuts"; + propagatedBuildInputs = [spotipy pyxdg desktop-notifier]; + pyproject = true; + build-system = [setuptools]; + src = ./.; + } diff --git a/old/pkgs/spotify-shortcuts/setup.py b/old/pkgs/spotify-shortcuts/setup.py new file mode 100644 index 0000000..474c0fe --- /dev/null +++ b/old/pkgs/spotify-shortcuts/setup.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +from setuptools import setup, find_packages + +setup( + name="spotify_shortcuts", + version="1.0", + packages=find_packages(), + entry_points={ + "console_scripts": [ + "spotisc=spotify_shortcuts.run:main", + "spotify-like=spotify_shortcuts.spotify_like:main", + "spotify-pl-add=spotify_shortcuts.spotify_pl_add:main", + ], + }, +) diff --git a/old/pkgs/spotify-shortcuts/shell.nix b/old/pkgs/spotify-shortcuts/shell.nix new file mode 100644 index 0000000..a863d83 --- /dev/null +++ b/old/pkgs/spotify-shortcuts/shell.nix @@ -0,0 +1,15 @@ +{pkgs ? import {}}: let + drv = pkgs.callPackage ./derivation.nix {}; +in + pkgs.mkShell { + packages = [ + pkgs.pyright + pkgs.black + ]; + + inputsFrom = [drv]; + + shellHook = '' + export PYTHONPATH="$PYTHONPATH:$(pwd)" + ''; + } diff --git a/old/pkgs/spotify-shortcuts/spotify_shortcuts/__init__.py b/old/pkgs/spotify-shortcuts/spotify_shortcuts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/old/pkgs/spotify-shortcuts/spotify_shortcuts/__main__.py b/old/pkgs/spotify-shortcuts/spotify_shortcuts/__main__.py new file mode 100644 index 0000000..8f3c09e --- /dev/null +++ b/old/pkgs/spotify-shortcuts/spotify_shortcuts/__main__.py @@ -0,0 +1,4 @@ +from spotify_shortcuts.run import main + +if __name__ == "__main__": + main() diff --git a/old/pkgs/spotify-shortcuts/spotify_shortcuts/config.py b/old/pkgs/spotify-shortcuts/spotify_shortcuts/config.py new file mode 100644 index 0000000..69901e1 --- /dev/null +++ b/old/pkgs/spotify-shortcuts/spotify_shortcuts/config.py @@ -0,0 +1,74 @@ +from pathlib import Path +from dataclasses import dataclass +from argparse import ArgumentParser +from typing import List +from os import getenv +from sys import argv +from xdg.BaseDirectory import xdg_cache_home +from json import loads + + +@dataclass +class Config: + cache_file: Path = Path(xdg_cache_home) / Path("spotify-shortcuts.json") + client_id: str | None = None + client_secret: str | None = None + notifications: bool = True + + @staticmethod + def from_file(path: Path): + if not path.exists(): + raise FileNotFoundError(f"Configuration file {path} does not exist.") + with open(path, "r") as f: + data = loads(f.read()) + + return Config( + cache_file=Path(data.get("cacheFile", Config.cache_file)), + client_id=data.get("clientId", Config.client_id), + client_secret=data.get("clientSecret", Config.client_secret), + ) + + +def load_config(args: List[str] = argv[1:]) -> Config: + parser = ArgumentParser(description="Spotify CLI Tool") + parser.add_argument( + "--cache-file", + type=Path, + default=Config.cache_file, + help="Path to the cache file for Spotify authentication", + ) + parser.add_argument( + "--client-id", + type=str, + default=Config.client_id, + help="Spotify API Client ID", + ) + parser.add_argument( + "--client-secret", + type=str, + default=Config.client_secret, + help="Spotify API Client Secret", + ) + parser.add_argument( + "--config-file", + type=str, + help="Path to a json configuration file with keys clientId and clientSecret", + ) + parser.add_argument( + "--no-notifications", + action="store_true", + help="Disable desktop notifications", + ) + + ns = parser.parse_args(args) + + cfg = Config() + if (cfg_file := ns.config_file or getenv("SPOTIFY_SHORTCUTS_CONFIG", None)) != None: + cfg = Config.from_file(Path(cfg_file)) + + return Config( + cache_file=ns.cache_file or cfg.cache_file, + client_id=ns.client_id or cfg.client_id, + client_secret=ns.client_secret or cfg.client_secret, + notifications=not ns.no_notifications or cfg.notifications, + ) diff --git a/old/pkgs/spotify-shortcuts/spotify_shortcuts/registry.py b/old/pkgs/spotify-shortcuts/spotify_shortcuts/registry.py new file mode 100644 index 0000000..7e6f694 --- /dev/null +++ b/old/pkgs/spotify-shortcuts/spotify_shortcuts/registry.py @@ -0,0 +1,7 @@ +from spotify_shortcuts.spotify_like import SpotifyLike +from spotify_shortcuts.spotify_pl_add import SpotifyPlAdd + +SHORTCUT_REGISTRY = { + "like": SpotifyLike(), + "pl_add": SpotifyPlAdd(), +} diff --git a/old/pkgs/spotify-shortcuts/spotify_shortcuts/run.py b/old/pkgs/spotify-shortcuts/spotify_shortcuts/run.py new file mode 100644 index 0000000..423ff6a --- /dev/null +++ b/old/pkgs/spotify-shortcuts/spotify_shortcuts/run.py @@ -0,0 +1,47 @@ +from spotify_shortcuts.config import Config, load_config +from spotify_shortcuts.shortcut import Shortcut +from spotify_shortcuts.spotify_auth import authenticated_session +from itertools import chain + + +def all_scopes() -> list[str]: + from spotify_shortcuts.registry import SHORTCUT_REGISTRY + + return list( + set( + chain.from_iterable( + shortcut.get_scopes() for shortcut in SHORTCUT_REGISTRY.values() + ) + ) + ) + + +def run_shortcut(shortcut: Shortcut, config: Config): + client = authenticated_session( + config, scopes=all_scopes() # use all scopes to avoid re-authentication + ) + + shortcut.execute(client, config) + + +def main(): + from spotify_shortcuts.registry import SHORTCUT_REGISTRY + import sys + + if len(sys.argv) < 2: + print(f"Usage: {sys.argv[0]} ") + sys.exit(1) + + shortcut_name = sys.argv[1] + if shortcut_name not in SHORTCUT_REGISTRY: + print(f"Shortcut '{shortcut_name}' not found.") + sys.exit(1) + + shortcut = SHORTCUT_REGISTRY[shortcut_name] + config = load_config(args=sys.argv[2:]) + + run_shortcut(shortcut, config) + + +if __name__ == "__main__": + main() diff --git a/old/pkgs/spotify-shortcuts/spotify_shortcuts/shortcut.py b/old/pkgs/spotify-shortcuts/spotify_shortcuts/shortcut.py new file mode 100644 index 0000000..e8d871b --- /dev/null +++ b/old/pkgs/spotify-shortcuts/spotify_shortcuts/shortcut.py @@ -0,0 +1,21 @@ +from abc import ABC, abstractmethod + +from spotify_shortcuts.config import Config +from spotipy import Spotify + + +class Shortcut(ABC): + @abstractmethod + def execute(self, client: Spotify, config: Config): + """Execute the shortcut action.""" + pass + + @abstractmethod + def get_help(self) -> str: + """Return a description of the shortcut.""" + pass + + @abstractmethod + def get_scopes(self) -> list[str]: + """Return the spotify API scopes required for the shortcut.""" + pass diff --git a/old/pkgs/spotify-shortcuts/spotify_shortcuts/spotify_auth.py b/old/pkgs/spotify-shortcuts/spotify_shortcuts/spotify_auth.py new file mode 100644 index 0000000..f4f6574 --- /dev/null +++ b/old/pkgs/spotify-shortcuts/spotify_shortcuts/spotify_auth.py @@ -0,0 +1,20 @@ +from spotipy.oauth2 import SpotifyOAuth +from spotipy import Spotify +from spotify_shortcuts.config import Config + +CALLBACK_URI = "http://127.0.0.1:45632/callback" + + +def authenticated_session(cfg: Config, scopes: list[str]) -> Spotify: + assert cfg.client_id, "Spotify client ID is required" + assert cfg.client_secret, "Spotify client secret is required" + + return Spotify( + auth_manager=SpotifyOAuth( + client_id=cfg.client_id, + client_secret=cfg.client_secret, + redirect_uri=CALLBACK_URI, + scope=" ".join(scopes), + cache_path=cfg.cache_file, + ) + ) diff --git a/old/pkgs/spotify-shortcuts/spotify_shortcuts/spotify_like.py b/old/pkgs/spotify-shortcuts/spotify_shortcuts/spotify_like.py new file mode 100644 index 0000000..32787ce --- /dev/null +++ b/old/pkgs/spotify-shortcuts/spotify_shortcuts/spotify_like.py @@ -0,0 +1,46 @@ +from spotify_shortcuts.run import run_shortcut +from spotify_shortcuts.shortcut import Shortcut +from spotify_shortcuts.config import load_config +from desktop_notifier import DesktopNotifierSync + +SCOPES = [ + "user-library-read", + "user-library-modify", + "user-read-playback-state", +] + + +class SpotifyLike(Shortcut): + def execute(self, client, config): + if (playback := client.current_playback()) is None: + print("No current playback found.") + return + + if (uri := playback.get("item", {}).get("uri", None)) is None: + print("No track URI found in current playback.") + return + + client.current_user_saved_tracks_add(tracks=[uri]) + + if config.notifications: + dn = DesktopNotifierSync() + dn.send( + title="Track Liked", + message=f"Track \"{playback.get('item', {}).get('name', '')}\" by \"{ + ", ".join(a.get('name', '') for a in playback.get('item', {}).get('artists', [])) + }\" has been liked.", + ) + + def get_help(self) -> str: + return "Like the currently playing track." + + def get_scopes(self) -> list[str]: + return SCOPES + + +def main(): + run_shortcut(SpotifyLike(), load_config()) + + +if __name__ == "__main__": + main() diff --git a/old/pkgs/spotify-shortcuts/spotify_shortcuts/spotify_pl_add.py b/old/pkgs/spotify-shortcuts/spotify_shortcuts/spotify_pl_add.py new file mode 100644 index 0000000..63d5426 --- /dev/null +++ b/old/pkgs/spotify-shortcuts/spotify_shortcuts/spotify_pl_add.py @@ -0,0 +1,57 @@ +from spotify_shortcuts.shortcut import Shortcut +from spotify_shortcuts.config import load_config +from desktop_notifier import DesktopNotifierSync +from spotify_shortcuts.run import run_shortcut + +SCOPES = [ + "playlist-modify-public", + "playlist-modify-private", + "user-read-playback-state", +] + + +class SpotifyPlAdd(Shortcut): + def execute(self, client, config): + if (playback := client.current_playback()) is None: + print("No current playback found.") + return + + if (track_uri := playback.get("item", {}).get("uri", None)) is None: + print("No track URI found in current playback.") + return + + if (context_uri := playback.get("context", {}).get("uri", None)) is None: + print("No context URI found in current playback.") + return + + client.playlist_add_items(context_uri, items=[track_uri]) + + if config.notifications: + track_name = playback.get("item", {}).get("name", "") + artists = ", ".join( + a.get("name", "") + for a in playback.get("item", {}).get("artists", []) + ) + playlist_name = (client.playlist(context_uri) or {}).get( + "name", "" + ) + + dn = DesktopNotifierSync() + dn.send( + title="Track Added to Playlist", + message=f'Track "{track_name}" by "{artists}" has been added to {playlist_name}.', + ) + + def get_help(self) -> str: + return "Add the currently playing track to the current playlist." + + def get_scopes(self) -> list[str]: + return SCOPES + + +def main(): + run_shortcut(SpotifyPlAdd(), load_config()) + + +if __name__ == "__main__": + main() diff --git a/old/static/keys/borg-jonas@comfy-station.pub b/old/static/keys/borg-jonas@comfy-station.pub new file mode 100644 index 0000000..e286cb7 --- /dev/null +++ b/old/static/keys/borg-jonas@comfy-station.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILNYmQ4HspLsunLyryI/ZbX4tTuRI6cRv0n/ai6+DNCc borg@jroeger.de diff --git a/old/static/keys/my_pub.asc b/old/static/keys/my_pub.asc new file mode 100644 index 0000000..3eecce5 --- /dev/null +++ b/old/static/keys/my_pub.asc @@ -0,0 +1,448 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Comment: Hostname: +Version: Hockeypuck 2.1.1-10-gec3b0e7 + +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 +=JVtR +-----END PGP PUBLIC KEY BLOCK----- diff --git a/old/static/keys/passgit-jonas@comfy-station.pub b/old/static/keys/passgit-jonas@comfy-station.pub new file mode 100644 index 0000000..a16c7c6 --- /dev/null +++ b/old/static/keys/passgit-jonas@comfy-station.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBodNTvEGT2J+w6qpJNvmwZuHCshzq2nwU92+VqRcyn4 jonas@comfy-station diff --git a/old/static/wallpaper/nord.png b/old/static/wallpaper/nord.png new file mode 100644 index 0000000..464e50e Binary files /dev/null and b/old/static/wallpaper/nord.png differ diff --git a/old/static/wallpaper/stones.jpg b/old/static/wallpaper/stones.jpg new file mode 100644 index 0000000..1e199ca Binary files /dev/null and b/old/static/wallpaper/stones.jpg differ diff --git a/old/templates/cmake-c/.gitignore b/old/templates/cmake-c/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/old/templates/cmake-c/.gitignore @@ -0,0 +1 @@ +build diff --git a/old/templates/cmake-c/CMakeLists.txt b/old/templates/cmake-c/CMakeLists.txt new file mode 100644 index 0000000..1f0e64f --- /dev/null +++ b/old/templates/cmake-c/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 3.15) + +project(Hello + DESCRIPTION "Hello World" + LANGUAGES C +) + +add_executable(hello src/main.c) + +install(TARGETS hello) diff --git a/old/templates/cmake-c/flake.nix b/old/templates/cmake-c/flake.nix new file mode 100644 index 0000000..1a56dc3 --- /dev/null +++ b/old/templates/cmake-c/flake.nix @@ -0,0 +1,56 @@ +{ + description = "Cmake C Flake"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + flake-parts.url = "github:hercules-ci/flake-parts"; + }; + + outputs = inputs @ { + self, + flake-parts, + ... + }: + flake-parts.lib.mkFlake {inherit inputs;} ( + top: { + imports = []; + + flake = { + overlays.default = final: prev: { + my-derivation = final.callPackage ./nix/derivation.nix {}; + }; + }; + + systems = [ + "x86_64-linux" + ]; + + perSystem = { + self', + pkgs, + system, + ... + }: { + _module.args.pkgs = import inputs.nixpkgs { + inherit system; + overlays = [self.overlays.default]; + }; + + packages.default = pkgs.my-derivation; + + devShells.default = pkgs.mkShell { + packages = [ + pkgs.cmake-language-server + pkgs.cmake-format + pkgs.clang-tools + pkgs.gdb + ]; + inputsFrom = [self'.packages.default]; + shellHook = '' + export CMAKE_EXPORT_COMPILE_COMMANDS=ON + ''; + }; + }; + } + ); +} diff --git a/old/templates/cmake-c/nix/derivation.nix b/old/templates/cmake-c/nix/derivation.nix new file mode 100644 index 0000000..c1d08b8 --- /dev/null +++ b/old/templates/cmake-c/nix/derivation.nix @@ -0,0 +1,17 @@ +{ + cmake, + stdenv, + ... +}: +stdenv.mkDerivation (finalAttrs: { + pname = "my-derivation"; + version = "0.1.0"; + src = ../.; + nativeBuildInputs = [cmake]; + buildInputs = []; + + meta = { + description = "Hello World Binary"; + mainProgram = "hello"; + }; +}) diff --git a/old/templates/cmake-c/src/main.c b/old/templates/cmake-c/src/main.c new file mode 100644 index 0000000..39ccd04 --- /dev/null +++ b/old/templates/cmake-c/src/main.c @@ -0,0 +1,6 @@ +#include + +int main() { + puts("Hello, Flake!"); + return 0; +} diff --git a/old/templates/rust/.envrc b/old/templates/rust/.envrc new file mode 100644 index 0000000..412cbef --- /dev/null +++ b/old/templates/rust/.envrc @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# ^ make editor happy + +# +# Use https://direnv.net/ to automatically load the dev shell. +# + +if ! has nix_direnv_version || ! nix_direnv_version 3.0.4; then + source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.4/direnvrc" "sha256-DzlYZ33mWF/Gs8DDeyjr8mnVmQGx7ASYqA5WlxwvBG4=" +fi + +watch_file nix/** +watch_file -- **/*.nix +# Adding files to git includes them in a flake +# But it is also a bit much reloading. +# watch_file .git/index .git/HEAD +use flake . --show-trace diff --git a/old/templates/rust/.gitignore b/old/templates/rust/.gitignore new file mode 100644 index 0000000..80c4fce --- /dev/null +++ b/old/templates/rust/.gitignore @@ -0,0 +1,3 @@ +.direnv/ +target/ +result/ diff --git a/old/templates/rust/Cargo.toml b/old/templates/rust/Cargo.toml new file mode 100644 index 0000000..9322e5e --- /dev/null +++ b/old/templates/rust/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "hello" +description = "A test rust binary" +publish = false +version = "0.1.0" + +edition = "2021" + +[[bin]] +name = "hello" +path = "src/main.rs" diff --git a/old/templates/rust/flake.nix b/old/templates/rust/flake.nix new file mode 100644 index 0000000..2d1b81a --- /dev/null +++ b/old/templates/rust/flake.nix @@ -0,0 +1,61 @@ +{ + description = "Rust-Hello"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + rust-overlay = { + url = "github:oxalica/rust-overlay"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + flake-utils.url = "github:numtide/flake-utils"; + crate2nix = { + url = "github:nix-community/crate2nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = inputs @ { + crate2nix, + flake-utils, + nixpkgs, + rust-overlay, + ... + }: + flake-utils.lib.eachDefaultSystem ( + system: let + # Overlay pkgs with rust-bin + overlays = [(import rust-overlay)]; + pkgs = import nixpkgs { + inherit system overlays; + }; + + # Use rust-bin to generate the toolchain from rust-toolchain.toml + rust-toolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; + + buildRustCrateForPkgs = _: + pkgs.buildRustCrate.override { + rustc = rust-toolchain; # Use rustc from toolchain + cargo = rust-toolchain; # Use cargo from toolchain + }; + + # Cargo.nix for IFD + generatedCargoNix = crate2nix.tools.${system}.generatedCargoNix { + name = "rustnix"; + src = ./.; + }; + + cargoNix = import generatedCargoNix { + inherit pkgs buildRustCrateForPkgs; + }; + in { + packages = rec { + hello = cargoNix.rootCrate.build; + default = hello; + }; + + devShell = pkgs.mkShell { + buildInputs = [rust-toolchain]; + }; + } + ); +} diff --git a/old/templates/rust/rust-toolchain.toml b/old/templates/rust/rust-toolchain.toml new file mode 100644 index 0000000..535db1f --- /dev/null +++ b/old/templates/rust/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "1.85.0" +components = [ "rustfmt", "rustc-dev", "rust-analyzer", "rust-src"] diff --git a/old/templates/rust/src/main.rs b/old/templates/rust/src/main.rs new file mode 100644 index 0000000..ea5b5d8 --- /dev/null +++ b/old/templates/rust/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("{}", "Hello, world!"); +} diff --git a/overlays/unstable.nix b/overlays/unstable.nix new file mode 100644 index 0000000..3cb2730 --- /dev/null +++ b/overlays/unstable.nix @@ -0,0 +1,8 @@ +{inputs, ...}: { + flake.overlays.unstable = final: prev: { + unstable = import inputs.nixpkgs-unstable { + system = prev.system; + config.allowUnfree = true; + }; + }; +} diff --git a/packages/bulk-transcode/.envrc b/packages/bulk-transcode/.envrc new file mode 100644 index 0000000..7ee6560 --- /dev/null +++ b/packages/bulk-transcode/.envrc @@ -0,0 +1 @@ +use flake ../../#bulk-transcode --show-trace diff --git a/packages/bulk-transcode/bulk-transcode.sh b/packages/bulk-transcode/bulk-transcode.sh new file mode 100644 index 0000000..b8c6d5b --- /dev/null +++ b/packages/bulk-transcode/bulk-transcode.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash + +declare -rA presets=( + [davinci-resolve]="-c:v dnxhd -profile:v dnxhr_hq -pix_fmt yuv422p -c:a pcm_s16le" + [instagram]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)':flags=lanczos -r 30 -c:v libx264 -profile:v high -level 4.1 -pix_fmt yuv420p -preset slow -crf 18 -bf 2 -g 15 -keyint_min 15 -x264-params \"open-gop=0:cabac=1:b-pyramid=none\" -movflags +faststart -c:a aac -b:a 96k" + [insta-4k]="-r 30 -c:v libx264 -profile:v high -level 4.1 -pix_fmt yuv420p -preset slow -crf 18 -bf 2 -g 15 -keyint_min 15 -x264-params \"open-gop=0:cabac=1:b-pyramid=none\" -movflags +faststart -c:a aac -b:a 96k" + [storage-hevc]="-c:v libx265 -preset slower -crf 18 -pix_fmt yuv420p10le -x265-params aq-mode=3:aq-strength=1.0:psy-rd=1.8:psy-rdoq=1.0 -c:a copy" + [storage-av1]="-c:v libsvtav1 -preset 6 -crf 28 -pix_fmt yuv420p -g 240 -svtav1-params tune=0:aq-mode=2 -c:a copy" + [storage-av1-1080p]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)' -c:v libsvtav1 -preset 6 -crf 28 -pix_fmt yuv420p -g 240 -svtav1-params tune=0:aq-mode=2 -c:a copy" + [storage-av1-nvenc]="-c:v av1_nvenc -cq 28 -preset slow -pix_fmt yuv420p10le -c:a copy" + [network]="-c:v libx264 -preset slow -crf 22 -pix_fmt yuv420p -c:a aac -b:a 128k" + [network-1080p]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)' -c:v libx264 -preset slow -crf 22 -pix_fmt yuv420p -c:a aac -b:a 128k" + [whatsapp]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)' -c:v libx264 -preset slow -crf 30 -profile:v baseline -level 3.0 -pix_fmt yuv420p -r 25 -g 50 -c:a aac -b:a 160k -r:a 44100" +) + +declare -rA containers=( + [davinci-resolve]="mov" + [instagram]="mp4" + [insta-4k]="mp4" + [storage-hevc]="mkv" + [storage-av1]="mkv" + [storage-av1-1080p]="mkv" + [storage-av1-nvenc]="mkv" + [network]="mp4" + [network-1080p]="mp4" + [whatsapp]="mp4" +) + +where="${1:-.}" +dest="${2:-$where}" + +selection=$(find "$where" -type f | fzf --multi --preview 'ffprobe -v error -show_format -show_streams {}' --preview-window=up:wrap) + +preset=$( + printf '%s\n' "${!presets[@]}" | \ + fzf --multi --prompt "Select a preset" +) +flags="${presets[$preset]}" +container="${containers[$preset]}" + +output_dir=$(find "$dest" -type d ! -name '.*' ! -path '*/.*/*' | fzf --preview 'tree -C {}' --preview-window=up:wrap --prompt "Select output directory: ") + +if gum confirm "Flatten the directory structure?"; +then + flatten=true +else + flatten=false +fi + + +function transcode_job { + local ifile="$1" + local output_dir="$2" + local flatten="$3" + local where="$4" + local flags="$5" + local container="$6" + local fname=$(basename "$ifile") + local segment=$(realpath --relative-to="$where" "$ifile") + + + if [ "$flatten" = true ]; then + output_file="$output_dir/$fname.$container" + else + output_file="$output_dir/$segment.$container" + fi + + tmp_file=$(mktemp) + + echo "Running Command: ffmpeg -y -i $ifile $flags $output_file" >> "$tmp_file" + + mkdir -p "$(dirname "$output_file")" + + if ffmpeg -y -i "$ifile" $(echo -n "$flags") "$output_file" 2>> "$tmp_file"; + then + rm -f "$tmp_file" + else + # gum log "Failed to transcode $ifile. Check ./error.log for details." + cat "$tmp_file" >> error.log + rm -f "$tmp_file" + + fi +} +export -f transcode_job + +mapfile -t files <<< "$selection" +len=${#files[@]} +i=1 +for file in "${files[@]}"; do + if [[ -f "$file" ]]; then + gum spin --spinner dot --title "[$i/$len] Transcoding $file" -- bash -c "source <(declare -f transcode_job); transcode_job \"$file\" \"$output_dir\" \"$flatten\" \"$where\" \"$flags\" \"$container\"" + else + echo "Skipping invalid file: $file" >&2 + fi + ((i++)) +done diff --git a/packages/bulk-transcode/default.nix b/packages/bulk-transcode/default.nix new file mode 100644 index 0000000..ec76987 --- /dev/null +++ b/packages/bulk-transcode/default.nix @@ -0,0 +1,9 @@ +{ + flake.overlays.bulk-transcode = final: prev: { + bulk-transcode = import ./overlay.nix {inherit final prev;}; + }; + perSystem = {pkgs, ...}: { + packages.bulk-transcode = pkgs.callPackage ./derivation.nix {}; + devShells.bulk-transcode = import ./shell.nix {inherit pkgs;}; + }; +} diff --git a/packages/bulk-transcode/derivation.nix b/packages/bulk-transcode/derivation.nix new file mode 100644 index 0000000..1e1d8c0 --- /dev/null +++ b/packages/bulk-transcode/derivation.nix @@ -0,0 +1,35 @@ +{ + bash, + coreutils, + ffmpeg, + findutils, + fzf, + gum, + lib, + makeWrapper, + stdenv, + tree, + ... +}: +stdenv.mkDerivation (finalAttrs: { + name = "bulk-transcode"; + src = ./.; + + buildInputs = [ + bash + coreutils + ffmpeg + findutils + fzf + gum + makeWrapper + tree + ]; + + installPhase = '' + install -Dm755 bulk-transcode.sh $out/bin/bulk-transcode + + wrapProgram $out/bin/bulk-transcode \ + --set PATH "${lib.makeBinPath finalAttrs.buildInputs}" + ''; +}) diff --git a/packages/bulk-transcode/shell.nix b/packages/bulk-transcode/shell.nix new file mode 100644 index 0000000..d1ee79e --- /dev/null +++ b/packages/bulk-transcode/shell.nix @@ -0,0 +1,7 @@ +{pkgs ? import {}}: let + bin = pkgs.callPackage ./derivation.nix {}; +in + pkgs.mkShell { + name = "bulk-transcode"; + inputsFrom = [bin]; + } diff --git a/packages/crossover.nix b/packages/crossover.nix new file mode 100644 index 0000000..d9185d0 --- /dev/null +++ b/packages/crossover.nix @@ -0,0 +1,40 @@ +{ + appimageTools, + fetchurl, + makeWrapper, + ... +}: let + pname = "crossover"; + version = "3.1.5"; + src = fetchurl { + url = "https://github.com/lacymorrow/crossover/releases/download/v${version}/CrossOver-${version}-x86_64.AppImage"; + sha256 = "sha256-64RPal8n1PJh1LB+CTyNFt04Pw1lVgcsyc63S8yQ/DA="; + }; + appimageContents = appimageTools.extract { + inherit pname version src; + }; +in + appimageTools.wrapType2 { + inherit pname version src; + + nativeBuildInputs = [makeWrapper]; + extraInstallCommands = '' + wrapProgram $out/bin/${pname} --add-flags "--no-sandbox" + + # Create a minimal .desktop file manually + mkdir -p $out/share/applications + cat > $out/share/applications/${pname}.desktop < {}}: +pkgs.callPackage ./derivation.nix {} diff --git a/packages/spotify-shortcuts/derivation.nix b/packages/spotify-shortcuts/derivation.nix new file mode 100644 index 0000000..4bfa123 --- /dev/null +++ b/packages/spotify-shortcuts/derivation.nix @@ -0,0 +1,9 @@ +{python3Packages}: +with python3Packages; + buildPythonApplication { + name = "spotify-shortcuts"; + propagatedBuildInputs = [spotipy pyxdg desktop-notifier]; + pyproject = true; + build-system = [setuptools]; + src = ./.; + } diff --git a/packages/spotify-shortcuts/setup.py b/packages/spotify-shortcuts/setup.py new file mode 100644 index 0000000..474c0fe --- /dev/null +++ b/packages/spotify-shortcuts/setup.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +from setuptools import setup, find_packages + +setup( + name="spotify_shortcuts", + version="1.0", + packages=find_packages(), + entry_points={ + "console_scripts": [ + "spotisc=spotify_shortcuts.run:main", + "spotify-like=spotify_shortcuts.spotify_like:main", + "spotify-pl-add=spotify_shortcuts.spotify_pl_add:main", + ], + }, +) diff --git a/packages/spotify-shortcuts/shell.nix b/packages/spotify-shortcuts/shell.nix new file mode 100644 index 0000000..a863d83 --- /dev/null +++ b/packages/spotify-shortcuts/shell.nix @@ -0,0 +1,15 @@ +{pkgs ? import {}}: let + drv = pkgs.callPackage ./derivation.nix {}; +in + pkgs.mkShell { + packages = [ + pkgs.pyright + pkgs.black + ]; + + inputsFrom = [drv]; + + shellHook = '' + export PYTHONPATH="$PYTHONPATH:$(pwd)" + ''; + } diff --git a/packages/spotify-shortcuts/spotify_shortcuts/__init__.py b/packages/spotify-shortcuts/spotify_shortcuts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/packages/spotify-shortcuts/spotify_shortcuts/__main__.py b/packages/spotify-shortcuts/spotify_shortcuts/__main__.py new file mode 100644 index 0000000..8f3c09e --- /dev/null +++ b/packages/spotify-shortcuts/spotify_shortcuts/__main__.py @@ -0,0 +1,4 @@ +from spotify_shortcuts.run import main + +if __name__ == "__main__": + main() diff --git a/packages/spotify-shortcuts/spotify_shortcuts/config.py b/packages/spotify-shortcuts/spotify_shortcuts/config.py new file mode 100644 index 0000000..69901e1 --- /dev/null +++ b/packages/spotify-shortcuts/spotify_shortcuts/config.py @@ -0,0 +1,74 @@ +from pathlib import Path +from dataclasses import dataclass +from argparse import ArgumentParser +from typing import List +from os import getenv +from sys import argv +from xdg.BaseDirectory import xdg_cache_home +from json import loads + + +@dataclass +class Config: + cache_file: Path = Path(xdg_cache_home) / Path("spotify-shortcuts.json") + client_id: str | None = None + client_secret: str | None = None + notifications: bool = True + + @staticmethod + def from_file(path: Path): + if not path.exists(): + raise FileNotFoundError(f"Configuration file {path} does not exist.") + with open(path, "r") as f: + data = loads(f.read()) + + return Config( + cache_file=Path(data.get("cacheFile", Config.cache_file)), + client_id=data.get("clientId", Config.client_id), + client_secret=data.get("clientSecret", Config.client_secret), + ) + + +def load_config(args: List[str] = argv[1:]) -> Config: + parser = ArgumentParser(description="Spotify CLI Tool") + parser.add_argument( + "--cache-file", + type=Path, + default=Config.cache_file, + help="Path to the cache file for Spotify authentication", + ) + parser.add_argument( + "--client-id", + type=str, + default=Config.client_id, + help="Spotify API Client ID", + ) + parser.add_argument( + "--client-secret", + type=str, + default=Config.client_secret, + help="Spotify API Client Secret", + ) + parser.add_argument( + "--config-file", + type=str, + help="Path to a json configuration file with keys clientId and clientSecret", + ) + parser.add_argument( + "--no-notifications", + action="store_true", + help="Disable desktop notifications", + ) + + ns = parser.parse_args(args) + + cfg = Config() + if (cfg_file := ns.config_file or getenv("SPOTIFY_SHORTCUTS_CONFIG", None)) != None: + cfg = Config.from_file(Path(cfg_file)) + + return Config( + cache_file=ns.cache_file or cfg.cache_file, + client_id=ns.client_id or cfg.client_id, + client_secret=ns.client_secret or cfg.client_secret, + notifications=not ns.no_notifications or cfg.notifications, + ) diff --git a/packages/spotify-shortcuts/spotify_shortcuts/registry.py b/packages/spotify-shortcuts/spotify_shortcuts/registry.py new file mode 100644 index 0000000..7e6f694 --- /dev/null +++ b/packages/spotify-shortcuts/spotify_shortcuts/registry.py @@ -0,0 +1,7 @@ +from spotify_shortcuts.spotify_like import SpotifyLike +from spotify_shortcuts.spotify_pl_add import SpotifyPlAdd + +SHORTCUT_REGISTRY = { + "like": SpotifyLike(), + "pl_add": SpotifyPlAdd(), +} diff --git a/packages/spotify-shortcuts/spotify_shortcuts/run.py b/packages/spotify-shortcuts/spotify_shortcuts/run.py new file mode 100644 index 0000000..423ff6a --- /dev/null +++ b/packages/spotify-shortcuts/spotify_shortcuts/run.py @@ -0,0 +1,47 @@ +from spotify_shortcuts.config import Config, load_config +from spotify_shortcuts.shortcut import Shortcut +from spotify_shortcuts.spotify_auth import authenticated_session +from itertools import chain + + +def all_scopes() -> list[str]: + from spotify_shortcuts.registry import SHORTCUT_REGISTRY + + return list( + set( + chain.from_iterable( + shortcut.get_scopes() for shortcut in SHORTCUT_REGISTRY.values() + ) + ) + ) + + +def run_shortcut(shortcut: Shortcut, config: Config): + client = authenticated_session( + config, scopes=all_scopes() # use all scopes to avoid re-authentication + ) + + shortcut.execute(client, config) + + +def main(): + from spotify_shortcuts.registry import SHORTCUT_REGISTRY + import sys + + if len(sys.argv) < 2: + print(f"Usage: {sys.argv[0]} ") + sys.exit(1) + + shortcut_name = sys.argv[1] + if shortcut_name not in SHORTCUT_REGISTRY: + print(f"Shortcut '{shortcut_name}' not found.") + sys.exit(1) + + shortcut = SHORTCUT_REGISTRY[shortcut_name] + config = load_config(args=sys.argv[2:]) + + run_shortcut(shortcut, config) + + +if __name__ == "__main__": + main() diff --git a/packages/spotify-shortcuts/spotify_shortcuts/shortcut.py b/packages/spotify-shortcuts/spotify_shortcuts/shortcut.py new file mode 100644 index 0000000..e8d871b --- /dev/null +++ b/packages/spotify-shortcuts/spotify_shortcuts/shortcut.py @@ -0,0 +1,21 @@ +from abc import ABC, abstractmethod + +from spotify_shortcuts.config import Config +from spotipy import Spotify + + +class Shortcut(ABC): + @abstractmethod + def execute(self, client: Spotify, config: Config): + """Execute the shortcut action.""" + pass + + @abstractmethod + def get_help(self) -> str: + """Return a description of the shortcut.""" + pass + + @abstractmethod + def get_scopes(self) -> list[str]: + """Return the spotify API scopes required for the shortcut.""" + pass diff --git a/packages/spotify-shortcuts/spotify_shortcuts/spotify_auth.py b/packages/spotify-shortcuts/spotify_shortcuts/spotify_auth.py new file mode 100644 index 0000000..f4f6574 --- /dev/null +++ b/packages/spotify-shortcuts/spotify_shortcuts/spotify_auth.py @@ -0,0 +1,20 @@ +from spotipy.oauth2 import SpotifyOAuth +from spotipy import Spotify +from spotify_shortcuts.config import Config + +CALLBACK_URI = "http://127.0.0.1:45632/callback" + + +def authenticated_session(cfg: Config, scopes: list[str]) -> Spotify: + assert cfg.client_id, "Spotify client ID is required" + assert cfg.client_secret, "Spotify client secret is required" + + return Spotify( + auth_manager=SpotifyOAuth( + client_id=cfg.client_id, + client_secret=cfg.client_secret, + redirect_uri=CALLBACK_URI, + scope=" ".join(scopes), + cache_path=cfg.cache_file, + ) + ) diff --git a/packages/spotify-shortcuts/spotify_shortcuts/spotify_like.py b/packages/spotify-shortcuts/spotify_shortcuts/spotify_like.py new file mode 100644 index 0000000..32787ce --- /dev/null +++ b/packages/spotify-shortcuts/spotify_shortcuts/spotify_like.py @@ -0,0 +1,46 @@ +from spotify_shortcuts.run import run_shortcut +from spotify_shortcuts.shortcut import Shortcut +from spotify_shortcuts.config import load_config +from desktop_notifier import DesktopNotifierSync + +SCOPES = [ + "user-library-read", + "user-library-modify", + "user-read-playback-state", +] + + +class SpotifyLike(Shortcut): + def execute(self, client, config): + if (playback := client.current_playback()) is None: + print("No current playback found.") + return + + if (uri := playback.get("item", {}).get("uri", None)) is None: + print("No track URI found in current playback.") + return + + client.current_user_saved_tracks_add(tracks=[uri]) + + if config.notifications: + dn = DesktopNotifierSync() + dn.send( + title="Track Liked", + message=f"Track \"{playback.get('item', {}).get('name', '')}\" by \"{ + ", ".join(a.get('name', '') for a in playback.get('item', {}).get('artists', [])) + }\" has been liked.", + ) + + def get_help(self) -> str: + return "Like the currently playing track." + + def get_scopes(self) -> list[str]: + return SCOPES + + +def main(): + run_shortcut(SpotifyLike(), load_config()) + + +if __name__ == "__main__": + main() diff --git a/packages/spotify-shortcuts/spotify_shortcuts/spotify_pl_add.py b/packages/spotify-shortcuts/spotify_shortcuts/spotify_pl_add.py new file mode 100644 index 0000000..63d5426 --- /dev/null +++ b/packages/spotify-shortcuts/spotify_shortcuts/spotify_pl_add.py @@ -0,0 +1,57 @@ +from spotify_shortcuts.shortcut import Shortcut +from spotify_shortcuts.config import load_config +from desktop_notifier import DesktopNotifierSync +from spotify_shortcuts.run import run_shortcut + +SCOPES = [ + "playlist-modify-public", + "playlist-modify-private", + "user-read-playback-state", +] + + +class SpotifyPlAdd(Shortcut): + def execute(self, client, config): + if (playback := client.current_playback()) is None: + print("No current playback found.") + return + + if (track_uri := playback.get("item", {}).get("uri", None)) is None: + print("No track URI found in current playback.") + return + + if (context_uri := playback.get("context", {}).get("uri", None)) is None: + print("No context URI found in current playback.") + return + + client.playlist_add_items(context_uri, items=[track_uri]) + + if config.notifications: + track_name = playback.get("item", {}).get("name", "") + artists = ", ".join( + a.get("name", "") + for a in playback.get("item", {}).get("artists", []) + ) + playlist_name = (client.playlist(context_uri) or {}).get( + "name", "" + ) + + dn = DesktopNotifierSync() + dn.send( + title="Track Added to Playlist", + message=f'Track "{track_name}" by "{artists}" has been added to {playlist_name}.', + ) + + def get_help(self) -> str: + return "Add the currently playing track to the current playlist." + + def get_scopes(self) -> list[str]: + return SCOPES + + +def main(): + run_shortcut(SpotifyPlAdd(), load_config()) + + +if __name__ == "__main__": + main()