diff --git a/kubernetes/apps/default/homelab/ks.yaml b/kubernetes/apps/default/homelab/ks.yaml index 629bbeeba..8331b68db 100644 --- a/kubernetes/apps/default/homelab/ks.yaml +++ b/kubernetes/apps/default/homelab/ks.yaml @@ -76,3 +76,27 @@ spec: postBuild: substitute: APP: *app +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/fluxcd-community/flux2-schemas/main/kustomization-kustomize-v1.json +apiVersion: kustomize.toolkit.fluxcd.io/v1 +kind: Kustomization +metadata: + name: &app photo-sort + namespace: flux-system +spec: + targetNamespace: default + commonMetadata: + labels: + app.kubernetes.io/name: *app + path: ./kubernetes/apps/default/homelab/truenas/photo-sort + prune: true + sourceRef: + kind: GitRepository + name: home-ops-kubernetes + wait: false + interval: 30m + retryInterval: 1m + timeout: 5m + postBuild: + substitute: + APP: *app diff --git a/kubernetes/apps/default/homelab/truenas/kustomization.yaml b/kubernetes/apps/default/homelab/truenas/kustomization.yaml index 3cf062b74..b0648bed8 100644 --- a/kubernetes/apps/default/homelab/truenas/kustomization.yaml +++ b/kubernetes/apps/default/homelab/truenas/kustomization.yaml @@ -8,3 +8,4 @@ resources: - ./certs-deploy - ./externalsecret.yaml - ./pgdump + - ./photo-sort diff --git a/kubernetes/apps/default/homelab/truenas/photo-sort/helmrelease.yaml b/kubernetes/apps/default/homelab/truenas/photo-sort/helmrelease.yaml new file mode 100644 index 000000000..66737ac33 --- /dev/null +++ b/kubernetes/apps/default/homelab/truenas/photo-sort/helmrelease.yaml @@ -0,0 +1,71 @@ +--- +# yaml-language-server: $schema=https://kubernetes-schemas.pages.dev/helm.toolkit.fluxcd.io/helmrelease_v2beta2.json +apiVersion: helm.toolkit.fluxcd.io/v2beta2 +kind: HelmRelease +metadata: + name: homelab-truenas-photo-sort + namespace: default +spec: + interval: 30m + chart: + spec: + chart: app-template + version: 2.5.0 + sourceRef: + kind: HelmRepository + name: bjw-s + namespace: flux-system + maxHistory: 2 + install: + createNamespace: true + remediation: + retries: 3 + upgrade: + cleanupOnFail: true + remediation: + retries: 3 + uninstall: + keepHistory: false + values: + controllers: + main: + type: cronjob + cronjob: + concurrencyPolicy: Forbid + schedule: "23 */3 * * *" + containers: + main: + image: + repository: ghcr.io/auricom/kubectl + tag: 1.29.1@sha256:f0b75eedfe63bcbe232b632238b69fed63ef7f886f229027ace69c19c4f77f5f + command: + - "/bin/bash" + - "-c" + - | + #!/bin/bash + + set -o errexit + set -o nounset + + /app/sort.sh + env: + SORT_SOURCE_DIR: /mnt/storage/photo/mobile + SORT_DEST_DIR: /mnt/storage/photo + service: + main: + enabled: false + persistence: + scripts: + type: configMap + name: homelab-truenas-photo-sort-configmap + defaultMode: 0775 + globalMounts: + - path: /app/sort.sh + subPath: sort.sh + readOnly: true + photo: + type: nfs + path: /mnt/storage/photo + server: 192.168.9.10 + globalMounts: + - path: /mnt/storage/photo diff --git a/kubernetes/apps/default/homelab/truenas/photo-sort/kustomization.yaml b/kubernetes/apps/default/homelab/truenas/photo-sort/kustomization.yaml new file mode 100644 index 000000000..aefef17d4 --- /dev/null +++ b/kubernetes/apps/default/homelab/truenas/photo-sort/kustomization.yaml @@ -0,0 +1,15 @@ +--- +# yaml-language-server: $schema=https://raw.githubusercontent.com/SchemaStore/schemastore/master/src/schemas/json/kustomization.json +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +namespace: default +resources: + - ./helmrelease.yaml +configMapGenerator: + - name: homelab-truenas-photo-sort-configmap + files: + - ./scripts/sort.sh +generatorOptions: + disableNameSuffixHash: true + annotations: + kustomize.toolkit.fluxcd.io/substitute: disabled diff --git a/kubernetes/apps/default/homelab/truenas/photo-sort/scripts/sort.sh b/kubernetes/apps/default/homelab/truenas/photo-sort/scripts/sort.sh new file mode 100755 index 000000000..f76c4df36 --- /dev/null +++ b/kubernetes/apps/default/homelab/truenas/photo-sort/scripts/sort.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +# set -x + +# Check if necessary environment variables are set +if [ -z "$SORT_SOURCE_DIR" ] || [ -z "$SORT_DEST_DIR" ]; then + echo "SORT_SOURCE_DIR and SORT_DEST_DIR environment variables must be set." + exit 1 +fi + +grep -q ID_LIKE=debian /etc/os-release + +# Function to log messages to stdout +log_message() { + echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" +} + +# Function to cleanup orphaned symlinks +cleanup_orphans() { + log_message "Cleaning up orphaned symlinks." + + # Use fd to find all broken symlinks in SORT_DEST_DIR + fd --follow --type symlink '' "$SORT_DEST_DIR" | while IFS= read -r symlink; do + # Check if the symlink is broken + if [ ! -e "$symlink" ]; then + echo "Removing broken symlink newer than 6 months: $symlink" + rm "$symlink" # Remove the broken symlink + log_message "Removed symlink $symlink." + fi + done +} + +# Function to process files +process_file() { + local file="$1" + + # Check if "DCIM" is in the file's full path + if [[ "$file" == *"/Camera/"* ]]; then + log_message "Processing file: $file" + + # Extract the EXIF creation date using exiftool + local exif_date=$(exiftool -d "%Y-%m-%d" -CreateDate -S -s "$file") + + if [ -z "$exif_date" ]; then + log_message "EXIF data not found for $file" + return # Skip files without EXIF data + fi + + # Parse the year, month, and day from the EXIF date + local year=$(echo "$exif_date" | cut -d "-" -f 1) + local month=$(echo "$exif_date" | cut -d "-" -f 2) + local day=$(echo "$exif_date" | cut -d "-" -f 3) + + # Construct the destination directory path based on the EXIF date + local dest_path="$SORT_DEST_DIR/$year/${year}-${month}/${year}-${month}-${day}" + + # Create the destination directory if it doesn't exist + mkdir -p "$dest_path" + + # Extract the device name (subfolder name in SORT_SOURCE_DIR) + local device_name=$(basename "$(dirname "$(dirname "$file")")") + + # Calculate the relative path from the destination directory back to the original file + local relative_path=$(realpath --relative-to="$dest_path" "$file") + + # Create a symlink for the file in the destination directory, prefixed with the device name + local symlink_name="${device_name}_$(basename "$file")" + local symlink_path="$dest_path/$symlink_name" + + # Check if the symlink already exists to avoid creating duplicates + if [ ! -L "$symlink_path" ]; then # -L tests if the file is a symlink + ln -s "$relative_path" "$symlink_path" + log_message "Processed and linked: $file -> $symlink_path" + else + log_message "Skipping symlink creation; already exists: $symlink_path" + fi + else + log_message "Skipping file (not in Camera directory): $file" + fi +} + + +export -f process_file log_message +export SORT_SOURCE_DIR SORT_DEST_DIR + +# Start processing +log_message "Starting to process files." + +cd $SORT_SOURCE_DIR + +# Use fd to find image files and process them +fd --type file --changed-within 15days --exec bash -c 'process_file "$@"' bash {} + +cleanup_orphans + +log_message "Processing complete."