Compare commits

..

No commits in common. "fa04def7a1d5faf35cc822088d82c42a54b60da0" and "545d7a099490da51ed3d7dbd703b688921f6642b" have entirely different histories.

20 changed files with 114 additions and 156 deletions

View file

@ -53,18 +53,18 @@
}; };
job = { job = {
backgroundTask.concurrency = 3; backgroundTask.concurrency = 5;
faceDetection.concurrency = 1; faceDetection.concurrency = 1;
library.concurrency = 5; library.concurrency = 7;
metadataExtraction.concurrency = 5; metadataExtraction.concurrency = 7;
migration.concurrency = 5; migration.concurrency = 5;
notifications.concurrency = 5; notifications.concurrency = 5;
search.concurrency = 5; search.concurrency = 5;
sidecar.concurrency = 5; sidecar.concurrency = 5;
ocr.concurrency = 1; ocr.concurrency = 1; # ML-intensive
smartSearch.concurrency = 1; smartSearch.concurrency = 1; # ML-intensive
thumbnailGeneration.concurrency = 3; thumbnailGeneration.concurrency = 5;
videoConversion.concurrency = 1; videoConversion.concurrency = 2;
}; };
library = { library = {

View file

@ -21,6 +21,8 @@
syncthing-custom.folders = { syncthing-custom.folders = {
Credentials.enable = true; Credentials.enable = true;
Documents.enable = true; Documents.enable = true;
Media.enable = true;
Consume.enable = true;
Archive.enable = true; Archive.enable = true;
}; };
@ -57,16 +59,17 @@
texlive.combined.scheme-full texlive.combined.scheme-full
httpie httpie
gnumake gnumake
bind bind # DNS utilities (dig, nslookup, mdig)
inetutils inetutils # Network utilities (telnet)
netcat-gnu netcat-gnu # Network connection utility
curl curl # HTTP client
wget wget # Web downloader
bandwhich bandwhich # Terminal bandwidth utilization tool
ncdu ncdu
delta
fastfetch fastfetch
coreutils coreutils # GNU core utilities (base64, etc.)
duti duti # Set default applications for file types (macOS)
rsync rsync
]; ];

View file

@ -101,7 +101,7 @@
screencapture = { screencapture = {
disable-shadow = true; disable-shadow = true;
location = "~/Downloads"; location = "~/Consume/dcim";
type = "png"; type = "png";
show-thumbnail = true; show-thumbnail = true;
}; };
@ -174,6 +174,8 @@
"slidepilot" "slidepilot"
"zotero" "zotero"
"aerospace" "aerospace"
"hiddenbar"
"keycastr"
"localsend" "localsend"
"maccy" "maccy"
]; ];

View file

@ -26,6 +26,7 @@
silent = true; silent = true;
}; };
# nixOS-specific alias
programs.zsh.shellAliases = { programs.zsh.shellAliases = {
oss = "sudo nixos-rebuild switch --flake ~/.config/nix#$(hostname)"; oss = "sudo nixos-rebuild switch --flake ~/.config/nix#$(hostname)";
}; };
@ -34,11 +35,12 @@
httpie httpie
gnumake gnumake
rsync rsync
bind bind # DNS utilities (dig, nslookup, mdig)
iputils iputils # Core network tools (ping, traceroute)
inetutils inetutils # Network utilities (telnet)
netcat-gnu netcat-gnu # Network connection utility
ncdu ncdu
delta
fastfetch fastfetch
]; ];
} }

View file

@ -17,7 +17,8 @@ in
volumes = [ volumes = [
"/var/lib/immich/config:/config" "/var/lib/immich/config:/config"
"/mnt/storage/photos:/photos" "/var/lib/immich/photos:/photos"
"/mnt/storage/DCIM:/library:ro"
"${immichConfigFile}:/config/immich.json:ro" "${immichConfigFile}:/config/immich.json:ro"
]; ];

View file

