commit a852333a80dfbc9264cf147456608e74c6699d3f Author: 28allday Date: Sat Mar 28 11:39:18 2026 +0000 Initial commit: DaVinci Resolve installer for Omarchy Co-Authored-By: Claude Opus 4.6 (1M context) diff --git a/Omarchy_resolve_v2.sh b/Omarchy_resolve_v2.sh new file mode 100755 index 0000000..9eade59 --- /dev/null +++ b/Omarchy_resolve_v2.sh @@ -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