diff --git a/.github/dylib_packer.zsh b/.github/dylib_packer.zsh
new file mode 100644
index 000000000000..573395cc5c2f
--- /dev/null
+++ b/.github/dylib_packer.zsh
@@ -0,0 +1,154 @@
+#!/bin/zsh
+
+# Define the fixed array of GStreamer libraries
+GSTREAMER_LIBS=(
+ "libgstapplemedia"
+ "libgstasf"
+ "libgstaudioconvert"
+ "libgstaudioparsers"
+ "libgstaudioresample"
+ "libgstavi"
+ "libgstcoreelements"
+ "libgstdebug"
+ "libgstdeinterlace"
+ "libgstid3demux"
+ "libgstisomp4"
+ "libgstlibav"
+ "libgstopengl"
+ "libgstplayback"
+ "libgsttypefindfunctions"
+ "libgstvideoconvertscale"
+ "libgstvideofilter"
+ "libgstvideoparsersbad"
+ "libgstwavparse"
+)
+
+# Global array to store all discovered dylibs, with unique entries only
+typeset -aU all_dylibs
+# Queue for iterative processing
+typeset -a queue
+
+# Function to resolve @rpath dependencies by searching in Homebrew's lib directory
+resolve_rpath() {
+ local ref_dylib="$1"
+
+ # Extract the actual filename after @rpath
+ local dylib_name="${ref_dylib#@rpath/}"
+
+ # Get Homebrew's lib directory
+ local brew_lib_dir="$(brew --prefix)/lib"
+
+ # Check if the dylib exists in Homebrew's lib directory
+ local resolved_path="${brew_lib_dir}/${dylib_name}"
+ if [[ -f "$resolved_path" ]]; then
+ echo "$resolved_path"
+ else
+ # If not found, return empty string to avoid trying to open unresolved @rpath
+ echo ""
+ fi
+}
+
+# Function to find all dylib dependencies iteratively
+find_dylib_dependencies() {
+ local dylib="$1"
+
+ # Initialize the queue with the initial dylib
+ queue+=("$dylib")
+
+ # Process each dylib in the queue
+ while [[ ${#queue[@]} -gt 0 ]]; do
+ local current_dylib="${queue[1]}"
+ queue=("${queue[@]:1}") # Remove the first element from the queue
+
+ # Get all referenced dylibs using otool
+ local referenced_dylibs=($(otool -L "$current_dylib" | awk '/^\t/ {print $1}' | grep '\.dylib'))
+
+ for ref_dylib in $referenced_dylibs; do
+ # Skip /usr/lib dylibs
+ if [[ "$ref_dylib" == /usr/lib/* ]]; then
+ continue
+ fi
+
+ # Resolve @rpath references by looking in Homebrew's lib directory
+ if [[ "$ref_dylib" == @rpath/* ]]; then
+ ref_dylib=$(resolve_rpath "$ref_dylib")
+ # Skip if @rpath couldn't be resolved
+ if [[ -z "$ref_dylib" ]]; then
+ echo "Warning: Could not resolve @rpath for $current_dylib" >&2
+ continue
+ fi
+ fi
+
+ # If the dylib is not already in the global array, add it to the array and the queue
+ if [[ ! " ${all_dylibs[*]} " =~ " $ref_dylib " ]]; then
+ all_dylibs+=("$ref_dylib")
+ queue+=("$ref_dylib")
+ fi
+ done
+ done
+}
+
+# Function to fix up brew dylib LCs
+update_dylib_paths() {
+ local dylib_file="$1"
+ local path_prefix="$2"
+ echo "Processing $dylib_file..."
+
+ otool -L "$dylib_file" | grep -v "$dylib_file" | awk '{print $1}' | while read -r dylib_path; do
+ if [[ $dylib_path != /usr/lib* && $dylib_path != /System/* ]]; then
+ # For paths not excluded, replace the prefix with @loader_path/
+ local lib_name="${dylib_path##*/}"
+ local new_dylib_path="${path_prefix}${lib_name}"
+ echo "Updating $dylib_path to $new_dylib_path"
+ # Use install_name_tool to change the path
+ install_name_tool -change "$dylib_path" "$new_dylib_path" "$dylib_file"
+ codesign -fs- "$dylib_file"
+ fi
+ done
+}
+
+# Function to copy the libraries into the appropriate directories
+copy_libraries() {
+ local lib="$1"
+ local gstreamer_dir="Libraries/Wine/lib/gstreamer-1.0"
+ local lib_dir="Libraries/Wine/lib"
+
+ mkdir -p "$gstreamer_dir" "$lib_dir"
+
+ # Check if the library is a GStreamer library by checking its path
+ if [[ "$lib" == *"/gstreamer-1.0/"* ]]; then
+ echo "Copying GStreamer library: $lib -> $gstreamer_dir"
+ cp "$lib" "$gstreamer_dir"
+ update_dylib_paths "$gstreamer_dir/$(basename "$lib")" "@loader_path/../"
+ else
+ echo "Copying non-GStreamer library: $lib -> $lib_dir"
+ cp "$lib" "$lib_dir"
+ update_dylib_paths "$lib_dir/$(basename "$lib")" "@loader_path/"
+ fi
+}
+
+# Get the Homebrew prefix for gstreamer
+GSTREAMER_PREFIX=$(brew --prefix gstreamer)
+
+# Iterate over the fixed GStreamer libraries array
+for lib in "${GSTREAMER_LIBS[@]}"; do
+ dylib_path="${GSTREAMER_PREFIX}/lib/gstreamer-1.0/${lib}.dylib"
+
+ if [ -f "$dylib_path" ]; then
+ echo "Checking dependencies for: $dylib_path"
+ find_dylib_dependencies "$dylib_path"
+ else
+ echo "Error: $dylib_path not found"
+ fi
+done
+
+# Copy all found dylibs to the appropriate directories
+for dylib in "${all_dylibs[@]}"; do
+ copy_libraries "$dylib"
+done
+
+# Copy GStreamer include files
+cp -a "$(brew --prefix gstreamer)/lib/gstreamer-1.0/include" Libraries/Wine/lib/gstreamer-1.0
+
+# Update specific GStreamer shared object
+update_dylib_paths Libraries/Wine/lib/wine/x86_64-unix/winegstreamer.so "@rpath/"
\ No newline at end of file
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 061904e173d6..708881067dbf 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -214,158 +214,8 @@ jobs:
- name: Copy External Libs
run: |
- LIBS=(
- "libaribb24.0"
- "libbluray.2"
- "libfontconfig.1"
- "libfreetype"
- "libfreetype.6"
- "libgio-2.0.0"
- "libglib-2.0.0"
- "libgmodule-2.0.0"
- "libgmp.10"
- "libgnutls.30"
- "libgobject-2.0.0"
- "libgraphene-1.0.0"
- "libgstallocators-1.0.0"
- "libgstapp-1.0.0"
- "libgstaudio-1.0.0"
- "libgstbase-1.0.0"
- "libgstcodecparsers-1.0.0"
- "libgstcodecs-1.0.0"
- "libgstcontroller-1.0.0"
- "libgstgl-1.0.0"
- "libgstpbutils-1.0.0"
- "libgstreamer-1.0.0"
- "libgstriff-1.0.0"
- "libgstrtp-1.0.0"
- "libgstrtsp-1.0.0"
- "libgstsdp-1.0.0"
- "libgsttag-1.0.0"
- "libgsttranscoder-1.0.0"
- "libgstvideo-1.0.0"
- "libgthread-2.0.0"
- "libharfbuzz.0"
- "libhogweed.6"
- "libidn2.0"
- "libintl.8"
- "libjpeg.8"
- "libjxl.0.11"
- "libjxl_threads.0.11"
- "libMoltenVK"
- "libnettle.8"
- "libogg.0"
- "liborc-0.4.0"
- "libp11-kit.0"
- "libpcre2-8.0"
- "libpng16.16"
- "librav1e.0.7"
- "librist.4"
- "librubberband.2"
- "libsamplerate.0"
- "libSDL2-2.0.0"
- "libsoxr.0"
- "libsrt.1.5"
- "libtasn1.6"
- "libunistring.5"
- "libvidstab.1.2"
- "libvmaf.3"
- "libvorbis.0"
- "libvorbisenc.2"
- "libvpx.8"
- "libwebp.7"
- "libwebpmux.3"
- "libXau.6"
- "libXdmcp.6"
- "libX11.6"
- "libX11-xcb.1"
- "libx264.164"
- "libx265.209"
- "libxcb.1"
- "libzimg.2"
- "libzmq.5"
- )
-
- FFMPEG_LIBS=(
- "libavfilter.10"
- "libavformat.61"
- "libavcodec.61"
- "libavutil.59"
- "libpostproc.58"
- "libswresample.5"
- "libswscale.8"
- )
-
- GSTREAMER_LIBS=(
- "libgstapplemedia"
- "libgstasf"
- "libgstaudioconvert"
- "libgstaudioparsers"
- "libgstaudioresample"
- "libgstavi"
- "libgstcoreelements"
- "libgstdebug"
- "libgstdeinterlace"
- "libgstid3demux"
- "libgstisomp4"
- "libgstlibav"
- "libgstopengl"
- "libgstplayback"
- "libgsttypefindfunctions"
- "libgstvideoconvertscale"
- "libgstvideofilter"
- "libgstvideoparsersbad"
- "libgstwavparse"
- )
-
- for i in "${LIBS[@]}"
- do
- cp -Lr $(brew --prefix)/lib/"$i".dylib Libraries/Wine/lib
- done
-
- for i in "${FFMPEG_LIBS[@]}"
- do
- cp -Lr $(brew --prefix ffmpeg@7)/lib/"$i".dylib Libraries/Wine/lib
- done
-
- mkdir Libraries/Wine/lib/gstreamer-1.0
-
- for i in "${GSTREAMER_LIBS[@]}"
- do
- cp -Lr $(brew --prefix gstreamer)/lib/gstreamer-1.0/"$i".dylib Libraries/Wine/lib/gstreamer-1.0
- done
-
- cp -a $(brew --prefix gstreamer)/lib/gstreamer-1.0/include Libraries/Wine/lib/gstreamer-1.0
-
- # Fixup brew dylib LCs
-
- update_dylib_paths() {
- local dylib_file="$1"
- local path_prefix="$2"
- echo "Processing $dylib_file..."
-
- # Extract LC_LOAD_DYLIB paths using otool
- local load_dylibs=$(otool -L "$dylib_file" | grep -v "$dylib_file" | awk '{print $1}')
-
- for path in $load_dylibs; do
- if [[ $path != /usr/lib* && $path != /System/* ]]; then
- # For paths not excluded, replace the prefix with @loader_path/
- local lib_name="${path##*/}"
- local new_path="${path_prefix}${lib_name}"
- echo "Updating $path to $new_path"
- # Use install_name_tool to change the path
- install_name_tool -change "$path" "$new_path" "$dylib_file"
- codesign -fs- "$dylib_file"
- fi
- done
- }
-
- export -f update_dylib_paths
-
- find Libraries/Wine/lib -maxdepth 1 -type f -name '*.dylib' -exec bash -c 'update_dylib_paths "$0" "@loader_path/"' {} \;
- find Libraries/Wine/lib/gstreamer-1.0 -maxdepth 1 -type f -name '*.dylib' -exec bash -c 'update_dylib_paths "$0" "@loader_path/../"' {} \;
-
- update_dylib_paths Libraries/Wine/lib/wine/x86_64-unix/winegstreamer.so "@rpath/"
+ chmod +x .github/dylib_packer.zsh
+ .github/dylib_packer.zsh
- name: Install GPTK
run: |
diff --git a/WhiskyWineVersion.plist b/WhiskyWineVersion.plist
index 90becb576974..a58f9dcdce82 100644
--- a/WhiskyWineVersion.plist
+++ b/WhiskyWineVersion.plist
@@ -11,7 +11,7 @@
minor
4
patch
- 3
+ 4
preRelease