@ -5,6 +5,7 @@
../home-default.nix ../home-default.nix
../../../modules/syncthing.nix ../../../modules/syncthing.nix
../../../modules/media/tool.nix ../../../modules/media/tool.nix
../../../modules/schedule.nix
]; ];
syncthing-custom.folders = { syncthing-custom.folders = {
@ -12,6 +13,17 @@
Documents = { enable = true; maxAgeDays = 30; }; Documents = { enable = true; maxAgeDays = 30; };
Media = { enable = true; maxAgeDays = 7; }; Media = { enable = true; maxAgeDays = 7; };
Archive = { enable = true; maxAgeDays = 30; }; Archive = { enable = true; maxAgeDays = 30; };
Consume = { enable = true; maxAgeDays = 7; };
DCIM = { enable = true; maxAgeDays = 7; path = "/mnt/storage/DCIM"; };
};
services.scheduled-commands.dcim-consume = {
enable = true;
description = "Move files in dcim consume folder to DCIM";
interval = "*-*-* *:00/15:00";
commands = [
"photo-move -d /home/yanlin/Consume/dcim /mnt/storage/DCIM"
];
}; };
} }

View file

@ -27,17 +27,6 @@
}; };
}; };
photo = {
rule = "Host(`photo.home.yanlincs.com`)";
service = "photo";
tls = {
certResolver = "cloudflare";
domains = [{
main = "*.home.yanlincs.com";
}];
};
};
}; };
services = { services = {
@ -50,15 +39,6 @@
}; };
}; };
photo = {
loadBalancer = {
serversTransport = "longTimeout";
servers = [{
url = "http://127.0.0.1:8080";
}];
};
};
}; };
}; };

View file

@ -140,21 +140,18 @@
# Media server services # Media server services
services.media-server = { services.media-server = {
user = "yanlin"; user = "yanlin";
navidrome.enable = true;
deluge.enable = true; deluge.enable = true;
}; };
services.samba-custom.shares = { services.samba-custom.shares = {
Downloads = "/home/yanlin/Downloads"; DCIM = "/mnt/storage/DCIM";
Media = "/home/yanlin/Media";
}; };
# Borg backup configuration # Borg backup configuration
services.borg-client-custom = { services.borg-client-custom = {
enable = true; enable = false;
repositoryUrl = "ssh://helsinki-box/./nfss"; repositoryUrl = "ssh://helsinki-box/./nfss";
backupPaths = [ backupPaths = [
"/mnt/storage/photos/library"
]; ];
backupFrequency = "*-*-* 01:00:00"; backupFrequency = "*-*-* 01:00:00";
retention = { retention = {

View file

@ -13,6 +13,8 @@
Documents = { enable = true; maxAgeDays = 30; }; Documents = { enable = true; maxAgeDays = 30; };
Media = { enable = true; maxAgeDays = 7; }; Media = { enable = true; maxAgeDays = 7; };
Archive = { enable = true; maxAgeDays = 30; }; Archive = { enable = true; maxAgeDays = 30; };
Consume = { enable = true; maxAgeDays = 7; };
DCIM = { enable = true; maxAgeDays = 7; path = "~/DCIM"; };
}; };
services.scheduled-commands.aicloud-backup = { services.scheduled-commands.aicloud-backup = {

View file

@ -198,6 +198,7 @@
"/home/yanlin/Credentials" "/home/yanlin/Credentials"
"/home/yanlin/Documents" "/home/yanlin/Documents"
"/home/yanlin/Media" "/home/yanlin/Media"
"/home/yanlin/DCIM"
]; ];
backupFrequency = "*-*-* 00:00:00"; backupFrequency = "*-*-* 00:00:00";
retention = { retention = {

View file

@ -1,8 +1,12 @@
{ lib, pkgs, modulesPath, ... }: # Hardware configuration for VPS
# This is a generic configuration suitable for most VPS providers
{ config, lib, pkgs, modulesPath, ... }:
{ {
imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
# Boot configuration - common kernel modules for VPS environments
boot.initrd.availableKernelModules = [ boot.initrd.availableKernelModules = [
"ata_piix" "ata_piix"
"uhci_hcd" "uhci_hcd"
@ -19,7 +23,20 @@
boot.kernelModules = [ ]; boot.kernelModules = [ ];
boot.extraModulePackages = [ ]; boot.extraModulePackages = [ ];
# Filesystems are managed by disko configuration
# No filesystem declarations needed here
# No swap devices configured here - handled by disko
# Networking hardware
networking.useDHCP = lib.mkDefault true; networking.useDHCP = lib.mkDefault true;
# Hardware-specific settings
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
# CPU microcode updates
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
# Enable firmware updates
hardware.enableRedistributableFirmware = lib.mkDefault true; hardware.enableRedistributableFirmware = lib.mkDefault true;
} }

View file

@ -27,28 +27,6 @@
}; };
}; };
music = {
rule = "Host(`music.yanlincs.com`)";
service = "music";
tls = {
certResolver = "cloudflare";
domains = [{
main = "*.yanlincs.com";
}];
};
};
git = {
rule = "Host(`git.yanlincs.com`)";
service = "git";
tls = {
certResolver = "cloudflare";
domains = [{
main = "*.yanlincs.com";
}];
};
};
}; };
services = { services = {
@ -62,22 +40,6 @@
}; };
}; };
music = {
loadBalancer = {
servers = [{
url = "http://10.1.1.152:4533";
}];
};
};
git = {
loadBalancer = {
servers = [{
url = "http://127.0.0.1:3000";
}];
};
};
}; };
}; };

