Skip to content

Commit

Permalink
Merge pull request #293817 from PatrickDaG/your_spotify
Browse files Browse the repository at this point in the history
nixos/your_spotify: init at 1.10.1
  • Loading branch information
drupol authored May 15, 2024
2 parents 9997402 + 05b36f0 commit 4275fc2
Show file tree
Hide file tree
Showing 9 changed files with 390 additions and 0 deletions.
9 changes: 9 additions & 0 deletions maintainers/maintainer-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -15488,6 +15488,15 @@
githubId = 69802930;
name = "patka";
};
patrickdag = {
email = "[email protected]";
github = "PatrickDaG";
githubId = 58092422;
name = "Patrick";
keys = [{
fingerprint = "5E4C 3D74 80C2 35FE 2F0B D23F 7DD6 A72E C899 617D";
}];
};
patricksjackson = {
email = "[email protected]";
github = "patricksjackson";
Expand Down
2 changes: 2 additions & 0 deletions nixos/doc/manual/release-notes/rl-2405.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m

- [xdg-terminal-exec](https://github.com/Vladimir-csp/xdg-terminal-exec), the proposed Default Terminal Execution Specification.

- [your_spotify](https://github.com/Yooooomi/your_spotify), a self hosted Spotify tracking dashboard. Available as [services.your_spotify](#opt-services.your_spotify.enable)

- [RustDesk](https://rustdesk.com), a full-featured open source remote control alternative for self-hosting and security with minimal configuration. Alternative to TeamViewer. Available as [services.rustdesk-server](#opt-services.rustdesk-server.enable).

- [Scrutiny](https://github.com/AnalogJ/scrutiny), a S.M.A.R.T monitoring tool for hard disks with a web frontend. Available as [services.scrutiny](#opt-services.scrutiny.enable).
Expand Down
1 change: 1 addition & 0 deletions nixos/modules/module-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -1431,6 +1431,7 @@
./services/web-apps/windmill.nix
./services/web-apps/wordpress.nix
./services/web-apps/writefreely.nix
./services/web-apps/your_spotify.nix
./services/web-apps/youtrack.nix
./services/web-apps/zabbix.nix
./services/web-apps/zitadel.nix
Expand Down
191 changes: 191 additions & 0 deletions nixos/modules/services/web-apps/your_spotify.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
{
pkgs,
config,
lib,
...
}: let
inherit
(lib)
boolToString
concatMapAttrs
concatStrings
isBool
mapAttrsToList
mkEnableOption
mkIf
mkOption
mkPackageOption
optionalAttrs
types
mkDefault
;
cfg = config.services.your_spotify;

configEnv = concatMapAttrs (name: value:
optionalAttrs (value != null) {
${name} =
if isBool value
then boolToString value
else toString value;
})
cfg.settings;

configFile = pkgs.writeText "your_spotify.env" (concatStrings (mapAttrsToList (name: value: "${name}=${value}\n") configEnv));
in {
options.services.your_spotify = let
inherit (types) nullOr port str path package;
in {
enable = mkEnableOption "your_spotify";

enableLocalDB = mkEnableOption "a local mongodb instance";
nginxVirtualHost = mkOption {
type = nullOr str;
default = null;
description = ''
If set creates an nginx virtual host for the client.
In most cases this should be the CLIENT_ENDPOINT without
protocol prefix.
'';
};

package = mkPackageOption pkgs "your_spotify" {};

clientPackage = mkOption {
type = package;
description = "Client package to use.";
};

spotifySecretFile = mkOption {
type = path;
description = ''
A file containing the secret key of your Spotify application.
Refer to: [Creating the Spotify Application](https://github.com/Yooooomi/your_spotify#creating-the-spotify-application).
'';
};

settings = mkOption {
description = ''
Your Spotify Configuration. Refer to [Your Spotify](https://github.com/Yooooomi/your_spotify) for definitions and values.
'';
example = lib.literalExpression ''
{
CLIENT_ENDPOINT = "https://example.com";
API_ENDPOINT = "https://api.example.com";
SPOTIFY_PUBLIC = "spotify_client_id";
}
'';
type = types.submodule {
freeformType = types.attrsOf types.str;
options = {
CLIENT_ENDPOINT = mkOption {
type = str;
description = ''
The endpoint of your web application.
Has to include a protocol Prefix (e.g. `http://`)
'';
example = "https://your_spotify.example.org";
};
API_ENDPOINT = mkOption {
type = str;
description = ''
The endpoint of your server
This api has to be reachable from the device you use the website from not from the server.
This means that for example you may need two nginx virtual hosts if you want to expose this on the
internet.
Has to include a protocol Prefix (e.g. `http://`)
'';
example = "https://localhost:3000";
};
SPOTIFY_PUBLIC = mkOption {
type = str;
description = ''
The public client ID of your Spotify application.
Refer to: [Creating the Spotify Application](https://github.com/Yooooomi/your_spotify#creating-the-spotify-application)
'';
};
MONGO_ENDPOINT = mkOption {
type = str;
description = ''The endpoint of the Mongo database.'';
default = "mongodb://localhost:27017/your_spotify";
};
PORT = mkOption {
type = port;
description = "The port of the api server";
default = 3000;
};
};
};
};
};

config = mkIf cfg.enable {
services.your_spotify.clientPackage = mkDefault (cfg.package.client.override {apiEndpoint = cfg.settings.API_ENDPOINT;});
systemd.services.your_spotify = {
after = ["network.target"];
script = ''
export SPOTIFY_SECRET=$(< "$CREDENTIALS_DIRECTORY/SPOTIFY_SECRET")
${lib.getExe' cfg.package "your_spotify_migrate"}
exec ${lib.getExe cfg.package}
'';
serviceConfig = {
User = "your_spotify";
Group = "your_spotify";
DynamicUser = true;
EnvironmentFile = [configFile];
StateDirectory = "your_spotify";
LimitNOFILE = "1048576";
PrivateTmp = true;
PrivateDevices = true;
StateDirectoryMode = "0700";
Restart = "always";

LoadCredential = ["SPOTIFY_SECRET:${cfg.spotifySecretFile}"];

# Hardening
CapabilityBoundingSet = "";
LockPersonality = true;
#MemoryDenyWriteExecute = true; # Leads to coredump because V8 does JIT
PrivateUsers = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProcSubset = "pid";
ProtectSystem = "strict";
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_NETLINK"
];
RestrictNamespaces = true;
RestrictRealtime = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"@pkey"
];
UMask = "0077";
};
wantedBy = ["multi-user.target"];
};
services.nginx = mkIf (cfg.nginxVirtualHost != null) {
enable = true;
virtualHosts.${cfg.nginxVirtualHost} = {
root = cfg.clientPackage;
locations."/".extraConfig = ''
add_header Content-Security-Policy "frame-ancestors 'none';" ;
add_header X-Content-Type-Options "nosniff" ;
try_files = $uri $uri/ /index.html ;
'';
};
};
services.mongodb = mkIf cfg.enableLocalDB {
enable = true;
};
};
meta.maintainers = with lib.maintainers; [patrickdag];
}
1 change: 1 addition & 0 deletions nixos/tests/all-tests.nix
Original file line number Diff line number Diff line change
Expand Up @@ -1042,6 +1042,7 @@ in {
yabar = handleTest ./yabar.nix {};
ydotool = handleTest ./ydotool.nix {};
yggdrasil = handleTest ./yggdrasil.nix {};
your_spotify = handleTest ./your_spotify.nix {};
zammad = handleTest ./zammad.nix {};
zeronet-conservancy = handleTest ./zeronet-conservancy.nix {};
zfs = handleTest ./zfs.nix {};
Expand Down
33 changes: 33 additions & 0 deletions nixos/tests/your_spotify.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import ./make-test-python.nix ({pkgs, ...}: {
name = "your_spotify";
meta = with pkgs.lib.maintainers; {
maintainers = [patrickdag];
};

nodes.machine = {
services.your_spotify = {
enable = true;
spotifySecretFile = pkgs.writeText "spotifySecretFile" "deadbeef";
settings = {
CLIENT_ENDPOINT = "http://localhost";
API_ENDPOINT = "http://localhost:3000";
SPOTIFY_PUBLIC = "beefdead";
};
enableLocalDB = true;
nginxVirtualHost = "localhost";
};
};

testScript = ''
machine.wait_for_unit("your_spotify.service")
machine.wait_for_open_port(3000)
machine.wait_for_open_port(80)
out = machine.succeed("curl --fail -X GET 'http://localhost:3000/'")
assert "Hello !" in out
out = machine.succeed("curl --fail -X GET 'http://localhost:80/'")
assert "<title>Your Spotify</title>" in out
'';
})
58 changes: 58 additions & 0 deletions pkgs/by-name/yo/your_spotify/client.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
apiEndpoint ? "http://localhost:3000",
fetchYarnDeps,
your_spotify,
mkYarnPackage,
fixup-yarn-lock,
src,
version,
yarn,
}:
mkYarnPackage rec {
inherit version src;
pname = "your_spotify_client";
name = "your_spotify_client-${version}";
packageJSON = ./package.json;
offlineCache = fetchYarnDeps {
yarnLock = src + "/yarn.lock";
hash = "sha256-5SgknaRVzgO2Dzc8MhAaM8UERWMv+PrItzevoWHbWnA=";
};
configurePhase = ''
runHook preConfigure
export HOME=$(mktemp -d)
yarn config --offline set yarn-offline-mirror $offlineCache
fixup-yarn-lock yarn.lock
yarn install --offline --frozen-lockfile --ignore-platform --ignore-scripts --no-progress --non-interactive
patchShebangs node_modules/
runHook postConfigure
'';
buildPhase = ''
runHook preBuild
pushd ./apps/client/
yarn --offline run build
export API_ENDPOINT="${apiEndpoint}"
substituteInPlace scripts/run/variables.sh --replace-quiet '/app/apps/client/' "./"
chmod +x ./scripts/run/variables.sh
patchShebangs --build ./scripts/run/variables.sh
./scripts/run/variables.sh
popd
runHook postBuild
'';
nativeBuildInputs = [yarn fixup-yarn-lock];

installPhase = ''
runHook preInstall
mkdir -p $out
cp -r ./apps/client/build/* $out
runHook postInstall
'';
doDist = false;
meta = {
inherit (your_spotify.meta) homepage changelog description license maintainers;
};
}
10 changes: 10 additions & 0 deletions pkgs/by-name/yo/your_spotify/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "@your_spotify/root",
"version": "1.10.1",
"repository": "[email protected]:Yooooomi/your_spotify.git",
"author": "Timothee <[email protected]>",
"private": true,
"workspaces": [
"apps/*"
]
}
Loading

0 comments on commit 4275fc2

Please sign in to comment.