#!/bin/bash SCENEDETECT="$HOME/.venvs/scenedetect-env/bin/scenedetect" PROCESSED_LOG="$HOME/.cache/processed_videos.log" set -e # Ensure log file exists mkdir -p "$(dirname "$PROCESSED_LOG")" touch "$PROCESSED_LOG" # Find all video files (case-insensitive match) find . -type f \( -iname "*.mp4" -o -iname "*.mkv" -o -iname "*.avi" \) -print0 | while IFS= read -r -d '' video; do echo "🔍 Processing: $video" # Skip if already processed if grep -Fxq "$video" "$PROCESSED_LOG"; then echo "⚠️ Already processed, skipping: $video" continue fi # Get duration in seconds duration=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$video") duration=${duration%.*} start=180 end=$((duration - 180)) [[ "$end" -le "$start" ]] && echo "❌ Skipping (too short): $video" && continue length=$((end - start)) base="${video%.*}" trimmed="${base}_trimmed_tmp.mp4" workdir="${base}_thumb_tmp" mkdir -p "$workdir" # Suppress ffmpeg output ffmpeg -hide_banner -loglevel error -y -ss "$start" -i "$video" -t "$length" -c copy "$trimmed" # Scene detection "$SCENEDETECT" -i "$trimmed" -o "$workdir" detect-content save-images # Rank images by sharpness best_image="" best_score=0 for img in "$workdir"/*.jpg; do score=$(identify -format "%[standard-deviation]" "$img" 2>/dev/null | cut -d',' -f1) score_float=$(printf "%.6f\n" "$score") if (( $(echo "$score_float > $best_score" | bc -l) )); then best_score=$score_float best_image="$img" fi done thumb="${base}-thumb.jpg" cp "$best_image" "$thumb" echo "✅ Thumbnail saved: $thumb" echo "$video" >> "$PROCESSED_LOG" rm -rf "$workdir" "$trimmed" done ########## Using full video duration ########## # #!/bin/bash # SCENEDETECT="$HOME/.venvs/scenedetect-env/bin/scenedetect" # PROCESSED_LOG="$HOME/.cache/processed_videos.log" # set -e # video="$1" # [[ ! -f "$video" ]] && echo "Video not found: $video" && exit 1 # # Ensure log file exists # mkdir -p "$(dirname "$PROCESSED_LOG")" # touch "$PROCESSED_LOG" # # Check if video is already processed # if grep -Fxq "$video" "$PROCESSED_LOG"; then # echo "⚠️ Video already processed: $video" # exit 0 # fi # # Prepare paths # base="${video%.*}" # workdir="${base}_thumb_tmp" # mkdir -p "$workdir" # # Step 1: Scene detection # "$SCENEDETECT" -i "$video" -o "$workdir" detect-content save-images # # Step 2: Rank images by sharpness (standard deviation) # best_image="" # best_score=0 # for img in "$workdir"/*.jpg; do # # Get standard deviation of luminance # score=$(identify -format "%[standard-deviation]" "$img" 2>/dev/null | cut -d',' -f1) # # Compare scores # score_float=$(printf "%.6f\n" "$score") # if (( $(echo "$score_float > $best_score" | bc -l) )); then # best_score=$score_float # best_image="$img" # fi # done # # Step 3: Save best image with Jellyfin naming scheme # thumb="${base}-thumb.jpg" # cp "$best_image" "$thumb" # echo "✅ Thumbnail saved: $thumb" # # Step 4: Mark as processed # echo "$video" >> "$PROCESSED_LOG" # # Step 5: Cleanup # rm -rf "$workdir"