View file

@ -10,7 +10,6 @@
../../../modules/podman.nix ../../../modules/podman.nix
../../../modules/traefik.nix ../../../modules/traefik.nix
../../../modules/borg/client.nix ../../../modules/borg/client.nix
../../../modules/git/server.nix
]; ];
# GRUB bootloader with UEFI support # GRUB bootloader with UEFI support
@ -73,18 +72,12 @@
services.tailscale-custom.exitNode = true; services.tailscale-custom.exitNode = true;
services.git-server-custom = {
enable = true;
domain = "git.yanlincs.com";
};
# Borg backup configuration # Borg backup configuration
services.borg-client-custom = { services.borg-client-custom = {
enable = true; enable = true;
repositoryUrl = "ssh://helsinki-box/./vps"; repositoryUrl = "ssh://helsinki-box/./vps";
backupPaths = [ backupPaths = [
"/var/lib/mongodb" "/var/lib/mongodb"
"/var/lib/forgejo"
]; ];
backupFrequency = "*-*-* 03:00:00"; backupFrequency = "*-*-* 03:00:00";
retention = { retention = {

View file

@ -144,8 +144,6 @@ in
home.packages = [ home.packages = [
pkgs.claude-code pkgs.claude-code
pkgs.poppler-utils pkgs.poppler-utils
pkgs.pandoc
pkgs.yq-go
]; ];
# Create global settings file (with permissions included) # Create global settings file (with permissions included)
@ -161,8 +159,6 @@ in
- Projects may use flake + direnv for project-specific runtimes - Projects may use flake + direnv for project-specific runtimes
- Common development tools (git, gh, ripgrep, jq, fzf, etc.) are globally available via nix - Common development tools (git, gh, ripgrep, jq, fzf, etc.) are globally available via nix
- PDF reading is supported (poppler-utils installed) - PDF reading is supported (poppler-utils installed)
- Document format conversion is supported (pandoc installed)
- YAML/TOML/XML processing is supported (yq-go installed)
''; '';
}; };
}; };

View file

