121 lines
3.1 KiB
Bash
Executable File
121 lines
3.1 KiB
Bash
Executable File
#!/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"
|