crosssubtitle-ai/scripts/prepare-bundled-ffmpeg.sh
2026-03-19 14:50:22 +08:00

157 lines
3.7 KiB
Bash

#!/bin/sh
set -eu
ROOT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
TARGET_ARCH=$(uname -m)
FFMPEG_SOURCE=${FFMPEG_SOURCE_PATH:-$(command -v ffmpeg)}
VENDOR_ROOT="$ROOT_DIR/src-tauri/vendor/ffmpeg/macos-$TARGET_ARCH"
BIN_DIR="$VENDOR_ROOT/bin"
LIB_DIR="$VENDOR_ROOT/lib"
MARK_DIR="$VENDOR_ROOT/.processed"
rm -rf "$VENDOR_ROOT"
mkdir -p "$BIN_DIR" "$LIB_DIR" "$MARK_DIR"
copy_binary() {
src_path=$1
dest_path=$2
cp -fL "$src_path" "$dest_path"
chmod 755 "$dest_path"
}
resolve_dep_source() {
file_path=$1
dep_path=$2
case "$dep_path" in
/System/*|/usr/lib/*)
return 1
;;
/*)
if [ -f "$dep_path" ]; then
printf '%s\n' "$dep_path"
return 0
fi
;;
@loader_path/*)
candidate="$(dirname "$file_path")/$(basename "$dep_path")"
if [ -f "$candidate" ]; then
printf '%s\n' "$candidate"
return 0
fi
;;
@executable_path/*)
candidate="$LIB_DIR/$(basename "$dep_path")"
if [ -f "$candidate" ]; then
printf '%s\n' "$candidate"
return 0
fi
;;
@rpath/*)
dep_name=$(basename "$dep_path")
for candidate in \
"$LIB_DIR/$dep_name" \
"/opt/homebrew/lib/$dep_name" \
$(find /opt/homebrew/Cellar -path "*/lib/$dep_name" -print 2>/dev/null)
do
if [ -n "$candidate" ] && [ -f "$candidate" ]; then
printf '%s\n' "$candidate"
return 0
fi
done
;;
esac
return 1
}
marker_path() {
printf '%s' "$1" | shasum -a 1 | awk '{print "'"$MARK_DIR"'/" $1 ".done"}'
}
process_file() {
file_path=$1
loader_prefix=$2
mark_file=$(marker_path "$file_path")
if [ -f "$mark_file" ]; then
return
fi
: > "$mark_file"
otool -L "$file_path" | tail -n +2 | awk '{print $1}' | while read -r dep_path; do
resolved_dep=$(resolve_dep_source "$file_path" "$dep_path" || true)
if [ -z "$resolved_dep" ]; then
continue
fi
dep_name=$(basename "$resolved_dep")
vendored_dep="$LIB_DIR/$dep_name"
if [ ! -f "$vendored_dep" ]; then
copy_binary "$resolved_dep" "$vendored_dep"
fi
install_name_tool -change "$dep_path" "$loader_prefix/$dep_name" "$file_path"
process_file "$vendored_dep" "@loader_path"
done
if [ "$loader_prefix" = "@loader_path" ]; then
install_name_tool -id "@loader_path/$(basename "$file_path")" "$file_path"
fi
}
normalize_file() {
file_path=$1
loader_prefix=$2
otool -L "$file_path" | tail -n +2 | awk '{print $1}' | while read -r dep_path; do
case "$dep_path" in
/System/*|/usr/lib/*)
continue
;;
@executable_path/*|@loader_path/*)
continue
;;
esac
dep_name=$(basename "$dep_path")
vendored_dep="$LIB_DIR/$dep_name"
if [ -f "$vendored_dep" ]; then
install_name_tool -change "$dep_path" "$loader_prefix/$dep_name" "$file_path"
fi
done
if [ "$loader_prefix" = "@loader_path" ]; then
install_name_tool -id "@loader_path/$(basename "$file_path")" "$file_path"
fi
}
sign_file() {
file_path=$1
codesign --force --sign - --timestamp=none "$file_path" >/dev/null 2>&1
}
echo "Bundling ffmpeg from: $FFMPEG_SOURCE"
copy_binary "$FFMPEG_SOURCE" "$BIN_DIR/ffmpeg"
process_file "$BIN_DIR/ffmpeg" "@executable_path/../lib"
normalize_file "$BIN_DIR/ffmpeg" "@executable_path/../lib"
find "$LIB_DIR" -type f -name '*.dylib' | while read -r dylib_path; do
normalize_file "$dylib_path" "@loader_path"
done
find "$LIB_DIR" -type f -name '*.dylib' | while read -r dylib_path; do
normalize_file "$dylib_path" "@loader_path"
done
find "$LIB_DIR" -type f -name '*.dylib' | while read -r dylib_path; do
sign_file "$dylib_path"
done
sign_file "$BIN_DIR/ffmpeg"
echo "Bundled ffmpeg ready at: $VENDOR_ROOT"