Initial commit: DaVinci Resolve installer for Omarchy
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
a852333a80
1 changed files with 305 additions and 0 deletions
305
Omarchy_resolve_v2.sh
Executable file
305
Omarchy_resolve_v2.sh
Executable file
|
|
@ -0,0 +1,305 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# DaVinci Resolve installer for Omarchy/Arch — one-shot, self-healing, ABI-safe
|
||||||
|
# - ZIP already in ~/Downloads/
|
||||||
|
# - Assumes NVIDIA drivers are already installed and working
|
||||||
|
# - Extracts in ~/Downloads, minimal validation, AUR-style unbundling (glib/gio/gmodule only), RPATH patch
|
||||||
|
# - Installs system desktop files & icons, creates wrapper, rewires system desktop
|
||||||
|
# - Creates a user .desktop pointing to the wrapper (Hyprland-friendly)
|
||||||
|
# - Leaves vendor libc++/libc++abi in place (prevents ABI breakage)
|
||||||
|
# - Ensures legacy libcrypt.so.1 via libxcrypt-compat + fallback symlink
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
log(){ echo -e "▶ $*"; }
|
||||||
|
warn(){ echo -e "⚠️ $*" >&2; }
|
||||||
|
err(){ echo -e "❌ $*" >&2; exit 1; }
|
||||||
|
|
||||||
|
ZIP_DIR="${HOME}/Downloads"
|
||||||
|
shopt -s nullglob
|
||||||
|
ZIP_FILES=("${ZIP_DIR}"/DaVinci_Resolve*_Linux.zip)
|
||||||
|
shopt -u nullglob
|
||||||
|
if [[ ${#ZIP_FILES[@]} -eq 0 ]]; then
|
||||||
|
err "Put the official DaVinci Resolve Linux ZIP in ${ZIP_DIR}"
|
||||||
|
fi
|
||||||
|
# Sort by modification time, newest first
|
||||||
|
RESOLVE_ZIP="$(ls -1t "${ZIP_FILES[@]}" 2>/dev/null | head -n1)"
|
||||||
|
[[ -n "${RESOLVE_ZIP}" ]] || err "Could not determine newest ZIP file"
|
||||||
|
log "Using installer ZIP: ${RESOLVE_ZIP}"
|
||||||
|
|
||||||
|
# ---------------- Packages ----------------
|
||||||
|
# Opt-in full system upgrade (can be slow and may update kernel/NVIDIA stack unexpectedly)
|
||||||
|
if [[ "${RESOLVE_FULL_UPGRADE:-0}" == "1" ]]; then
|
||||||
|
log "Updating system packages (RESOLVE_FULL_UPGRADE=1)..."
|
||||||
|
sudo pacman -Syu --noconfirm
|
||||||
|
else
|
||||||
|
log "Skipping full system upgrade (set RESOLVE_FULL_UPGRADE=1 to enable)"
|
||||||
|
# Just sync package database without upgrading
|
||||||
|
sudo pacman -Sy --noconfirm
|
||||||
|
fi
|
||||||
|
log "Installing required tools..."
|
||||||
|
if ! sudo pacman -S --needed --noconfirm unzip patchelf libarchive xdg-user-dirs desktop-file-utils file gtk-update-icon-cache; then
|
||||||
|
warn "Some optional tools failed to install, continuing anyway..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Runtime bits (KEEP vendor libc++/libc++abi)
|
||||||
|
log "Installing runtime dependencies..."
|
||||||
|
if ! sudo pacman -S --needed --noconfirm libxcrypt-compat ffmpeg4.4 glu gtk2 fuse2; then
|
||||||
|
warn "Some runtime dependencies failed to install (may affect functionality)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# TLS path for extras downloader
|
||||||
|
if [[ ! -e /etc/pki/tls ]]; then
|
||||||
|
sudo mkdir -p /etc/pki
|
||||||
|
sudo ln -sf /etc/ssl /etc/pki/tls
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---------------- Extract in Downloads ----------------
|
||||||
|
NEEDED_GB=10
|
||||||
|
FREE_KB=$(df --output=avail -k "${ZIP_DIR}" | tail -n1); FREE_GB=$((FREE_KB/1024/1024))
|
||||||
|
(( FREE_GB >= NEEDED_GB )) || err "Not enough free space in ${ZIP_DIR}: ${FREE_GB} GiB < ${NEEDED_GB} GiB"
|
||||||
|
|
||||||
|
WORKDIR="$(mktemp -d -p "${ZIP_DIR}" .resolve-extract-XXXXXXXX)"
|
||||||
|
cleanup() {
|
||||||
|
if [[ -n "${WORKDIR:-}" && -d "${WORKDIR}" ]]; then
|
||||||
|
log "Cleaning up temporary directory..."
|
||||||
|
rm -rf "${WORKDIR}" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
log "Unpacking ZIP to ${WORKDIR}…"
|
||||||
|
unzip -q "${RESOLVE_ZIP}" -d "${WORKDIR}"
|
||||||
|
|
||||||
|
RUN_FILE="$(find "${WORKDIR}" -maxdepth 2 -type f -name 'DaVinci_Resolve_*_Linux.run' | head -n1 || true)"
|
||||||
|
[[ -n "${RUN_FILE}" ]] || err "Could not find the .run installer in the ZIP"
|
||||||
|
chmod +x "${RUN_FILE}"
|
||||||
|
|
||||||
|
EX_DIR="$(dirname "${RUN_FILE}")"
|
||||||
|
log "Extracting AppImage payload…"
|
||||||
|
if ! ( cd "${EX_DIR}" && "./$(basename "${RUN_FILE}")" --appimage-extract >/dev/null ); then
|
||||||
|
err "Failed to extract AppImage payload"
|
||||||
|
fi
|
||||||
|
APPDIR="${EX_DIR}/squashfs-root"
|
||||||
|
[[ -d "${APPDIR}" ]] || err "Extraction failed (no squashfs-root)"
|
||||||
|
|
||||||
|
# Normalize perms
|
||||||
|
chmod -R u+rwX,go+rX,go-w "${APPDIR}" || warn "Could not normalize all permissions"
|
||||||
|
|
||||||
|
# Minimal validation
|
||||||
|
[[ -s "${APPDIR}/bin/resolve" ]] || err "resolve binary missing or zero-size"
|
||||||
|
|
||||||
|
# ---------------- AUR-style niceties (ABI-safe) ----------------
|
||||||
|
# IMPORTANT: Do NOT touch vendor libc++/libc++abi. Only swap glib/gio/gmodule to system libs.
|
||||||
|
pushd "${APPDIR}" >/dev/null
|
||||||
|
|
||||||
|
# Verify system libraries exist before replacing bundled ones
|
||||||
|
declare -A GLIB_LIBS=(
|
||||||
|
["/usr/lib/libglib-2.0.so.0"]="libs/libglib-2.0.so.0"
|
||||||
|
["/usr/lib/libgio-2.0.so.0"]="libs/libgio-2.0.so.0"
|
||||||
|
["/usr/lib/libgmodule-2.0.so.0"]="libs/libgmodule-2.0.so.0"
|
||||||
|
)
|
||||||
|
for syslib in "${!GLIB_LIBS[@]}"; do
|
||||||
|
target="${GLIB_LIBS[$syslib]}"
|
||||||
|
if [[ -e "${syslib}" ]]; then
|
||||||
|
rm -f "${target}" || true
|
||||||
|
ln -sf "${syslib}" "${target}" || warn "Failed to symlink ${syslib}"
|
||||||
|
else
|
||||||
|
warn "System library ${syslib} not found, keeping bundled version"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Panels -> libs/ (best-effort)
|
||||||
|
if [[ -d "share/panels" ]]; then
|
||||||
|
pushd "share/panels" >/dev/null
|
||||||
|
tar -zxf dvpanel-framework-linux-x86_64.tgz 2>/dev/null || true
|
||||||
|
mkdir -p "${APPDIR}/libs"
|
||||||
|
find . -maxdepth 1 -type f -name '*.so' -exec mv -f {} "${APPDIR}/libs" \; 2>/dev/null || true
|
||||||
|
if [[ -d lib ]]; then
|
||||||
|
find lib -type f -name '*.so*' -exec mv -f {} "${APPDIR}/libs" \; 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
popd >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "AppRun" "AppRun*" 2>/dev/null || true
|
||||||
|
rm -rf "installer" "installer*" 2>/dev/null || true
|
||||||
|
mkdir -p "bin"
|
||||||
|
ln -sf "../BlackmagicRAWPlayer/BlackmagicRawAPI" "bin/" 2>/dev/null || true
|
||||||
|
popd >/dev/null
|
||||||
|
|
||||||
|
# ---------------- Install to /opt/resolve ----------------
|
||||||
|
log "Installing Resolve to /opt/resolve…"
|
||||||
|
sudo rm -rf /opt/resolve
|
||||||
|
sudo mkdir -p /opt/resolve
|
||||||
|
if command -v rsync >/dev/null 2>&1; then
|
||||||
|
sudo rsync -a --delete "${APPDIR}/" /opt/resolve/
|
||||||
|
else
|
||||||
|
sudo cp -a "${APPDIR}/." /opt/resolve/
|
||||||
|
fi
|
||||||
|
sudo mkdir -p /opt/resolve/.license
|
||||||
|
|
||||||
|
# RPATH patch - done AFTER installation to /opt/resolve
|
||||||
|
# NOTE: No size limit - large libs like libQt5WebEngineCore.so (~200M) must also be patched
|
||||||
|
# to avoid mixed RPATH issues where some libs search old AppImage paths
|
||||||
|
log "Applying RPATH with patchelf (this may take a while for large libraries)…"
|
||||||
|
RPATH_DIRS=( "libs" "libs/plugins/sqldrivers" "libs/plugins/xcbglintegrations" "libs/plugins/imageformats"
|
||||||
|
"libs/plugins/platforms" "libs/Fusion" "plugins" "bin"
|
||||||
|
"BlackmagicRAWSpeedTest/BlackmagicRawAPI" "BlackmagicRAWSpeedTest/plugins/platforms"
|
||||||
|
"BlackmagicRAWSpeedTest/plugins/imageformats" "BlackmagicRAWSpeedTest/plugins/mediaservice"
|
||||||
|
"BlackmagicRAWSpeedTest/plugins/audio" "BlackmagicRAWSpeedTest/plugins/xcbglintegrations"
|
||||||
|
"BlackmagicRAWSpeedTest/plugins/bearer"
|
||||||
|
"BlackmagicRAWPlayer/BlackmagicRawAPI" "BlackmagicRAWPlayer/plugins/mediaservice"
|
||||||
|
"BlackmagicRAWPlayer/plugins/imageformats" "BlackmagicRAWPlayer/plugins/audio"
|
||||||
|
"BlackmagicRAWPlayer/plugins/platforms" "BlackmagicRAWPlayer/plugins/xcbglintegrations"
|
||||||
|
"BlackmagicRAWPlayer/plugins/bearer"
|
||||||
|
"Onboarding/plugins/xcbglintegrations" "Onboarding/plugins/qtwebengine"
|
||||||
|
"Onboarding/plugins/platforms" "Onboarding/plugins/imageformats"
|
||||||
|
"DaVinci Control Panels Setup/plugins/platforms"
|
||||||
|
"DaVinci Control Panels Setup/plugins/imageformats"
|
||||||
|
"DaVinci Control Panels Setup/plugins/bearer"
|
||||||
|
"DaVinci Control Panels Setup/AdminUtility/PlugIns/DaVinciKeyboards"
|
||||||
|
"DaVinci Control Panels Setup/AdminUtility/PlugIns/DaVinciPanels" )
|
||||||
|
RPATH_ABS=""; for p in "${RPATH_DIRS[@]}"; do RPATH_ABS+="/opt/resolve/${p}:"; done; RPATH_ABS+="\$ORIGIN"
|
||||||
|
if command -v patchelf >/dev/null 2>&1; then
|
||||||
|
PATCH_COUNT=0
|
||||||
|
PATCH_FAIL=0
|
||||||
|
PATCH_SKIP=0
|
||||||
|
# Process all ELF files regardless of size
|
||||||
|
while IFS= read -r -d '' f; do
|
||||||
|
FILE_INFO="$(file -b "$f" 2>/dev/null)"
|
||||||
|
if [[ "${FILE_INFO}" =~ ELF.*executable ]] || [[ "${FILE_INFO}" =~ ELF.*shared\ object ]]; then
|
||||||
|
# Skip if file already has correct RPATH (optimization for re-runs)
|
||||||
|
CURRENT_RPATH="$(patchelf --print-rpath "$f" 2>/dev/null || true)"
|
||||||
|
if [[ "${CURRENT_RPATH}" == "${RPATH_ABS}" ]]; then
|
||||||
|
((PATCH_SKIP++)) || true
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if sudo patchelf --set-rpath "${RPATH_ABS}" "$f" 2>/dev/null; then
|
||||||
|
((PATCH_COUNT++)) || true
|
||||||
|
else
|
||||||
|
((PATCH_FAIL++)) || true
|
||||||
|
# Log failures for large files specifically as they're more critical
|
||||||
|
FILE_SIZE=$(stat -c%s "$f" 2>/dev/null || echo 0)
|
||||||
|
if (( FILE_SIZE > 33554432 )); then # >32M
|
||||||
|
warn "Failed to patch large file: ${f##/opt/resolve/}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done < <(find /opt/resolve -type f -print0)
|
||||||
|
log "Patched RPATH: ${PATCH_COUNT} files (${PATCH_FAIL} failures, ${PATCH_SKIP} already correct)"
|
||||||
|
else
|
||||||
|
warn "patchelf not found, skipping RPATH patching"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Ensure legacy libcrypt is available (Arch fix for Resolve) -------------
|
||||||
|
sudo pacman -S --needed --noconfirm libxcrypt-compat || true
|
||||||
|
sudo ldconfig || true
|
||||||
|
if [[ -e /usr/lib/libcrypt.so.1 ]]; then
|
||||||
|
sudo ln -sf /usr/lib/libcrypt.so.1 /opt/resolve/libs/libcrypt.so.1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---------------- Desktop, icons, udev (system) ----------------
|
||||||
|
log "Installing desktop entries and icons..."
|
||||||
|
declare -A DESKTOP_FILES=(
|
||||||
|
["/opt/resolve/share/DaVinciResolve.desktop"]="/usr/share/applications/DaVinciResolve.desktop"
|
||||||
|
["/opt/resolve/share/DaVinciControlPanelsSetup.desktop"]="/usr/share/applications/DaVinciControlPanelsSetup.desktop"
|
||||||
|
["/opt/resolve/share/blackmagicraw-player.desktop"]="/usr/share/applications/blackmagicraw-player.desktop"
|
||||||
|
["/opt/resolve/share/blackmagicraw-speedtest.desktop"]="/usr/share/applications/blackmagicraw-speedtest.desktop"
|
||||||
|
)
|
||||||
|
for src in "${!DESKTOP_FILES[@]}"; do
|
||||||
|
dest="${DESKTOP_FILES[$src]}"
|
||||||
|
if [[ -f "${src}" ]]; then
|
||||||
|
sudo install -D -m 0644 "${src}" "${dest}"
|
||||||
|
else
|
||||||
|
warn "Desktop file not found: ${src}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Icons (ensure hicolor sizes present so menus show right icon)
|
||||||
|
declare -A ICON_FILES=(
|
||||||
|
["/opt/resolve/graphics/DV_Resolve.png"]="/usr/share/icons/hicolor/128x128/apps/davinci-resolve.png"
|
||||||
|
["/opt/resolve/graphics/DV_Panels.png"]="/usr/share/icons/hicolor/128x128/apps/davinci-resolve-panels-setup.png"
|
||||||
|
["/opt/resolve/graphics/blackmagicraw-player_256x256_apps.png"]="/usr/share/icons/hicolor/256x256/apps/blackmagicraw-player.png"
|
||||||
|
["/opt/resolve/graphics/blackmagicraw-speedtest_256x256_apps.png"]="/usr/share/icons/hicolor/256x256/apps/blackmagicraw-speedtest.png"
|
||||||
|
)
|
||||||
|
for src in "${!ICON_FILES[@]}"; do
|
||||||
|
dest="${ICON_FILES[$src]}"
|
||||||
|
if [[ -f "${src}" ]]; then
|
||||||
|
sudo install -D -m 0644 "${src}" "${dest}"
|
||||||
|
else
|
||||||
|
warn "Icon file not found: ${src}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
sudo update-desktop-database >/dev/null 2>&1 || true
|
||||||
|
sudo gtk-update-icon-cache -f /usr/share/icons/hicolor >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
# udev rules
|
||||||
|
for r in 99-BlackmagicDevices.rules 99-ResolveKeyboardHID.rules 99-DavinciPanel.rules; do
|
||||||
|
if [[ -f "/opt/resolve/share/etc/udev/rules.d/${r}" ]]; then
|
||||||
|
sudo install -D -m 0644 "/opt/resolve/share/etc/udev/rules.d/${r}" "/usr/lib/udev/rules.d/${r}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
sudo udevadm control --reload-rules && sudo udevadm trigger || true
|
||||||
|
|
||||||
|
# ---------------- Wrapper + helper ----------------
|
||||||
|
cat << 'EOF' | sudo tee /usr/local/bin/resolve-nvidia-open >/dev/null
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
# Clear stale single-instance Qt lockfiles (only if we have permission)
|
||||||
|
if [[ -r /tmp ]]; then
|
||||||
|
for lockfile in /tmp/qtsingleapp-DaVinci*lockfile; do
|
||||||
|
[[ -f "$lockfile" ]] && rm -f "$lockfile" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
# Force XWayland under Hyprland/Wayland
|
||||||
|
export QT_QPA_PLATFORM=xcb
|
||||||
|
export QT_AUTO_SCREEN_SCALE_FACTOR=1
|
||||||
|
# For hybrid laptops, optionally force dGPU:
|
||||||
|
# export __NV_PRIME_RENDER_OFFLOAD=1
|
||||||
|
# export __GLX_VENDOR_LIBRARY_NAME=nvidia
|
||||||
|
exec /opt/resolve/bin/resolve "$@"
|
||||||
|
EOF
|
||||||
|
sudo chmod +x /usr/local/bin/resolve-nvidia-open
|
||||||
|
|
||||||
|
if [[ ! -e /usr/bin/davinci-resolve ]]; then
|
||||||
|
if [[ -x /usr/local/bin/resolve-nvidia-open ]]; then
|
||||||
|
echo -e '#!/usr/bin/env bash\nexec /usr/local/bin/resolve-nvidia-open "$@"' | sudo tee /usr/bin/davinci-resolve >/dev/null
|
||||||
|
else
|
||||||
|
echo -e '#!/usr/bin/env bash\nexec /opt/resolve/bin/resolve "$@"' | sudo tee /usr/bin/davinci-resolve >/dev/null
|
||||||
|
fi
|
||||||
|
sudo chmod +x /usr/bin/davinci-resolve
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Point system desktop launchers at the wrapper
|
||||||
|
WRAPPER="/usr/local/bin/resolve-nvidia-open"
|
||||||
|
if [[ -f /usr/share/applications/DaVinciResolve.desktop ]]; then
|
||||||
|
sudo sed -i "s|^Exec=.*|Exec=${WRAPPER} %U|" /usr/share/applications/DaVinciResolve.desktop
|
||||||
|
fi
|
||||||
|
if [[ -f /usr/share/applications/DaVinciResolveCaptureLogs.desktop ]]; then
|
||||||
|
sudo sed -i "s|^Exec=.*|Exec=${WRAPPER} %U|" /usr/share/applications/DaVinciResolveCaptureLogs.desktop
|
||||||
|
fi
|
||||||
|
sudo update-desktop-database >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
# ---------------- User-level desktop entry (takes precedence) ----------------
|
||||||
|
mkdir -p "${HOME}/.local/share/applications"
|
||||||
|
cat > "${HOME}/.local/share/applications/davinci-resolve-wrapper.desktop" << EOF
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=DaVinci Resolve
|
||||||
|
Comment=DaVinci Resolve via XWayland wrapper (NVIDIA-Open)
|
||||||
|
Exec=${WRAPPER} %U
|
||||||
|
TryExec=${WRAPPER}
|
||||||
|
Terminal=false
|
||||||
|
Icon=davinci-resolve
|
||||||
|
Categories=AudioVideo;Video;Audio;Graphics;
|
||||||
|
StartupWMClass=resolve
|
||||||
|
X-GNOME-UsesNotifications=true
|
||||||
|
EOF
|
||||||
|
|
||||||
|
update-desktop-database "${HOME}/.local/share/applications" >/dev/null 2>&1 || true
|
||||||
|
sudo gtk-update-icon-cache -f /usr/share/icons/hicolor >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "✅ DaVinci Resolve installed to /opt/resolve"
|
||||||
|
echo " (vendor libc++ kept; libcrypt.so.1 ensured)"
|
||||||
|
echo " Launch from your app menu, or run: resolve-nvidia-open"
|
||||||
|
echo " Logs: ~/.local/share/DaVinciResolve/logs/ResolveDebug.txt"
|
||||||
|
echo
|
||||||
Loading…
Add table
Reference in a new issue