@ -1,10 +1,6 @@
{ config, pkgs, ... }: { config, pkgs, ... }:
{ {
home.packages = [
pkgs.gh
];
programs.git-credential-oauth = { programs.git-credential-oauth = {
enable = true; enable = true;
}; };

View file

@ -1,8 +1,6 @@
{ config, pkgs, lib, ... }: { config, pkgs, lib, ... }:
{ {
home.packages = [ pkgs.delta ];
programs.lazygit = { programs.lazygit = {
enable = true; enable = true;
settings = { settings = {

View file

@ -1,7 +1,4 @@
# NOTE: After install, use the following command to create admin account. { config, lib, ... }:
# sudo -u forgejo forgejo --config /var/lib/forgejo/custom/conf/app.ini admin user create --admin --username <user> --password <pass> --email <email>
{ config, lib, pkgs, ... }:
let let
cfg = config.services.git-server-custom; cfg = config.services.git-server-custom;
@ -27,8 +24,6 @@ in
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
environment.systemPackages = [ config.services.forgejo.package ];
services.forgejo = { services.forgejo = {
enable = true; enable = true;
lfs.enable = true; lfs.enable = true;
@ -40,7 +35,6 @@ in
HTTP_ADDR = "127.0.0.1"; HTTP_ADDR = "127.0.0.1";
HTTP_PORT = cfg.httpPort; HTTP_PORT = cfg.httpPort;
SSH_PORT = cfg.sshPort; SSH_PORT = cfg.sshPort;
LANDING_PAGE = "/yanlin";
}; };
service.DISABLE_REGISTRATION = true; service.DISABLE_REGISTRATION = true;
}; };

View file

@ -1,5 +1,3 @@
# NOTE: Immich credentials file at: `~/.config/immich-env` with IMMICH_URL and IMMICH_APIKEY
{ config, pkgs, lib, ... }: { config, pkgs, lib, ... }:
{ {
@ -9,12 +7,10 @@
shntool shntool
cuetools cuetools
flac flac
zip
unzip unzip
p7zip p7zip
imagemagick imagemagick
exiftool exiftool
immich-go
]; ];
programs.zsh.initContent = '' programs.zsh.initContent = ''
@ -90,29 +86,6 @@
done done
} }
function cbz-compress() {
local dir="''${1:-.}"
dir="$(cd "$dir" && pwd)"
mkdir -p "$dir/compressed"
find "$dir" -path "$dir/compressed" -prune -o -type f \( -iname '*.zip' -o -iname '*.cbz' \) -print | while read -r f; do
echo "Processing: $f"
local tmpdir=$(mktemp -d)
7z x -o"$tmpdir" -y "$f" > /dev/null
find "$tmpdir" -type f \( -iname '*.png' -o -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.gif' -o -iname '*.heic' -o -iname '*.heif' \) -print0 | xargs -0 -P4 -n1 sh -c '
img="$1"
outfile="''${img%.*}.webp"
${pkgs.imagemagick}/bin/magick "$img" -resize "1500>" -quality 75 "$outfile"
[ "$img" != "$outfile" ] && rm "$img"
' _
local relpath="''${f#$dir/}"
local outfile="$dir/compressed/$relpath"
mkdir -p "$(dirname "$outfile")"
(cd "$tmpdir" && zip -r -q "$outfile" .)
rm -rf "$tmpdir"
echo "Done: $outfile"
done
}
function webp2png() { function webp2png() {
local dir="''${1:-.}" local dir="''${1:-.}"
find "$dir" -type f -iname '*.webp' | while read -r img; do find "$dir" -type f -iname '*.webp' | while read -r img; do
@ -145,24 +118,56 @@
done done
} }
function photo-upload() { function photo-move() {
local envfile="$HOME/.config/immich-env" local mode=copy
if [[ ! -f "$envfile" ]]; then if [[ "$1" == "-d" || "$1" == "--delete" ]]; then
echo "Missing $envfile" >&2 mode=move; shift
return 1 elif [[ "$1" == "-l" || "$1" == "--link" ]]; then
mode=link; shift
fi fi
source "$envfile"
if [[ -z "$IMMICH_URL" || -z "$IMMICH_APIKEY" ]]; then if [[ $# -ne 2 ]]; then
echo "IMMICH_URL and IMMICH_APIKEY must be set in $envfile" >&2 echo "Usage: photo-move [-d|--delete|-l|--link] <source_dir> <destination>"
echo " -d, --delete Move files instead of copying"
echo " -l, --link Hardlink instead of copying"
echo " photo-move /Volumes/CAMERA/DCIM ~/DCIM"
return 1 return 1
fi fi
if [[ $# -eq 0 ]]; then local src="$1" dest="$2"
echo "Usage: photo-upload <source_dir>" >&2
if [[ ! -d "$src" ]]; then
echo "Source not found: $src" >&2
return 1 return 1
fi fi
immich-go upload from-folder --server="$IMMICH_URL" --api-key="$IMMICH_APIKEY" "$1" local name raw_date target
while IFS= read -r -d "" file; do
name=$(basename "$file")
[[ "$name" == .* ]] && continue
raw_date=$(${pkgs.exiftool}/bin/exiftool -s3 -d '%Y-%m-%d' \
-DateTimeOriginal -CreateDate -MediaCreateDate "$file" 2>/dev/null | head -1)
if [[ ! "$raw_date" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ || "$raw_date" == "0000-00-00" ]]; then
raw_date=$(${pkgs.coreutils}/bin/date -d "@$(${pkgs.coreutils}/bin/stat -c '%Y' "$file")" +%Y-%m-%d)
fi
target="$dest/''${raw_date:0:4}/$raw_date"
mkdir -p "$target"
[[ -e "$target/$name" ]] && continue
case $mode in
move) mv "$file" "$target/$name" ;;
link) ln "$file" "$target/$name" ;;
*) cp -a "$file" "$target/$name" ;;
esac
done < <(find "$src" -type f \( \
-iname "*.mp4" -o -iname "*.mov" -o -iname "*.mts" -o -iname "*.m2ts" -o -iname "*.avi" \
-o -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.heic" -o -iname "*.heif" \
-o -iname "*.cr2" -o -iname "*.cr3" -o -iname "*.nef" -o -iname "*.arw" -o -iname "*.dng" -o -iname "*.raf" -o -iname "*.orf" -o -iname "*.rw2" \
\) -print0)
} }
function extract() { function extract() {
@ -190,7 +195,7 @@
*.gz) gunzip -k "$file" ;; *.gz) gunzip -k "$file" ;;
*.bz2) bunzip2 -k "$file" ;; *.bz2) bunzip2 -k "$file" ;;
*.xz) unxz -k "$file" ;; *.xz) unxz -k "$file" ;;
*.zip|*.cbz) unzip -q "$file" -d "$dest" ;; *.zip) unzip -q "$file" -d "$dest" ;;
*.7z) 7z x "$file" -o"$dest" ;; *.7z) 7z x "$file" -o"$dest" ;;
*.rar) 7z x "$file" -o"$dest" ;; *.rar) 7z x "$file" -o"$dest" ;;
*) *)
@ -230,7 +235,7 @@
case "''${file:l}" in case "''${file:l}" in
*.tar.gz|*.tgz|*.tar.bz2|*.tbz2|*.tar.xz|*.txz|*.tar.zst|*.tzst|*.tar) *.tar.gz|*.tgz|*.tar.bz2|*.tbz2|*.tar.xz|*.txz|*.tar.zst|*.tzst|*.tar)
tar -tf "$file" ;; tar -tf "$file" ;;
*.zip|*.cbz) unzip -l "$file" ;; *.zip) unzip -l "$file" ;;
*.7z) 7z l "$file" ;; *.7z) 7z l "$file" ;;
*.rar) 7z l "$file" ;; *.rar) 7z l "$file" ;;
*) echo "Unknown archive format: $file" >&2; return 1 ;; *) echo "Unknown archive format: $file" >&2; return 1 ;;

