Linux
Unraid
iCloud 媒体文件同步与处理 预计阅读时长 : 13 分钟
整体逻辑
flowchart TB
iCloudpd([iCloudpd 下载文件]) --> HEICCheck{图片格式\n是否为 HEIC} & MOVCheck{视频格式\n是否为 MOV}
HEICCheck -- 是 --> TransferHEIC[使用 iCloudpd 自动转化]
MOVCheck -- 是 --> CronCopy[监测脚本自动复制\n文件到监测文件夹] --> TransferMOV[使用 Handbrake 自动转化] --> CronMove([转移脚本自动转移\n文件原始文件夹])
文件下载
作为尊贵的 2T iCloud 用户,拍起图片和视频来可谓是随心所欲,不过带来的副作用就是甜蜜的烦恼了:筛选图片和视频实在是让人头秃。
使用 iCloudpd ,可以自动把 iCloud 的图片全部下载到本地,并自动将 HEIC 格式的图片转化为 JPG,再配合 Handbrake 自动把 MOV 格式的视频转化为 MP4,再一步进行管理就方便了许多。
boredazfcuk/icloudpd ⧉ 是目前最完善的 icloudpd 的 Docker 版本,从 Unraid 的应用商店里面可以直接安装配置脚本。为了得到最佳的使用体验,还是建议参照以下配置使用 Docker-Compose 创建服务:
version : "3.8"
services :
icloudpd :
image : boredazfcuk/icloudpd
container_name : icloudpd
network_mode : bridge
hostname : Unraid
environment :
- apple_id=xiaobuyao@gmail.com
- authentication_type=2FA
- icloud_china=True #(1)
- auth_china=True
- user_id=1000
- group=users #(2)
- group_id=100
- force_gid=True
- download_path=/home/xxxx/iCloud
- synchronisation_interval=86400
- directory_permissions=750
- file_permissions=640
- folder_structure={:%Y/%m}
- skip_check=True
- convert_heic_to_jpeg=True #(3)
- jpeg_quality=100
- auto_delete=True
- TZ=Asia/Shanghai
volumes :
- /mnt/user/appdata/icloudpd:/config # 配置文件路径
- /mnt/user/Backup/Likai/Photo/iCloud:/home/xxxx/iCloud # 下载文件路径
restart : unless-stopped
icloud_china
参数用于指定是否使用国内的 iCloud 服务,如果使用国内的服务,需要将 auth_china
参数也设置为 True
。
group
参数用于指定下载文件的用户 ID 所在的 Group,如果对应 groupd_id 已经存在,那么需要将 force_gid
参数设置为 True
,以及将 group 设为对应的 group 名称。
convert_heic_to_jpeg
参数用于指定是否将 HEIC 格式的图片转化为 JPG 格式。
根据 Apple 最新安全性规范,icloudpd 强制要求使用 2FA 以及 App-Specific Passwords 进行账号授权。因此,在容器安装完成之后,还需要在 Unraid 的终端中执行以下命令进行初始化:
docker exec -it icloudpd sync-icloud.sh --Initialise
最后,作为防呆设计,还需要在文件存储目录中手动创建一个 .mounted
文件,这样就能启动下载的任务了。
格式转换
简要说明
在使用 iCloudpd 将所有媒体文件下载下来之后,接下去的流程就是将苹果的专用格式转化一份跨平台支持的格式,便于后续的处理流程使用。
对于 HEIC 格式的图片,可以根据上述的配置使用 iCloudpd 在下载的同时完成转化,而MOV 格式的文件转化则需要使用 Handbrake 来进行转化。
它可以自动监控放置到指定文件夹中的文件,将其按照指定的格式转化之后再放入输出文件夹。有了这个基础,我们通过定时脚本自动将 iCloud 中符合条件的 MOV 文件筛选出来,并自动拷贝至监控文件夹就可以完成全自动的转化任务了。
需要特别说明的是,早期的 iCloud 中可能会在不同的月份中出现同名的文件,因此在处理文件的时候,需要使用 日期_文件名
的临时文件名作为唯一标示符,这样可以避免重复文件名的文件在处理时被遗漏。
处理逻辑
flowchart TD
A[监控定时脚本查找\n所有 MOV/mov 结尾的文件] --> B[切分文件路径]
B --> F[临时文件名]
B --> D[后缀名]
B --> E[目录] -----> H
F --> G[检查是否有与临时文件名相同的 MP4/mp4 文件]
G -- 否 --> J[判断 Handbrake 监控目录是否有同名 MOV/mov 文件]
J -- 否 --> K[将文件用临时文件名\n复制至 Handbrake 监控目录] --> L[等待 Handbrake 自动转换格式完毕] & H[将文件相关信息添加\n至待处理文件列表] --> M[等待文件转移定时脚本调用]
Handbrake 配置
为了保证拍摄的视频能有最佳的效果,iPhone 的默认视频格式为 MOV。麻烦的是,这种格式在 Windows 系统以及浏览器上都无法顺畅的预览。因此,为了更好的对视频文件进行管理,可以使用 Handbrake 自动将 MOV 格式的文件转化为 MP4 格式,这样既能保证源文件的高质量,又能便于管理。
Unraid 中可以参照以下的配置,定义好导出目录、显卡支持和 CJK 文本支持,再配合后面的自定义脚本,即可完成全自动化的处理流程。
version : "3"
services :
handbrake :
image : jlesage/handbrake:latest
container_name : handbrake
network_mode : bridge
environment :
- UID=1000
- GID=100
- ENABLE_CJK_FONT=1 # 添加中文支持
- DISPLAY_WIDTH=1280
- DISPLAY_HEIGHT=1240
- TZ=Asia/Shanghai
volumes :
- /mnt/user/appdata/HandBrake:/config:rw # 配置文件路径
- /mnt/user/Download:/storage:ro # 媒体文件路径
- /mnt/user/Video/Watch:/watch:rw # 监控文件路径
- /mnt/user/Video/Output:/output:rw # 输出文件路径
ports :
- 5800:5800 # WebUI 端口
- 5900:5900 # VNC 端口
devices :
- /dev/dri/renderD128:/dev/dri/renderD128 # 配置转码用显卡
restart : unless-stopped
监控脚本
设置好了 Handbrake 的监控文件夹后,只要将媒体文件放入即可以实现自动转换的功能。以下的脚本会使用 Cron 自动定时运行定期检查新下载的文件,然后将符合条件的文件复制到监控文件夹中。
#! /bin/bash
SCRIPT_DIR = $( cd $( dirname ${ BASH_SOURCE [0] } ) ; pwd )
iCloud_PATH = "/mnt/user/Backup/Likai/Photo/iCloud/2023"
MOV_LIST = $( find ${ iCloud_PATH } -iname "*.mov" )
### 清空待处理文件列表 ###
if [ -f ${ SCRIPT_DIR } /mov.list ] ; then
cat /dev/null > ${ SCRIPT_DIR } /mov.list
fi
### 解决文件名中有空格的问题 ###
IFS_BACKUP = $IFS
IFS = $( echo -en "\n\b" )
### 判断视频是否已转换,更新待处理文件列表 ###
for mov_file in $MOV_LIST
do
dir_all = ${ mov_file %/* }
dir_date = $( echo $dir_all | awk -F/ '{print $8"_"$9"_"}' )
file_all = ${ mov_file ##*/ }
file_name = ${ file_all % \. * }
file_ext = ${ file_all ##* \. }
if [ ! -f " ${ dir_all } / ${ file_name } .MP4" ] && [ ! -f " ${ dir_all } / ${ file_name } .mp4" ] ; then
echo -e " ${ file_name } : ${ file_ext } : ${ dir_all # \. } : ${ dir_date }${ file_name } " >> ${ SCRIPT_DIR } /mov.list
let mov_file_number++
fi
done
printf "%s\t总计%4d 个文件有转换需要\n" " $( date +"%Y-%m-%d %H:%M:%S" ) " ${ mov_file_number } | tee -a ${ SCRIPT_DIR } /icloud.log
### 将待处理文件拷贝至 Handbrake 监控文件夹 ###
WATCH_PATH = "/mnt/user/Video/Watch"
for cp_file in $( cat ${ SCRIPT_DIR } /mov.list)
do
file_path = $( echo $cp_file | awk 'BEGIN{FS=":"} {print $3"/"$1"."$2}' )
file_name = $( echo $cp_file | awk 'BEGIN{FS=":"} {print $4"."$2}' )
if [ ! -f ${ WATCH_PATH } /${ file_name } ] ; then
# 使用复制硬链接方式,减少复制占用的空间和时间
cp ${ file_path } ${ WATCH_PATH } /${ file_name }
# 为复制的文件修改权限,使 Handbrake 可以进行处理
chmod a = rw ${ WATCH_PATH } /${ file_name }
let move_num++
fi
done
IFS = $IFS_BACKUP
printf "%s\t复制%4d 个文件到监控目录\n" " $( date +"%Y-%m-%d %H:%M:%S" ) " ${ move_num :- 0 } | tee -a ${ SCRIPT_DIR } /icloud.log
文件转移
简要说明
Handbrake 将文件转化完之后,接下去的流程就是将转化后的文件复制回源文件夹。这样在使用例如 PhotoPrism 等第三方软件进行管理的时候,就可以将转化后的文件作为预览文件,同时也能便捷的定位到源文件。
产品逻辑
flowchart TB
A([获取 Handbrake 输出目录文件列表]) --> B{文件名是否在\n待处理文件列表中}
B -- 是 --> C[将文件恢复原名并移动至原始目录] --> D[删除监控文件夹的待处理文件] --> E([输出操作记录到日志文件])
B -- 否 --> D
转移脚本
和监控脚本类似,这个转移脚本也使用 Cron 进行定时操作,将转化后的文件移动回原始目录。
#! /bin/bash
SCRIPT_DIR = $( cd $( dirname ${ BASH_SOURCE [0] } ) ; pwd )
WATCH_PATH = "/mnt/user/Video/Watch"
OUTPUT_PATH = "/mnt/user/Video/Output"
tred_files_list = $( ls ${ OUTPUT_PATH } )
todo_files_list = $( cat ${ SCRIPT_DIR } /mov.list)
### 解决文件名中有空格的问题 ###
IFS_BACKUP = $IFS
IFS = $( echo -en "\n\b" )
for tred_file in ${ tred_files_list }
do
file_detail = $( grep " ${ tred_file % \. * } " <<< ${ todo_files_list } )
file_name = $( echo ${ file_detail } | awk 'BEGIN{FS=":"} {print $1}' )
file_ext = $( echo ${ file_detail } | awk 'BEGIN{FS=":"} {print $2}' )
file_path = $( echo ${ file_detail } | awk 'BEGIN{FS=":"} {print $3}' )
# 将转化后的文件移动回原目录时改名回原来的文件名
mv_result = $( mv -f " ${ OUTPUT_PATH } / ${ tred_file } " " ${ file_path } / ${ file_name } .mp4" )
rm_result = $( rm -f " ${ WATCH_PATH } / ${ tred_file % \. * } . ${ file_ext } " )
if [ -z ${ mv_result } ] && [ -z ${ rm_result } ] ; then
let success_num++
fi
done
IFS = $IFS_BACKU
printf "%s\t转移%4d 个文件回原始目录\n" " $( date +"%Y-%m-%d %H:%M:%S" ) " ${ success_num :- 0 } | tee -a ${ SCRIPT_DIR } /icloud.log
定时任务
要实现整个流程的完全自动化,最后一步就是将定时任务加入到 Cron 中按计划执行。
至此,这个流程就不再需要人工干预了,并且有日志文件记录操作细节,整个需求得到了完美的实现,🤭 。
# Run daily icloud mov trans job at 12:40 every day:
40 12 * * * sh /etc/script/icloud/todo.sh & > /dev/null
# Run daily icloud files move job at 23:40 every day: #(1)
40 22 * * * sh /etc/script/icloud/tred.sh & > /dev/null
为了避免 Handbrake 还未完成转换,就开始移动文件,这里将转换脚本的执行时间设置为转换脚本的 10 小时之后。