Skip to content

release: v0.9.8

release: v0.9.8 #14

Workflow file for this run

# Builds the double-click TinyPlay desktop apps for Windows and macOS (both
# Apple Silicon and Intel), with mpv bundled, and attaches them to a GitHub
# Release when you push a v* tag.
#
# Windows → TinyPlay-windows.zip (TinyPlay.exe + mpv/, unzip & double-click)
# macOS → TinyPlay-macos-arm64.dmg (Apple Silicon)
# TinyPlay-macos-intel.dmg (Intel)
# signed+notarized, drag TinyPlay.app to
# Applications. Before the signing
# secrets exist each falls back to an
# unsigned TinyPlay-macos-<arch>.zip so
# the build still runs.
#
# macOS is Developer ID signed + notarized + stapled when the signing secrets
# are present, so users are not blocked by Gatekeeper ("unidentified developer").
# The signing job only runs on tag pushes / manual dispatch — never on pull
# requests — so the certificate secrets are never exposed to untrusted forks.
# Windows artifacts are UNSIGNED for now (no Windows code-signing certificate);
# users may still see a SmartScreen "unknown publisher" prompt.
#
# The Intel macOS leg cross-builds from the arm64 runner: the Go core and
# Swift shell cross-compile natively, but bundling a real x86_64 mpv binary
# needs an x86_64 Homebrew prefix, which this job installs under Rosetta
# (adds a few minutes of extra job time versus the native arm64 leg).
name: release
on:
push:
tags: ["v*"]
workflow_dispatch:
permissions:
contents: write
jobs:
windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.22"
- name: Download & bundle mpv
shell: bash
run: |
set -euo pipefail
api=$(curl -sL https://api.github.com/repos/zhongfly/mpv-winbuild/releases/latest)
# Pick the plain x86_64 build (not the -v3- or -dev- variants).
url=$(echo "$api" | grep -oE 'https://[^"]*mpv-x86_64-2[0-9]+[^"]*\.7z' | head -1)
echo "mpv archive: $url"
curl -L -o mpv.7z "$url"
7z x mpv.7z -ompv_extract
mpv_exe=$(find mpv_extract -name mpv.exe | head -1)
mpv_dir=$(dirname "$mpv_exe")
mkdir -p dist/mpv
cp "$mpv_exe" dist/mpv/
# These builds are mostly static, but copy any sibling DLLs just in case.
cp "$mpv_dir"/*.dll dist/mpv/ 2>/dev/null || true
- name: Embed exe icon
shell: bash
run: |
go install github.com/akavel/rsrc@latest
"$(go env GOPATH)/bin/rsrc" -ico assets/icon.ico -o cmd/tvremote/rsrc_windows.syso
- name: Build exe
shell: bash
run: |
set -euo pipefail
if [[ "$GITHUB_REF" == refs/tags/* ]]; then VER="${GITHUB_REF_NAME#v}"; else VER="0.0.0-dev"; fi
go build -ldflags "-H windowsgui -X main.version=$VER" -o dist/TinyPlay.exe ./cmd/tvremote
- name: Bundle third-party notices
shell: bash
run: cp THIRD_PARTY_NOTICES.md dist/THIRD_PARTY_NOTICES.md
- name: Package zip
shell: bash
run: |
cd dist
7z a ../TinyPlay-windows.zip ./*
- uses: actions/upload-artifact@v4
with:
name: TinyPlay-windows
path: TinyPlay-windows.zip
- name: Attach to release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v2
with:
files: TinyPlay-windows.zip
macos:
strategy:
fail-fast: false
matrix:
include:
- arch: arm64
goarch: arm64
label: arm64
- arch: x86_64
goarch: amd64
label: intel
runs-on: macos-14 # Apple Silicon; the intel leg cross-builds (see notes above)
env:
# 'true' only when the signing secrets exist; gates the sign step so the
# build still succeeds (unsigned) before you've added them.
HAS_SIGNING: ${{ secrets.MACOS_CERTIFICATE != '' && secrets.SIGN_IDENTITY != '' }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.22"
- name: Build Go core (${{ matrix.goarch }})
run: GOOS=darwin GOARCH=${{ matrix.goarch }} go build -o build/tvremote-core-darwin-${{ matrix.goarch }} ./cmd/tvremote
- name: Install packaging tools (dylibbundler, create-dmg)
run: brew install dylibbundler create-dmg
- name: Install x86_64 Homebrew under Rosetta (intel leg only)
if: matrix.arch == 'x86_64'
run: |
set -euo pipefail
softwareupdate --install-rosetta --agree-to-license
if [ ! -x /usr/local/bin/brew ]; then
NONINTERACTIVE=1 arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi
# GitHub's runner image ships a pre-existing python.org install under
# /Library/Frameworks/Python.framework with matching /usr/local/bin
# symlinks (idle3, pip3, ...). --overwrite only applies to the
# formula named on the command line, not transitive build
# dependencies, so when brewing mpv pulls in python@3.x (only to
# build man pages) as a dependency, `brew link` on THAT dependency
# still aborts on those pre-existing symlinks even with --overwrite
# here. mpv itself finishes installing regardless, so tolerate the
# failure and verify mpv is actually present instead of treating any
# non-zero exit as fatal.
arch -x86_64 /usr/local/bin/brew install --overwrite mpv || true
if ! arch -x86_64 /usr/local/bin/brew list mpv >/dev/null 2>&1; then
echo "mpv did not install successfully" >&2
exit 1
fi
- name: Download & bundle mpv (self-contained via dylibbundler)
run: |
set -euo pipefail
if [ "${{ matrix.arch }}" = "x86_64" ]; then
real_mpv=$(readlink -f /usr/local/bin/mpv)
else
brew install mpv
real_mpv=$(readlink -f "$(brew --prefix)/bin/mpv")
fi
mkdir -p mpvstage/bin/libs
cp "$real_mpv" mpvstage/bin/mpv
chmod u+w mpvstage/bin/mpv
# Copy every non-system dylib next to the binary and rewrite load paths
# so the bundle runs on a machine without Homebrew. -cd/-of/-od keep it
# non-interactive (it otherwise prompts to create/overwrite and aborts).
dylibbundler -cd -of -od -b -x mpvstage/bin/mpv -d mpvstage/bin/libs -p @executable_path/libs/
- name: Build .app
run: |
set -euo pipefail
if [[ "$GITHUB_REF" == refs/tags/* ]]; then VER="${GITHUB_REF_NAME#v}"; else VER="0.0.0-dev"; fi
ARCH="${{ matrix.arch }}" VERSION="$VER" MPV_DIR="$PWD/mpvstage" REQUIRE_BUNDLED_MPV=1 ./macos/build-app.sh
# Import the Developer ID cert into a keychain that persists for the whole
# job, so both the app-signing and DMG-signing steps below can use it.
- name: Import signing certificate
if: ${{ env.HAS_SIGNING == 'true' }}
env:
MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
MACOS_CERTIFICATE_PWD: ${{ secrets.MACOS_CERTIFICATE_PWD }}
run: ./macos/import-cert.sh
- name: Sign & notarize app
if: ${{ env.HAS_SIGNING == 'true' }}
env:
SIGN_IDENTITY: ${{ secrets.SIGN_IDENTITY }}
AC_API_KEY: ${{ secrets.AC_API_KEY }}
AC_KEY_ID: ${{ secrets.AC_KEY_ID }}
AC_ISSUER_ID: ${{ secrets.AC_ISSUER_ID }}
run: ./macos/sign-notarize.sh "$PWD/build/TinyPlay.app"
- name: Package signed DMG
if: ${{ env.HAS_SIGNING == 'true' }}
env:
SIGN_IDENTITY: ${{ secrets.SIGN_IDENTITY }}
AC_API_KEY: ${{ secrets.AC_API_KEY }}
AC_KEY_ID: ${{ secrets.AC_KEY_ID }}
AC_ISSUER_ID: ${{ secrets.AC_ISSUER_ID }}
run: ./macos/make-dmg.sh "$PWD/build/TinyPlay.app" "$PWD/TinyPlay-macos-${{ matrix.label }}.dmg"
- name: Package unsigned zip (fallback before secrets exist)
if: ${{ env.HAS_SIGNING != 'true' }}
run: |
cd build
ditto -c -k --keepParent "TinyPlay.app" "../TinyPlay-macos-${{ matrix.label }}.zip"
- uses: actions/upload-artifact@v4
with:
name: TinyPlay-macos-${{ matrix.label }}
path: |
TinyPlay-macos-${{ matrix.label }}.dmg
TinyPlay-macos-${{ matrix.label }}.zip
if-no-files-found: warn
- name: Attach to release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v2
with:
files: |
TinyPlay-macos-${{ matrix.label }}.dmg
TinyPlay-macos-${{ matrix.label }}.zip