{ pkgs }: pkgs.writeShellScriptBin "filebot-process" '' #!/usr/bin/env bash set -euo pipefail # FileBot AMC script for automated media organization # Called by PyLoad's package_extracted hook with parameters: # $1 = package_id # $2 = package_name # $3 = download_folder (actual path to extracted files) # $4 = password (optional) PACKAGE_ID="''${1:-}" PACKAGE_NAME="''${2:-unknown}" DOWNLOAD_DIR="''${3:-/var/lib/downloads}" PASSWORD="''${4:-}" OUTPUT_DIR="/var/lib/multimedia" LOG_FILE="/var/lib/pyload/filebot-amc.log" EXCLUDE_LIST="/var/lib/pyload/filebot-exclude-list.txt" PASSWORD_FILE="/var/lib/pyload/extraction-passwords.txt" # Ensure FileBot data directory exists mkdir -p /var/lib/pyload/.local/share/filebot/data mkdir -p "$(dirname "$LOG_FILE")" touch "$EXCLUDE_LIST" # Install FileBot license if not already installed if [ ! -f /var/lib/pyload/.local/share/filebot/data/.license ]; then echo "$(date): Installing FileBot license..." >> "$LOG_FILE" ${pkgs.filebot}/bin/filebot --license /var/lib/pyload/filebot-license.psm || true fi echo "===========================================" >> "$LOG_FILE" echo "$(date): PyLoad package hook triggered" >> "$LOG_FILE" echo "Package ID: $PACKAGE_ID" >> "$LOG_FILE" echo "Package Name: $PACKAGE_NAME" >> "$LOG_FILE" echo "Download Directory: $DOWNLOAD_DIR" >> "$LOG_FILE" echo "===========================================" >> "$LOG_FILE" # Check if download directory exists if [ ! -d "$DOWNLOAD_DIR" ]; then echo "$(date): Download directory does not exist: $DOWNLOAD_DIR" >> "$LOG_FILE" exit 0 fi # --- Archive Extraction --- # Try extraction with passwords, then without try_extract() { local archive="$1" local outdir outdir="$(dirname "$archive")" # Try each password from file if [ -f "$PASSWORD_FILE" ]; then while IFS= read -r pass || [ -n "$pass" ]; do [ -z "$pass" ] && continue case "$archive" in *.rar) ${pkgs.unrar}/bin/unrar x -p"$pass" -o+ "$archive" "$outdir/" >/dev/null 2>&1 && return 0 ;; *.7z) ${pkgs.p7zip}/bin/7z x -p"$pass" -aoa -o"$outdir" "$archive" >/dev/null 2>&1 && return 0 ;; *.zip) ${pkgs.p7zip}/bin/7z x -p"$pass" -aoa -o"$outdir" "$archive" >/dev/null 2>&1 && return 0 ;; esac done < "$PASSWORD_FILE" fi # Try without password case "$archive" in *.rar) ${pkgs.unrar}/bin/unrar x -o+ "$archive" "$outdir/" >/dev/null 2>&1 && return 0 ;; *.7z) ${pkgs.p7zip}/bin/7z x -aoa -o"$outdir" "$archive" >/dev/null 2>&1 && return 0 ;; *.zip) ${pkgs.p7zip}/bin/7z x -aoa -o"$outdir" "$archive" >/dev/null 2>&1 && return 0 ;; esac return 1 } # Delete all parts of a split RAR archive delete_rar_parts() { local first_part="$1" local base dir dir="$(dirname "$first_part")" # Extract base name: "foo.part1.rar" -> "foo", "foo.part01.rar" -> "foo" base="$(basename "$first_part" | ${pkgs.gnused}/bin/sed -E 's/\.part[0-9]+\.rar$//')" # Delete all parts matching the pattern find "$dir" -maxdepth 1 -type f -iname "''${base}.part*.rar" -delete echo "$(date): Deleted all parts: ''${base}.part*.rar" >> "$LOG_FILE" } # Extract archives in directory extract_archives() { local dir="$1" local extracted=0 # 1. Handle split RAR archives (*.part1.rar or *.part01.rar - first part only) while IFS= read -r -d "" archive; do echo "$(date): Extracting split RAR: $archive" >> "$LOG_FILE" if try_extract "$archive"; then echo "$(date): Extraction successful" >> "$LOG_FILE" delete_rar_parts "$archive" extracted=1 else echo "$(date): Extraction FAILED: $archive" >> "$LOG_FILE" fi done < <(find "$dir" -type f \( -iname "*.part1.rar" -o -iname "*.part01.rar" \) -print0 2>/dev/null) # 2. Handle single RAR files (not part of split archive) while IFS= read -r -d "" archive; do echo "$(date): Extracting RAR: $archive" >> "$LOG_FILE" if try_extract "$archive"; then echo "$(date): Extraction successful, deleting: $archive" >> "$LOG_FILE" rm -f "$archive" extracted=1 else echo "$(date): Extraction FAILED: $archive" >> "$LOG_FILE" fi done < <(find "$dir" -type f -iname "*.rar" ! -iname "*.part*.rar" -print0 2>/dev/null) # 3. Handle 7z and zip archives while IFS= read -r -d "" archive; do echo "$(date): Extracting: $archive" >> "$LOG_FILE" if try_extract "$archive"; then echo "$(date): Extraction successful, deleting: $archive" >> "$LOG_FILE" rm -f "$archive" extracted=1 else echo "$(date): Extraction FAILED: $archive" >> "$LOG_FILE" fi done < <(find "$dir" -type f \( -iname "*.7z" -o -iname "*.zip" \) -print0 2>/dev/null) [ "$extracted" -eq 1 ] && return 0 || return 1 } # Run extraction (loop to handle nested archives) echo "$(date): Starting archive extraction..." >> "$LOG_FILE" for i in 1 2 3; do extract_archives "$DOWNLOAD_DIR" || break done echo "$(date): Archive extraction complete" >> "$LOG_FILE" # --- Media Processing --- # Check if there are any video/media files to process if ! find "$DOWNLOAD_DIR" -type f \( -iname "*.mkv" -o -iname "*.mp4" -o -iname "*.avi" -o -iname "*.m4v" -o -iname "*.mov" \) -print -quit | grep -q .; then echo "$(date): No media files found in: $DOWNLOAD_DIR" >> "$LOG_FILE" echo "$(date): Skipping FileBot processing" >> "$LOG_FILE" exit 0 fi echo "$(date): Starting FileBot processing" >> "$LOG_FILE" # Run FileBot AMC script set +e # Temporarily disable exit on error to capture exit code ${pkgs.filebot}/bin/filebot \ -script fn:amc \ --output "$OUTPUT_DIR" \ --action move \ --conflict auto \ -non-strict \ --log-file "$LOG_FILE" \ --def \ excludeList="$EXCLUDE_LIST" \ movieFormat="$OUTPUT_DIR/movies/{n} ({y})/{n} ({y}) - {vf}" \ seriesFormat="$OUTPUT_DIR/tv-shows/{n}/Season {s.pad(2)}/{n} - {s00e00} - {t}" \ ut_dir="$DOWNLOAD_DIR" \ ut_kind=multi \ clean=y \ skipExtract=y FILEBOT_EXIT_CODE=$? set -e # Re-enable exit on error if [ $FILEBOT_EXIT_CODE -ne 0 ]; then echo "$(date): FileBot processing failed with exit code $FILEBOT_EXIT_CODE" >> "$LOG_FILE" exit 0 # Don't fail the hook even if FileBot fails fi echo "$(date): FileBot processing completed successfully" >> "$LOG_FILE" # Clean up any remaining empty directories find "$DOWNLOAD_DIR" -type d -empty -delete 2>/dev/null || true echo "$(date): All processing completed" >> "$LOG_FILE" exit 0 ''