From b855d75b8adccf0383ddddaa1de3b6f387af1dd2 Mon Sep 17 00:00:00 2001 From: Yan Lin Date: Mon, 26 Jan 2026 11:38:57 +0100 Subject: [PATCH] rearrange media-process module --- hosts/darwin/home-default.nix | 2 +- hosts/nixos/home-default.nix | 2 +- modules/media-process.nix | 136 ++++++++++++++++++++++++++++++++++ modules/rsync.nix | 64 ---------------- modules/transcode.nix | 55 -------------- 5 files changed, 138 insertions(+), 121 deletions(-) create mode 100644 modules/media-process.nix delete mode 100644 modules/transcode.nix diff --git a/hosts/darwin/home-default.nix b/hosts/darwin/home-default.nix index 2d72d1e..b79fe62 100644 --- a/hosts/darwin/home-default.nix +++ b/hosts/darwin/home-default.nix @@ -17,7 +17,7 @@ ../../modules/claude-code.nix ../../modules/gemini-cli.nix ../../modules/tex.nix - ../../modules/transcode.nix + ../../modules/media-process.nix ../../modules/fonts.nix ../../modules/aerospace.nix ../../modules/env.nix diff --git a/hosts/nixos/home-default.nix b/hosts/nixos/home-default.nix index 4c2924d..336e276 100644 --- a/hosts/nixos/home-default.nix +++ b/hosts/nixos/home-default.nix @@ -13,7 +13,7 @@ ../../modules/btop.nix ../../modules/claude-code.nix ../../modules/gemini-cli.nix - ../../modules/transcode.nix + ../../modules/media-process.nix ../../modules/fonts.nix ../../modules/env.nix ]; diff --git a/modules/media-process.nix b/modules/media-process.nix new file mode 100644 index 0000000..0125ae3 --- /dev/null +++ b/modules/media-process.nix @@ -0,0 +1,136 @@ +{ config, pkgs, lib, ... }: + +{ + home.packages = with pkgs; [ + ffmpeg + shntool + cuetools + flac + ]; + + programs.zsh.initContent = '' + function audio2aac() { + local dir="''${1:-.}" + find "$dir" \( -name '*.flac' -o -name '*.mp3' -o -name '*.wav' -o -name '*.ogg' -o -name '*.wma' -o -name '*.aiff' \) -type f -print0 | xargs -0 -P4 -n1 sh -c ' + f="$1" + outfile="./transcode/''${f%.*}.m4a" + mkdir -p "$(dirname "$outfile")" + ffmpeg -i "$f" -vn -c:a aac -b:a 256k -movflags +faststart "$outfile" + ' _ + } + + function video2av1() { + local height="''${1:-720}" + local dir="''${2:-.}" + for f in "$dir"/**/*.(mp4|mkv|avi); do + if [[ -f "$f" ]]; then + local outfile="./transcode/''${f%.*}.mkv" + mkdir -p "$(dirname "$outfile")" + ffmpeg -i "$f" \ + -c:v libsvtav1 -crf 30 -preset 6 \ + -vf "scale=-2:'min($height,ih)'" \ + -c:a copy \ + "$outfile" + fi + done + } + + function cuesplit() { + local audio="$1" + local cue="''${2:-''${audio%.*}.cue}" + if [[ ! -f "$audio" ]]; then + echo "Audio file not found: $audio" >&2 + return 1 + fi + if [[ ! -f "$cue" ]]; then + echo "Cue file not found: $cue" >&2 + return 1 + fi + local ext="''${audio##*.}" + local fmt="''${ext:l}" + mkdir -p ./tracks + shnsplit -f "$cue" -t "%n - %t" -o "$fmt" -d ./tracks "$audio" + } + + function camera-copy() { + local delete_source=0 + if [[ "$1" == "-d" || "$1" == "--delete" ]]; then + delete_source=1 + shift + fi + + if [[ $# -ne 2 ]]; then + echo "Usage: camera-copy [-d|--delete] " + echo "" + echo "Copy photo and video files organized by date (YYYY-MM-DD/filename)" + echo "" + echo "Options:" + echo " -d, --delete Delete source files after successful copy" + echo "" + echo "Examples:" + echo " camera-copy /media/sdcard/DCIM ~/Videos/imports" + echo " camera-copy -d /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_media_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 filename=$(basename "$file") + + [[ "$filename" == .* ]] && continue + + local date_dir=$(_get_media_date "$file") + local year=''${date_dir:0:4} + + echo "[$date_dir] $filename" + + local rsync_opts=(-a --mkpath --progress --partial --ignore-existing) + [[ $delete_source -eq 1 ]] && rsync_opts+=(--remove-source-files) + + if ${pkgs.rsync}/bin/rsync "''${rsync_opts[@]}" "$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" \ + -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) + + echo "" + echo "=== Summary ===" + echo "Copied: $copied" + echo "Failed: $failed" + [[ $delete_source -eq 1 ]] && echo "(source files removed)" + } + + ''; +} diff --git a/modules/rsync.nix b/modules/rsync.nix index d4d71c4..9b10cc1 100644 --- a/modules/rsync.nix +++ b/modules/rsync.nix @@ -33,70 +33,6 @@ 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 filename=$(basename "$file") - - [[ "$filename" == .* ]] && continue - - local date_dir=$(_get_video_date "$file") - local year=''${date_dir:0:4} - - 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" - } ''; programs.zsh.shellAliases = { diff --git a/modules/transcode.nix b/modules/transcode.nix deleted file mode 100644 index 74dfb7e..0000000 --- a/modules/transcode.nix +++ /dev/null @@ -1,55 +0,0 @@ -{ config, pkgs, lib, ... }: - -{ - home.packages = with pkgs; [ - ffmpeg - shntool - cuetools - flac - ]; - - programs.zsh.initContent = '' - function audio2aac() { - local dir="''${1:-.}" - find "$dir" \( -name '*.flac' -o -name '*.mp3' -o -name '*.wav' -o -name '*.ogg' -o -name '*.wma' -o -name '*.aiff' \) -type f -print0 | xargs -0 -P4 -n1 sh -c ' - f="$1" - outfile="./transcode/''${f%.*}.m4a" - mkdir -p "$(dirname "$outfile")" - ffmpeg -i "$f" -vn -c:a aac -b:a 256k -movflags +faststart "$outfile" - ' _ - } - - function video2av1() { - local height="''${1:-720}" - local dir="''${2:-.}" - for f in "$dir"/**/*.(mp4|mkv|avi); do - if [[ -f "$f" ]]; then - local outfile="./transcode/''${f%.*}.mkv" - mkdir -p "$(dirname "$outfile")" - ffmpeg -i "$f" \ - -c:v libsvtav1 -crf 30 -preset 6 \ - -vf "scale=-2:'min($height,ih)'" \ - -c:a copy \ - "$outfile" - fi - done - } - - function cuesplit() { - local audio="$1" - local cue="''${2:-''${audio%.*}.cue}" - if [[ ! -f "$audio" ]]; then - echo "Audio file not found: $audio" >&2 - return 1 - fi - if [[ ! -f "$cue" ]]; then - echo "Cue file not found: $cue" >&2 - return 1 - fi - local ext="''${audio##*.}" - local fmt="''${ext:l}" - mkdir -p ./tracks - shnsplit -f "$cue" -t "%n - %t" -o "$fmt" -d ./tracks "$audio" - } - ''; -}