Skip to content

Instantly share code, notes, and snippets.

@devome
Last active April 6, 2024 09:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save devome/59ef47caf10e7a58a0bcbe315f2bed1a to your computer and use it in GitHub Desktop.
Save devome/59ef47caf10e7a58a0bcbe315f2bed1a to your computer and use it in GitHub Desktop.
pho.sh
#!/usr/bin/env bash
## 运行本脚本需要事先安装好以下包:bc exiftool ffmpeg findutils grep jq mediainfo perl
## 对于三种途径都获取不到时间的话,会将这类文件路径写入源文件夹下的 "不能处理的文件清单.txt"
## 仅处理源文件夹下的mp4和jpg格式的文件,将其复制到Pho下面能识别的目录结构,源文件夹下的文件不会被删除。
## 源文件夹,绝对路径
source_dir=""
## 目标文件夹,绝对路径
target_dir=""
## 缩略图文件夹,默认在目标文件夹下面,即使要在其他地方生成,也要自己软连接到目标文件夹下,并且能够在webdav中正常识别
thumbnail_dir="$target_dir/.thumbnail"
## 依次按照什么顺序获取照片/视频的拍摄时间,如果从第一项获取不到就尝试获取第二项,如果第二项仍然获取不到再获取第三项。可以调整这三项的顺序。
## 一般来说,file_modify_time 是肯定会存在的,而其他两项不一定会存在,所以建议将 file_modify_time 作为最后的兜底。
## exif_time:是exif信息中的拍摄日期,可以在Windows中照片上鼠标 右键->属性->详细信息 中查看到
## filename_time:是照片/视频文件名中的时间信息,只要含有年月日时分秒信息即可
## file_modify_time:照片/视频文件的修改日期,可以在Windows中照片上鼠标 右键->属性->详细信息 中查看到
method_to_get_time=( exif_time filename_time file_modify_time )
######################## 分隔线 ########################
## $1: 文件完整路径
exif_time() {
local file="$1"
local exiftime=$(exiftool "$file" | grep -P '^Create Date' | awk '{print $4$5}' | perl -pe "s|:||g" | head -1 | cut -c1-14)
if [[ -n $exiftime && ${#exiftime} == 14 && $exiftime != 00000000000000 ]]; then
echo "$exiftime"
fi
}
## $1:文件完整路径
filename_time() {
local file="$1"
local basename=$(basename "$file")
local filenametime=$(echo "$basename" | grep -oP "20[0-2]\d(_|-|\.)?(0[1-9]|1[0-2])(_|-|\.)?(0[1-9]|[12]\d|3[01])(_|-|\.)?([01]\d|2[0-3])(_|-|\.)?[0-5]\d(_|-|\.)?[0-5]\d" | perl -pe '{s|_||g; s|-||g; s|\.||g}')
if [[ -n $filenametime && ${#filenametime} == 14 ]]; then
echo "$filenametime"
fi
}
## $1: 文件完整路径
file_modify_time() {
local file="$1"
local filemodifytime=$(date +'%Y%m%d%H%M%S' -d @$(stat -c "%Y" "$file"))
if [[ -n $filemodifytime && ${#filemodifytime} == 14 ]]; then
echo "$filemodifytime"
fi
}
if [[ -f "$source_dir/不能处理的文件清单.txt" ]]; then
rm -rf "$source_dir/不能处理的文件清单.txt"
fi
find "$source_dir" -type f \( -iname "*.jpg" -o -iname "*.mp4" \) | sort | while read file; do
targettime=""
basename=$(basename "$file")
dirname=$(dirname "$file")
## 获取时间
for ((i=0; i<${#method_to_get_time[@]}; i++)); do
targettime=$(${method_to_get_time[i]} "$file")
if [[ -n "$targettime" ]]; then
break
fi
done
if [[ -n $targettime ]]; then
## 获取年、月、日、时、分、秒
year=$(echo "$targettime" | cut -c1-4)
month=$(echo "$targettime" | cut -c5-6)
day=$(echo "$targettime" | cut -c7-8)
hour=$(echo "$targettime" | cut -c9-10)
minute=$(echo "$targettime" | cut -c11-12)
second=$(echo "$targettime" | cut -c13-14)
## 创建对应的文件夹
dirname_new="${target_dir}/${year}/${month}/${day}"
dirname_new_thumbnail="${thumbnail_dir}/${year}/${month}/${day}"
if [[ ! -d "$dirname_new" ]]; then
mkdir -p "$dirname_new"
fi
if [[ ! -d "$dirname_new_thumbnail" ]]; then
mkdir -p "$dirname_new_thumbnail"
fi
## 复制文件
# touch -d "${year}-${month}-${day}T${hour}:${minute}:${second}" "$file" # 这一句可以按照“拍摄时间”(或者文件名中的时间)重设文件的“修改时间”,如有需要,可解除注释
cp -afv "$file" "${dirname_new}/${basename}"
## 生成缩略图
case $file in
*.jpg | *.JPG) minpx=200;;
*.mp4 | *.MP4) minpx=800;;
esac
info=$(mediainfo --Output=JSON "$file" | jq .media.track[])
width=$(echo $info | jq -r .Width | grep -v null | head -1)
height=$(echo $info | jq -r .Height | grep -v null | head -1)
if [[ $width -gt $height ]]; then
width_n=$(printf "%.0f\n" $(echo "scale=2; $width * $minpx / $height" | bc))
height_n=$minpx
if [[ $height_n -ge $height ]]; then
height_n=$height
width_n=$width
fi
else
width_n=$minpx
height_n=$(printf "%.0f\n" $(echo "scale=2; $height * $minpx / $width" | bc))
if [[ $width_n -ge $width ]]; then
height_n=$height
width_n=$width
fi
fi
echo "生成缩略图: $dirname_new_thumbnail/${basename}"
case $file in
*.jpg | *.JPG)
ffmpeg -loglevel quiet -hide_banner -nostdin -stats -y -i "$file" -vf scale=${width_n}x${height_n} "$dirname_new_thumbnail/${basename}"
;;
*.mp4 | *.MP4)
ffmpeg -loglevel quiet -hide_banner -nostdin -stats -y -i "$file" -vf "select=eq(n\,0)" -vframes 1 /tmp/tmp_pho.jpg
ffmpeg -loglevel quiet -hide_banner -nostdin -stats -y -i "/tmp/tmp_pho.jpg" -vf scale=${width_n}x${height_n} "$dirname_new_thumbnail/${basename%.*}.jpg"
mv "$dirname_new_thumbnail/${basename%.*}.jpg" "$dirname_new_thumbnail/${basename}"
;;
esac
echo
## 如果三种途径都获取不到时间,则记录下来
else
echo -e "无法获取到时间:$file\n"
echo "$file" >> "$source_dir/不能处理的文件清单.txt"
fi
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment