From ba60b3f65dea158c6fc0f9b5f7ac24c79a503fff Mon Sep 17 00:00:00 2001 From: Yan Lin Date: Fri, 5 Dec 2025 18:15:09 +0100 Subject: [PATCH] add camera copy function --- config/immich.nix | 2 +- modules/rsync.nix | 151 +++++++++++++++++++++++++++++----------------- 2 files changed, 96 insertions(+), 57 deletions(-) diff --git a/config/immich.nix b/config/immich.nix index 0683a02..20aa6fc 100644 --- a/config/immich.nix +++ b/config/immich.nix @@ -76,7 +76,7 @@ cronExpression = "0 19 * * *"; enabled = true; }; - watch.enabled = false; + watch.enabled = true; }; logging = { diff --git a/modules/rsync.nix b/modules/rsync.nix index 18481ff..011a1ab 100644 --- a/modules/rsync.nix +++ b/modules/rsync.nix @@ -2,7 +2,7 @@ { # Install rsync package - home.packages = [ pkgs.rsync ]; + home.packages = with pkgs; [ rsync exiftool ]; # Rsync exclude patterns for common files and directories home.file.".rsync-exclude".text = '' ''; @@ -37,64 +37,103 @@ --dry-run # Remove this line when you're ready to run for real ''; - # Create a convenient rsync wrapper script - home.file.".local/bin/rsync-backup".text = '' - # Convenient rsync backup wrapper - # Usage: rsync-backup source/ destination/ - # - - if [ $# -ne 2 ]; then - echo "Usage: $0 " - echo "Example: $0 ~/Documents/ /backup/documents/" - exit 1 - fi - - SOURCE="$1" - DEST="$2" - - # Ensure source ends with slash for proper rsync behavior - if [[ "$SOURCE" != */ ]]; then + programs.zsh.initContent = '' + function rsync-backup() { + if [[ $# -ne 2 ]]; then + echo "Usage: rsync-backup " + echo "Example: rsync-backup ~/Documents/ /backup/documents/" + return 1 + fi + + local SOURCE="$1" + local DEST="$2" + + if [[ "$SOURCE" != */ ]]; then SOURCE="$SOURCE/" - fi - - echo "=== Rsync Backup ===" - echo "Source: $SOURCE" - echo "Destination: $DEST" - echo "===================" - - # Use the configuration file options - rsync $(cat ~/.rsync-backup.conf | grep -v '^#' | grep -v '^$' | tr '\n' ' ') "$SOURCE" "$DEST" - - if [ $? -eq 0 ]; then + fi + + echo "=== Rsync Backup ===" + echo "Source: $SOURCE" + echo "Destination: $DEST" + echo "===================" + + rsync $(cat ~/.rsync-backup.conf | grep -v '^#' | grep -v '^$' | tr '\n' ' ') "$SOURCE" "$DEST" + + if [[ $? -eq 0 ]]; then echo "Backup completed successfully!" - else + else echo "Backup failed with exit code $?" - exit 1 - fi + return 1 + fi + } + + function camera-copy() { + if [[ $# -ne 2 ]]; then + echo "Usage: camera-copy " + echo "" + echo "Copy video files organized by date (YYYY-MM-DD/filename)" + echo "" + echo "Examples:" + echo " camera-copy /media/sdcard/DCIM ~/Videos/imports" + echo " camera-copy /Volumes/CAMERA/DCIM user@nas:/backup/camera" + return 1 + fi + + local SOURCE="$1" + local DEST="$2" + + if [[ ! -d "$SOURCE" ]]; then + echo "Error: Source directory does not exist: $SOURCE" + return 1 + fi + + _get_video_date() { + local file="$1" + local raw_date + + raw_date=$(${pkgs.exiftool}/bin/exiftool -s3 -d '%Y-%m-%d' \ + -DateTimeOriginal -CreateDate -MediaCreateDate "$file" 2>/dev/null | head -1) + + if [[ -n "$raw_date" && "$raw_date" != "0000-00-00" ]]; then + echo "$raw_date" + else + local mtime + mtime=$(${pkgs.coreutils}/bin/stat -c '%Y' "$file" 2>/dev/null) + ${pkgs.coreutils}/bin/date -d "@$mtime" +%Y-%m-%d + fi + } + + local copied=0 + local failed=0 + + while IFS= read -r -d "" file; do + local date_dir=$(_get_video_date "$file") + local year=''${date_dir:0:4} + local filename=$(basename "$file") + + echo "[$date_dir] $filename" + + if ${pkgs.rsync}/bin/rsync -a --mkpath --progress --partial --ignore-existing \ + "$file" "$DEST/$year/$date_dir/$filename"; then + ((copied++)) || true + else + echo " Failed to copy: $file" + ((failed++)) || true + fi + done < <(find "$SOURCE" -type f \( -iname "*.mp4" -o -iname "*.mov" -o -iname "*.mts" -o -iname "*.m2ts" -o -iname "*.avi" \) -print0) + + echo "" + echo "=== Summary ===" + echo "Copied: $copied" + echo "Failed: $failed" + } ''; - # Make the backup script executable - home.file.".local/bin/rsync-backup".executable = true; - - # Optional: Add rsync aliases to shell configuration - # This can be integrated with your existing zsh module - home.file.".rsync-aliases".text = '' - # Rsync aliases for common operations - # Source this file in your shell configuration - - # Quick backup with progress - alias rsync-quick='rsync -avh --progress --exclude-from=~/.rsync-exclude' - - # Dry run backup (safe testing) - alias rsync-dry='rsync -avh --progress --exclude-from=~/.rsync-exclude --dry-run' - - # Full backup with all safety options - alias rsync-full='rsync-backup' - - # Sync directories (no delete) - alias rsync-sync='rsync -avh --progress --exclude-from=~/.rsync-exclude' - - # Mirror directories (with delete) - alias rsync-mirror='rsync -avh --progress --exclude-from=~/.rsync-exclude --delete' - ''; + programs.zsh.shellAliases = { + rsync-quick = "rsync -avh --progress --exclude-from=~/.rsync-exclude"; + rsync-dry = "rsync -avh --progress --exclude-from=~/.rsync-exclude --dry-run"; + rsync-full = "rsync-backup"; + rsync-sync = "rsync -avh --progress --exclude-from=~/.rsync-exclude"; + rsync-mirror = "rsync -avh --progress --exclude-from=~/.rsync-exclude --delete"; + }; }