name: Build Project
on:
  workflow_call:
jobs:
  check-event:
    name: Event Data 🔎
    runs-on: ubuntu-24.04
    defaults:
      run:
        shell: bash
    outputs:
      package: ${{ steps.setup.outputs.package }}
      codesign: ${{ steps.setup.outputs.codesign }}
      notarize: ${{ steps.setup.outputs.notarize }}
      config: ${{ steps.setup.outputs.config }}
      commitHash: ${{ steps.setup.outputs.commitHash }}
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
        with:
          fetch-depth: 0
      - name: Check Event Data ☑️
        id: setup
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          : Check Event Data ☑️
          if [[ "${RUNNER_DEBUG}" ]]; then set -x; fi

          case "${GITHUB_EVENT_NAME}" in
            pull_request)
              config_data=('codesign:false' 'notarize:false' 'package:false' 'config:RelWithDebInfo')
              if gh pr view ${{ github.event.number }} --json labels \
                | jq -e -r '.labels[] | select(.name == "Seeking Testers")' > /dev/null; then
                config_data[0]='codesign:true'
                config_data[2]='package:true'
              fi
              ;;
            push)
              config_data=('codesign:true' 'notarize:false' 'package:true' 'config:RelWithDebInfo')
              if [[ ${GITHUB_REF_NAME} =~ [0-9]+.[0-9]+.[0-9]+(-(rc|beta).+)? ]]; then
                config_data[1]='notarize:true'
                config_data[3]='config:Release'
              fi
              ;;
            workflow_dispatch)
              config_data=('codesign:true' 'notarize:false' 'package:false' 'config:RelWithDebInfo')
              ;;
            schedule)
              config_data=('codesign:true' 'notarize:false' 'package:true' 'config:RelWithDebInfo')
              ;;
            *) ;;
          esac

          for config in "${config_data[@]}"; do
            IFS=':' read -r key value <<< "${config}"
            echo "${key}=${value}" >> $GITHUB_OUTPUT
          done
          echo "commitHash=${GITHUB_SHA:0:9}" >> $GITHUB_OUTPUT

  macos-build:
    name: macOS 🍏
    runs-on: macos-15
    needs: check-event
    strategy:
      fail-fast: false
      matrix:
        target: [arm64, x86_64]
    defaults:
      run:
        shell: zsh --no-rcs --errexit --pipefail {0}
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
        with:
          submodules: recursive
          fetch-depth: 0

      - name: Set Up Environment 🔧
        id: setup
        run: |
          : Set Up Environment 🔧
          if (( ${+RUNNER_DEBUG} )) setopt XTRACE

          print '::group::Enable Xcode 26.1'
          sudo xcode-select --switch /Applications/Xcode_26.1.app/Contents/Developer
          print '::endgroup::'

          print '::group::Clean Homebrew Environment'
          local -a unwanted_formulas=()
          local -a remove_formulas=()
          for formula (${unwanted_formulas}) {
            if [[ -d ${HOMEBREW_PREFIX}/Cellar/${formula} ]] remove_formulas+=(${formula})
          }

          if (( #remove_formulas )) brew uninstall --ignore-dependencies ${remove_formulas}
          print '::endgroup::'

          local -A arch_names=(x86_64 intel arm64 apple)
          print "cpuName=${arch_names[${{ matrix.target }}]}" >> $GITHUB_OUTPUT

          local xcode_cas_path="${HOME}/Library/Developer/Xcode/DerivedData/CompilationCache.noindex"

          if ! [[ -d ${xcode_cas_path} ]] mkdir -p ${xcode_cas_path}

          print "xcodeCasPath=${xcode_cas_path}" >> $GITHUB_OUTPUT

      - uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830
        id: xcode-cache
        with:
          path: ${{ steps.setup.outputs.xcodeCasPath }}
          key: ${{ runner.os }}-xcode-${{ matrix.target }}-${{ needs.check-event.outputs.config }}
          restore-keys: |
            ${{ runner.os }}-xcode-${{ matrix.target }}-

      - name: Set Up Code Signing 🔑
        uses: ./.github/actions/setup-macos-codesigning
        if: fromJSON(needs.check-event.outputs.codesign)
        id: codesign
        with:
          codesignIdentity: ${{ secrets.MACOS_SIGNING_IDENTITY }}
          codesignCertificate: ${{ secrets.MACOS_SIGNING_CERT }}
          certificatePassword: ${{ secrets.MACOS_SIGNING_CERT_PASSWORD }}
          keychainPassword: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }}
          provisioningProfile: ${{ secrets.MACOS_SIGNING_PROVISIONING_PROFILE }}
          notarizationUser: ${{ secrets.MACOS_NOTARIZATION_USERNAME }}
          notarizationPassword: ${{ secrets.MACOS_NOTARIZATION_PASSWORD }}

      - name: Build OBS Studio 🧱
        uses: ./.github/actions/build-obs
        env:
          TWITCH_CLIENTID: ${{ secrets.TWITCH_CLIENT_ID }}
          TWITCH_HASH: ${{ secrets.TWITCH_HASH }}
          RESTREAM_CLIENTID: ${{ secrets.RESTREAM_CLIENTID }}
          RESTREAM_HASH: ${{ secrets.RESTREAM_HASH }}
          YOUTUBE_CLIENTID: ${{ secrets.YOUTUBE_CLIENTID }}
          YOUTUBE_CLIENTID_HASH: ${{ secrets.YOUTUBE_CLIENTID_HASH }}
          YOUTUBE_SECRET: ${{ secrets.YOUTUBE_SECRET }}
          YOUTUBE_SECRET_HASH: ${{ secrets.YOUTUBE_SECRET_HASH }}
          XCODE_CAS_PATH: ${{ steps.setup.outputs.xcodeCasPath }}
        with:
          target: ${{ matrix.target }}
          config: ${{ needs.check-event.outputs.config }}
          codesign: ${{ fromJSON(needs.check-event.outputs.codesign) }}
          codesignIdent: ${{ steps.codesign.outputs.codesignIdent }}
          codesignTeam: ${{ steps.codesign.outputs.codesignTeam }}
          provisioningProfileUUID: ${{ steps.codesign.outputs.provisioningProfileUUID }}

      - name: Package OBS Studio 📀
        uses: ./.github/actions/package-obs
        with:
          target: ${{ matrix.target }}
          config: ${{ needs.check-event.outputs.config }}
          package: ${{ fromJSON(needs.check-event.outputs.package) }}
          codesign: ${{ fromJSON(needs.check-event.outputs.codesign) && fromJSON(steps.codesign.outputs.haveCodesignIdent) }}
          codesignIdent: ${{ steps.codesign.outputs.codesignIdent }}
          notarize: ${{ fromJSON(needs.check-event.outputs.notarize) && fromJSON(steps.codesign.outputs.haveNotarizationUser) }}
          codesignUser: ${{ secrets.MACOS_NOTARIZATION_USERNAME }}
          codesignPass: ${{ secrets.MACOS_NOTARIZATION_PASSWORD }}

      - name: Upload Artifacts 📡
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
        with:
          name: obs-studio-macos-${{ matrix.target }}-${{ needs.check-event.outputs.commitHash }}
          path: ${{ github.workspace }}/build_macos/obs-studio-*-macos-${{ steps.setup.outputs.cpuName }}.*

      - name: Upload Debug Symbol Artifacts 🪲
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
        if: ${{ needs.check-event.outputs.config == 'Release' }}
        with:
          name: obs-studio-macos-${{ matrix.target }}-${{ needs.check-event.outputs.commitHash }}-dSYMs
          path: ${{ github.workspace }}/build_macos/obs-studio-*-macos-${{ steps.setup.outputs.cpuName }}-dSYMs.tar.xz

      - uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830
        if: github.event_name != 'pull_request' && steps.xcode-cache.outputs.cache-hit != 'true'
        with:
          path: ${{ steps.setup.outputs.xcodeCasPath }}
          key: ${{ runner.os }}-xcode-${{ matrix.target }}-${{ needs.check-event.outputs.config }}

  ubuntu-build:
    name: Ubuntu 🐧
    strategy:
      matrix:
        os: [ubuntu-24.04]
    runs-on: ${{ matrix.os }}
    needs: check-event
    defaults:
      run:
        shell: bash
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
        with:
          submodules: recursive
          fetch-depth: 0

      - uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830
        id: ccache-cache
        with:
          path: ${{ github.workspace }}/.ccache
          key: ${{ runner.os }}-${{ matrix.os }}-ccache-x86_64-${{ needs.check-event.outputs.config }}
          restore-keys: |
            ${{ runner.os }}-${{ matrix.os }}-ccache-x86_64-

      - name: Build OBS Studio 🧱
        uses: ./.github/actions/build-obs
        env:
          TWITCH_CLIENTID: ${{ secrets.TWITCH_CLIENT_ID }}
          TWITCH_HASH: ${{ secrets.TWITCH_HASH }}
          RESTREAM_CLIENTID: ${{ secrets.RESTREAM_CLIENTID }}
          RESTREAM_HASH: ${{ secrets.RESTREAM_HASH }}
          YOUTUBE_CLIENTID: ${{ secrets.YOUTUBE_CLIENTID }}
          YOUTUBE_CLIENTID_HASH: ${{ secrets.YOUTUBE_CLIENTID_HASH }}
          YOUTUBE_SECRET: ${{ secrets.YOUTUBE_SECRET }}
          YOUTUBE_SECRET_HASH: ${{ secrets.YOUTUBE_SECRET_HASH }}
        with:
          target: x86_64
          config: ${{ needs.check-event.outputs.config }}

      - name: Package OBS Studio 📀
        uses: ./.github/actions/package-obs
        with:
          target: x86_64
          config: ${{ needs.check-event.outputs.config }}
          package: ${{ fromJSON(needs.check-event.outputs.package) }}

      - name: Upload Source Tarball 🗜️
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
        with:
          name: obs-studio-${{ matrix.os }}-sources-${{ needs.check-event.outputs.commitHash }}
          path: ${{ github.workspace }}/build_ubuntu/obs-studio-*-sources.*

      - name: Upload Artifacts 📡
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
        with:
          name: obs-studio-${{ matrix.os }}-x86_64-${{ needs.check-event.outputs.commitHash }}
          path: ${{ github.workspace }}/build_ubuntu/obs-studio-*-x86_64-ubuntu-gnu.*

      - name: Upload Debug Symbol Artifacts 🪲
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
        if: ${{ fromJSON(needs.check-event.outputs.package) }}
        with:
          name: obs-studio-${{ matrix.os }}-x86_64-${{ needs.check-event.outputs.commitHash }}-dbgsym
          path: ${{ github.workspace }}/build_ubuntu/obs-studio-*-x86_64-ubuntu-gnu-dbgsym.ddeb

      - uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830
        if: github.event_name != 'pull_request' && steps.ccache-cache.outputs.cache-hit != 'true'
        with:
          path: ${{ github.workspace }}/.ccache
          key: ${{ runner.os }}-${{ matrix.os }}-ccache-x86_64-${{ needs.check-event.outputs.config }}

  flatpak-build:
    name: Flatpak 📦
    runs-on: ubuntu-24.04
    needs: check-event
    defaults:
      run:
        shell: bash
    env:
      FLATPAK_BUILD_SHARE_PATH: flatpak_app/files/share
    container:
      image: ghcr.io/flathub-infra/flatpak-github-actions:freedesktop-25.08
      options: --privileged
      volumes:
        - /usr/local/lib/android:/to_clean/android
        - /opt/hostedtoolcache/CodeQL:/to_clean/codeql
        - /usr/local/.ghcup:/to_clean/ghcup
        - /opt/hostedtoolcache/Python:/to_clean/python
        - /usr/share/swift:/to_clean/swift
        - /usr/share/dotnet:/to_clean/dotnet
    steps:
      - name: Prepare build space
        shell: bash
        run: |
          : Prepare build space

          echo ::group::Available storage
          df -h
          echo ::endgroup::

          echo ::group::Remove Android stuff
          rm -rf /to_clean/android/*
          echo ::endgroup::

          echo ::group::Remove CodeQL stuff
          rm -rf /to_clean/codeql/*
          echo ::endgroup::

          echo ::group::Remove GHCup stuff
          rm -rf /to_clean/ghcup/*
          echo ::endgroup::

          echo ::group::Remove Python stuff
          rm -rf /to_clean/python/*
          echo ::endgroup::

          echo ::group::Remove Swift stuff
          rm -rf /to_clean/swift/*
          echo ::endgroup::

          echo ::group::Remove .NET stuff
          rm -rf /to_clean/dotnet/*
          echo ::endgroup::

          echo ::group::Available storage
          df -h
          echo ::endgroup::

      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
        with:
          submodules: recursive
          fetch-depth: 0
          set-safe-directory: ${{ env.GITHUB_WORKSPACE }}

      - name: Set Up Environment 🔧
        id: setup
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          : Set Up Environment 🔧
          if [[ "${RUNNER_DEBUG}" ]]; then set -x; fi

          git config --global --add safe.directory "${GITHUB_WORKSPACE}"

          cache_key='flatpak-builder-${{ hashFiles('build-aux/com.obsproject.Studio.json') }}'
          cache_ref='master'
          read -r id key size unit created accessed <<< \
            "$(gh cache list --ref "refs/heads/${cache_ref}" --key "${cache_key}-x86_64" | head -1)"

          if [[ "${key}" ]]; then
            echo "cacheHit=true" >> $GITHUB_OUTPUT
          else
            echo "cacheHit=false" >> $GITHUB_OUTPUT
          fi

          echo "cacheKey=${cache_key}" >> $GITHUB_OUTPUT

      - name: Validate Flatpak manifest
        uses: ./.github/actions/flatpak-builder-lint
        with:
          artifact: manifest
          path: build-aux/com.obsproject.Studio.json

      - name: Build Flatpak Manifest 🧾
        uses: flatpak/flatpak-github-actions/flatpak-builder@b8a638469ea7ec62844d7b6e487b697e6f249576
        with:
          build-bundle: ${{ fromJSON(needs.check-event.outputs.package) }}
          bundle: obs-studio-flatpak-${{ needs.check-event.outputs.commitHash }}.flatpak
          manifest-path: ${{ github.workspace }}/build-aux/com.obsproject.Studio.json
          cache: ${{ fromJSON(steps.setup.outputs.cacheHit) || (github.event_name == 'push' && github.ref_name == 'master')}}
          restore-cache: ${{ fromJSON(steps.setup.outputs.cacheHit) }}
          cache-key: ${{ steps.setup.outputs.cacheKey }}
          mirror-screenshots-url: https://dl.flathub.org/media

      - name: Validate AppStream
        uses: ./.github/actions/flatpak-builder-lint
        with:
          artifact: appstream
          path: ${{ env.FLATPAK_BUILD_SHARE_PATH }}/metainfo/com.obsproject.Studio.metainfo.xml

      - name: Verify Icon and Metadata in app-info
        working-directory: ${{ env.FLATPAK_BUILD_SHARE_PATH }}
        run: |
          : Verify Icon and Metadata in app-info
          test -f app-info/icons/flatpak/128x128/com.obsproject.Studio.png || { echo "::error::Missing 128x128 icon in app-info"; exit 1; }
          test -f app-info/xmls/com.obsproject.Studio.xml.gz || { echo "::error::Missing com.obsproject.Studio.xml.gz in app-info"; exit 1; }

      - name: Validate build directory
        uses: ./.github/actions/flatpak-builder-lint
        with:
          artifact: builddir
          path: flatpak_app

      - name: Validate repository
        uses: ./.github/actions/flatpak-builder-lint
        with:
          artifact: repo
          path: repo

  windows-build:
    name: Windows 🪟
    strategy:
      matrix:
        architecture: [x64, arm64]
    runs-on: windows-2022
    needs: check-event
    defaults:
      run:
        shell: pwsh
    steps:
      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
        with:
          submodules: recursive
          fetch-depth: 0

      - name: Build OBS Studio 🧱
        uses: ./.github/actions/build-obs
        env:
          TWITCH_CLIENTID: ${{ secrets.TWITCH_CLIENT_ID }}
          TWITCH_HASH: ${{ secrets.TWITCH_HASH }}
          RESTREAM_CLIENTID: ${{ secrets.RESTREAM_CLIENTID }}
          RESTREAM_HASH: ${{ secrets.RESTREAM_HASH }}
          YOUTUBE_CLIENTID: ${{ secrets.YOUTUBE_CLIENTID }}
          YOUTUBE_CLIENTID_HASH: ${{ secrets.YOUTUBE_CLIENTID_HASH }}
          YOUTUBE_SECRET: ${{ secrets.YOUTUBE_SECRET }}
          YOUTUBE_SECRET_HASH: ${{ secrets.YOUTUBE_SECRET_HASH }}
          GPU_PRIORITY_VAL: ${{ secrets.GPU_PRIORITY_VAL }}
        with:
          target: ${{ matrix.architecture }}
          config: ${{ needs.check-event.outputs.config }}

      - name: Package OBS Studio 📀
        uses: ./.github/actions/package-obs
        with:
          target: ${{ matrix.architecture }}
          config: ${{ needs.check-event.outputs.config }}
          package: ${{ fromJSON(needs.check-event.outputs.package) }}

      - name: Upload Artifacts 📡
        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
        with:
          name: obs-studio-windows-${{ matrix.architecture }}-${{ needs.check-event.outputs.commitHash }}
          path: ${{ github.workspace }}/build_${{ matrix.architecture }}/obs-studio-*-windows-${{ matrix.architecture }}.zip
