Merge pull request #136993 from sbruder/invidious

invidious: init

authored by Michael Raskin and committed by GitHub 14b348fa 9e2d9250

+578 -2
+2 -2
doc/languages-frameworks/crystal.section.md
··· 4 4 5 5 This section uses [Mint](https://github.com/mint-lang/mint) as an example for how to build a Crystal package. 6 6 7 - If the Crystal project has any dependencies, the first step is to get a `shards.nix` file encoding those. Get a copy of the project and go to its root directory such that its `shard.lock` file is in the current directory, then run `crystal2nix` in it 8 - 7 + If the Crystal project has any dependencies, the first step is to get a `shards.nix` file encoding those. Get a copy of the project and go to its root directory such that its `shard.lock` file is in the current directory. Executable projects should usually commit the `shard.lock` file, but sometimes that's not the case, which means you need to generate it yourself. With an existing `shard.lock` file, `crystal2nix` can be run. 9 8 ```bash 10 9 $ git clone https://github.com/mint-lang/mint 11 10 $ cd mint 12 11 $ git checkout 0.5.0 12 + $ if [ ! -f shard.lock ]; then nix-shell -p shards --run "shards lock"; fi 13 13 $ nix-shell -p crystal2nix --run crystal2nix 14 14 ``` 15 15
+1
nixos/modules/module-list.nix
··· 992 992 ./services/web-apps/jitsi-meet.nix 993 993 ./services/web-apps/keycloak.nix 994 994 ./services/web-apps/lemmy.nix 995 + ./services/web-apps/invidious.nix 995 996 ./services/web-apps/limesurvey.nix 996 997 ./services/web-apps/mastodon.nix 997 998 ./services/web-apps/mattermost.nix
+263
nixos/modules/services/web-apps/invidious.nix
··· 1 + { lib, config, pkgs, options, ... }: 2 + let 3 + cfg = config.services.invidious; 4 + # To allow injecting secrets with jq, json (instead of yaml) is used 5 + settingsFormat = pkgs.formats.json { }; 6 + inherit (lib) types; 7 + 8 + settingsFile = settingsFormat.generate "invidious-settings" cfg.settings; 9 + 10 + serviceConfig = { 11 + systemd.services.invidious = { 12 + description = "Invidious (An alternative YouTube front-end)"; 13 + wants = [ "network-online.target" ]; 14 + after = [ "syslog.target" "network-online.target" ]; 15 + wantedBy = [ "multi-user.target" ]; 16 + 17 + script = 18 + let 19 + jqFilter = "." 20 + + lib.optionalString (cfg.database.host != null) "[0].db.password = \"'\"'\"$(cat ${lib.escapeShellArg cfg.database.passwordFile})\"'\"'\"" 21 + + " | .[0]" 22 + + lib.optionalString (cfg.extraSettingsFile != null) " * .[1]"; 23 + jqFiles = [ settingsFile ] ++ lib.optional (cfg.extraSettingsFile != null) cfg.extraSettingsFile; 24 + in 25 + '' 26 + export INVIDIOUS_CONFIG="$(${pkgs.jq}/bin/jq -s "${jqFilter}" ${lib.escapeShellArgs jqFiles})" 27 + exec ${cfg.package}/bin/invidious 28 + ''; 29 + 30 + serviceConfig = { 31 + RestartSec = "2s"; 32 + DynamicUser = true; 33 + 34 + CapabilityBoundingSet = ""; 35 + PrivateDevices = true; 36 + PrivateUsers = true; 37 + ProtectHome = true; 38 + ProtectKernelLogs = true; 39 + ProtectProc = "invisible"; 40 + RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ]; 41 + RestrictNamespaces = true; 42 + SystemCallArchitectures = "native"; 43 + SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ]; 44 + }; 45 + }; 46 + 47 + services.invidious.settings = { 48 + inherit (cfg) port; 49 + 50 + # Automatically initialises and migrates the database if necessary 51 + check_tables = true; 52 + 53 + db = { 54 + user = lib.mkDefault "kemal"; 55 + dbname = lib.mkDefault "invidious"; 56 + port = cfg.database.port; 57 + # Blank for unix sockets, see 58 + # https://github.com/will/crystal-pg/blob/1548bb255210/src/pq/conninfo.cr#L100-L108 59 + host = if cfg.database.host == null then "" else cfg.database.host; 60 + # Not needed because peer authentication is enabled 61 + password = lib.mkIf (cfg.database.host == null) ""; 62 + }; 63 + } // (lib.optionalAttrs (cfg.domain != null) { 64 + inherit (cfg) domain; 65 + }); 66 + 67 + assertions = [{ 68 + assertion = cfg.database.host != null -> cfg.database.passwordFile != null; 69 + message = "If database host isn't null, database password needs to be set"; 70 + }]; 71 + }; 72 + 73 + # Settings necessary for running with an automatically managed local database 74 + localDatabaseConfig = lib.mkIf cfg.database.createLocally { 75 + # Default to using the local database if we create it 76 + services.invidious.database.host = lib.mkDefault null; 77 + 78 + services.postgresql = { 79 + enable = true; 80 + ensureDatabases = lib.singleton cfg.settings.db.dbname; 81 + ensureUsers = lib.singleton { 82 + name = cfg.settings.db.user; 83 + ensurePermissions = { 84 + "DATABASE ${cfg.settings.db.dbname}" = "ALL PRIVILEGES"; 85 + }; 86 + }; 87 + # This is only needed because the unix user invidious isn't the same as 88 + # the database user. This tells postgres to map one to the other. 89 + identMap = '' 90 + invidious invidious ${cfg.settings.db.user} 91 + ''; 92 + # And this specifically enables peer authentication for only this 93 + # database, which allows passwordless authentication over the postgres 94 + # unix socket for the user map given above. 95 + authentication = '' 96 + local ${cfg.settings.db.dbname} ${cfg.settings.db.user} peer map=invidious 97 + ''; 98 + }; 99 + 100 + systemd.services.invidious-db-clean = { 101 + description = "Invidious database cleanup"; 102 + documentation = [ "https://docs.invidious.io/Database-Information-and-Maintenance.md" ]; 103 + startAt = lib.mkDefault "weekly"; 104 + path = [ config.services.postgresql.package ]; 105 + script = '' 106 + psql ${cfg.settings.db.dbname} ${cfg.settings.db.user} -c "DELETE FROM nonces * WHERE expire < current_timestamp" 107 + psql ${cfg.settings.db.dbname} ${cfg.settings.db.user} -c "TRUNCATE TABLE videos" 108 + ''; 109 + serviceConfig = { 110 + DynamicUser = true; 111 + User = "invidious"; 112 + }; 113 + }; 114 + 115 + systemd.services.invidious = { 116 + requires = [ "postgresql.service" ]; 117 + after = [ "postgresql.service" ]; 118 + 119 + serviceConfig = { 120 + User = "invidious"; 121 + }; 122 + }; 123 + }; 124 + 125 + nginxConfig = lib.mkIf cfg.nginx.enable { 126 + services.invidious.settings = { 127 + https_only = config.services.nginx.virtualHosts.${cfg.domain}.forceSSL; 128 + external_port = 80; 129 + }; 130 + 131 + services.nginx = { 132 + enable = true; 133 + virtualHosts.${cfg.domain} = { 134 + locations."/".proxyPass = "http://127.0.0.1:${toString cfg.port}"; 135 + 136 + enableACME = lib.mkDefault true; 137 + forceSSL = lib.mkDefault true; 138 + }; 139 + }; 140 + 141 + assertions = [{ 142 + assertion = cfg.domain != null; 143 + message = "To use services.invidious.nginx, you need to set services.invidious.domain"; 144 + }]; 145 + }; 146 + in 147 + { 148 + options.services.invidious = { 149 + enable = lib.mkEnableOption "Invidious"; 150 + 151 + package = lib.mkOption { 152 + type = types.package; 153 + default = pkgs.invidious; 154 + defaultText = "pkgs.invidious"; 155 + description = "The Invidious package to use."; 156 + }; 157 + 158 + settings = lib.mkOption { 159 + type = settingsFormat.type; 160 + default = { }; 161 + description = '' 162 + The settings Invidious should use. 163 + 164 + See <link xlink:href="https://github.com/iv-org/invidious/blob/master/config/config.example.yml">config.example.yml</link> for a list of all possible options. 165 + ''; 166 + }; 167 + 168 + extraSettingsFile = lib.mkOption { 169 + type = types.nullOr types.str; 170 + default = null; 171 + description = '' 172 + A file including Invidious settings. 173 + 174 + It gets merged with the setttings specified in <option>services.invidious.settings</option> 175 + and can be used to store secrets like <literal>hmac_key</literal> outside of the nix store. 176 + ''; 177 + }; 178 + 179 + # This needs to be outside of settings to avoid infinite recursion 180 + # (determining if nginx should be enabled and therefore the settings 181 + # modified). 182 + domain = lib.mkOption { 183 + type = types.nullOr types.str; 184 + default = null; 185 + description = '' 186 + The FQDN Invidious is reachable on. 187 + 188 + This is used to configure nginx and for building absolute URLs. 189 + ''; 190 + }; 191 + 192 + port = lib.mkOption { 193 + type = types.port; 194 + # Default from https://docs.invidious.io/Configuration.md 195 + default = 3000; 196 + description = '' 197 + The port Invidious should listen on. 198 + 199 + To allow access from outside, 200 + you can use either <option>services.invidious.nginx</option> 201 + or add <literal>config.services.invidious.port</literal> to <option>networking.firewall.allowedTCPPorts</option>. 202 + ''; 203 + }; 204 + 205 + database = { 206 + createLocally = lib.mkOption { 207 + type = types.bool; 208 + default = true; 209 + description = '' 210 + Whether to create a local database with PostgreSQL. 211 + ''; 212 + }; 213 + 214 + host = lib.mkOption { 215 + type = types.nullOr types.str; 216 + default = null; 217 + description = '' 218 + The database host Invidious should use. 219 + 220 + If <literal>null</literal>, the local unix socket is used. Otherwise 221 + TCP is used. 222 + ''; 223 + }; 224 + 225 + port = lib.mkOption { 226 + type = types.port; 227 + default = options.services.postgresql.port.default; 228 + description = '' 229 + The port of the database Invidious should use. 230 + 231 + Defaults to the the default postgresql port. 232 + ''; 233 + }; 234 + 235 + passwordFile = lib.mkOption { 236 + type = types.nullOr types.str; 237 + apply = lib.mapNullable toString; 238 + default = null; 239 + description = '' 240 + Path to file containing the database password. 241 + ''; 242 + }; 243 + }; 244 + 245 + nginx.enable = lib.mkOption { 246 + type = types.bool; 247 + default = false; 248 + description = '' 249 + Whether to configure nginx as a reverse proxy for Invidious. 250 + 251 + It serves it under the domain specified in <option>services.invidious.settings.domain</option> with enabled TLS and ACME. 252 + Further configuration can be done through <option>services.nginx.virtualHosts.''${config.services.invidious.settings.domain}.*</option>, 253 + which can also be used to disable AMCE and TLS. 254 + ''; 255 + }; 256 + }; 257 + 258 + config = lib.mkIf cfg.enable (lib.mkMerge [ 259 + serviceConfig 260 + localDatabaseConfig 261 + nginxConfig 262 + ]); 263 + }
+1
nixos/tests/all-tests.nix
··· 173 173 hedgedoc = handleTest ./hedgedoc.nix {}; 174 174 herbstluftwm = handleTest ./herbstluftwm.nix {}; 175 175 installed-tests = pkgs.recurseIntoAttrs (handleTest ./installed-tests {}); 176 + invidious = handleTest ./invidious.nix {}; 176 177 oci-containers = handleTestOn ["x86_64-linux"] ./oci-containers.nix {}; 177 178 # 9pnet_virtio used to mount /nix partition doesn't support 178 179 # hibernation. This test happens to work on x86_64-linux but
+81
nixos/tests/invidious.nix
··· 1 + import ./make-test-python.nix ({ pkgs, ... }: { 2 + name = "invidious"; 3 + 4 + meta = with pkgs.lib.maintainers; { 5 + maintainers = [ sbruder ]; 6 + }; 7 + 8 + machine = { config, lib, pkgs, ... }: { 9 + services.invidious = { 10 + enable = true; 11 + }; 12 + 13 + specialisation = { 14 + nginx.configuration = { 15 + services.invidious = { 16 + nginx.enable = true; 17 + domain = "invidious.example.com"; 18 + }; 19 + services.nginx.virtualHosts."invidious.example.com" = { 20 + forceSSL = false; 21 + enableACME = false; 22 + }; 23 + networking.hosts."127.0.0.1" = [ "invidious.example.com" ]; 24 + }; 25 + postgres-tcp.configuration = { 26 + services.invidious = { 27 + database = { 28 + createLocally = false; 29 + host = "127.0.0.1"; 30 + passwordFile = toString (pkgs.writeText "database-password" "correct horse battery staple"); 31 + }; 32 + }; 33 + # Normally not needed because when connecting to postgres over TCP/IP 34 + # the database is most likely on another host. 35 + systemd.services.invidious = { 36 + after = [ "postgresql.service" ]; 37 + requires = [ "postgresql.service" ]; 38 + }; 39 + services.postgresql = 40 + let 41 + inherit (config.services.invidious.settings.db) dbname user; 42 + in 43 + { 44 + enable = true; 45 + initialScript = pkgs.writeText "init-postgres-with-password" '' 46 + CREATE USER kemal WITH PASSWORD 'correct horse battery staple'; 47 + CREATE DATABASE invidious; 48 + GRANT ALL PRIVILEGES ON DATABASE invidious TO kemal; 49 + ''; 50 + }; 51 + }; 52 + }; 53 + }; 54 + 55 + testScript = { nodes, ... }: '' 56 + def curl_assert_status_code(url, code, form=None): 57 + assert int(machine.succeed(f"curl -s -o /dev/null -w %{{http_code}} {'-F ' + form + ' ' if form else '''}{url}")) == code 58 + 59 + 60 + def activate_specialisation(name: str): 61 + machine.succeed(f"${nodes.machine.config.system.build.toplevel}/specialisation/{name}/bin/switch-to-configuration test >&2") 62 + 63 + 64 + url = "http://localhost:${toString nodes.machine.config.services.invidious.port}" 65 + port = ${toString nodes.machine.config.services.invidious.port} 66 + 67 + machine.wait_for_open_port(port) 68 + curl_assert_status_code(f"{url}/search", 200) 69 + 70 + activate_specialisation("nginx") 71 + machine.wait_for_open_port(80) 72 + curl_assert_status_code("http://invidious.example.com/search", 200) 73 + 74 + # Remove the state so the `initialScript` gets run 75 + machine.succeed("systemctl stop postgresql") 76 + machine.succeed("rm -r /var/lib/postgresql") 77 + activate_specialisation("postgres-tcp") 78 + machine.wait_for_open_port(port) 79 + curl_assert_status_code(f"{url}/search", 200) 80 + ''; 81 + })
+99
pkgs/servers/invidious/default.nix
··· 1 + { lib, crystal, fetchFromGitHub, librsvg, pkg-config, libxml2, openssl, sqlite, lsquic, nixosTests }: 2 + let 3 + # When updating, always update the following: 4 + # * the git revision 5 + # * the version attribute 6 + # * the source hash (sha256) 7 + # If the shards.lock file changed, also the following: 8 + # * shards.nix (by running `crystal2nix` in invidious’ source tree) 9 + # * If the lsquic.cr dependency changed: lsquic in lsquic.nix (version, sha256) 10 + # * If the lsquic version changed: boringssl' in lsquic.nix (version, sha256) 11 + rev = "21b96a31599e890fe063e3e24cf5f3a995779a69"; 12 + in 13 + crystal.buildCrystalPackage rec { 14 + pname = "invidious"; 15 + version = "unstable-2021-10-15"; 16 + 17 + src = fetchFromGitHub { 18 + owner = "iv-org"; 19 + repo = pname; 20 + inherit rev; 21 + sha256 = "sha256-Rp3YqjHbP6szohlaEpgopFNdLK31yrcHtyKCeVz76CA="; 22 + }; 23 + 24 + postPatch = 25 + let 26 + # Replacing by the value (templates) of the variables ensures that building 27 + # fails if upstream changes the way the metadata is formatted. 28 + branchTemplate = ''{{ "#{`git branch | sed -n '/* /s///p'`.strip}" }}''; 29 + commitTemplate = ''{{ "#{`git rev-list HEAD --max-count=1 --abbrev-commit`.strip}" }}''; 30 + versionTemplate = ''{{ "#{`git log -1 --format=%ci | awk '{print $1}' | sed s/-/./g`.strip}" }}''; 31 + # This always uses the latest commit which invalidates the cache even if 32 + # the assets were not changed 33 + assetCommitTemplate = ''{{ "#{`git rev-list HEAD --max-count=1 --abbrev-commit -- assets`.strip}" }}''; 34 + in 35 + '' 36 + # Use the version metadata from the derivation instead of using git at 37 + # build-time 38 + substituteInPlace src/invidious.cr \ 39 + --replace ${lib.escapeShellArg branchTemplate} '"master"' \ 40 + --replace ${lib.escapeShellArg commitTemplate} '"${lib.substring 0 7 rev}"' \ 41 + --replace ${lib.escapeShellArg versionTemplate} '"${lib.replaceChars ["-"] ["."] (lib.substring 9 10 version)}"' \ 42 + --replace ${lib.escapeShellArg assetCommitTemplate} '"${lib.substring 0 7 rev}"' 43 + 44 + # Patch the assets and locales paths to be absolute 45 + substituteInPlace src/invidious.cr \ 46 + --replace 'public_folder "assets"' 'public_folder "${placeholder "out"}/share/invidious/assets"' 47 + substituteInPlace src/invidious/helpers/i18n.cr \ 48 + --replace 'File.read("locales/' 'File.read("${placeholder "out"}/share/invidious/locales/' 49 + 50 + # Reference sql initialisation/migration scripts by absolute path 51 + substituteInPlace src/invidious/helpers/helpers.cr \ 52 + --replace 'config/sql' '${placeholder "out"}/share/invidious/config/sql' 53 + 54 + substituteInPlace src/invidious/users.cr \ 55 + --replace 'Process.run(%(rsvg-convert' 'Process.run(%(${lib.getBin librsvg}/bin/rsvg-convert' 56 + ''; 57 + 58 + nativeBuildInputs = [ pkg-config ]; 59 + buildInputs = [ libxml2 openssl sqlite ]; 60 + 61 + format = "crystal"; 62 + shardsFile = ./shards.nix; 63 + crystalBinaries.invidious.src = "src/invidious.cr"; 64 + 65 + postConfigure = '' 66 + # lib includes nix store paths which can’t be patched, so the links have to 67 + # be dereferenced first. 68 + cp -rL lib lib2 69 + rm -r lib 70 + mv lib2 lib 71 + chmod +w -R lib 72 + cp ${lsquic}/lib/liblsquic.a lib/lsquic/src/lsquic/ext 73 + ''; 74 + 75 + postInstall = '' 76 + mkdir -p $out/share/invidious/config 77 + 78 + # Copy static parts 79 + cp -r assets locales $out/share/invidious 80 + cp -r config/sql $out/share/invidious/config 81 + ''; 82 + 83 + # Invidious tries to open config/config.yml and connect to the database, even 84 + # when running --help. This specifies a minimal configuration in an 85 + # environment variable. Even though the database is bogus, --help still 86 + # works. 87 + installCheckPhase = '' 88 + INVIDIOUS_CONFIG="database_url: sqlite3:///dev/null" $out/bin/invidious --help 89 + ''; 90 + 91 + passthru.tests = { inherit (nixosTests) invidious; }; 92 + 93 + meta = with lib; { 94 + description = "An open source alternative front-end to YouTube"; 95 + homepage = "https://invidious.io/"; 96 + license = licenses.agpl3; 97 + maintainers = with maintainers; [ infinisil sbruder ]; 98 + }; 99 + }
+58
pkgs/servers/invidious/lsquic.nix
··· 1 + { lib, boringssl, stdenv, fetchgit, fetchFromGitHub, cmake, zlib, perl, libevent }: 2 + let 3 + # lsquic requires a specific boringssl version (noted in its README) 4 + boringssl' = boringssl.overrideAttrs (old: rec { 5 + version = "251b5169fd44345f455438312ec4e18ae07fd58c"; 6 + src = fetchgit { 7 + url = "https://boringssl.googlesource.com/boringssl"; 8 + rev = version; 9 + sha256 = "sha256-EU6T9yQCdOLx98Io8o01rEsgxDFF/Xoy42LgPopD2/A="; 10 + }; 11 + }); 12 + in 13 + stdenv.mkDerivation rec { 14 + pname = "lsquic"; 15 + version = "2.18.1"; 16 + 17 + src = fetchFromGitHub { 18 + owner = "litespeedtech"; 19 + repo = pname; 20 + rev = "v${version}"; 21 + sha256 = "sha256-hG8cUvhbCNeMOsKkaJlgGpzUrIx47E/WhmPIdI5F3qM="; 22 + fetchSubmodules = true; 23 + }; 24 + 25 + nativeBuildInputs = [ cmake perl ]; 26 + buildInputs = [ boringssl' libevent zlib ]; 27 + 28 + cmakeFlags = [ 29 + "-DBORINGSSL_DIR=${boringssl'}" 30 + "-DBORINGSSL_LIB_crypto=${boringssl'}/lib/libcrypto.a" 31 + "-DBORINGSSL_LIB_ssl=${boringssl'}/lib/libssl.a" 32 + "-DZLIB_LIB=${zlib}/lib/libz.so" 33 + ]; 34 + 35 + # adapted from lsquic.cr’s Dockerfile 36 + # (https://github.com/iv-org/lsquic.cr/blob/master/docker/Dockerfile) 37 + installPhase = '' 38 + runHook preInstall 39 + 40 + mkdir combinedlib 41 + cd combinedlib 42 + ar -x ${boringssl'}/lib/libssl.a 43 + ar -x ${boringssl'}/lib/libcrypto.a 44 + ar -x ../src/liblsquic/liblsquic.a 45 + ar rc liblsquic.a *.o 46 + ranlib liblsquic.a 47 + install -D liblsquic.a $out/lib/liblsquic.a 48 + 49 + runHook postInstall 50 + ''; 51 + 52 + meta = with lib; { 53 + description = "A library for QUIC and HTTP/3 (version for Invidious)"; 54 + homepage = "https://github.com/litespeedtech/lsquic"; 55 + maintainers = with maintainers; [ infinisil sbruder ]; 56 + license = with licenses; [ openssl isc mit bsd3 ]; # statically links against boringssl, so has to include its licenses 57 + }; 58 + }
+68
pkgs/servers/invidious/shards.nix
··· 1 + { 2 + athena-negotiation = { 3 + owner = "athena-framework"; 4 + repo = "negotiation"; 5 + rev = "v0.1.1"; 6 + sha256 = "1vkk59lqrxb0l8kyzs114i3c18zb2bdiah2xhazkk8q7x6fz4yzk"; 7 + }; 8 + backtracer = { 9 + owner = "sija"; 10 + repo = "backtracer.cr"; 11 + rev = "v1.2.1"; 12 + sha256 = "02r1l7rn2wsljkx495s5s7j04zgn73m2kx0hkzs7620camvlwbqq"; 13 + }; 14 + db = { 15 + owner = "crystal-lang"; 16 + repo = "crystal-db"; 17 + rev = "v0.10.1"; 18 + sha256 = "03c5h14z6h2mxnx949lihnyqjd19hcj38iasdwq9fp95h8cld376"; 19 + }; 20 + exception_page = { 21 + owner = "crystal-loot"; 22 + repo = "exception_page"; 23 + rev = "v0.2.0"; 24 + sha256 = "0nlgnh5iykbr1v2132342k2mz6s2laws6nkgqsqlwhhcr4gb4jcx"; 25 + }; 26 + kemal = { 27 + owner = "kemalcr"; 28 + repo = "kemal"; 29 + rev = "v1.1.0"; 30 + sha256 = "07vlvddy4mba9li2bvskzqzywwq55cyvlgkz13q6dsl4zfgc96ca"; 31 + }; 32 + kilt = { 33 + owner = "jeromegn"; 34 + repo = "kilt"; 35 + rev = "v0.6.1"; 36 + sha256 = "0dpc15y9m8c5l9zdfif6jlf7zmkrlm9w4m2igi5xa22fdjwamwfp"; 37 + }; 38 + lsquic = { 39 + owner = "iv-org"; 40 + repo = "lsquic.cr"; 41 + rev = "v2.18.1-2"; 42 + sha256 = "0bljk0pwbjb813dfwrhgi00w2ai09k868xvak4hfzdkbmpc7id6y"; 43 + }; 44 + pg = { 45 + owner = "will"; 46 + repo = "crystal-pg"; 47 + rev = "v0.24.0"; 48 + sha256 = "07i5bqkv5j6y6f8v5cpqdxc5wzzrvgv3ds24znv4mzv6nc84csn4"; 49 + }; 50 + protodec = { 51 + owner = "iv-org"; 52 + repo = "protodec"; 53 + rev = "v0.1.4"; 54 + sha256 = "15azh9izxqgwpgkpicmivfdz31wkibnwy09rwhxsg0lyc4wf8xj9"; 55 + }; 56 + radix = { 57 + owner = "luislavena"; 58 + repo = "radix"; 59 + rev = "v0.4.1"; 60 + sha256 = "1l08cydkdidq9yyil1wl240hvk41iycv04jrg6nx5mkvzw4z1bzg"; 61 + }; 62 + sqlite3 = { 63 + owner = "crystal-lang"; 64 + repo = "crystal-sqlite3"; 65 + rev = "v0.18.0"; 66 + sha256 = "03nnvpchhq9f9ywsm3pk2rrj4a3figw7xs96zdziwgr5znkz6x93"; 67 + }; 68 + }
+5
pkgs/top-level/all-packages.nix
··· 6401 6401 6402 6402 intermodal = callPackage ../tools/misc/intermodal { }; 6403 6403 6404 + invidious = callPackage ../servers/invidious { 6405 + # needs a specific version of lsquic 6406 + lsquic = callPackage ../servers/invidious/lsquic.nix { }; 6407 + }; 6408 + 6404 6409 invoice2data = callPackage ../tools/text/invoice2data { }; 6405 6410 6406 6411 inxi = callPackage ../tools/system/inxi { };