diff --git a/config/immich.nix b/config/immich.nix index 0cb5577..4ca6228 100644 --- a/config/immich.nix +++ b/config/immich.nix @@ -53,18 +53,18 @@ }; job = { - backgroundTask.concurrency = 5; + backgroundTask.concurrency = 3; faceDetection.concurrency = 1; - library.concurrency = 7; - metadataExtraction.concurrency = 7; + library.concurrency = 5; + metadataExtraction.concurrency = 5; migration.concurrency = 5; notifications.concurrency = 5; search.concurrency = 5; sidecar.concurrency = 5; - ocr.concurrency = 1; # ML-intensive - smartSearch.concurrency = 1; # ML-intensive - thumbnailGeneration.concurrency = 5; - videoConversion.concurrency = 2; + ocr.concurrency = 1; + smartSearch.concurrency = 1; + thumbnailGeneration.concurrency = 3; + videoConversion.concurrency = 1; }; library = { diff --git a/hosts/darwin/home-default.nix b/hosts/darwin/home-default.nix index f455681..bd058a3 100644 --- a/hosts/darwin/home-default.nix +++ b/hosts/darwin/home-default.nix @@ -21,8 +21,6 @@ syncthing-custom.folders = { Credentials.enable = true; Documents.enable = true; - Media.enable = true; - Consume.enable = true; Archive.enable = true; }; @@ -59,17 +57,16 @@ texlive.combined.scheme-full httpie gnumake - bind # DNS utilities (dig, nslookup, mdig) - inetutils # Network utilities (telnet) - netcat-gnu # Network connection utility - curl # HTTP client - wget # Web downloader - bandwhich # Terminal bandwidth utilization tool + bind + inetutils + netcat-gnu + curl + wget + bandwhich ncdu - delta fastfetch - coreutils # GNU core utilities (base64, etc.) - duti # Set default applications for file types (macOS) + coreutils + duti rsync ]; diff --git a/hosts/darwin/system-default.nix b/hosts/darwin/system-default.nix index 182c514..422d708 100644 --- a/hosts/darwin/system-default.nix +++ b/hosts/darwin/system-default.nix @@ -101,7 +101,7 @@ screencapture = { disable-shadow = true; - location = "~/Consume/dcim"; + location = "~/Downloads"; type = "png"; show-thumbnail = true; }; @@ -174,8 +174,6 @@ "slidepilot" "zotero" "aerospace" - "hiddenbar" - "keycastr" "localsend" "maccy" ]; diff --git a/hosts/nixos/home-default.nix b/hosts/nixos/home-default.nix index 09afe7e..f05b2f8 100644 --- a/hosts/nixos/home-default.nix +++ b/hosts/nixos/home-default.nix @@ -26,7 +26,6 @@ silent = true; }; - # nixOS-specific alias programs.zsh.shellAliases = { oss = "sudo nixos-rebuild switch --flake ~/.config/nix#$(hostname)"; }; @@ -35,12 +34,11 @@ httpie gnumake rsync - bind # DNS utilities (dig, nslookup, mdig) - iputils # Core network tools (ping, traceroute) - inetutils # Network utilities (telnet) - netcat-gnu # Network connection utility + bind + iputils + inetutils + netcat-gnu ncdu - delta fastfetch ]; } diff --git a/hosts/nixos/nfss/containers.nix b/hosts/nixos/nfss/containers.nix index 36e88e6..4b74247 100644 --- a/hosts/nixos/nfss/containers.nix +++ b/hosts/nixos/nfss/containers.nix @@ -17,8 +17,7 @@ in volumes = [ "/var/lib/immich/config:/config" - "/var/lib/immich/photos:/photos" - "/mnt/storage/DCIM:/library:ro" + "/mnt/storage/photos:/photos" "${immichConfigFile}:/config/immich.json:ro" ]; diff --git a/hosts/nixos/nfss/home.nix b/hosts/nixos/nfss/home.nix index 8eea131..948c50d 100644 --- a/hosts/nixos/nfss/home.nix +++ b/hosts/nixos/nfss/home.nix @@ -5,7 +5,6 @@ ../home-default.nix ../../../modules/syncthing.nix ../../../modules/media/tool.nix - ../../../modules/schedule.nix ]; syncthing-custom.folders = { @@ -13,17 +12,6 @@ Documents = { enable = true; maxAgeDays = 30; }; Media = { enable = true; maxAgeDays = 7; }; 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" - ]; }; } diff --git a/hosts/nixos/nfss/proxy.nix b/hosts/nixos/nfss/proxy.nix index 9a3a96a..b905d37 100644 --- a/hosts/nixos/nfss/proxy.nix +++ b/hosts/nixos/nfss/proxy.nix @@ -27,6 +27,17 @@ }; }; + photo = { + rule = "Host(`photo.home.yanlincs.com`)"; + service = "photo"; + tls = { + certResolver = "cloudflare"; + domains = [{ + main = "*.home.yanlincs.com"; + }]; + }; + }; + }; services = { @@ -39,6 +50,15 @@ }; }; + photo = { + loadBalancer = { + serversTransport = "longTimeout"; + servers = [{ + url = "http://127.0.0.1:8080"; + }]; + }; + }; + }; }; diff --git a/hosts/nixos/nfss/system.nix b/hosts/nixos/nfss/system.nix index 31b1c3d..06c3fc6 100644 --- a/hosts/nixos/nfss/system.nix +++ b/hosts/nixos/nfss/system.nix @@ -140,18 +140,21 @@ # Media server services services.media-server = { user = "yanlin"; + navidrome.enable = true; deluge.enable = true; }; services.samba-custom.shares = { - DCIM = "/mnt/storage/DCIM"; + Downloads = "/home/yanlin/Downloads"; + Media = "/home/yanlin/Media"; }; # Borg backup configuration services.borg-client-custom = { - enable = false; + enable = true; repositoryUrl = "ssh://helsinki-box/./nfss"; backupPaths = [ + "/mnt/storage/photos/library" ]; backupFrequency = "*-*-* 01:00:00"; retention = { diff --git a/hosts/nixos/thinkpad/home.nix b/hosts/nixos/thinkpad/home.nix index 3aed2df..6d2c823 100644 --- a/hosts/nixos/thinkpad/home.nix +++ b/hosts/nixos/thinkpad/home.nix @@ -13,8 +13,6 @@ Documents = { enable = true; maxAgeDays = 30; }; Media = { enable = true; maxAgeDays = 7; }; Archive = { enable = true; maxAgeDays = 30; }; - Consume = { enable = true; maxAgeDays = 7; }; - DCIM = { enable = true; maxAgeDays = 7; path = "~/DCIM"; }; }; services.scheduled-commands.aicloud-backup = { diff --git a/hosts/nixos/thinkpad/system.nix b/hosts/nixos/thinkpad/system.nix index e882200..467a882 100644 --- a/hosts/nixos/thinkpad/system.nix +++ b/hosts/nixos/thinkpad/system.nix @@ -198,7 +198,6 @@ "/home/yanlin/Credentials" "/home/yanlin/Documents" "/home/yanlin/Media" - "/home/yanlin/DCIM" ]; backupFrequency = "*-*-* 00:00:00"; retention = { diff --git a/hosts/nixos/vps/hardware-configuration.nix b/hosts/nixos/vps/hardware-configuration.nix index ecf2974..3b24ed5 100644 --- a/hosts/nixos/vps/hardware-configuration.nix +++ b/hosts/nixos/vps/hardware-configuration.nix @@ -1,12 +1,8 @@ -# Hardware configuration for VPS -# This is a generic configuration suitable for most VPS providers - -{ config, lib, pkgs, modulesPath, ... }: +{ lib, pkgs, modulesPath, ... }: { imports = [ (modulesPath + "/profiles/qemu-guest.nix") ]; - # Boot configuration - common kernel modules for VPS environments boot.initrd.availableKernelModules = [ "ata_piix" "uhci_hcd" @@ -23,20 +19,7 @@ boot.kernelModules = [ ]; 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; - - # Hardware-specific settings 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; -} \ No newline at end of file +} diff --git a/hosts/nixos/vps/proxy.nix b/hosts/nixos/vps/proxy.nix index bf542ab..1743577 100644 --- a/hosts/nixos/vps/proxy.nix +++ b/hosts/nixos/vps/proxy.nix @@ -27,6 +27,28 @@ }; }; + 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 = { @@ -40,6 +62,22 @@ }; }; + music = { + loadBalancer = { + servers = [{ + url = "http://10.1.1.152:4533"; + }]; + }; + }; + + git = { + loadBalancer = { + servers = [{ + url = "http://127.0.0.1:3000"; + }]; + }; + }; + }; }; diff --git a/hosts/nixos/vps/system.nix b/hosts/nixos/vps/system.nix index bf64008..0094da4 100644 --- a/hosts/nixos/vps/system.nix +++ b/hosts/nixos/vps/system.nix @@ -10,6 +10,7 @@ ../../../modules/podman.nix ../../../modules/traefik.nix ../../../modules/borg/client.nix + ../../../modules/git/server.nix ]; # GRUB bootloader with UEFI support @@ -72,12 +73,18 @@ services.tailscale-custom.exitNode = true; + services.git-server-custom = { + enable = true; + domain = "git.yanlincs.com"; + }; + # Borg backup configuration services.borg-client-custom = { enable = true; repositoryUrl = "ssh://helsinki-box/./vps"; backupPaths = [ "/var/lib/mongodb" + "/var/lib/forgejo" ]; backupFrequency = "*-*-* 03:00:00"; retention = { diff --git a/modules/claude-code.nix b/modules/claude-code.nix index 5cb55eb..05f837c 100644 --- a/modules/claude-code.nix +++ b/modules/claude-code.nix @@ -144,6 +144,8 @@ in home.packages = [ pkgs.claude-code pkgs.poppler-utils + pkgs.pandoc + pkgs.yq-go ]; # Create global settings file (with permissions included) @@ -159,6 +161,8 @@ in - Projects may use flake + direnv for project-specific runtimes - Common development tools (git, gh, ripgrep, jq, fzf, etc.) are globally available via nix - PDF reading is supported (poppler-utils installed) + - Document format conversion is supported (pandoc installed) + - YAML/TOML/XML processing is supported (yq-go installed) ''; }; }; diff --git a/modules/git/home.nix b/modules/git/home.nix index 1e6b2cd..6a7e031 100644 --- a/modules/git/home.nix +++ b/modules/git/home.nix @@ -1,6 +1,10 @@ { config, pkgs, ... }: { + home.packages = [ + pkgs.gh + ]; + programs.git-credential-oauth = { enable = true; }; diff --git a/modules/git/lazygit.nix b/modules/git/lazygit.nix index 262fcee..a0a9a8b 100644 --- a/modules/git/lazygit.nix +++ b/modules/git/lazygit.nix @@ -1,6 +1,8 @@ { config, pkgs, lib, ... }: { + home.packages = [ pkgs.delta ]; + programs.lazygit = { enable = true; settings = { diff --git a/modules/git/server.nix b/modules/git/server.nix index 365e2ac..62f09af 100644 --- a/modules/git/server.nix +++ b/modules/git/server.nix @@ -1,4 +1,7 @@ -{ config, lib, ... }: +# NOTE: After install, use the following command to create admin account. +# sudo -u forgejo forgejo --config /var/lib/forgejo/custom/conf/app.ini admin user create --admin --username --password --email + +{ config, lib, pkgs, ... }: let cfg = config.services.git-server-custom; @@ -24,6 +27,8 @@ in }; config = lib.mkIf cfg.enable { + environment.systemPackages = [ config.services.forgejo.package ]; + services.forgejo = { enable = true; lfs.enable = true; @@ -35,6 +40,7 @@ in HTTP_ADDR = "127.0.0.1"; HTTP_PORT = cfg.httpPort; SSH_PORT = cfg.sshPort; + LANDING_PAGE = "/yanlin"; }; service.DISABLE_REGISTRATION = true; }; diff --git a/modules/media/tool.nix b/modules/media/tool.nix index 9869dbf..20ea7dc 100644 --- a/modules/media/tool.nix +++ b/modules/media/tool.nix @@ -1,3 +1,5 @@ +# NOTE: Immich credentials file at: `~/.config/immich-env` with IMMICH_URL and IMMICH_APIKEY + { config, pkgs, lib, ... }: { @@ -7,10 +9,12 @@ shntool cuetools flac + zip unzip p7zip imagemagick exiftool + immich-go ]; programs.zsh.initContent = '' @@ -86,6 +90,29 @@ 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() { local dir="''${1:-.}" find "$dir" -type f -iname '*.webp' | while read -r img; do @@ -118,56 +145,24 @@ done } - function photo-move() { - local mode=copy - if [[ "$1" == "-d" || "$1" == "--delete" ]]; then - mode=move; shift - elif [[ "$1" == "-l" || "$1" == "--link" ]]; then - mode=link; shift + function photo-upload() { + local envfile="$HOME/.config/immich-env" + if [[ ! -f "$envfile" ]]; then + echo "Missing $envfile" >&2 + return 1 fi - - if [[ $# -ne 2 ]]; then - echo "Usage: photo-move [-d|--delete|-l|--link] " - echo " -d, --delete Move files instead of copying" - echo " -l, --link Hardlink instead of copying" - echo " photo-move /Volumes/CAMERA/DCIM ~/DCIM" + source "$envfile" + if [[ -z "$IMMICH_URL" || -z "$IMMICH_APIKEY" ]]; then + echo "IMMICH_URL and IMMICH_APIKEY must be set in $envfile" >&2 return 1 fi - local src="$1" dest="$2" - - if [[ ! -d "$src" ]]; then - echo "Source not found: $src" >&2 + if [[ $# -eq 0 ]]; then + echo "Usage: photo-upload " >&2 return 1 fi - 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) + immich-go upload from-folder --server="$IMMICH_URL" --api-key="$IMMICH_APIKEY" "$1" } function extract() { @@ -195,7 +190,7 @@ *.gz) gunzip -k "$file" ;; *.bz2) bunzip2 -k "$file" ;; *.xz) unxz -k "$file" ;; - *.zip) unzip -q "$file" -d "$dest" ;; + *.zip|*.cbz) unzip -q "$file" -d "$dest" ;; *.7z) 7z x "$file" -o"$dest" ;; *.rar) 7z x "$file" -o"$dest" ;; *) @@ -235,7 +230,7 @@ case "''${file:l}" in *.tar.gz|*.tgz|*.tar.bz2|*.tbz2|*.tar.xz|*.txz|*.tar.zst|*.tzst|*.tar) tar -tf "$file" ;; - *.zip) unzip -l "$file" ;; + *.zip|*.cbz) unzip -l "$file" ;; *.7z) 7z l "$file" ;; *.rar) 7z l "$file" ;; *) echo "Unknown archive format: $file" >&2; return 1 ;; diff --git a/modules/ssh.nix b/modules/ssh.nix index c773b11..9ed224b 100644 --- a/modules/ssh.nix +++ b/modules/ssh.nix @@ -51,6 +51,11 @@ in identityFile = "${keyDir}/hetzner"; }; + "git.yanlincs.com" = { + user = "forgejo"; + identityFile = "${keyDir}/hetzner"; + }; + "borg-box" = { hostname = "u518619.your-storagebox.de"; user = "u518619"; diff --git a/modules/syncthing.nix b/modules/syncthing.nix index cabe71a..4bbf464 100644 --- a/modules/syncthing.nix +++ b/modules/syncthing.nix @@ -41,10 +41,8 @@ in folders = { Credentials = mkFolderOptions "Credentials" {}; Documents = mkFolderOptions "Documents" { devices = pcDevices ++ serverDevices; }; - Media = mkFolderOptions "Media" { devices = lib.filter (d: d != "iphone") allDevices; }; + Media = mkFolderOptions "Media" { devices = serverDevices ++ [ "ipad" ]; }; Archive = mkFolderOptions "Archive" {}; - Consume = mkFolderOptions "Consume" {}; - DCIM = mkFolderOptions "DCIM" { devices = serverDevices; }; }; enableGui = lib.mkOption { type = lib.types.bool;