mirror of
https://github.com/nimbold/Firelink.git
synced 2026-07-26 12:08:27 +00:00
7b3d620efa
Gatekeeper enforces Library Validation and prevents `dlopen` of quarantined ad-hoc signed dynamic libraries on ARM64. Because the `_internal` folder was shipped inside the DMG, the user's system flagged it with the com.apple.quarantine attribute, causing the Python shared library to fail to load inside `yt-dlp`. By reverting back to the single-file PyInstaller binary (which is now properly code-signable without corruption on macOS), PyInstaller extracts the `_internal` folder at runtime to `/var/folders/...`. These extracted files do not inherit the quarantine flag, allowing AMFI to successfully load them and completely bypassing the dlopen system policy rejection.
196 lines
6.2 KiB
Bash
Executable File
196 lines
6.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
APP_NAME="Firelink"
|
|
CONFIGURATION="${CONFIGURATION:-release}"
|
|
DEFAULT_MARKETING_VERSION="$(git describe --tags --abbrev=0 2>/dev/null | sed 's/^v//' || true)"
|
|
DEFAULT_BUILD_NUMBER="$(git rev-list --count HEAD 2>/dev/null || true)"
|
|
MARKETING_VERSION="${MARKETING_VERSION:-${DEFAULT_MARKETING_VERSION:-0.1.0}}"
|
|
BUILD_NUMBER="${BUILD_NUMBER:-${DEFAULT_BUILD_NUMBER:-1}}"
|
|
SIGNING_IDENTITY="${CODE_SIGN_IDENTITY:-${SIGNING_IDENTITY:-}}"
|
|
APP_DIR="$ROOT_DIR/build/$APP_NAME.app"
|
|
CONTENTS_DIR="$APP_DIR/Contents"
|
|
MACOS_DIR="$CONTENTS_DIR/MacOS"
|
|
RESOURCES_DIR="$CONTENTS_DIR/Resources"
|
|
ICON_NAME="AppIcon"
|
|
|
|
cd "$ROOT_DIR"
|
|
|
|
is_valid_mach_o() {
|
|
local path="$1"
|
|
if ! file "$path" | grep -q 'Mach-O'; then
|
|
return 1
|
|
fi
|
|
|
|
lipo -archs "$path" >/dev/null 2>&1
|
|
}
|
|
|
|
ensure_ytdlp() {
|
|
local ytdlp_path="$ROOT_DIR/Sources/Firelink/yt-dlp"
|
|
|
|
if [[ -x "$ytdlp_path" ]] && is_valid_mach_o "$ytdlp_path"; then
|
|
return
|
|
fi
|
|
|
|
if ! command -v curl >/dev/null; then
|
|
echo "WARNING: yt-dlp is missing, and curl is not available to refresh it." >&2
|
|
return
|
|
fi
|
|
|
|
echo "Refreshing bundled yt-dlp runtime..."
|
|
curl -fsSL https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_macos -o "$ytdlp_path"
|
|
chmod +x "$ytdlp_path"
|
|
|
|
# Remove legacy _internal directory if it exists
|
|
rm -rf "$ROOT_DIR/Sources/Firelink/_internal"
|
|
}
|
|
|
|
ensure_ytdlp
|
|
|
|
swift build -c "$CONFIGURATION"
|
|
|
|
rm -rf "$APP_DIR"
|
|
mkdir -p "$MACOS_DIR" "$RESOURCES_DIR"
|
|
cp ".build/$CONFIGURATION/$APP_NAME" "$MACOS_DIR/$APP_NAME"
|
|
cp "$ROOT_DIR/Resources/$ICON_NAME.icns" "$RESOURCES_DIR/$ICON_NAME.icns"
|
|
cp "$ROOT_DIR/Sources/Firelink/Assets.xcassets/MenuBarIcon.imageset/MenuBarIconTemplate.png" "$RESOURCES_DIR/MenuBarIconTemplate.png"
|
|
cp "$ROOT_DIR/Resources/GitHubTemplate.png" "$RESOURCES_DIR/GitHubTemplate.png"
|
|
|
|
for media_engine in yt-dlp ffmpeg; do
|
|
media_engine_path="$ROOT_DIR/Sources/Firelink/$media_engine"
|
|
if [[ -x "$media_engine_path" ]]; then
|
|
cp "$media_engine_path" "$RESOURCES_DIR/$media_engine"
|
|
chmod +x "$RESOURCES_DIR/$media_engine"
|
|
else
|
|
echo "WARNING: $media_engine not found or not executable at $media_engine_path"
|
|
fi
|
|
done
|
|
|
|
if [[ -d "$ROOT_DIR/Sources/Firelink/_internal" ]]; then
|
|
cp -R "$ROOT_DIR/Sources/Firelink/_internal" "$RESOURCES_DIR/_internal"
|
|
fi
|
|
|
|
echo "Packaging Firefox extension..."
|
|
mkdir -p "$RESOURCES_DIR/FirefoxExtension"
|
|
cp "$ROOT_DIR/Extensions/Firefox/background.js" "$RESOURCES_DIR/FirefoxExtension/background.js"
|
|
cp "$ROOT_DIR/Extensions/Firefox/content.js" "$RESOURCES_DIR/FirefoxExtension/content.js"
|
|
cp "$ROOT_DIR/Extensions/Firefox/manifest.json" "$RESOURCES_DIR/FirefoxExtension/manifest.json"
|
|
cp -R "$ROOT_DIR/Extensions/Firefox/icons" "$RESOURCES_DIR/FirefoxExtension/icons"
|
|
cp -R "$ROOT_DIR/Extensions/Firefox/popup" "$RESOURCES_DIR/FirefoxExtension/popup"
|
|
|
|
|
|
ARIA2C_PATH=$(which aria2c || true)
|
|
if [[ -n "$ARIA2C_PATH" && -x "$ARIA2C_PATH" ]]; then
|
|
echo "Bundling aria2c from $ARIA2C_PATH..."
|
|
cp "$ARIA2C_PATH" "$RESOURCES_DIR/aria2c"
|
|
|
|
if ! command -v dylibbundler &> /dev/null; then
|
|
echo "Installing dylibbundler..."
|
|
brew install dylibbundler
|
|
fi
|
|
|
|
FRAMEWORKS_DIR="$CONTENTS_DIR/Frameworks"
|
|
mkdir -p "$FRAMEWORKS_DIR"
|
|
dylibbundler -od -b -x "$RESOURCES_DIR/aria2c" -d "$FRAMEWORKS_DIR" -p "@executable_path/../Frameworks/"
|
|
else
|
|
echo "WARNING: aria2c not found! It will not be bundled. Please install it first."
|
|
fi
|
|
|
|
FRAMEWORKS_DIR="$CONTENTS_DIR/Frameworks"
|
|
mkdir -p "$FRAMEWORKS_DIR"
|
|
|
|
install_name_tool -add_rpath "@executable_path/../Frameworks" "$MACOS_DIR/$APP_NAME" || true
|
|
|
|
|
|
cat > "$CONTENTS_DIR/Info.plist" <<PLIST
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>CFBundleDevelopmentRegion</key>
|
|
<string>en</string>
|
|
<key>CFBundleExecutable</key>
|
|
<string>$APP_NAME</string>
|
|
<key>CFBundleIdentifier</key>
|
|
<string>local.firelink.swiftui</string>
|
|
<key>CFBundleInfoDictionaryVersion</key>
|
|
<string>6.0</string>
|
|
<key>CFBundleName</key>
|
|
<string>$APP_NAME</string>
|
|
<key>CFBundleIconFile</key>
|
|
<string>$ICON_NAME</string>
|
|
<key>CFBundlePackageType</key>
|
|
<string>APPL</string>
|
|
<key>CFBundleShortVersionString</key>
|
|
<string>$MARKETING_VERSION</string>
|
|
<key>CFBundleVersion</key>
|
|
<string>$BUILD_NUMBER</string>
|
|
<key>LSMinimumSystemVersion</key>
|
|
<string>14.0</string>
|
|
<key>LSApplicationCategoryType</key>
|
|
<string>public.app-category.utilities</string>
|
|
<key>NSHighResolutionCapable</key>
|
|
<true/>
|
|
<key>NSAppleEventsUsageDescription</key>
|
|
<string>Firelink needs permission to control Finder so it can sleep, restart, or shut down your Mac after scheduled downloads finish.</string>
|
|
<key>CFBundleURLTypes</key>
|
|
<array>
|
|
<dict>
|
|
<key>CFBundleURLName</key>
|
|
<string>local.firelink.swiftui</string>
|
|
<key>CFBundleURLSchemes</key>
|
|
<array>
|
|
<string>firelink</string>
|
|
</array>
|
|
</dict>
|
|
</array>
|
|
</dict>
|
|
</plist>
|
|
PLIST
|
|
|
|
if command -v codesign &> /dev/null; then
|
|
if [[ -n "$SIGNING_IDENTITY" ]]; then
|
|
CODESIGN_ARGS=(--force --timestamp --options runtime --sign "$SIGNING_IDENTITY")
|
|
echo "Signing app bundle with identity: $SIGNING_IDENTITY"
|
|
else
|
|
CODESIGN_ARGS=(--force --sign -)
|
|
echo "Ad-hoc signing app bundle for local use."
|
|
fi
|
|
|
|
sign_path() {
|
|
local path="$1"
|
|
codesign "${CODESIGN_ARGS[@]}" "$path"
|
|
}
|
|
|
|
sign_mach_o_file() {
|
|
local path="$1"
|
|
|
|
if file "$path" | grep -q 'Mach-O'; then
|
|
if ! sign_path "$path"; then
|
|
echo "WARNING: Could not sign Mach-O executable for local build: $path" >&2
|
|
fi
|
|
fi
|
|
}
|
|
|
|
if [[ -d "$FRAMEWORKS_DIR" ]]; then
|
|
while IFS= read -r -d '' executable_path; do
|
|
sign_mach_o_file "$executable_path"
|
|
done < <(find "$FRAMEWORKS_DIR" -type f -print0)
|
|
|
|
while IFS= read -r -d '' bundle_path; do
|
|
sign_path "$bundle_path"
|
|
done < <(find "$FRAMEWORKS_DIR" \( -name "*.xpc" -o -name "*.framework" \) -type d -depth -print0)
|
|
fi
|
|
|
|
while IFS= read -r -d '' executable_path; do
|
|
sign_mach_o_file "$executable_path"
|
|
done < <(find "$RESOURCES_DIR" -type f -print0)
|
|
|
|
sign_path "$MACOS_DIR/$APP_NAME"
|
|
sign_path "$APP_DIR"
|
|
codesign --verify --deep --verbose=2 "$APP_DIR" || true
|
|
fi
|
|
|
|
echo "Created $APP_DIR"
|