View file

@ -51,11 +51,6 @@ in
identityFile = "${keyDir}/hetzner"; identityFile = "${keyDir}/hetzner";
}; };
"git.yanlincs.com" = {
user = "forgejo";
identityFile = "${keyDir}/hetzner";
};
"borg-box" = { "borg-box" = {
hostname = "u518619.your-storagebox.de"; hostname = "u518619.your-storagebox.de";
user = "u518619"; user = "u518619";

View file

@ -41,8 +41,10 @@ in
folders = { folders = {
Credentials = mkFolderOptions "Credentials" {}; Credentials = mkFolderOptions "Credentials" {};
Documents = mkFolderOptions "Documents" { devices = pcDevices ++ serverDevices; }; Documents = mkFolderOptions "Documents" { devices = pcDevices ++ serverDevices; };
Media = mkFolderOptions "Media" { devices = serverDevices ++ [ "ipad" ]; }; Media = mkFolderOptions "Media" { devices = lib.filter (d: d != "iphone") allDevices; };
Archive = mkFolderOptions "Archive" {}; Archive = mkFolderOptions "Archive" {};
Consume = mkFolderOptions "Consume" {};
DCIM = mkFolderOptions "DCIM" { devices = serverDevices; };
}; };
enableGui = lib.mkOption { enableGui = lib.mkOption {
type = lib.types.bool; type = lib.types.bool;