Implement r5500 media stack configuration with NFS and Docker services
- Added configuration for media stack on r5500, including paths for Jellyfin, Sonarr, Radarr, and other media services. - Integrated NFS client for accessing Jellyfin libraries from nixdesk. - Established Docker services for Dispatcharr and Organizr, including necessary user and group setups. - Created systemd services for managing media directories and ensuring proper permissions.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
# NFS exports from nixdesk (14900k) to nix-server (192.168.2.238):
|
# NFS exports from nixdesk (14900k) to r5500 (192.168.2.100), formerly nix-server (192.168.2.238):
|
||||||
# - /mnt/deep/jellyfin → nix-server /mnt/nixdesk-jellyfin (Jellyfin bulk libraries)
|
# - /mnt/deep/jellyfin → nix-server /mnt/nixdesk-jellyfin (Jellyfin bulk libraries)
|
||||||
#
|
#
|
||||||
# Jellyfin root on nixdesk uses owner olivier + group nfsmedia (990); dirs here are 2775 so
|
# Jellyfin root on nixdesk uses owner olivier + group nfsmedia (990); dirs here are 2775 so
|
||||||
@@ -48,7 +48,8 @@ in
|
|||||||
# Squash nix-server clients to olivier:nfsmedia so Jellyfin can write .nfo/posters into
|
# Squash nix-server clients to olivier:nfsmedia so Jellyfin can write .nfo/posters into
|
||||||
# existing olivier-owned library folders (990-only squash was "other" r-x on typical 755 trees).
|
# existing olivier-owned library folders (990-only squash was "other" r-x on typical 755 trees).
|
||||||
exports = ''
|
exports = ''
|
||||||
/mnt/deep/jellyfin 192.168.2.238(rw,sync,no_subtree_check,crossmnt,root_squash,all_squash,anonuid=${toString olivierUid},anongid=990,fsid=1)
|
/mnt/deep/jellyfin 192.168.2.100(rw,sync,no_subtree_check,crossmnt,root_squash,all_squash,anonuid=${toString olivierUid},anongid=990,fsid=1)
|
||||||
|
/mnt/deep/jellyfin 192.168.2.238(rw,sync,no_subtree_check,crossmnt,root_squash,all_squash,anonuid=${toString olivierUid},anongid=990,fsid=2)
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,9 @@
|
|||||||
{
|
{
|
||||||
systemd.tmpfiles.settings."nix-server-dispatcharr-data" = {
|
systemd.tmpfiles.settings."nix-server-dispatcharr-data" = {
|
||||||
"/var/lib/dispatcharr"."d" = {
|
"/var/lib/dispatcharr"."d" = {
|
||||||
mode = "0755";
|
# Dispatcharr runs as a non-root user inside the container; keep /data writable.
|
||||||
|
# (Plugins like EPG Janitor write to `/data/*.json`.)
|
||||||
|
mode = "0777";
|
||||||
user = "root";
|
user = "root";
|
||||||
group = "root";
|
group = "root";
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,20 +17,10 @@
|
|||||||
self.nixosModules.users
|
self.nixosModules.users
|
||||||
./_services/attic-cache-server.nix
|
./_services/attic-cache-server.nix
|
||||||
./_services/portainer.nix
|
./_services/portainer.nix
|
||||||
./_services/organizr.nix
|
|
||||||
./_services/swiftshare.nix
|
./_services/swiftshare.nix
|
||||||
./_services/personal-website.nix
|
./_services/personal-website.nix
|
||||||
./_services/immich.nix
|
./_services/immich.nix
|
||||||
./_services/jellyfin.nix
|
|
||||||
./_services/nixdesk-nfs-client.nix
|
|
||||||
./_services/ddrm-media-server.nix
|
./_services/ddrm-media-server.nix
|
||||||
./_services/sonarr.nix
|
|
||||||
./_services/prowlarr.nix
|
|
||||||
./_services/flaresolverr.nix
|
|
||||||
./_services/radarr.nix
|
|
||||||
./_services/qbittorrent.nix
|
|
||||||
./_services/seerr.nix
|
|
||||||
./_services/dispatcharr.nix
|
|
||||||
./_services/gitea.nix
|
./_services/gitea.nix
|
||||||
./_services/cloudflare-dyndns.nix
|
./_services/cloudflare-dyndns.nix
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
# Media stack storage on r5500: btrfs subvolume @media-stack on the OS disk (sda4).
|
||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
let
|
||||||
|
btrfsUuid = "934a5ec3-4bab-49c3-96c9-c857c50076ba";
|
||||||
|
btrfsDevice = "/dev/disk/by-uuid/${btrfsUuid}";
|
||||||
|
# Created under subvol=@ → full path is @/@media-stack (not a top-level @media-stack).
|
||||||
|
mediaSubvol = "@/@media-stack";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# Create @media-stack before /mnt/media-stack is mounted.
|
||||||
|
systemd.services.r5500-media-stack-subvolume = {
|
||||||
|
description = "Create btrfs subvolume @media-stack on sda4 if missing";
|
||||||
|
before = [ "mnt-media\\x2dmedia\\x2dstack.mount" ];
|
||||||
|
wantedBy = [ "local-fs-pre.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
};
|
||||||
|
script = ''
|
||||||
|
rootMount="/mnt/.r5500-btrfs-root"
|
||||||
|
mkdir -p "$rootMount"
|
||||||
|
if ! mountpoint -q "$rootMount"; then
|
||||||
|
mount -o subvol=@ "${btrfsDevice}" "$rootMount"
|
||||||
|
umountAfter=1
|
||||||
|
else
|
||||||
|
umountAfter=0
|
||||||
|
fi
|
||||||
|
if ! ${pkgs.btrfs-progs}/bin/btrfs subvolume show "$rootMount/@media-stack" >/dev/null 2>&1; then
|
||||||
|
${pkgs.btrfs-progs}/bin/btrfs subvolume create "$rootMount/@media-stack"
|
||||||
|
fi
|
||||||
|
if [ "$umountAfter" -eq 1 ]; then
|
||||||
|
umount "$rootMount"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# Optional 1 TiB cap (run once after first boot if desired):
|
||||||
|
# sudo btrfs quota enable /mnt/media-stack && sudo btrfs qgroup limit 1T /mnt/media-stack
|
||||||
|
|
||||||
|
fileSystems."/mnt/media-stack" = {
|
||||||
|
device = btrfsDevice;
|
||||||
|
fsType = "btrfs";
|
||||||
|
neededForBoot = false;
|
||||||
|
options = [
|
||||||
|
"subvol=${mediaSubvol}"
|
||||||
|
"compress=zstd"
|
||||||
|
"noatime"
|
||||||
|
"nofail"
|
||||||
|
"x-systemd.device-timeout=30"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
# Shared media group, directory layout, and Jellyfin config bind-mount on /mnt/media-stack.
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
paths = import ./media-stack-paths.nix;
|
||||||
|
prowlarrCustomIndexer = "${./../_services/prowlarr/torrent9-custom.yml}";
|
||||||
|
inherit (paths)
|
||||||
|
mediaRoot
|
||||||
|
downloadsDir
|
||||||
|
downloadsIncompleteDir
|
||||||
|
sonarrDataDir
|
||||||
|
radarrDataDir
|
||||||
|
prowlarrDataDir
|
||||||
|
qbittorrentDataDir
|
||||||
|
seerrConfigDir
|
||||||
|
dispatcharrDataDir
|
||||||
|
organizrDataDir
|
||||||
|
jellyfinConfigDir
|
||||||
|
jellyfinMoviesDir
|
||||||
|
jellyfinTvDir
|
||||||
|
;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
_module.args.mediaStackPaths = paths;
|
||||||
|
|
||||||
|
users.groups.media = { };
|
||||||
|
|
||||||
|
users.users.server.extraGroups = [ "media" ];
|
||||||
|
|
||||||
|
# Layout dirs only after /mnt/media-stack is mounted (tmpfiles at early boot would
|
||||||
|
# otherwise create paths on the root fs and break bind mounts / boot).
|
||||||
|
systemd.services.r5500-media-stack-dirs = {
|
||||||
|
description = "Create media-stack directory layout";
|
||||||
|
after = [ "mnt-media\\x2dmedia\\x2dstack.mount" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
};
|
||||||
|
script = ''
|
||||||
|
set -e
|
||||||
|
install -d -m 0775 -o root -g media ${mediaRoot}
|
||||||
|
install -d -m 2775 -o root -g media ${jellyfinMoviesDir} ${jellyfinTvDir} ${downloadsDir}
|
||||||
|
install -d -m 2775 -o root -g media ${downloadsIncompleteDir}
|
||||||
|
install -d -m 0755 -o jellyfin -g jellyfin ${jellyfinConfigDir}
|
||||||
|
install -d -m 0700 -o sonarr -g sonarr ${sonarrDataDir}
|
||||||
|
install -d -m 0700 -o radarr -g radarr ${radarrDataDir}
|
||||||
|
install -d -m 0700 -o prowlarr -g prowlarr ${prowlarrDataDir}
|
||||||
|
install -d -m 0750 -o qbittorrent -g qbittorrent ${qbittorrentDataDir}
|
||||||
|
install -d -m 0755 -o jellyseerr -g jellyseerr ${seerrConfigDir} 2>/dev/null \
|
||||||
|
|| install -d -m 0755 -o root -g root ${seerrConfigDir}
|
||||||
|
install -d -m 0777 -o root -g root ${dispatcharrDataDir}
|
||||||
|
install -d -m 0755 -o organizr -g organizr ${organizrDataDir} 2>/dev/null \
|
||||||
|
|| install -d -m 0755 -o root -g root ${organizrDataDir}
|
||||||
|
install -d -m 0700 -o prowlarr -g prowlarr ${prowlarrDataDir}/Definitions/Custom
|
||||||
|
ln -sfn ${prowlarrCustomIndexer} ${prowlarrDataDir}/Definitions/Custom/torrent9-custom.yml
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# Jellyfin metadata on the media subvolume; nofail so a missing subvol never bricks boot.
|
||||||
|
fileSystems."/var/lib/jellyfin" = {
|
||||||
|
device = jellyfinConfigDir;
|
||||||
|
fsType = "none";
|
||||||
|
neededForBoot = false;
|
||||||
|
options = [
|
||||||
|
"bind"
|
||||||
|
"nofail"
|
||||||
|
"x-systemd.after=mnt-media\\x2dmedia\\x2dstack.mount"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# Path constants for the r5500 media stack (imported by _services/* and media-paths.nix).
|
||||||
|
{
|
||||||
|
mediaRoot = "/mnt/media-stack";
|
||||||
|
downloadsDir = "/mnt/media-stack/downloads";
|
||||||
|
downloadsIncompleteDir = "/mnt/media-stack/downloads/incomplete";
|
||||||
|
sonarrDataDir = "/mnt/media-stack/sonarr";
|
||||||
|
radarrDataDir = "/mnt/media-stack/radarr";
|
||||||
|
prowlarrDataDir = "/mnt/media-stack/prowlarr";
|
||||||
|
qbittorrentDataDir = "/mnt/media-stack/qbittorrent";
|
||||||
|
seerrConfigDir = "/mnt/media-stack/seerr";
|
||||||
|
dispatcharrDataDir = "/mnt/media-stack/dispatcharr";
|
||||||
|
organizrDataDir = "/mnt/media-stack/organizr";
|
||||||
|
jellyfinConfigDir = "/mnt/media-stack/jellyfin/config";
|
||||||
|
jellyfinMoviesDir = "/mnt/media-stack/jellyfin/movies";
|
||||||
|
jellyfinTvDir = "/mnt/media-stack/jellyfin/tv";
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
{ lib, pkgs, mediaStackPaths, ... }:
|
||||||
|
let
|
||||||
|
dataDir = mediaStackPaths.dispatcharrDataDir;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
systemd.tmpfiles.settings."r5500-dispatcharr-data" = {
|
||||||
|
"${dataDir}"."d" = {
|
||||||
|
mode = "0777";
|
||||||
|
user = "root";
|
||||||
|
group = "root";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.docker-dispatcharr.preStart = lib.mkBefore ''
|
||||||
|
${pkgs.coreutils}/bin/mkdir -p ${dataDir}
|
||||||
|
'';
|
||||||
|
|
||||||
|
virtualisation.oci-containers.containers.dispatcharr = {
|
||||||
|
image = "ghcr.io/dispatcharr/dispatcharr:latest";
|
||||||
|
ports = [ "9191:9191" ];
|
||||||
|
volumes = [
|
||||||
|
"${dataDir}:/data"
|
||||||
|
];
|
||||||
|
environment = {
|
||||||
|
DISPATCHARR_ENV = "aio";
|
||||||
|
REDIS_HOST = "localhost";
|
||||||
|
CELERY_BROKER_URL = "redis://localhost:6379/0";
|
||||||
|
DISPATCHARR_LOG_LEVEL = "info";
|
||||||
|
TZ = "America/Moncton";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [ 9191 ];
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# Docker backend for Dispatcharr and Organizr on r5500.
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
virtualisation.docker.enable = true;
|
||||||
|
virtualisation.oci-containers.backend = "docker";
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
services.flaresolverr.enable = true;
|
||||||
|
networking.firewall.allowedTCPPorts = [ 8191 ];
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# Jellyfin on r5500. Local libraries: /mnt/media-stack/jellyfin/{movies,tv}.
|
||||||
|
# Bulk libraries: /mnt/nixdesk-jellyfin/{movies,tv} (NFS from 14900k).
|
||||||
|
{ lib, ... }:
|
||||||
|
{
|
||||||
|
nixpkgs.overlays = [
|
||||||
|
(final: prev: {
|
||||||
|
jellyfin-web = prev.jellyfin-web.overrideAttrs (oldAttrs: {
|
||||||
|
postInstall =
|
||||||
|
(oldAttrs.postInstall or "")
|
||||||
|
+ ''
|
||||||
|
find "$out" -type f \( -name 'banner-light.*.png' -o -name 'banner-dark.*.png' \) \
|
||||||
|
-exec truncate -s 0 {} \;
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
users.users.jellyfin.extraGroups = [ "media" ];
|
||||||
|
|
||||||
|
services.jellyfin = {
|
||||||
|
enable = true;
|
||||||
|
openFirewall = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.jellyfin.serviceConfig = {
|
||||||
|
SupplementaryGroups = [ "media" ];
|
||||||
|
PrivateUsers = lib.mkForce false;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# NFS mounts of nixdesk (14900k) bulk storage for r5500. Exports live in
|
||||||
|
# modules/hosts/14900k/_private/jellyfin-nfs-export.nix
|
||||||
|
#
|
||||||
|
# Jellyfin library paths:
|
||||||
|
# Movies → /mnt/nixdesk-jellyfin/movies
|
||||||
|
# Shows → /mnt/nixdesk-jellyfin/tv
|
||||||
|
{ ... }:
|
||||||
|
let
|
||||||
|
nfsExportHost = "192.168.2.25";
|
||||||
|
nfsClientOpts = [
|
||||||
|
"rw"
|
||||||
|
"noatime"
|
||||||
|
"nofail"
|
||||||
|
"_netdev"
|
||||||
|
"nfsvers=3"
|
||||||
|
"tcp"
|
||||||
|
"lookupcache=none"
|
||||||
|
"x-systemd.automount"
|
||||||
|
"x-systemd.idle-timeout=3600"
|
||||||
|
];
|
||||||
|
in
|
||||||
|
{
|
||||||
|
fileSystems."/mnt/nixdesk-jellyfin" = {
|
||||||
|
device = "${nfsExportHost}:/mnt/deep/jellyfin";
|
||||||
|
fsType = "nfs";
|
||||||
|
options = nfsClientOpts;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
{ lib, pkgs, mediaStackPaths, ... }:
|
||||||
|
let
|
||||||
|
configDir = mediaStackPaths.organizrDataDir;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
users.groups.organizr = { gid = 950; };
|
||||||
|
users.users.organizr = {
|
||||||
|
isSystemUser = true;
|
||||||
|
uid = 950;
|
||||||
|
group = "organizr";
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.tmpfiles.settings."r5500-organizr-config" = {
|
||||||
|
"${configDir}"."d" = {
|
||||||
|
mode = "0755";
|
||||||
|
user = "organizr";
|
||||||
|
group = "organizr";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.tmpfiles.settings."r5500-organizr-config-perms" = {
|
||||||
|
"${configDir}"."Z" = {
|
||||||
|
mode = "0755";
|
||||||
|
user = "organizr";
|
||||||
|
group = "organizr";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.docker-organizr.preStart = lib.mkBefore ''
|
||||||
|
${pkgs.coreutils}/bin/mkdir -p ${configDir}
|
||||||
|
${pkgs.coreutils}/bin/chown -R organizr:organizr ${configDir}
|
||||||
|
'';
|
||||||
|
|
||||||
|
virtualisation.oci-containers.containers.organizr = {
|
||||||
|
image = "ghcr.io/organizr/organizr:latest";
|
||||||
|
ports = [ "8888:80" ];
|
||||||
|
volumes = [
|
||||||
|
"${configDir}:/config"
|
||||||
|
];
|
||||||
|
environment = {
|
||||||
|
PUID = "950";
|
||||||
|
PGID = "950";
|
||||||
|
TZ = "America/Moncton";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [ 8888 ];
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{ lib, mediaStackPaths, ... }:
|
||||||
|
{
|
||||||
|
services.prowlarr = {
|
||||||
|
enable = true;
|
||||||
|
dataDir = mediaStackPaths.prowlarrDataDir;
|
||||||
|
};
|
||||||
|
|
||||||
|
users.groups.prowlarr = { };
|
||||||
|
users.users.prowlarr = {
|
||||||
|
isSystemUser = true;
|
||||||
|
group = "prowlarr";
|
||||||
|
extraGroups = [ "media" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.prowlarr.serviceConfig.ReadWritePaths = lib.mkAfter [
|
||||||
|
mediaStackPaths.prowlarrDataDir
|
||||||
|
];
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [ 9696 ];
|
||||||
|
}
|
||||||
@@ -0,0 +1,193 @@
|
|||||||
|
---
|
||||||
|
id: torrent9-custom
|
||||||
|
name: Torrent9 (Custom URL)
|
||||||
|
description: "Torrent9 is a FRENCH Public site for MOVIES / TV / GENERAL"
|
||||||
|
language: fr-FR
|
||||||
|
type: public
|
||||||
|
encoding: UTF-8
|
||||||
|
followredirect: true
|
||||||
|
testlinktorrent: false
|
||||||
|
links:
|
||||||
|
- https://www.torrent9.club/
|
||||||
|
- https://www6.torrent9.to/
|
||||||
|
legacylinks:
|
||||||
|
- https://www.torrent9.pl/ # this is a proxy for torrent9clone
|
||||||
|
- https://torrent9.black-mirror.xyz/ # this is a proxy for torrent9clone
|
||||||
|
- https://torrent9.unblocked.casa/ # this is a proxy for torrent9clone
|
||||||
|
- https://torrent9.proxyportal.fun/ # this is a proxy for torrent9clone
|
||||||
|
- https://torrent9.uk-unblock.xyz/ # this is a proxy for torrent9clone
|
||||||
|
- https://torrent9.ind-unblock.xyz/ # this is a proxy for torrent9clone
|
||||||
|
- https://ww1.torrent9.to/
|
||||||
|
- https://www.torrent9.is/
|
||||||
|
- https://torrent9.li/ # not a proxy for torrent9 or torrent9clone
|
||||||
|
- https://www.oxtorrent.me/
|
||||||
|
- https://www.torrent9.gg/
|
||||||
|
- https://www.torrent9.fi/ # this is the torrent9clone domain
|
||||||
|
- https://www.torrent9.fm/
|
||||||
|
- https://torrent9.se/ # redirect to www.
|
||||||
|
- https://torrent9.ninjaproxy1.com/ # no response data
|
||||||
|
- https://torrent9.proxyninja.org/ # Error 1007
|
||||||
|
- https://www.torrent9.se/
|
||||||
|
- https://torrent9.unblockninja.com/ # 403 forbidden
|
||||||
|
- https://ww1.torrent9.fm/
|
||||||
|
- https://www.torrent9.zone/ # clone? details links are broken
|
||||||
|
- https://torrent9.to/
|
||||||
|
- https://ww2.torrent9.to/
|
||||||
|
- https://www5.torrent9.to/
|
||||||
|
|
||||||
|
caps:
|
||||||
|
# dont forget to update the search fields category case block
|
||||||
|
categorymappings:
|
||||||
|
- {id: films, cat: Movies, desc: "Movies"}
|
||||||
|
- {id: series, cat: TV, desc: "TV"}
|
||||||
|
- {id: musique, cat: Audio, desc: "Music"}
|
||||||
|
- {id: ebook, cat: Books, desc: "Books"}
|
||||||
|
- {id: logiciels, cat: PC, desc: "Software"}
|
||||||
|
- {id: jeux-pc, cat: PC/Games, desc: "PC Games"}
|
||||||
|
- {id: other, cat: Other, desc: "Other"} # dummy cat for results missing icon
|
||||||
|
|
||||||
|
modes:
|
||||||
|
search: [q]
|
||||||
|
tv-search: [q, season, ep]
|
||||||
|
movie-search: [q]
|
||||||
|
music-search: [q]
|
||||||
|
book-search: [q]
|
||||||
|
allowrawsearch: true
|
||||||
|
|
||||||
|
settings:
|
||||||
|
- name: info_flaresolverr
|
||||||
|
type: info_flaresolverr
|
||||||
|
- name: multilang
|
||||||
|
type: checkbox
|
||||||
|
label: Replace MULTi by another language in release name
|
||||||
|
default: false
|
||||||
|
- name: multilanguage
|
||||||
|
type: select
|
||||||
|
label: Replace MULTi by this language
|
||||||
|
default: FRENCH
|
||||||
|
options:
|
||||||
|
FRENCH: FRENCH
|
||||||
|
MULTi FRENCH: MULTi FRENCH
|
||||||
|
ENGLISH: ENGLISH
|
||||||
|
MULTi ENGLISH: MULTi ENGLISH
|
||||||
|
VOSTFR: VOSTFR
|
||||||
|
MULTi VOSTFR: MULTi VOSTFR
|
||||||
|
- name: vostfr
|
||||||
|
type: checkbox
|
||||||
|
label: Replace VOSTFR and SUBFRENCH with ENGLISH
|
||||||
|
default: false
|
||||||
|
- name: sort
|
||||||
|
type: select
|
||||||
|
label: Sort requested from site (Only works for searches with Keywords)
|
||||||
|
default: ".html"
|
||||||
|
options:
|
||||||
|
".html": best
|
||||||
|
".html,trie-date-d": created desc
|
||||||
|
".html,trie-date-a": created asc
|
||||||
|
".html,trie-seeds-d": seeders desc
|
||||||
|
".html,trie-seeds-a": seeders asc
|
||||||
|
".html,trie-poid-d": size desc
|
||||||
|
".html,trie-poid-a": size asc
|
||||||
|
".html,trie-nom-d": title desc
|
||||||
|
".html,trie-nom-a": title asc
|
||||||
|
|
||||||
|
download:
|
||||||
|
selectors:
|
||||||
|
- selector: a[href^="magnet:?"]
|
||||||
|
attribute: href
|
||||||
|
- selector: script:contains("magnet:?")
|
||||||
|
filters:
|
||||||
|
- name: regexp
|
||||||
|
args: "\\s'(magnet:\\?.+?)';"
|
||||||
|
|
||||||
|
search:
|
||||||
|
paths:
|
||||||
|
- path: "{{ if .Keywords }}search_torrent/{{ .Keywords }}{{ .Config.sort }}{{ else }}home/{{ end }}"
|
||||||
|
keywordsfilters:
|
||||||
|
# if searching for season packs with S01 to saison 1 #9712
|
||||||
|
- name: re_replace
|
||||||
|
args: ["(?i)(S0)(\\d{1,2})$", "saison $2"]
|
||||||
|
- name: re_replace
|
||||||
|
args: ["(?i)(S)(\\d{1,3})$", "saison $2"]
|
||||||
|
- name: replace
|
||||||
|
args: [" ", "-"]
|
||||||
|
|
||||||
|
headers:
|
||||||
|
# site blocks all Linux User-Agents, so use a slightly altered Windows Jackett UA here (e.g. Safari/537.36 > Safari/537.35)
|
||||||
|
User-Agent: ["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.35"]
|
||||||
|
|
||||||
|
rows:
|
||||||
|
selector: table.table-striped > tbody > tr
|
||||||
|
filters:
|
||||||
|
- name: andmatch
|
||||||
|
|
||||||
|
fields:
|
||||||
|
category_optional:
|
||||||
|
selector: td:nth-child(1) i
|
||||||
|
optional: true
|
||||||
|
case:
|
||||||
|
i[class="fa fa-video-camera"]: films
|
||||||
|
i[class="fa fa-tv"]: series # search by name
|
||||||
|
i[class="fa fa-desktop"]: series # keywordless search
|
||||||
|
i[class="fa fa-music"]: musique
|
||||||
|
i[class="fa fa-gamepad"]: jeux-pc
|
||||||
|
i[class="fa fa-laptop"]: logiciels
|
||||||
|
i[class="fa fa-book"]: ebook
|
||||||
|
category:
|
||||||
|
text: "{{ if .Result.category_optional }}{{ .Result.category_optional }}{{ else }}other{{ end }}"
|
||||||
|
title_default:
|
||||||
|
selector: td:nth-child(1) a
|
||||||
|
title_optional:
|
||||||
|
selector: td:nth-child(1) a[title]
|
||||||
|
attribute: title
|
||||||
|
optional: true
|
||||||
|
title_phase1:
|
||||||
|
text: "{{ if .Result.title_optional }}{{ .Result.title_optional }}{{ else }}{{ .Result.title_default }}{{ end }}"
|
||||||
|
filters:
|
||||||
|
- name: re_replace
|
||||||
|
args: ["(?i)\\b(FRENCH|MULTI|TRUEFRENCH|VOSTFR|SUBFRENCH)\\b(.+?)(\\b((19|20)\\d{2})\\b)$", "$3 $1$2"]
|
||||||
|
title_vostfr:
|
||||||
|
text: "{{ .Result.title_phase1 }}"
|
||||||
|
filters:
|
||||||
|
- name: re_replace
|
||||||
|
args: ["(?i)\\b(vostfr|subfrench)\\b", "ENGLISH"]
|
||||||
|
title_phase2:
|
||||||
|
text: "{{ if .Config.vostfr }}{{ .Result.title_vostfr }}{{ else }}{{ .Result.title_phase1 }}{{ end }}"
|
||||||
|
title_multilang:
|
||||||
|
text: "{{ .Result.title_phase2 }}"
|
||||||
|
filters:
|
||||||
|
- name: re_replace
|
||||||
|
args: ["(?i)\\b(MULTI(?!.*(?:FRENCH|ENGLISH|VOSTFR)))\\b", "{{ .Config.multilanguage }}"]
|
||||||
|
title:
|
||||||
|
text: "{{ if .Config.multilang }}{{ .Result.title_multilang }}{{ else }}{{ .Result.title_phase2 }}{{ end }}"
|
||||||
|
details:
|
||||||
|
selector: td:nth-child(1) a
|
||||||
|
attribute: href
|
||||||
|
download:
|
||||||
|
selector: td:nth-child(1) a
|
||||||
|
attribute: href
|
||||||
|
date:
|
||||||
|
selector: td:nth-child(2):contains("/")
|
||||||
|
optional: true
|
||||||
|
default: now
|
||||||
|
filters:
|
||||||
|
- name: dateparse
|
||||||
|
args: "dd/MM/yyyy"
|
||||||
|
size:
|
||||||
|
selector: "{{ if .Keywords }}td:nth-child(3){{ else }}td:nth-child(2){{ end }}"
|
||||||
|
filters:
|
||||||
|
- name: re_replace
|
||||||
|
args: ["(\\w)o", "$1B"]
|
||||||
|
seeders:
|
||||||
|
selector: "{{ if .Keywords }}td:nth-child(4){{ else }}td:nth-child(3){{ end }}"
|
||||||
|
optional: true
|
||||||
|
default: 0
|
||||||
|
leechers:
|
||||||
|
selector: "{{ if .Keywords }}td:nth-child(5){{ else }}td:nth-child(4){{ end }}"
|
||||||
|
optional: true
|
||||||
|
default: 0
|
||||||
|
downloadvolumefactor:
|
||||||
|
text: 0
|
||||||
|
uploadvolumefactor:
|
||||||
|
text: 1
|
||||||
|
# engine n/a
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
{ lib, mediaStackPaths, ... }:
|
||||||
|
let
|
||||||
|
webPort = 8081;
|
||||||
|
btPort = 51413;
|
||||||
|
inherit (mediaStackPaths) downloadsDir downloadsIncompleteDir qbittorrentDataDir;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
services.qbittorrent = {
|
||||||
|
enable = true;
|
||||||
|
openFirewall = true;
|
||||||
|
webuiPort = webPort;
|
||||||
|
torrentingPort = btPort;
|
||||||
|
};
|
||||||
|
|
||||||
|
users.groups.qbittorrent = { };
|
||||||
|
users.users.qbittorrent = {
|
||||||
|
isSystemUser = true;
|
||||||
|
group = "qbittorrent";
|
||||||
|
extraGroups = [ "media" ];
|
||||||
|
home = qbittorrentDataDir;
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/var/lib/qbittorrent" = {
|
||||||
|
device = qbittorrentDataDir;
|
||||||
|
fsType = "none";
|
||||||
|
neededForBoot = false;
|
||||||
|
options = [
|
||||||
|
"bind"
|
||||||
|
"nofail"
|
||||||
|
"x-systemd.after=mnt-media\\x2dmedia\\x2dstack.mount"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [ webPort btPort ];
|
||||||
|
networking.firewall.allowedUDPPorts = [ btPort ];
|
||||||
|
|
||||||
|
# Default save path for new torrents (existing qBittorrent.conf may override after migration).
|
||||||
|
systemd.services.qbittorrent.preStart = lib.mkAfter ''
|
||||||
|
mkdir -p ${downloadsDir} ${downloadsIncompleteDir}
|
||||||
|
chmod 2775 ${downloadsDir} ${downloadsIncompleteDir}
|
||||||
|
chgrp media ${downloadsDir} ${downloadsIncompleteDir}
|
||||||
|
'';
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{ lib, mediaStackPaths, ... }:
|
||||||
|
{
|
||||||
|
services.radarr = {
|
||||||
|
enable = true;
|
||||||
|
dataDir = mediaStackPaths.radarrDataDir;
|
||||||
|
};
|
||||||
|
|
||||||
|
users.groups.radarr = { };
|
||||||
|
users.users.radarr = {
|
||||||
|
isSystemUser = true;
|
||||||
|
group = "radarr";
|
||||||
|
extraGroups = [ "media" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.radarr.serviceConfig.ReadWritePaths = lib.mkAfter [
|
||||||
|
mediaStackPaths.radarrDataDir
|
||||||
|
];
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [ 7878 ];
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
{ lib, mediaStackPaths, ... }:
|
||||||
|
{
|
||||||
|
nixpkgs.overlays = [
|
||||||
|
(final: prev: {
|
||||||
|
seerr = prev.seerr.overrideAttrs (oldAttrs: {
|
||||||
|
postInstall =
|
||||||
|
(oldAttrs.postInstall or "")
|
||||||
|
+ ''
|
||||||
|
find "$out/share/public" -maxdepth 1 -type f \( -name 'logo_full.svg' -o -name 'logo_stacked.svg' \) \
|
||||||
|
-exec truncate -s 0 {} \;
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
services.seerr = {
|
||||||
|
enable = true;
|
||||||
|
openFirewall = true;
|
||||||
|
configDir = mediaStackPaths.seerrConfigDir;
|
||||||
|
};
|
||||||
|
|
||||||
|
users.groups.jellyseerr = { };
|
||||||
|
users.users.jellyseerr = {
|
||||||
|
isSystemUser = true;
|
||||||
|
group = "jellyseerr";
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.seerr.serviceConfig = {
|
||||||
|
DynamicUser = lib.mkForce false;
|
||||||
|
User = "jellyseerr";
|
||||||
|
Group = "jellyseerr";
|
||||||
|
ReadWritePaths = [ mediaStackPaths.seerrConfigDir ];
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{ lib, mediaStackPaths, ... }:
|
||||||
|
{
|
||||||
|
services.sonarr = {
|
||||||
|
enable = true;
|
||||||
|
dataDir = mediaStackPaths.sonarrDataDir;
|
||||||
|
};
|
||||||
|
|
||||||
|
users.groups.sonarr = { };
|
||||||
|
users.users.sonarr = {
|
||||||
|
isSystemUser = true;
|
||||||
|
group = "sonarr";
|
||||||
|
extraGroups = [ "media" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.sonarr.serviceConfig.ReadWritePaths = lib.mkAfter [
|
||||||
|
mediaStackPaths.sonarrDataDir
|
||||||
|
];
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [ 8989 ];
|
||||||
|
}
|
||||||
@@ -14,6 +14,19 @@
|
|||||||
inputs.sops-nix.nixosModules.sops
|
inputs.sops-nix.nixosModules.sops
|
||||||
self.nixosModules.system
|
self.nixosModules.system
|
||||||
self.nixosModules.users
|
self.nixosModules.users
|
||||||
|
./_private/media-disk.nix
|
||||||
|
./_private/media-paths.nix
|
||||||
|
./_services/docker-media.nix
|
||||||
|
./_services/nixdesk-nfs-client.nix
|
||||||
|
./_services/jellyfin.nix
|
||||||
|
./_services/sonarr.nix
|
||||||
|
./_services/radarr.nix
|
||||||
|
./_services/prowlarr.nix
|
||||||
|
./_services/flaresolverr.nix
|
||||||
|
./_services/seerr.nix
|
||||||
|
./_services/qbittorrent.nix
|
||||||
|
./_services/dispatcharr.nix
|
||||||
|
./_services/organizr.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
boot.loader.grub = {
|
boot.loader.grub = {
|
||||||
|
|||||||
Reference in New Issue
Block a user