Compare commits

..

1 Commits

Author SHA1 Message Date
ReenigneArcher
5b863f760b feat(api): add openapi specification 2025-02-01 10:07:42 -05:00
174 changed files with 3364 additions and 4058 deletions

View File

@@ -0,0 +1,11 @@
# install dependencies for C++ analysis
set -e
chmod +x ./scripts/linux_build.sh
./scripts/linux_build.sh --skip-package --ubuntu-test-repo
# Delete CUDA
rm -rf ./build/cuda
# skip autobuild
echo "skip_autobuild=true" >> "$GITHUB_OUTPUT"

View File

@@ -0,0 +1,37 @@
# install dependencies for C++ analysis
set -e
# update pacman
pacman --noconfirm -Syu
# install dependencies
dependencies=(
"git"
"mingw-w64-ucrt-x86_64-boost"
"mingw-w64-ucrt-x86_64-cmake"
"mingw-w64-ucrt-x86_64-cppwinrt"
"mingw-w64-ucrt-x86_64-curl-winssl"
"mingw-w64-ucrt-x86_64-MinHook"
"mingw-w64-ucrt-x86_64-miniupnpc"
"mingw-w64-ucrt-x86_64-nlohmann-json"
"mingw-w64-ucrt-x86_64-nodejs"
"mingw-w64-ucrt-x86_64-nsis"
"mingw-w64-ucrt-x86_64-onevpl"
"mingw-w64-ucrt-x86_64-openssl"
"mingw-w64-ucrt-x86_64-opus"
"mingw-w64-ucrt-x86_64-toolchain"
)
pacman -S --noconfirm "${dependencies[@]}"
# build
mkdir -p build
cmake \
-B build \
-G Ninja \
-S . \
-DBUILD_DOCS=OFF \
-DBUILD_WERROR=ON
ninja -C build
# skip autobuild
echo "skip_autobuild=true" >> "$GITHUB_OUTPUT"

View File

@@ -0,0 +1,29 @@
# install dependencies for C++ analysis
set -e
# install dependencies
dependencies=(
"boost"
"cmake"
"miniupnpc"
"ninja"
"node"
"openssl@3"
"opus"
"pkg-config"
)
brew install "${dependencies[@]}"
# build
mkdir -p build
cmake \
-B build \
-G Ninja \
-S . \
-DBOOST_USE_STATIC=OFF \
-DBUILD_DOCS=OFF \
-DBUILD_WERROR=ON
ninja -C build
# skip autobuild
echo "skip_autobuild=true" >> "$GITHUB_OUTPUT"

View File

@@ -3,5 +3,4 @@ filename =
*.py
max-line-length = 120
extend-exclude =
.venv/
venv/

View File

@@ -5,15 +5,9 @@
blank_issues_enabled: false
contact_links:
- name: Discussions
url: https://github.com/orgs/LizardByte/discussions
about: Community discussions
- name: Questions
url: https://github.com/orgs/LizardByte/discussions
about: Ask questions
- name: Feature Requests
url: https://github.com/orgs/LizardByte/discussions
about: Request new features
- name: Support Center
url: https://app.lizardbyte.dev/support
about: Official LizardByte support
- name: Discussions
url: https://github.com/orgs/LizardByte/discussions
about: Community discussions, questions, and feature requests

49
.github/label-actions.yml vendored Normal file
View File

@@ -0,0 +1,49 @@
---
# This file is centrally managed in https://github.com/<organization>/.github/
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
# the above-mentioned repo.
# Configuration for Label Actions - https://github.com/dessant/label-actions
added:
comment: >
This feature has been added and will be available in the next release.
fixed:
comment: >
This issue has been fixed and will be available in the next release.
invalid:duplicate:
comment: >
:wave: @{issue-author}, this appears to be a duplicate of a pre-existing issue.
close: true
lock: true
unlabel: 'status:awaiting-triage'
-invalid:duplicate:
reopen: true
unlock: true
invalid:support:
comment: >
:wave: @{issue-author}, we use the issue tracker exclusively for bug reports.
However, this issue appears to be a support request. Please use our
[Support Center](https://app.lizardbyte.dev/support) for support issues. Thanks.
close: true
lock: true
lock-reason: 'off-topic'
unlabel: 'status:awaiting-triage'
-invalid:support:
reopen: true
unlock: true
invalid:template-incomplete:
issues:
comment: >
:wave: @{issue-author}, please edit your issue to complete the template with
all the required info. Your issue will be automatically closed in 5 days if
the template is not completed. Thanks.
prs:
comment: >
:wave: @{issue-author}, please edit your PR to complete the template with
all the required info. Your PR will be automatically closed in 5 days if
the template is not completed. Thanks.

View File

@@ -12,4 +12,3 @@ titleAndCommits: false
anyCommit: false
allowMergeCommits: false
allowRevertCommits: false
targetUrl: https://docs.lizardbyte.dev/latest/developers/contributing.html#creating-a-pull-request

View File

@@ -1,19 +1,12 @@
---
name: CI
permissions:
contents: read
on:
pull_request:
branches:
- master
types:
- opened
- synchronize
- reopened
branches: [master]
types: [opened, synchronize, reopened]
push:
branches:
- master
branches: [master]
workflow_dispatch:
concurrency:
@@ -24,6 +17,7 @@ jobs:
github_env:
name: GitHub Env Debug
runs-on: ubuntu-latest
steps:
- name: Dump github context
run: echo "$GITHUB_CONTEXT"
@@ -40,8 +34,6 @@ jobs:
release_generate_release_notes: ${{ steps.setup_release.outputs.release_generate_release_notes }}
release_tag: ${{ steps.setup_release.outputs.release_tag }}
release_version: ${{ steps.setup_release.outputs.release_version }}
permissions:
contents: write # read does not work to check squash and merge details
runs-on: ubuntu-latest
steps:
- name: Checkout
@@ -49,29 +41,50 @@ jobs:
- name: Setup Release
id: setup_release
uses: LizardByte/setup-release-action@v2025.612.120948
uses: LizardByte/setup-release-action@v2025.102.14715
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
setup_flatpak_matrix:
name: Setup Flatpak Matrix
runs-on: ubuntu-latest
steps:
- name: Set release details
id: flatpak_matrix
# https://www.cynkra.com/blog/2020-12-23-dynamic-gha
run: |
# determine which architectures to build
if [[ "${{ github.event_name }}" == "push" ]]; then
matrix=$((
echo '{ "arch" : ["x86_64", "aarch64"] }'
) | jq -c .)
else
matrix=$((
echo '{ "arch" : ["x86_64"] }'
) | jq -c .)
fi
echo $matrix
echo $matrix | jq .
echo "matrix=$matrix" >> $GITHUB_OUTPUT
outputs:
matrix: ${{ steps.flatpak_matrix.outputs.matrix }}
build_linux_flatpak:
name: Linux Flatpak
env:
APP_ID: dev.lizardbyte.app.Sunshine
NODE_VERSION: "20"
PLATFORM_VERSION: "23.08"
needs: setup_release
runs-on: ${{ matrix.runner }}
name: Linux Flatpak
runs-on: ubuntu-22.04
needs: [setup_release, setup_flatpak_matrix]
strategy:
fail-fast: false # false to test all, true to fail entire job if any fail
matrix:
include:
- arch: x86_64
runner: ubuntu-22.04
- arch: aarch64
runner: ubuntu-22.04-arm
matrix: ${{fromJson(needs.setup_flatpak_matrix.outputs.matrix)}}
steps:
- name: Maximize build space
if: matrix.arch == 'x86_64'
uses: easimon/maximize-build-space@v10
with:
root-reserve-mb: 10240
@@ -93,10 +106,12 @@ jobs:
node-version: ${{ env.NODE_VERSION }}
- name: Install npm dependencies
run: npm install --package-lock-only
run: |
npm install --package-lock-only
- name: Debug package-lock.json
run: cat package-lock.json
run: |
cat package-lock.json
- name: Setup python
id: python
@@ -111,7 +126,8 @@ jobs:
sudo apt-get update -y
sudo apt-get install -y \
cmake \
flatpak
flatpak \
qemu-user-static
sudo su $(whoami) -c "flatpak --user remote-add --if-not-exists flathub \
https://flathub.org/repo/flathub.flatpakrepo"
@@ -127,10 +143,12 @@ jobs:
- name: flatpak node generator
# https://github.com/flatpak/flatpak-builder-tools/blob/master/node/README.md
run: flatpak-node-generator npm package-lock.json
run: |
flatpak-node-generator npm package-lock.json
- name: Debug generated-sources.json
run: cat generated-sources.json
run: |
cat generated-sources.json
- name: Cache Flatpak build
uses: actions/cache@v4
@@ -175,7 +193,8 @@ jobs:
- name: Debug Manifest
working-directory: build
run: cat ${APP_ID}.yml
run: |
cat ${APP_ID}.yml
- name: Build Linux Flatpak
working-directory: build
@@ -208,27 +227,56 @@ jobs:
- name: Lint Flatpak
working-directory: build
run: |
exceptions_file="${{ github.workspace }}/packaging/linux/flatpak/exceptions.json"
echo "Linting flatpak manifest"
flatpak run --command=flatpak-builder-lint org.flatpak.Builder \
--exceptions \
--user-exceptions "${exceptions_file}" \
manifest \
${APP_ID}.yml
manifest ${APP_ID}.yml > _flatpak-lint-exceptions_manifest.json || true
echo "Linting flatpak repo"
# TODO: add arg
# --mirror-screenshots-url=https://dl.flathub.org/media \
flatpak run --command=flatpak-builder-lint org.flatpak.Builder \
--exceptions \
--user-exceptions "${exceptions_file}" \
repo \
repo
repo repo > _flatpak-lint-exceptions_repo.json || true
checks=(manifest repo)
exit_code=0
# check if files are equal
for check in "${checks[@]}"; do
echo "Validating $check"
# load baseline and result files
baseline="${{ github.workspace }}/packaging/linux/flatpak/flatpak-lint-baseline_${check}.json"
result="_flatpak-lint-exceptions_${check}.json"
# Extract errors from both JSON files
readarray -t result_errors < <(jq -r '.errors[]' "$result")
readarray -t baseline_errors < <(jq -r '.errors[]' "$baseline")
# Loop through result errors and check against baseline errors
for error in "${result_errors[@]}"; do
if printf '%s\n' "${baseline_errors[@]}" | grep -q -F "$error"; then
echo "::warning:: '$error'"
else
echo "::error:: '$error'"
exit_code=1
fi
done
done
# if exit code is not 0, print results
if [ $exit_code -ne 0 ]; then
echo "Manifest lint results:"
cat _flatpak-lint-exceptions_manifest.json
echo "Repo lint results:"
cat _flatpak-lint-exceptions_repo.json
fi
# exit with the correct code
exit $exit_code
- name: Package Flathub repo archive
# copy files required to generate the Flathub repo
if: matrix.arch == 'x86_64'
if: ${{ matrix.arch == 'x86_64' }}
run: |
mkdir -p flathub/modules
cp ./build/generated-sources.json ./flathub/
@@ -248,11 +296,10 @@ jobs:
with:
name: sunshine-linux-flatpak-${{ matrix.arch }}
path: artifacts/
if-no-files-found: error
- name: Create/Update GitHub Release
if: needs.setup_release.outputs.publish_release == 'true'
uses: LizardByte/create-release-action@v2025.612.13419
if: ${{ needs.setup_release.outputs.publish_release == 'true' }}
uses: LizardByte/create-release-action@v2025.102.13208
with:
allowUpdates: true
body: ${{ needs.setup_release.outputs.release_body }}
@@ -264,10 +311,8 @@ jobs:
build_linux:
name: Linux ${{ matrix.type }}
env:
APP_ID: dev.lizardbyte.app.Sunshine
runs-on: ubuntu-${{ matrix.dist }}
needs: setup_release
needs: [setup_release]
strategy:
fail-fast: false # false to test all, true to fail entire job if any fail
matrix:
@@ -275,6 +320,7 @@ jobs:
- type: AppImage
EXTRA_ARGS: '--appimage-build'
dist: 22.04
steps:
- name: Maximize build space
uses: easimon/maximize-build-space@v10
@@ -349,13 +395,14 @@ jobs:
--ubuntu-test-repo ${{ matrix.EXTRA_ARGS }}
- name: Set AppImage Version
if: matrix.type == 'AppImage'
if: |
matrix.type == 'AppImage'
run: |
version=${{ needs.setup_release.outputs.release_tag }}
echo "VERSION=${version}" >> $GITHUB_ENV
- name: Package Linux - AppImage
if: matrix.type == 'AppImage'
if: ${{ matrix.type == 'AppImage' }}
working-directory: build
run: |
# install sunshine to the DESTDIR
@@ -366,7 +413,7 @@ jobs:
chmod +x ./AppDir/AppRun
# variables
DESKTOP_FILE="${DESKTOP_FILE:-${APP_ID}.desktop}"
DESKTOP_FILE="${DESKTOP_FILE:-sunshine.desktop}"
ICON_FILE="${ICON_FILE:-sunshine.png}"
# AppImage
@@ -400,7 +447,7 @@ jobs:
rm -rf ./build/cuda
- name: Verify AppImage
if: matrix.type == 'AppImage'
if: ${{ matrix.type == 'AppImage' }}
run: |
wget https://github.com/TheAssassin/appimagelint/releases/download/continuous/appimagelint-x86_64.AppImage
chmod +x appimagelint-x86_64.AppImage
@@ -412,7 +459,6 @@ jobs:
with:
name: sunshine-linux-${{ matrix.type }}-${{ matrix.dist }}
path: artifacts/
if-no-files-found: error
- name: Install test deps
run: |
@@ -433,14 +479,12 @@ jobs:
Xvfb ${DISPLAY} -screen 0 1024x768x24 &
sleep 5 # give Xvfb time to start
./test_sunshine --gtest_color=yes --gtest_output=xml:test_results.xml
./test_sunshine --gtest_color=yes
- name: Generate gcov report
id: test_report
# any except canceled or skipped
if: >-
always() &&
(steps.test.outcome == 'success' || steps.test.outcome == 'failure')
if: always() && (steps.test.outcome == 'success' || steps.test.outcome == 'failure')
id: test_report
working-directory: build
run: |
${{ steps.python.outputs.python-path }} -m pip install gcovr
@@ -452,22 +496,6 @@ jobs:
--xml-pretty \
-o coverage.xml
- name: Upload test results to Codecov
# any except canceled or skipped
if: >-
always() &&
(steps.test.outcome == 'success' || steps.test.outcome == 'failure') &&
startsWith(github.repository, 'LizardByte/')
uses: codecov/test-results-action@v1
with:
disable_search: true
fail_ci_if_error: true
files: ./build/tests/test_results.xml
flags: ${{ runner.os }}
handle_no_reports_found: true
token: ${{ secrets.CODECOV_TOKEN }}
verbose: true
- name: Upload coverage
# any except canceled or skipped
if: >-
@@ -484,8 +512,8 @@ jobs:
verbose: true
- name: Create/Update GitHub Release
if: needs.setup_release.outputs.publish_release == 'true'
uses: LizardByte/create-release-action@v2025.612.13419
if: ${{ needs.setup_release.outputs.publish_release == 'true' }}
uses: LizardByte/create-release-action@v2025.102.13208
with:
allowUpdates: true
body: ${{ needs.setup_release.outputs.release_body }}
@@ -496,8 +524,7 @@ jobs:
token: ${{ secrets.GH_BOT_TOKEN }}
build_homebrew:
name: Homebrew (${{ matrix.os_name }}-${{ matrix.os_version }}${{ matrix.release == true && ' (Release)' || '' }})
needs: setup_release
needs: [setup_release]
strategy:
fail-fast: false # false to test all, true to fail entire job if any fail
matrix:
@@ -508,14 +535,14 @@ jobs:
os_name: "macos"
- os_version: "14"
os_name: "macos"
- os_version: "15"
os_name: "macos"
- os_version: "latest"
os_name: "ubuntu"
- os_version: "latest" # this job will only configure the formula for release, no validation
os_name: "ubuntu"
release: true
name: Homebrew (${{ matrix.os_name }}-${{ matrix.os_version }}${{ matrix.release == true && ' (Release)' || '' }})
runs-on: ${{ matrix.os_name }}-${{ matrix.os_version }}
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -527,19 +554,19 @@ jobs:
rm '/usr/local/bin/2to3-3.12'
rm '/usr/local/bin/idle3'
rm '/usr/local/bin/idle3.12'
rm '/usr/local/bin/idle3.13'
rm '/usr/local/bin/pip3.12'
rm '/usr/local/bin/pip3.13'
rm '/usr/local/bin/pydoc3'
rm '/usr/local/bin/pydoc3.12'
rm '/usr/local/bin/pydoc3.13'
rm '/usr/local/bin/python3'
rm '/usr/local/bin/python3.12'
rm '/usr/local/bin/python3.13'
rm '/usr/local/bin/python3-config'
rm '/usr/local/bin/python3.12'
rm '/usr/local/bin/python3.12-config'
rm '/usr/local/bin/python3.13-config'
brew install python3
brew install python
- name: Setup python
id: python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Configure formula
run: |
@@ -599,15 +626,16 @@ jobs:
cat ./homebrew/sunshine.rb
- name: Upload Artifacts
if: matrix.release
if: ${{ matrix.release }}
uses: actions/upload-artifact@v4
with:
name: sunshine-homebrew
path: homebrew/
if-no-files-found: error
- name: Setup Xvfb
if: matrix.release != true && runner.os == 'Linux'
if: |
matrix.release != true &&
runner.os == 'Linux'
run: |
sudo apt-get update -y
sudo apt-get install -y \
@@ -620,8 +648,9 @@ jobs:
- name: Validate Homebrew Formula
id: test
if: matrix.release != true
uses: LizardByte/homebrew-release-action@v2025.612.123332
if: |
matrix.release != true
uses: LizardByte/homebrew-release-action@v2024.1115.14934
with:
formula_file: ${{ github.workspace }}/homebrew/sunshine.rb
git_email: ${{ secrets.GH_BOT_EMAIL }}
@@ -630,14 +659,7 @@ jobs:
token: ${{ secrets.GH_BOT_TOKEN }}
validate: true
- name: Setup python
id: python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Generate gcov report
id: test_report
# any except canceled or skipped
# TODO: fix coverage, no .gcno files are being created
# TODO: .gcno files are supposed to be created next to .o files
@@ -646,8 +668,17 @@ jobs:
# always() &&
# matrix.release != true &&
# (steps.test.outcome == 'success' || steps.test.outcome == 'failure')
id: test_report
run: |
cp -rf ${{ steps.test.outputs.buildpath }}/build/ ./build/
# if linux
if [ "${{ runner.os }}" == "Linux" ]; then
prefix="/tmp"
else
prefix="/private/tmp"
fi
brew_dir=$(find ${prefix} -type d -name "sunshine-*" -maxdepth 1 2>/dev/null)
cp -rf $brew_dir/build/ ./build/
cd build
ls -Ra
@@ -660,23 +691,6 @@ jobs:
--xml-pretty \
-o coverage.xml
- name: Upload test results to Codecov
# any except canceled or skipped
if: >-
always() &&
matrix.release != true &&
(steps.test.outcome == 'success' || steps.test.outcome == 'failure') &&
startsWith(github.repository, 'LizardByte/')
uses: codecov/test-results-action@v1
with:
disable_search: true
fail_ci_if_error: true
files: ${{ steps.test.outputs.testpath }}/test_results.xml
flags: ${{ matrix.os_name }}-${{ matrix.os_version }} (Homebrew)
handle_no_reports_found: true
token: ${{ secrets.CODECOV_TOKEN }}
verbose: true
- name: Upload coverage
# any except canceled or skipped
# TODO: enable this once coverage report is fixed
@@ -699,7 +713,7 @@ jobs:
if: >-
matrix.release &&
needs.setup_release.outputs.publish_release == 'true'
uses: LizardByte/create-release-action@v2025.612.13419
uses: LizardByte/create-release-action@v2025.102.13208
with:
allowUpdates: true
artifacts: '${{ github.workspace }}/homebrew/*'
@@ -713,7 +727,8 @@ jobs:
- name: Patch homebrew formula
# create beta version of the formula
# don't run this on macOS, as the sed command fails
if: matrix.release
if: >-
matrix.release
run: |
# variables
formula_file="homebrew/sunshine-beta.rb"
@@ -734,7 +749,7 @@ jobs:
github.repository_owner == 'LizardByte' &&
matrix.release &&
needs.setup_release.outputs.publish_release == 'true'
uses: LizardByte/homebrew-release-action@v2025.612.123332
uses: LizardByte/homebrew-release-action@v2024.1115.14934
with:
formula_file: ${{ github.workspace }}/homebrew/sunshine-beta.rb
git_email: ${{ secrets.GH_BOT_EMAIL }}
@@ -745,8 +760,9 @@ jobs:
build_win:
name: Windows
needs: setup_release
runs-on: windows-2022
runs-on: windows-2019
needs: [setup_release]
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -858,72 +874,27 @@ jobs:
Get-Content -Path monitor_list.txt
- name: Setup Dependencies Windows
# if a dependency needs to be pinned, see https://github.com/LizardByte/build-deps/pull/186
uses: msys2/setup-msys2@v2
with:
msystem: ucrt64
update: true
install: >-
git
mingw-w64-ucrt-x86_64-boost
mingw-w64-ucrt-x86_64-cmake
mingw-w64-ucrt-x86_64-cppwinrt
mingw-w64-ucrt-x86_64-curl-winssl
mingw-w64-ucrt-x86_64-graphviz
mingw-w64-ucrt-x86_64-MinHook
mingw-w64-ucrt-x86_64-miniupnpc
mingw-w64-ucrt-x86_64-nodejs
mingw-w64-ucrt-x86_64-nsis
mingw-w64-ucrt-x86_64-onevpl
mingw-w64-ucrt-x86_64-openssl
mingw-w64-ucrt-x86_64-opus
mingw-w64-ucrt-x86_64-toolchain
wget
- name: Update Windows dependencies
env:
MSYSTEM: "ucrt64"
TOOLCHAIN: "ucrt-x86_64"
shell: msys2 {0}
run: |
# variables
declare -A pinned_deps
# dependencies
dependencies=(
"git"
"mingw-w64-${TOOLCHAIN}-cmake"
"mingw-w64-${TOOLCHAIN}-cppwinrt"
"mingw-w64-${TOOLCHAIN}-curl-winssl"
"mingw-w64-${TOOLCHAIN}-gcc"
"mingw-w64-${TOOLCHAIN}-graphviz"
"mingw-w64-${TOOLCHAIN}-MinHook"
"mingw-w64-${TOOLCHAIN}-miniupnpc"
"mingw-w64-${TOOLCHAIN}-nlohmann-json"
"mingw-w64-${TOOLCHAIN}-nodejs"
"mingw-w64-${TOOLCHAIN}-nsis"
"mingw-w64-${TOOLCHAIN}-onevpl"
"mingw-w64-${TOOLCHAIN}-openssl"
"mingw-w64-${TOOLCHAIN}-opus"
"mingw-w64-${TOOLCHAIN}-toolchain"
)
# do not modify below this line
ignore_packages=()
tarballs=""
for pkg in "${!pinned_deps[@]}"; do
ignore_packages+=("${pkg}")
version="${pinned_deps[$pkg]}"
tarball="${pkg}-${version}-any.pkg.tar.zst"
# download working version
wget "https://repo.msys2.org/mingw/${MSYSTEM}/${tarball}"
tarballs="${tarballs} ${tarball}"
done
# Create the ignore string for pacman
ignore_list=$(IFS=,; echo "${ignore_packages[*]}")
# install pinned dependencies
if [ -n "$tarballs" ]; then
pacman -U --noconfirm ${tarballs}
fi
# Only add --ignore if we have packages to ignore
if [ -n "$ignore_list" ]; then
pacman -Syu --noconfirm --ignore="${ignore_list}" "${dependencies[@]}"
else
pacman -Syu --noconfirm "${dependencies[@]}"
fi
- name: Install Doxygen
# GCC compiled doxygen has issues when running graphviz
env:
@@ -971,7 +942,6 @@ jobs:
env:
BRANCH: ${{ github.head_ref || github.ref_name }}
BUILD_VERSION: ${{ needs.setup_release.outputs.release_tag }}
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
COMMIT: ${{ needs.setup_release.outputs.release_commit }}
run: |
mkdir -p build
@@ -1006,12 +976,12 @@ jobs:
shell: msys2 {0}
working-directory: build/tests
run: |
./test_sunshine.exe --gtest_color=yes --gtest_output=xml:test_results.xml
./test_sunshine.exe --gtest_color=yes
- name: Generate gcov report
id: test_report
# any except canceled or skipped
if: always() && (steps.test.outcome == 'success' || steps.test.outcome == 'failure')
id: test_report
shell: msys2 {0}
working-directory: build
run: |
@@ -1024,22 +994,6 @@ jobs:
--xml-pretty \
-o coverage.xml
- name: Upload test results to Codecov
# any except canceled or skipped
if: >-
always() &&
(steps.test.outcome == 'success' || steps.test.outcome == 'failure') &&
startsWith(github.repository, 'LizardByte/')
uses: codecov/test-results-action@v1
with:
disable_search: true
fail_ci_if_error: true
files: ./build/tests/test_results.xml
flags: ${{ runner.os }}
handle_no_reports_found: true
token: ${{ secrets.CODECOV_TOKEN }}
verbose: true
- name: Upload coverage
# any except canceled or skipped
if: >-
@@ -1073,11 +1027,10 @@ jobs:
with:
name: sunshine-windows
path: artifacts/
if-no-files-found: error
- name: Create/Update GitHub Release
if: needs.setup_release.outputs.publish_release == 'true'
uses: LizardByte/create-release-action@v2025.612.13419
if: ${{ needs.setup_release.outputs.publish_release == 'true' }}
uses: LizardByte/create-release-action@v2025.102.13208
with:
allowUpdates: true
body: ${{ needs.setup_release.outputs.release_body }}

View File

@@ -1,30 +0,0 @@
---
# This workflow is centrally managed in https://github.com/LizardByte/.github/
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
# the above-mentioned repo.
name: CodeQL
permissions:
actions: read
contents: read
security-events: write
on:
push:
branches:
- master
pull_request:
branches:
- master
schedule:
- cron: '00 12 * * 0' # every Sunday at 12:00 UTC
concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: true
jobs:
call-codeql:
name: CodeQL
uses: LizardByte/.github/.github/workflows/__call-codeql.yml@master
if: ${{ github.repository != 'LizardByte/.github' }}

View File

@@ -1,27 +0,0 @@
---
# This workflow is centrally managed in https://github.com/LizardByte/.github/
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
# the above-mentioned repo.
name: common lint
permissions:
contents: read
on:
pull_request:
branches:
- master
types:
- opened
- synchronize
- reopened
concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: true
jobs:
lint:
name: Common Lint
uses: LizardByte/.github/.github/workflows/__call-common-lint.yml@master
if: ${{ github.repository != 'LizardByte/.github' }}

View File

@@ -1,39 +0,0 @@
---
# This workflow is centrally managed in https://github.com/LizardByte/.github/
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
# the above-mentioned repo.
name: Docker
permissions:
contents: write
packages: write
on:
pull_request:
branches:
- master
types:
- opened
- synchronize
- reopened
push:
branches:
- master
workflow_dispatch:
concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: true
jobs:
call-docker:
name: Docker
uses: LizardByte/.github/.github/workflows/__call-docker.yml@master
if: ${{ github.repository != 'LizardByte/.github' }}
secrets:
DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }}
DOCKER_HUB_PASSWORD: ${{ secrets.DOCKER_HUB_PASSWORD }}
DOCKER_HUB_ACCESS_TOKEN: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
GH_BOT_NAME: ${{ secrets.GH_BOT_NAME }}
GH_BOT_TOKEN: ${{ secrets.GH_BOT_TOKEN }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,23 +0,0 @@
---
# This workflow is centrally managed in https://github.com/LizardByte/.github/
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
# the above-mentioned repo.
# Create a blog post for a new release and open a PR to the blog repo
name: Release Notifications
permissions:
contents: read
on:
release:
types:
- released # this triggers when a release is published, but does not include pre-releases or drafts
jobs:
update-blog:
name: Update blog
uses: LizardByte/.github/.github/workflows/__call-release-notifier.yml@master
if: github.repository_owner == 'LizardByte'
secrets:
GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }}

View File

@@ -1,31 +0,0 @@
---
# This workflow is centrally managed in https://github.com/LizardByte/.github/
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
# the above-mentioned repo.
name: Update changelog
permissions:
contents: read
on:
release:
types:
- created
- edited
- deleted
workflow_dispatch:
concurrency:
group: "${{ github.workflow }}"
cancel-in-progress: true
jobs:
update-changelog:
name: Update Changelog
uses: LizardByte/.github/.github/workflows/__call-update-changelog.yml@master
if: >-
github.repository_owner == 'LizardByte' &&
(github.event_name == 'workflow_dispatch' ||
(!github.event.release.prerelease && !github.event.release.draft))
secrets:
GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }}

View File

@@ -1,34 +0,0 @@
---
# This workflow is centrally managed in https://github.com/LizardByte/.github/
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
# the above-mentioned repo.
# To use, add the `rtd` repository label to identify repositories that should trigger this workflow.
# If the project slug is not the repository name, add a repository variable named `READTHEDOCS_SLUG` with the value of
# the ReadTheDocs project slug.
# Update readthedocs on release events.
name: Update docs
permissions: {}
on:
release:
types:
- created
- edited
- deleted
concurrency:
group: "${{ github.workflow }}-${{ github.event.release.tag_name }}"
cancel-in-progress: true
jobs:
update-docs:
name: Update docs
uses: LizardByte/.github/.github/workflows/__call-update-docs.yml@master
if: github.repository_owner == 'LizardByte'
with:
readthedocs_slug: ${{ vars.READTHEDOCS_SLUG }}
secrets:
READTHEDOCS_TOKEN: ${{ secrets.READTHEDOCS_TOKEN }}

View File

@@ -1,29 +0,0 @@
---
# This workflow is centrally managed in https://github.com/LizardByte/.github/
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
# the above-mentioned repo.
# To use, add the `flathub-pkg` repository label to identify repositories that should trigger this workflow.
# Update Flathub on release events.
name: Update Flathub repo
permissions:
contents: read
on:
release:
types:
- released
concurrency:
group: "${{ github.workflow }}-${{ github.event.release.tag_name }}"
cancel-in-progress: true
jobs:
update-flathub-repo:
name: Update Flathub Repo
uses: LizardByte/.github/.github/workflows/__call-update-flathub-repo.yml@master
if: github.repository_owner == 'LizardByte'
secrets:
GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }}

View File

@@ -1,31 +0,0 @@
---
# This workflow is centrally managed in https://github.com/LizardByte/.github/
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
# the above-mentioned repo.
# To use, add the `homebrew-pkg` repository label to identify repositories that should trigger this workflow.
# Update Homebrew on release events.
name: Update Homebrew repo
permissions:
contents: read
on:
release:
types:
- released
concurrency:
group: "${{ github.workflow }}-${{ github.event.release.tag_name }}"
cancel-in-progress: true
jobs:
update-homebrew-repo:
name: Update Homebrew repo
uses: LizardByte/.github/.github/workflows/__call-update-homebrew-repo.yml@master
if: github.repository_owner == 'LizardByte'
secrets:
GH_EMAIL: ${{ secrets.GH_BOT_EMAIL }}
GH_USERNAME: ${{ secrets.GH_BOT_NAME }}
GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }}

View File

@@ -1,29 +0,0 @@
---
# This workflow is centrally managed in https://github.com/LizardByte/.github/
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
# the above-mentioned repo.
# To use, add the `pacman-pkg` repository label to identify repositories that should trigger this workflow.
# Update pacman repo on release events.
name: Update pacman repo
permissions:
contents: read
on:
release:
types:
- released
concurrency:
group: "${{ github.workflow }}-${{ github.event.release.tag_name }}"
cancel-in-progress: true
jobs:
update-homebrew-release:
name: Update pacman repo
uses: LizardByte/.github/.github/workflows/__call-update-pacman-repo.yml@master
if: github.repository_owner == 'LizardByte'
secrets:
GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }}

View File

@@ -1,29 +0,0 @@
---
# This workflow is centrally managed in https://github.com/LizardByte/.github/
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
# the above-mentioned repo.
# To use, add the `winget-pkg` repository label to identify repositories that should trigger this workflow.
# Update Winget on release events.
name: Update Winget repo
permissions:
contents: read
on:
release:
types:
- released
concurrency:
group: "${{ github.workflow }}-${{ github.event.release.tag_name }}"
cancel-in-progress: true
jobs:
update-winget-repo:
name: Update Winget repo
uses: LizardByte/.github/.github/workflows/__call-update-winget-repo.yml@master
if: github.repository_owner == 'LizardByte'
secrets:
GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }}

View File

@@ -1,7 +1,5 @@
---
name: CI Copr
permissions:
contents: read
on:
pull_request:
@@ -28,7 +26,7 @@ jobs:
github_org_owner: LizardByte
copr_ownername: lizardbyte
auto_update_package: true
job_timeout: 90
job_timeout: 60
secrets:
COPR_BETA_WEBHOOK_TOKEN: ${{ secrets.COPR_BETA_WEBHOOK_TOKEN }}
COPR_STABLE_WEBHOOK_TOKEN: ${{ secrets.COPR_STABLE_WEBHOOK_TOKEN }}

366
.github/workflows/ci-docker.yml vendored Normal file
View File

@@ -0,0 +1,366 @@
---
# This action is centrally managed in https://github.com/<organization>/.github/
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
# the above-mentioned repo.
# This workflow is intended to work with all our organization Docker projects. A readme named `DOCKER_README.md`
# will be used to update the description on Docker hub.
# custom comments in dockerfiles:
# `# platforms: `
# Comma separated list of platforms, i.e. `# platforms: linux/386,linux/amd64`. Docker platforms can alternatively
# be listed in a file named `.docker_platforms`.
# `# platforms_pr: `
# Comma separated list of platforms to run for PR events, i.e. `# platforms_pr: linux/amd64`. This will take
# precedence over the `# platforms: ` directive.
# `# artifacts: `
# `true` to build in two steps, stopping at `artifacts` build stage and extracting the image from there to the
# GitHub runner.
name: CI Docker
on:
pull_request:
branches: [master]
types: [opened, synchronize, reopened]
push:
branches: [master]
workflow_dispatch:
concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: true
jobs:
check_dockerfiles:
name: Check Dockerfiles
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Find dockerfiles
id: find
run: |
dockerfiles=$(find . -type f -iname "Dockerfile" -o -iname "*.dockerfile")
echo "found dockerfiles: ${dockerfiles}"
# do not quote to keep this as a single line
echo dockerfiles=${dockerfiles} >> $GITHUB_OUTPUT
MATRIX_COMBINATIONS=""
for FILE in ${dockerfiles}; do
# extract tag from file name
tag=$(echo $FILE | sed -r -z -e 's/(\.\/)*.*\/(Dockerfile)/None/gm')
if [[ $tag == "None" ]]; then
MATRIX_COMBINATIONS="$MATRIX_COMBINATIONS {\"dockerfile\": \"$FILE\"},"
else
tag=$(echo $FILE | sed -r -z -e 's/(\.\/)*.*\/(.+)(\.dockerfile)/-\2/gm')
MATRIX_COMBINATIONS="$MATRIX_COMBINATIONS {\"dockerfile\": \"$FILE\", \"tag\": \"$tag\"},"
fi
done
# removes the last character (i.e. comma)
MATRIX_COMBINATIONS=${MATRIX_COMBINATIONS::-1}
# setup matrix for later jobs
matrix=$((
echo "{ \"include\": [$MATRIX_COMBINATIONS] }"
) | jq -c .)
echo $matrix
echo $matrix | jq .
echo "matrix=$matrix" >> $GITHUB_OUTPUT
- name: Find dotnet solution file
id: find_dotnet
run: |
solution=$(find . -maxdepth 1 -type f -iname "*.sln")
echo "found solution: ${solution}"
# do not quote to keep this as a single line
echo solution=${solution} >> $GITHUB_OUTPUT
if [[ $solution != "" ]]; then
echo "dotnet=true" >> $GITHUB_OUTPUT
else
echo "dotnet=false" >> $GITHUB_OUTPUT
fi
outputs:
dockerfiles: ${{ steps.find.outputs.dockerfiles }}
matrix: ${{ steps.find.outputs.matrix }}
dotnet: ${{ steps.find_dotnet.outputs.dotnet }}
solution: ${{ steps.find_dotnet.outputs.solution }}
setup_release:
if: ${{ needs.check_dockerfiles.outputs.dockerfiles }}
name: Setup Release
needs:
- check_dockerfiles
outputs:
publish_release: ${{ steps.setup_release.outputs.publish_release }}
release_body: ${{ steps.setup_release.outputs.release_body }}
release_commit: ${{ steps.setup_release.outputs.release_commit }}
release_generate_release_notes: ${{ steps.setup_release.outputs.release_generate_release_notes }}
release_tag: ${{ steps.setup_release.outputs.release_tag }}
release_version: ${{ steps.setup_release.outputs.release_version }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Release
id: setup_release
uses: LizardByte/setup-release-action@v2025.102.14715
with:
dotnet: ${{ needs.check_dockerfiles.outputs.dotnet }}
github_token: ${{ secrets.GITHUB_TOKEN }}
docker:
needs: [check_dockerfiles, setup_release]
if: ${{ needs.check_dockerfiles.outputs.dockerfiles }}
runs-on: ubuntu-latest
permissions:
packages: write
contents: write
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.check_dockerfiles.outputs.matrix) }}
name: Docker${{ matrix.tag }}
steps:
- name: Maximize build space
uses: easimon/maximize-build-space@v10
with:
root-reserve-mb: 30720 # https://github.com/easimon/maximize-build-space#caveats
remove-dotnet: 'true'
remove-android: 'true'
remove-haskell: 'true'
remove-codeql: 'true'
remove-docker-images: 'true'
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Prepare
id: prepare
env:
NV: ${{ needs.setup_release.outputs.release_tag }}
run: |
# get branch name
BRANCH=${GITHUB_HEAD_REF}
RELEASE=${{ needs.setup_release.outputs.publish_release }}
COMMIT=${{ needs.setup_release.outputs.release_commit }}
if [ -z "$BRANCH" ]; then
echo "This is a PUSH event"
BRANCH=${{ github.ref_name }}
CLONE_URL=${{ github.event.repository.clone_url }}
else
echo "This is a PULL REQUEST event"
CLONE_URL=${{ github.event.pull_request.head.repo.clone_url }}
fi
# determine to push image to dockerhub and ghcr or not
if [[ $GITHUB_EVENT_NAME == "push" ]]; then
PUSH=true
else
PUSH=false
fi
# setup the tags
REPOSITORY=${{ github.repository }}
BASE_TAG=$(echo $REPOSITORY | tr '[:upper:]' '[:lower:]')
TAGS="${BASE_TAG}:${COMMIT:0:7}${{ matrix.tag }},ghcr.io/${BASE_TAG}:${COMMIT:0:7}${{ matrix.tag }}"
if [[ $GITHUB_REF == refs/heads/master ]]; then
TAGS="${TAGS},${BASE_TAG}:latest${{ matrix.tag }},ghcr.io/${BASE_TAG}:latest${{ matrix.tag }}"
TAGS="${TAGS},${BASE_TAG}:master${{ matrix.tag }},ghcr.io/${BASE_TAG}:master${{ matrix.tag }}"
else
TAGS="${TAGS},${BASE_TAG}:test${{ matrix.tag }},ghcr.io/${BASE_TAG}:test${{ matrix.tag }}"
fi
if [[ ${NV} != "" ]]; then
TAGS="${TAGS},${BASE_TAG}:${NV}${{ matrix.tag }},ghcr.io/${BASE_TAG}:${NV}${{ matrix.tag }}"
fi
# parse custom directives out of dockerfile
# try to get the platforms from the dockerfile custom directive, i.e. `# platforms: xxx,yyy`
# directives for PR event, i.e. not push event
if [[ ${RELEASE} == "false" ]]; then
while read -r line; do
if [[ $line == "# platforms_pr: "* && $PLATFORMS == "" ]]; then
# echo the line and use `sed` to remove the custom directive
PLATFORMS=$(echo -e "$line" | sed 's/# platforms_pr: //')
elif [[ $PLATFORMS != "" ]]; then
# break while loop once all custom "PR" event directives are found
break
fi
done <"${{ matrix.dockerfile }}"
fi
# directives for all events... above directives will not be parsed if they were already found
while read -r line; do
if [[ $line == "# platforms: "* && $PLATFORMS == "" ]]; then
# echo the line and use `sed` to remove the custom directive
PLATFORMS=$(echo -e "$line" | sed 's/# platforms: //')
elif [[ $line == "# artifacts: "* && $ARTIFACTS == "" ]]; then
# echo the line and use `sed` to remove the custom directive
ARTIFACTS=$(echo -e "$line" | sed 's/# artifacts: //')
elif [[ $line == "# no-cache-filters: "* && $NO_CACHE_FILTERS == "" ]]; then
# echo the line and use `sed` to remove the custom directive
NO_CACHE_FILTERS=$(echo -e "$line" | sed 's/# no-cache-filters: //')
elif [[ $PLATFORMS != "" && $ARTIFACTS != "" && $NO_CACHE_FILTERS != "" ]]; then
# break while loop once all custom directives are found
break
fi
done <"${{ matrix.dockerfile }}"
# if PLATFORMS is blank, fall back to the legacy method of reading from the `.docker_platforms` file
if [[ $PLATFORMS == "" ]]; then
# read the platforms from `.docker_platforms`
PLATFORMS=$(<.docker_platforms)
fi
# if PLATFORMS is still blank, fall back to `linux/amd64`
if [[ $PLATFORMS == "" ]]; then
PLATFORMS="linux/amd64"
fi
echo "branch=${BRANCH}" >> $GITHUB_OUTPUT
echo "build_date=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
echo "clone_url=${CLONE_URL}" >> $GITHUB_OUTPUT
echo "artifacts=${ARTIFACTS}" >> $GITHUB_OUTPUT
echo "no_cache_filters=${NO_CACHE_FILTERS}" >> $GITHUB_OUTPUT
echo "platforms=${PLATFORMS}" >> $GITHUB_OUTPUT
echo "tags=${TAGS}" >> $GITHUB_OUTPUT
- name: Set Up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
id: buildx
- name: Cache Docker Layers
uses: actions/cache@v4
with:
path: /tmp/.buildx-cache
key: Docker-buildx${{ matrix.tag }}-${{ github.sha }}
restore-keys: |
Docker-buildx${{ matrix.tag }}-
- name: Log in to Docker Hub
if: ${{ needs.setup_release.outputs.publish_release == 'true' }} # PRs do not have access to secrets
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Log in to the Container registry
if: ${{ needs.setup_release.outputs.publish_release == 'true' }} # PRs do not have access to secrets
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ secrets.GH_BOT_NAME }}
password: ${{ secrets.GH_BOT_TOKEN }}
- name: Build artifacts
if: ${{ steps.prepare.outputs.artifacts == 'true' }}
id: build_artifacts
uses: docker/build-push-action@v6
with:
context: ./
file: ${{ matrix.dockerfile }}
target: artifacts
outputs: type=local,dest=artifacts
push: false
platforms: ${{ steps.prepare.outputs.platforms }}
build-args: |
BRANCH=${{ steps.prepare.outputs.branch }}
BUILD_DATE=${{ steps.prepare.outputs.build_date }}
BUILD_VERSION=${{ needs.setup_release.outputs.release_tag }}
COMMIT=${{ needs.setup_release.outputs.release_commit }}
CLONE_URL=${{ steps.prepare.outputs.clone_url }}
RELEASE=${{ needs.setup_release.outputs.publish_release }}
tags: ${{ steps.prepare.outputs.tags }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache
no-cache-filters: ${{ steps.prepare.outputs.no_cache_filters }}
- name: Build and push
id: build
uses: docker/build-push-action@v6
with:
context: ./
file: ${{ matrix.dockerfile }}
push: ${{ needs.setup_release.outputs.publish_release }}
platforms: ${{ steps.prepare.outputs.platforms }}
build-args: |
BRANCH=${{ steps.prepare.outputs.branch }}
BUILD_DATE=${{ steps.prepare.outputs.build_date }}
BUILD_VERSION=${{ needs.setup_release.outputs.release_tag }}
COMMIT=${{ needs.setup_release.outputs.release_commit }}
CLONE_URL=${{ steps.prepare.outputs.clone_url }}
RELEASE=${{ needs.setup_release.outputs.publish_release }}
tags: ${{ steps.prepare.outputs.tags }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache
no-cache-filters: ${{ steps.prepare.outputs.no_cache_filters }}
- name: Arrange Artifacts
if: ${{ steps.prepare.outputs.artifacts == 'true' }}
working-directory: artifacts
run: |
# debug directory
echo "Current directory: $(pwd)"
echo "Directory contents: $(ls -Ra)"
# artifacts will be in sub directories named after the docker target platform, e.g. `linux_amd64`
# so move files to the artifacts directory
# https://unix.stackexchange.com/a/52816
find \
./ \
-maxdepth 2 \
-mindepth 2 \
-type f \
-not -name 'provenance.json' \
-exec mv -t ./ -n '{}' +
# remove provenance file
rm -f ./provenance.json
- name: Upload Artifacts
if: ${{ steps.prepare.outputs.artifacts == 'true' }}
uses: actions/upload-artifact@v4
with:
name: Docker${{ matrix.tag }}
path: artifacts/
- name: Create/Update GitHub Release
if: ${{ needs.setup_release.outputs.publish_release == 'true' && steps.prepare.outputs.artifacts == 'true' }}
uses: LizardByte/create-release-action@v2025.102.13208
with:
allowUpdates: true
artifacts: "*artifacts/*"
body: ${{ needs.setup_release.outputs.release_body }}
generateReleaseNotes: ${{ needs.setup_release.outputs.release_generate_release_notes }}
name: ${{ needs.setup_release.outputs.release_tag }}
prerelease: true
tag: ${{ needs.setup_release.outputs.release_tag }}
token: ${{ secrets.GH_BOT_TOKEN }}
- name: Update Docker Hub Description
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
uses: peter-evans/dockerhub-description@v4
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }} # token is not currently supported
repository: ${{ env.BASE_TAG }}
short-description: ${{ github.event.repository.description }}
readme-filepath: ./DOCKER_README.md

214
.github/workflows/codeql.yml vendored Normal file
View File

@@ -0,0 +1,214 @@
---
# This action is centrally managed in https://github.com/<organization>/.github/
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
# the above-mentioned repo.
# This workflow will analyze all supported languages in the repository using CodeQL Analysis.
name: "CodeQL"
on:
push:
branches: ["master"]
pull_request:
branches: ["master"]
schedule:
- cron: '00 12 * * 0' # every Sunday at 12:00 UTC
concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: true
jobs:
languages:
name: Get language matrix
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.lang.outputs.result }}
continue: ${{ steps.continue.outputs.result }}
steps:
- name: Get repo languages
uses: actions/github-script@v7
id: lang
with:
script: |
// CodeQL supports ['cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby', 'swift']
// Use only 'java' to analyze code written in Java, Kotlin or both
// Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
// Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
const supported_languages = ['cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby', 'swift']
const remap_languages = {
'c++': 'cpp',
'c#': 'csharp',
'kotlin': 'java',
'typescript': 'javascript',
}
const repo = context.repo
const response = await github.rest.repos.listLanguages(repo)
let matrix = {
"include": []
}
for (let [key, value] of Object.entries(response.data)) {
// remap language
if (remap_languages[key.toLowerCase()]) {
console.log(`Remapping language: ${key} to ${remap_languages[key.toLowerCase()]}`)
key = remap_languages[key.toLowerCase()]
}
if (supported_languages.includes(key.toLowerCase())) {
console.log(`Found supported language: ${key}`)
let osList = ['ubuntu-latest'];
if (key.toLowerCase() === 'swift') {
osList = ['macos-latest'];
} else if (key.toLowerCase() === 'cpp') {
// TODO: update macos to latest after the below issue is resolved
// https://github.com/github/codeql-action/issues/2266
osList = ['macos-13', 'ubuntu-latest', 'windows-latest'];
}
for (let os of osList) {
// set name for matrix
if (osList.length == 1) {
name = key.toLowerCase()
} else {
name = `${key.toLowerCase()}, ${os}`
}
// add to matrix
matrix['include'].push({"language": key.toLowerCase(), "os": os, "name": name})
}
}
}
// print languages
console.log(`matrix: ${JSON.stringify(matrix)}`)
return matrix
- name: Continue
uses: actions/github-script@v7
id: continue
with:
script: |
// if matrix['include'] is an empty list return false, otherwise true
const matrix = ${{ steps.lang.outputs.result }} // this is already json encoded
if (matrix['include'].length == 0) {
return false
} else {
return true
}
analyze:
name: Analyze (${{ matrix.name }})
if: ${{ needs.languages.outputs.continue == 'true' }}
defaults:
run:
shell: ${{ matrix.os == 'windows-latest' && 'msys2 {0}' || 'bash' }}
env:
GITHUB_CODEQL_BUILD: true
needs: [languages]
runs-on: ${{ matrix.os || 'ubuntu-latest' }}
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.languages.outputs.matrix) }}
steps:
- name: Maximize build space
if: >-
runner.os == 'Linux' &&
matrix.language == 'cpp'
uses: easimon/maximize-build-space@v10
with:
root-reserve-mb: 30720
remove-dotnet: ${{ (matrix.language == 'csharp' && 'false') || 'true' }}
remove-android: 'true'
remove-haskell: 'true'
remove-codeql: 'false'
remove-docker-images: 'true'
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup msys2
if: >-
runner.os == 'Windows' &&
matrix.language == 'cpp'
uses: msys2/setup-msys2@v2
with:
msystem: ucrt64
update: true
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# yamllint disable-line rule:line-length
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
config: |
paths-ignore:
- build
- node_modules
- third-party
# Pre autobuild
# create a file named .codeql-prebuild-${{ matrix.language }}.sh in the root of your repository
# create a file named .codeql-build-${{ matrix.language }}.sh in the root of your repository
- name: Prebuild
id: prebuild
run: |
# check if prebuild script exists
filename=".codeql-prebuild-${{ matrix.language }}-${{ runner.os }}.sh"
if [ -f "./${filename}" ]; then
echo "Running prebuild script: ${filename}"
./${filename}
fi
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
- name: Autobuild
if: steps.prebuild.outputs.skip_autobuild != 'true'
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
output: sarif-results
upload: failure-only
- name: filter-sarif
uses: advanced-security/filter-sarif@v1
with:
input: sarif-results/${{ matrix.language }}.sarif
output: sarif-results/${{ matrix.language }}.sarif
patterns: |
-build/**
-node_modules/**
-third\-party/**
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: sarif-results/${{ matrix.language }}.sarif
- name: Upload loc as a Build Artifact
uses: actions/upload-artifact@v4
with:
name: sarif-results-${{ matrix.language }}-${{ runner.os }}
path: sarif-results
retention-days: 1

267
.github/workflows/common-lint.yml vendored Normal file
View File

@@ -0,0 +1,267 @@
---
# This action is centrally managed in https://github.com/<organization>/.github/
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
# the above-mentioned repo.
# Common linting.
name: common lint
on:
pull_request:
branches: [master]
types: [opened, synchronize, reopened]
concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: true
jobs:
lint:
name: Common Lint
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: |
python -m pip install --upgrade \
pip \
setuptools \
wheel \
cmakelang \
flake8 \
nb-clean \
nbqa[toolchain]
- name: C++ - find files
id: cpp_files
run: |
# find files
found_files=$(find . -type f \
-iname "*.c" -o \
-iname "*.cpp" -o \
-iname "*.h" -o \
-iname "*.hpp" -o \
-iname "*.m" -o \
-iname "*.mm" \
)
ignore_files=$(find . -type f -iname ".clang-format-ignore")
# Loop through each C++ file
for file in $found_files; do
for ignore_file in $ignore_files; do
ignore_directory=$(dirname "$ignore_file")
# if directory of ignore_file is beginning of file
if [[ "$file" == "$ignore_directory"* ]]; then
echo "ignoring file: ${file}"
found_files="${found_files//${file}/}"
break 1
fi
done
done
# remove empty lines
found_files=$(echo "$found_files" | sed '/^\s*$/d')
echo "found cpp files: ${found_files}"
# do not quote to keep this as a single line
echo found_files=${found_files} >> $GITHUB_OUTPUT
- name: C++ - Clang format lint
if: always() && steps.cpp_files.outputs.found_files
uses: DoozyX/clang-format-lint-action@v0.18
with:
source: ${{ steps.cpp_files.outputs.found_files }}
extensions: 'c,cpp,h,hpp,m,mm'
style: file
inplace: false
- name: CMake - find files
id: cmake_files
if: always()
run: |
# find files
found_files=$(find . -type f -iname "CMakeLists.txt" -o -iname "*.cmake")
ignore_files=$(find . -type f -iname ".cmake-lint-ignore")
# Loop through each C++ file
for file in $found_files; do
for ignore_file in $ignore_files; do
ignore_directory=$(dirname "$ignore_file")
# if directory of ignore_file is beginning of file
if [[ "$file" == "$ignore_directory"* ]]; then
echo "ignoring file: ${file}"
found_files="${found_files//${file}/}"
break 1
fi
done
done
# remove empty lines
found_files=$(echo "$found_files" | sed '/^\s*$/d')
echo "found cmake files: ${found_files}"
# do not quote to keep this as a single line
echo found_files=${found_files} >> $GITHUB_OUTPUT
- name: CMake - cmake-lint
if: always() && steps.cmake_files.outputs.found_files
run: |
cmake-lint --line-width 120 --tab-size 4 ${{ steps.cmake_files.outputs.found_files }}
- name: Docker - find files
id: dokcer_files
if: always()
run: |
found_files=$(find . -type f -iname "Dockerfile" -o -iname "*.dockerfile")
echo "found_files: ${found_files}"
# do not quote to keep this as a single line
echo found_files=${found_files} >> $GITHUB_OUTPUT
- name: Docker - hadolint
if: always() && steps.dokcer_files.outputs.found_files
run: |
docker pull hadolint/hadolint
# create hadolint config file
cat <<EOF > .hadolint.yaml
---
ignored:
- DL3008
- DL3013
- DL3016
- DL3018
- DL3028
- DL3059
EOF
failed=0
failed_files=""
for file in ${{ steps.dokcer_files.outputs.found_files }}; do
echo "::group::${file}"
docker run --rm -i \
-e "NO_COLOR=0" \
-e "HADOLINT_VERBOSE=1" \
-v $(pwd)/.hadolint.yaml:/.config/hadolint.yaml \
hadolint/hadolint < $file || {
failed=1
failed_files="$failed_files $file"
}
echo "::endgroup::"
done
if [ $failed -ne 0 ]; then
echo "::error:: hadolint failed for the following files: $failed_files"
exit 1
fi
- name: Python - flake8
if: always()
run: |
python -m flake8 \
--color=always \
--verbose
- name: Python - nbqa flake8
if: always()
run: |
python -m nbqa flake8 \
--color=always \
--verbose \
.
- name: Python - nb-clean
if: always()
run: |
output=$(find . -name '*.ipynb' -exec nb-clean check {} \;)
# fail if there are any issues
if [ -n "$output" ]; then
echo "$output"
exit 1
fi
- name: Rust - find Cargo.toml
id: run_cargo
if: always()
run: |
# check if Cargo.toml exists
if [ -f "Cargo.toml" ]; then
echo "found_cargo=true" >> $GITHUB_OUTPUT
else
echo "found_cargo=false" >> $GITHUB_OUTPUT
fi
- name: Rust - setup toolchain
if: always() && steps.run_cargo.outputs.found_cargo == 'true'
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- name: Rust - cargo fmt
if: always() && steps.run_cargo.outputs.found_cargo == 'true'
run: |
cargo fmt -- --check
- name: YAML - find files
id: yaml_files
if: always()
run: |
# space separated list of files
FILES=.clang-format
# empty placeholder
found_files=""
for FILE in ${FILES}; do
if [ -f "$FILE" ]
then
found_files="$found_files $FILE"
fi
done
echo "found_files=${found_files}" >> $GITHUB_OUTPUT
- name: YAML - yamllint
id: yamllint
if: always()
uses: ibiqlik/action-yamllint@v3
with:
# https://yamllint.readthedocs.io/en/stable/configuration.html#default-configuration
config_data: |
extends: default
rules:
comments:
level: error
document-start:
level: error
line-length:
max: 120
new-line-at-end-of-file:
level: error
new-lines:
type: unix
truthy:
# GitHub uses "on" for workflow event triggers
# .clang-format file has options of "Yes" "No" that will be caught by this, so changed to "warning"
allowed-values: ['true', 'false', 'on']
check-keys: true
level: warning
file_or_dir: . ${{ steps.yaml_files.outputs.found_files }}
- name: YAML - log
if: always() && steps.yamllint.outcome == 'failure'
run: |
cat "${{ steps.yamllint.outputs.logfile }}" >> $GITHUB_STEP_SUMMARY

25
.github/workflows/issues.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
---
# This action is centrally managed in https://github.com/<organization>/.github/
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
# the above-mentioned repo.
# Label and un-label actions using `../label-actions.yml`.
name: Issues
on:
issues:
types: [labeled, unlabeled]
discussion:
types: [labeled, unlabeled]
jobs:
label:
name: Label Actions
if: startsWith(github.repository, 'LizardByte/')
runs-on: ubuntu-latest
steps:
- name: Label Actions
uses: dessant/label-actions@v4
with:
github-token: ${{ secrets.GH_BOT_TOKEN }}

View File

@@ -1,13 +1,10 @@
---
name: localize
permissions:
contents: read
on:
push:
branches:
- master
paths:
branches: [master]
paths: # prevents workflow from running unless these files change
- '.github/workflows/localize.yml'
- 'src/**'
- 'locale/sunshine.po'
@@ -57,7 +54,7 @@ jobs:
python ./scripts/_locale.py --extract
- name: git diff
if: env.new_file == 'false'
if: ${{ env.new_file == 'false' }}
run: |
# disable the pager
git config --global pager.diff false
@@ -71,9 +68,7 @@ jobs:
- name: git reset
# only run if a single line changed (date/time) and file already existed
if: >-
env.git_diff == '1 1 locale/sunshine.po' &&
env.new_file == 'false'
if: ${{ env.git_diff == '1 1 locale/sunshine.po' && env.new_file == 'false' }}
run: |
git reset --hard

View File

@@ -1,6 +1,5 @@
---
name: Release Notifications (Moonlight)
permissions: {}
on:
release:
@@ -9,30 +8,20 @@ on:
jobs:
discord:
if: github.repository_owner == 'LizardByte'
if: >-
startsWith(github.repository, 'LizardByte/') &&
!github.event.release.prerelease &&
!github.event.release.draft
runs-on: ubuntu-latest
steps:
- name: Check if latest GitHub release
id: check-release
uses: actions/github-script@v7
with:
script: |
const latestRelease = await github.rest.repos.getLatestRelease({
owner: context.repo.owner,
repo: context.repo.repo
});
core.setOutput('isLatestRelease', latestRelease.data.tag_name === context.payload.release.tag_name);
- name: discord
if: steps.check-release.outputs.isLatestRelease == 'true'
uses: sarisia/actions-status-discord@v1
uses: sarisia/actions-status-discord@v1 # https://github.com/sarisia/actions-status-discord
with:
avatar_url: ${{ vars.ORG_LOGO_URL }}256
color: 0x${{ vars.COLOR_HEX_GREEN }}
description: ${{ github.event.release.body }}
webhook: ${{ secrets.DISCORD_RELEASE_WEBHOOK_MOONLIGHT }}
nodetail: true
nofail: false
title: ${{ github.event.repository.name }} ${{ github.ref_name }} Released
username: ${{ secrets.DISCORD_USERNAME }}
webhook: ${{ secrets.DISCORD_RELEASE_WEBHOOK_MOONLIGHT }}
avatar_url: ${{ secrets.ORG_LOGO_URL }}
title: ${{ github.event.repository.name }} ${{ github.ref_name }} Released
description: ${{ github.event.release.body }}
color: 0xFF4500

138
.github/workflows/release-notifier.yml vendored Normal file
View File

@@ -0,0 +1,138 @@
---
# This action is centrally managed in https://github.com/<organization>/.github/
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
# the above-mentioned repo.
# Create a blog post for a new release and open a PR to the blog repo
name: Release Notifications
on:
release:
types:
- released # this triggers when a release is published, but does not include pre-releases or drafts
jobs:
update-blog:
if: >-
github.repository_owner == 'LizardByte'
runs-on: ubuntu-latest
steps:
- name: Check topics
env:
TOPIC: replicator-release-notifications
id: check-label
uses: actions/github-script@v7
with:
script: |
const topic = process.env.TOPIC;
console.log(`Checking if repo has topic: ${topic}`);
const repoTopics = await github.rest.repos.getAllTopics({
owner: context.repo.owner,
repo: context.repo.repo
});
console.log(`Repo topics: ${repoTopics.data.names}`);
const hasTopic = repoTopics.data.names.includes(topic);
console.log(`Has topic: ${hasTopic}`);
core.setOutput('hasTopic', hasTopic);
- name: Check if latest GitHub release
id: check-release
if: >-
steps.check-label.outputs.hasTopic == 'true'
uses: actions/github-script@v7
with:
script: |
const latestRelease = await github.rest.repos.getLatestRelease({
owner: context.repo.owner,
repo: context.repo.repo
});
core.setOutput('isLatestRelease', latestRelease.data.tag_name === context.payload.release.tag_name);
- name: Checkout blog
if: >-
steps.check-label.outputs.hasTopic == 'true' &&
steps.check-release.outputs.isLatestRelease == 'true'
uses: actions/checkout@v4
with:
repository: "LizardByte/LizardByte.github.io"
- name: Create blog post
if: >-
steps.check-label.outputs.hasTopic == 'true' &&
steps.check-release.outputs.isLatestRelease == 'true'
run: |
# setup variables
tag_name="${{ github.event.release.tag_name }}"
semver="${tag_name#v}"
repo_lower="$(echo "${{ github.event.repository.name }}" | tr '[:upper:]' '[:lower:]')"
# extract year, month, and day
year="${semver%%.*}"
month_day="${semver#*.}"
month_day="${month_day%%.*}"
# ensure month_day is 4 digits
month_day=$(printf "%04d" "$month_day")
# create the filename
file_name="_posts/releases/${repo_lower}/${year}-${month_day:0:2}-${month_day:2:2}-v${semver}.md"
mkdir -p "$(dirname "${file_name}")"
# create jekyll blog post
echo "---" > "${file_name}"
echo "layout: release" >> "${file_name}"
echo "title: ${{ github.event.repository.name }} ${tag_name} Released" >> "${file_name}"
echo "release-tag: ${tag_name}" >> "${file_name}"
echo "gh-repo: ${{ github.repository }}" >> "${file_name}"
echo "gh-badge: [follow, fork, star]" >> "${file_name}"
echo "tags: [release, ${repo_lower}]" >> "${file_name}"
echo "comments: true" >> "${file_name}"
echo "author: LizardByte-bot" >> "${file_name}"
echo "---" >> "${file_name}"
echo "" >> "${file_name}"
release_body=$(cat <<EOF
${{ github.event.release.body }}
EOF
)
echo "${release_body}" >> "${file_name}"
- name: Create/Update Pull Request
id: create-pr
if: >-
steps.check-label.outputs.hasTopic == 'true' &&
steps.check-release.outputs.isLatestRelease == 'true'
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.GH_BOT_TOKEN }}
commit-message: |
chore: Add blog post for ${{ github.event.repository.name }} release ${{ github.event.release.tag_name }}
branch: bot/add-${{ github.event.repository.name }}-${{ github.event.release.tag_name }}
delete-branch: true
title: |
chore: Add blog post for ${{ github.event.repository.name }} release ${{ github.event.release.tag_name }}
body: ${{ github.event.release.body }}
labels:
blog
- name: Automerge PR
env:
GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }}
if: >-
steps.check-label.outputs.hasTopic == 'true' &&
steps.check-release.outputs.isLatestRelease == 'true'
run: |
gh \
pr \
merge \
--auto \
--delete-branch \
--repo "LizardByte/LizardByte.github.io" \
--squash \
"${{ steps.create-pr.outputs.pull-request-number }}"

31
.github/workflows/update-changelog.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
---
# This action is centrally managed in https://github.com/<organization>/.github/
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
# the above-mentioned repo.
# Update changelog on release events.
name: Update changelog
on:
release:
types: [created, edited, deleted]
workflow_dispatch:
concurrency:
group: "${{ github.workflow }}"
cancel-in-progress: true
jobs:
update-changelog:
if: >-
github.event_name == 'workflow_dispatch' ||
(!github.event.release.prerelease && !github.event.release.draft)
runs-on: ubuntu-latest
steps:
- name: Update Changelog
uses: LizardByte/update-changelog-action@v2024.919.152649
with:
changelogBranch: changelog
changelogFile: CHANGELOG.md
token: ${{ secrets.GH_BOT_TOKEN }}

96
.github/workflows/update-docs.yml vendored Normal file
View File

@@ -0,0 +1,96 @@
---
# This action is centrally managed in https://github.com/<organization>/.github/
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
# the above-mentioned repo.
# Use the `rtd` repository label to identify repositories that should trigger have this workflow.
# If the project slug is not the repository name, add a repository variable named `READTHEDOCS_SLUG` with the value of
# the ReadTheDocs project slug.
# Update readthedocs on release events.
name: Update docs
on:
release:
types: [created, edited, deleted]
concurrency:
group: "${{ github.workflow }}-${{ github.event.release.tag_name }}"
cancel-in-progress: true
jobs:
update-docs:
env:
RTD_SLUG: ${{ vars.READTHEDOCS_SLUG }}
RTD_TOKEN: ${{ secrets.READTHEDOCS_TOKEN }}
TAG: ${{ github.event.release.tag_name }}
if: >-
!github.event.release.draft
runs-on: ubuntu-latest
steps:
- name: Get RTD_SLUG
run: |
# if the RTD_SLUG is not set, use the repository name in lowercase
if [ -z "${RTD_SLUG}" ]; then
RTD_SLUG=$(echo "${{ github.event.repository.name }}" | tr '[:upper:]' '[:lower:]')
fi
echo "RTD_SLUG=${RTD_SLUG}" >> $GITHUB_ENV
- name: Deactivate deleted release
if: >-
github.event_name == 'release' &&
github.event.action == 'deleted'
run: |
json_body=$(jq -n \
--arg active "false" \
--arg hidden "false" \
--arg privacy_level "public" \
'{active: $active, hidden: $hidden, privacy_level: $privacy_level}')
curl \
-X PATCH \
-H "Authorization: Token ${RTD_TOKEN}" \
https://readthedocs.org/api/v3/projects/${RTD_SLUG}/versions/${TAG}/ \
-H "Content-Type: application/json" \
-d "$json_body"
- name: Check if edited release is latest GitHub release
id: check
if: >-
github.event_name == 'release' &&
github.event.action == 'edited'
uses: actions/github-script@v7
with:
script: |
const latestRelease = await github.rest.repos.getLatestRelease({
owner: context.repo.owner,
repo: context.repo.repo
});
core.setOutput('isLatestRelease', latestRelease.data.tag_name === context.payload.release.tag_name);
- name: Update RTD project
# changing the default branch in readthedocs makes "latest" point to that branch/tag
# we can also update other properties like description, etc.
if: >-
steps.check.outputs.isLatestRelease == 'true'
run: |
json_body=$(jq -n \
--arg default_branch "${TAG}" \
--arg description "${{ github.event.repository.description }}" \
'{default_branch: $default_branch}')
# change the default branch to the latest release
curl \
-X PATCH \
-H "Authorization: Token ${RTD_TOKEN}" \
-H "Content-Type: application/json" \
https://readthedocs.org/api/v3/projects/${RTD_SLUG}/ \
-d "$json_body"
# trigger a build for the latest version
curl \
-X POST \
-H "Authorization: Token ${RTD_TOKEN}" \
https://readthedocs.org/api/v3/projects/${RTD_SLUG}/versions/latest/builds/

View File

@@ -0,0 +1,187 @@
---
# This action is a candidate to centrally manage in https://github.com/<organization>/.github/
# If more Flathub applications are developed, consider moving this action to the organization's .github repository,
# using the `flathub-pkg` repository label to identify repositories that should trigger this workflow.
# Update Flathub on release events.
name: Update flathub repo
on:
release:
types: [released]
concurrency:
group: "${{ github.workflow }}-${{ github.event.release.tag_name }}"
cancel-in-progress: true
jobs:
update-flathub-repo:
env:
FLATHUB_PKG: dev.lizardbyte.app.${{ github.event.repository.name }}
if: >-
github.repository_owner == 'LizardByte'
runs-on: ubuntu-latest
steps:
- name: Check if flathub repo
env:
TOPIC: flathub-pkg
id: check-label
uses: actions/github-script@v7
with:
script: |
const topic = process.env.TOPIC;
console.log(`Checking if repo has topic: ${topic}`);
const repoTopics = await github.rest.repos.getAllTopics({
owner: context.repo.owner,
repo: context.repo.repo
});
console.log(`Repo topics: ${repoTopics.data.names}`);
const hasTopic = repoTopics.data.names.includes(topic);
console.log(`Has topic: ${hasTopic}`);
core.setOutput('hasTopic', hasTopic);
- name: Check if latest GitHub release
id: check-release
if: >-
steps.check-label.outputs.hasTopic == 'true'
uses: actions/github-script@v7
with:
script: |
const latestRelease = await github.rest.repos.getLatestRelease({
owner: context.repo.owner,
repo: context.repo.repo
});
core.setOutput('isLatestRelease', latestRelease.data.tag_name === context.payload.release.tag_name);
- name: Checkout
if: >-
steps.check-label.outputs.hasTopic == 'true' &&
steps.check-release.outputs.isLatestRelease == 'true'
uses: actions/checkout@v4
- name: Checkout flathub-repo
if: >-
steps.check-label.outputs.hasTopic == 'true' &&
steps.check-release.outputs.isLatestRelease == 'true'
uses: actions/checkout@v4
with:
repository: "flathub/${{ env.FLATHUB_PKG }}"
path: "flathub/${{ env.FLATHUB_PKG }}"
- name: Clean up legacy files
if: >-
steps.check-label.outputs.hasTopic == 'true' &&
steps.check-release.outputs.isLatestRelease == 'true'
working-directory: flathub/${{ env.FLATHUB_PKG }}
run: |
rm -rf ./*
- name: Copy github files
if: >-
steps.check-label.outputs.hasTopic == 'true' &&
steps.check-release.outputs.isLatestRelease == 'true'
working-directory: flathub/${{ env.FLATHUB_PKG }}
run: |
mkdir -p .github/ISSUE_TEMPLATE
# sponsors
curl -sSL https://github.com/LizardByte/.github/raw/refs/heads/master/.github/FUNDING.yml \
-o .github/FUNDING.yml
# pull request template
curl -sSL https://github.com/LizardByte/.github/raw/refs/heads/master/.github/pull_request_template.md \
-o .github/pull_request_template.md
# issue config
curl -sSL https://github.com/LizardByte/.github/raw/refs/heads/master/.github/ISSUE_TEMPLATE/config.yml \
-o .github/ISSUE_TEMPLATE/config.yml
- name: Download release asset
id: download
if: >-
steps.check-label.outputs.hasTopic == 'true' &&
steps.check-release.outputs.isLatestRelease == 'true'
uses: robinraju/release-downloader@v1.11
with:
repository: "${{ github.repository }}"
tag: "${{ github.event.release.tag_name }}"
fileName: "flathub.tar.gz"
tarBall: false
zipBall: false
out-file-path: "flathub/${{ env.FLATHUB_PKG }}"
extract: true
- name: Delete arhive
if: >-
steps.check-label.outputs.hasTopic == 'true' &&
steps.check-release.outputs.isLatestRelease == 'true'
run: |
rm -f flathub/${{ env.FLATHUB_PKG }}/flathub.tar.gz
- name: Update metainfo.xml
id: update_metainfo
if: >-
steps.check-label.outputs.hasTopic == 'true' &&
steps.check-release.outputs.isLatestRelease == 'true'
run: |
xml_file="flathub/${{ env.FLATHUB_PKG }}/${{ env.FLATHUB_PKG }}.metainfo.xml"
# Extract release information
version="${{ github.event.release.tag_name }}" && version="${version#v}"
date="${{ github.event.release.published_at }}" && date="${date%%T*}"
changelog="${{ github.event.release.body }}" && changelog="${changelog//&/&amp;}" && \
changelog="${changelog//</&lt;}" && changelog="${changelog//>/&gt;}"
# Store the old release information into a temp file to be used for precise replacement
tmpfile=$(mktemp)
# Match the existing <release> block, replace it with the new data
awk -v version="$version" -v date="$date" -v changelog="$changelog" '
BEGIN { replaced = 0 }
/<release version=.*>/ {
if (!replaced) {
print " <release version=\"" version "\" date=\"" date "\">"
print " <description><p>" changelog "</p></description>"
print " </release>"
replaced = 1
}
}
!/<release version=.*>/ && !/<\/release>/ { print $0 }
' "$xml_file" > "$tmpfile"
# Move the updated file back to the original location
mv "$tmpfile" "$xml_file"
- name: Update submodule
if: >-
steps.check-label.outputs.hasTopic == 'true' &&
steps.check-release.outputs.isLatestRelease == 'true'
run: |
# Get the current commit of the submodule in the main repository
git submodule update --init packaging/linux/flatpak/deps/shared-modules
cd ${{ github.workspace }}/packaging/linux/flatpak/deps/shared-modules
main_commit=$(git rev-parse HEAD)
# update submodules
cd ${{ github.workspace }}/flathub/${{ env.FLATHUB_PKG }}
git submodule update --init shared-modules
cd shared-modules
git checkout $main_commit
- name: Create/Update Pull Request
if: >-
steps.check-label.outputs.hasTopic == 'true' &&
steps.check-release.outputs.isLatestRelease == 'true' &&
fromJson(steps.download.outputs.downloaded_files)[0]
uses: peter-evans/create-pull-request@v7
with:
path: "flathub/${{ env.FLATHUB_PKG }}"
token: ${{ secrets.GH_BOT_TOKEN }}
commit-message: "chore: Update ${{ env.FLATHUB_PKG }} to ${{ github.event.release.tag_name }}"
branch: bot/bump-${{ env.FLATHUB_PKG }}-${{ github.event.release.tag_name }}
delete-branch: true
title: "chore: Update ${{ env.FLATHUB_PKG }} to ${{ github.event.release.tag_name }}"
body: ${{ github.event.release.body }}

View File

@@ -0,0 +1,70 @@
---
# This action is a candidate to centrally manage in https://github.com/<organization>/.github/
# If more Homebrew applications are developed, consider moving this action to the organization's .github repository,
# using the `homebrew-pkg` repository label to identify repositories that should trigger this workflow.
# Update Homebrew on release events.
name: Update Homebrew release
on:
release:
types: [released]
concurrency:
group: "${{ github.workflow }}-${{ github.event.release.tag_name }}"
cancel-in-progress: true
jobs:
update-homebrew-release:
if: >-
github.repository_owner == 'LizardByte'
runs-on: ubuntu-latest
steps:
- name: Check if Homebrew repo
env:
TOPIC: homebrew-pkg
id: check-label
uses: actions/github-script@v7
with:
script: |
const topic = process.env.TOPIC;
console.log(`Checking if repo has topic: ${topic}`);
const repoTopics = await github.rest.repos.getAllTopics({
owner: context.repo.owner,
repo: context.repo.repo
});
console.log(`Repo topics: ${repoTopics.data.names}`);
const hasTopic = repoTopics.data.names.includes(topic);
console.log(`Has topic: ${hasTopic}`);
core.setOutput('hasTopic', hasTopic);
- name: Download release asset
id: download
if: >-
steps.check-label.outputs.hasTopic == 'true'
uses: robinraju/release-downloader@v1.11
with:
repository: "${{ github.repository }}"
tag: "${{ github.event.release.tag_name }}"
fileName: "*.rb"
tarBall: false
zipBall: false
out-file-path: "release_downloads"
extract: false
- name: Publish Homebrew Formula
if: >-
steps.check-label.outputs.hasTopic == 'true' &&
fromJson(steps.download.outputs.downloaded_files)[0]
uses: LizardByte/homebrew-release-action@v2024.1115.14934
with:
formula_file: ${{ fromJson(steps.download.outputs.downloaded_files)[0] }}
git_email: ${{ secrets.GH_BOT_EMAIL }}
git_username: ${{ secrets.GH_BOT_NAME }}
publish: true
token: ${{ secrets.GH_BOT_TOKEN }}
validate: false

107
.github/workflows/update-pacman-repo.yml vendored Normal file
View File

@@ -0,0 +1,107 @@
---
# This action is a candidate to centrally manage in https://github.com/<organization>/.github/
# If more pacman packages are developed, consider moving this action to the organization's .github repository,
# using the `pacman-pkg` repository label to identify repositories that should trigger have this workflow.
# Update pacman repo on release events.
name: Update pacman repo
on:
release:
types: [released]
concurrency:
group: "${{ github.workflow }}-${{ github.event.release.tag_name }}"
cancel-in-progress: true
jobs:
update-homebrew-release:
if: >-
github.repository_owner == 'LizardByte'
runs-on: ubuntu-latest
steps:
- name: Check if pacman repo
env:
TOPIC: pacman-pkg
id: check-label
uses: actions/github-script@v7
with:
script: |
const topic = process.env.TOPIC;
console.log(`Checking if repo has topic: ${topic}`);
const repoTopics = await github.rest.repos.getAllTopics({
owner: context.repo.owner,
repo: context.repo.repo
});
console.log(`Repo topics: ${repoTopics.data.names}`);
const hasTopic = repoTopics.data.names.includes(topic);
console.log(`Has topic: ${hasTopic}`);
core.setOutput('hasTopic', hasTopic);
- name: Check if latest GitHub release
id: check-release
if: >-
steps.check-label.outputs.hasTopic == 'true'
uses: actions/github-script@v7
with:
script: |
const latestRelease = await github.rest.repos.getLatestRelease({
owner: context.repo.owner,
repo: context.repo.repo
});
core.setOutput('isLatestRelease', latestRelease.data.tag_name === context.payload.release.tag_name);
- name: Checkout pacman-repo
if: >-
steps.check-label.outputs.hasTopic == 'true' &&
steps.check-release.outputs.isLatestRelease == 'true'
uses: actions/checkout@v4
with:
repository: ${{ github.repository_owner }}/pacman-repo
- name: Prep
id: prep
if: >-
steps.check-label.outputs.hasTopic == 'true' &&
steps.check-release.outputs.isLatestRelease == 'true'
run: |
echo "pkg_name=$(echo ${{ github.event.repository.name }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
- name: Download release asset
id: download
if: >-
steps.check-label.outputs.hasTopic == 'true' &&
steps.check-release.outputs.isLatestRelease == 'true'
uses: robinraju/release-downloader@v1.11
with:
repository: "${{ github.repository }}"
tag: "${{ github.event.release.tag_name }}"
fileName: "*.pkg.tar.gz"
tarBall: false
zipBall: false
out-file-path: "pkgbuilds/${{ steps.prep.outputs.pkg_name }}"
extract: true
- name: Create/Update Pull Request
if: >-
steps.check-label.outputs.hasTopic == 'true' &&
steps.check-release.outputs.isLatestRelease == 'true' &&
fromJson(steps.download.outputs.downloaded_files)[0]
uses: peter-evans/create-pull-request@v7
with:
add-paths: |
pkgbuilds/*
token: ${{ secrets.GH_BOT_TOKEN }}
commit-message: "chore: Update ${{ github.repository }} to ${{ github.event.release.tag_name }}"
branch: bot/bump-${{ github.repository }}-${{ github.event.release.tag_name }}
delete-branch: true
title: "chore: Update ${{ github.repository }} to ${{ github.event.release.tag_name }}"
body: ${{ github.event.release.body }}
labels: |
auto-approve
auto-merge

View File

@@ -1,7 +1,5 @@
---
name: Build GH-Pages
permissions:
contents: read
on:
pull_request:
@@ -39,11 +37,11 @@ jobs:
call-jekyll-build:
needs: prep
uses: LizardByte/LizardByte.github.io/.github/workflows/jekyll-build.yml@master
with:
site_artifact: 'prep'
target_branch: 'gh-pages'
clean_gh_pages: true
secrets:
GH_BOT_EMAIL: ${{ secrets.GH_BOT_EMAIL }}
GH_BOT_NAME: ${{ secrets.GH_BOT_NAME }}
GH_BOT_TOKEN: ${{ secrets.GH_BOT_TOKEN }}
with:
clean_gh_pages: true
site_artifact: 'prep'
target_branch: 'gh-pages'

View File

@@ -0,0 +1,68 @@
---
# This action is a candidate to centrally manage in https://github.com/<organization>/.github/
# If more Winget applications are developed, consider moving this action to the organization's .github repository,
# using the `winget-pkg` repository label to identify repositories that should trigger this workflow.
# Update Winget on release events.
name: Update Winget release
on:
release:
types: [released]
concurrency:
group: "${{ github.workflow }}-${{ github.event.release.tag_name }}"
cancel-in-progress: true
jobs:
update-winget-release:
if: >-
github.repository_owner == 'LizardByte'
runs-on: ubuntu-latest
steps:
- name: Check if Winget repo
env:
TOPIC: winget-pkg
id: check-label
uses: actions/github-script@v7
with:
script: |
const topic = process.env.TOPIC;
console.log(`Checking if repo has topic: ${topic}`);
const repoTopics = await github.rest.repos.getAllTopics({
owner: context.repo.owner,
repo: context.repo.repo
});
console.log(`Repo topics: ${repoTopics.data.names}`);
const hasTopic = repoTopics.data.names.includes(topic);
console.log(`Has topic: ${hasTopic}`);
core.setOutput('hasTopic', hasTopic);
- name: Download release asset
id: download
if: >-
steps.check-label.outputs.hasTopic == 'true'
uses: robinraju/release-downloader@v1.11
with:
repository: "${{ github.repository }}"
tag: "${{ github.event.release.tag_name }}"
fileName: "*.exe"
tarBall: false
zipBall: false
out-file-path: "release_downloads"
extract: false
- name: Release to WinGet
if: >-
steps.check-label.outputs.hasTopic == 'true' &&
fromJson(steps.download.outputs.downloaded_files)[0]
uses: vedantmgoyal2009/winget-releaser@v2
with:
identifier: "${{ github.repository_owner }}.${{ github.event.repository.name }}"
release-tag: ${{ github.event.release.tag_name }}
installers-regex: '\.exe$'
token: ${{ secrets.GH_BOT_TOKEN }}

6
.gitmodules vendored
View File

@@ -44,7 +44,7 @@
branch = sdk
[submodule "third-party/Simple-Web-Server"]
path = third-party/Simple-Web-Server
url = https://github.com/LizardByte-infrastructure/Simple-Web-Server.git
url = https://gitlab.com/eidheim/Simple-Web-Server.git
branch = master
[submodule "third-party/TPCircularBuffer"]
path = third-party/TPCircularBuffer
@@ -60,9 +60,9 @@
branch = master
[submodule "third-party/wayland-protocols"]
path = third-party/wayland-protocols
url = https://github.com/LizardByte-infrastructure/wayland-protocols.git
url = https://gitlab.freedesktop.org/wayland/wayland-protocols.git
branch = main
[submodule "third-party/wlr-protocols"]
path = third-party/wlr-protocols
url = https://github.com/LizardByte-infrastructure/wlr-protocols.git
url = https://gitlab.freedesktop.org/wlroots/wlr-protocols.git
branch = master

View File

@@ -27,9 +27,6 @@ endif()
# set the module path, used for includes
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
# export compile_commands.json
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# set version info for this build
include(${CMAKE_MODULE_PATH}/prep/build_version.cmake)

View File

@@ -5,18 +5,42 @@
</div>
<div align="center">
<a href="https://github.com/LizardByte/Sunshine"><img src="https://img.shields.io/github/stars/lizardbyte/sunshine.svg?logo=github&style=for-the-badge" alt="GitHub stars"></a>
<a href="https://github.com/LizardByte/Sunshine/releases/latest"><img src="https://img.shields.io/github/downloads/lizardbyte/sunshine/total.svg?style=for-the-badge&logo=github" alt="GitHub Releases"></a>
<a href="https://hub.docker.com/r/lizardbyte/sunshine"><img src="https://img.shields.io/docker/pulls/lizardbyte/sunshine.svg?style=for-the-badge&logo=docker" alt="Docker"></a>
<a href="https://github.com/LizardByte/Sunshine/pkgs/container/sunshine"><img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fipitio.github.io%2Fbackage%2FLizardByte%2FSunshine%2Fsunshine.json&query=%24.downloads&label=ghcr%20pulls&style=for-the-badge&logo=github" alt="GHCR"></a>
<a href="https://flathub.org/apps/dev.lizardbyte.app.Sunshine"><img src="https://img.shields.io/flathub/downloads/dev.lizardbyte.app.Sunshine?style=for-the-badge&logo=flathub" alt="Flathub installs"></a>
<a href="https://flathub.org/apps/dev.lizardbyte.app.Sunshine"><img src="https://img.shields.io/flathub/v/dev.lizardbyte.app.Sunshine?style=for-the-badge&logo=flathub" alt="Flathub Version"></a>
<a href="https://github.com/microsoft/winget-pkgs/tree/master/manifests/l/LizardByte/Sunshine"><img src="https://img.shields.io/winget/v/LizardByte.Sunshine?style=for-the-badge&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHuSURBVFhH7ZfNTtRQGIYZiMDwN/IrCAqIhMSNKxcmymVwG+5dcDVsWHgDrtxwCYQVl+BChzDEwSnPY+eQ0sxoOz1mQuBNnpyvTdvz9jun5/SrjfxnJUkyQbMEz2ELduF1l0YUA3QyTrMAa2AnPtyOXsELeAYNyKtV2EC3k3lYgTOwg09ghy/BTp7CKBRV844BOpmmMV2+ySb4BmInG7AKY7AHH+EYqqhZo9PPBG/BVDlOizAD/XQFmnoPXzxRQX8M/CCYS48L6RIc4ygGHK9WGg9HZSZMUNRPVwNJGg5Hg2Qgqh4N3FsDsb6EmgYm07iwwvUxstdxJTwgmILf4CfZ6bb5OHANX8GN5x20IVxnG8ge94pt2xpwU3GnCwayF4Q2G2vgFLzHndFzQdk4q77nNfCdwL28qNyMtmEf3A1/QV5FjDiPWo5jrwf8TWZChTlgJvL4F9QL50/A43qVidTvLcuoM2wDQ1+IkgefgUpLcYwMVBqCKNJA2b0gKNocOIITOIef8C/F/CdMbh/GklynsSawKLHS8d9/B1x2LUqsfFyy3TMsWj5A1cLkotDbYO4JjWWZlZEGv8EbOIR1CAVN2eG8W5oNKgxaeC6DmTJjZs7ixUxpznLPLT+v4sXpoMLcLI3mzFSonDXIEI/M3QCIO4YuimBJ/gAAAABJRU5ErkJggg==" alt="Winget Version"></a>
<a href="https://gurubase.io/g/sunshine"><img src="https://img.shields.io/badge/Gurubase-Ask%20Guru-ef1a1b?style=for-the-badge&logo=data:image/jpeg;base64,/9j/2wCEAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDIBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIABgAGAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AOLqSO3mlilljido4QGkYDIQEgAn05IH41seFo7aS+uRKlrJci2Y2cd2QImlyOGyQPu7sA8ZxXapAlvpThbPRkv7nTQWhDoIZZRc/XaSAOmcZGOnFfP06XMr3P17F5iqE+Tl1uuvf9Lde55dRW74pit4r61EcdtFdG2U3kVqQY0lyeBgkD5duQOASawqykuV2O6jV9rTU0rXLNjf3Om3QubSXy5QCudoYEEYIIOQR7GnahqV3qk6zXk3mOqhFAUKqqOyqAAByeAKqUUXdrFezhz89lfv1+8KKKKRZ//Z" alt="Gurubase"></a>
<a href="https://github.com/LizardByte/Sunshine/actions/workflows/CI.yml?query=branch%3Amaster"><img src="https://img.shields.io/github/actions/workflow/status/lizardbyte/sunshine/CI.yml.svg?branch=master&label=CI%20build&logo=github&style=for-the-badge" alt="GitHub Workflow Status (CI)"></a>
<a href="https://github.com/LizardByte/Sunshine/actions/workflows/localize.yml?query=branch%3Amaster"><img src="https://img.shields.io/github/actions/workflow/status/lizardbyte/sunshine/localize.yml.svg?branch=master&label=localize%20build&logo=github&style=for-the-badge" alt="GitHub Workflow Status (localize)"></a>
<a href="https://docs.lizardbyte.dev/projects/sunshine"><img src="https://img.shields.io/readthedocs/sunshinestream.svg?label=Docs&style=for-the-badge&logo=readthedocs" alt="Read the Docs"></a>
<a href="https://codecov.io/gh/LizardByte/Sunshine"><img src="https://img.shields.io/codecov/c/gh/LizardByte/Sunshine?token=SMGXQ5NVMJ&style=for-the-badge&logo=codecov&label=codecov" alt="Codecov"></a>
<a href="https://github.com/LizardByte/Sunshine">
<img src="https://img.shields.io/github/stars/lizardbyte/sunshine.svg?logo=github&style=for-the-badge" alt="GitHub stars">
</a>
<a href="https://github.com/LizardByte/Sunshine/releases/latest">
<img src="https://img.shields.io/github/downloads/lizardbyte/sunshine/total.svg?style=for-the-badge&logo=github" alt="GitHub Releases">
</a>
<a href="https://hub.docker.com/r/lizardbyte/sunshine">
<img src="https://img.shields.io/docker/pulls/lizardbyte/sunshine.svg?style=for-the-badge&logo=docker" alt="Docker">
</a>
<a href="https://github.com/LizardByte/Sunshine/pkgs/container/sunshine">
<img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fipitio.github.io%2Fbackage%2FLizardByte%2FSunshine%2Fsunshine.json&query=%24.downloads&label=ghcr%20pulls&style=for-the-badge&logo=github" alt="GHCR">
</a>
<a href="https://flathub.org/apps/dev.lizardbyte.app.Sunshine">
<img src="https://img.shields.io/flathub/downloads/dev.lizardbyte.app.Sunshine?style=for-the-badge&logo=flathub" alt="Flathub installs">
</a>
<a href="https://flathub.org/apps/dev.lizardbyte.app.Sunshine">
<img src="https://img.shields.io/flathub/v/dev.lizardbyte.app.Sunshine?style=for-the-badge&logo=flathub" alt="Flathub Version">
</a>
<a href="https://github.com/microsoft/winget-pkgs/tree/master/manifests/l/LizardByte/Sunshine">
<img src="https://img.shields.io/winget/v/LizardByte.Sunshine?style=for-the-badge&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHuSURBVFhH7ZfNTtRQGIYZiMDwN/IrCAqIhMSNKxcmymVwG+5dcDVsWHgDrtxwCYQVl+BChzDEwSnPY+eQ0sxoOz1mQuBNnpyvTdvz9jun5/SrjfxnJUkyQbMEz2ELduF1l0YUA3QyTrMAa2AnPtyOXsELeAYNyKtV2EC3k3lYgTOwg09ghy/BTp7CKBRV844BOpmmMV2+ySb4BmInG7AKY7AHH+EYqqhZo9PPBG/BVDlOizAD/XQFmnoPXzxRQX8M/CCYS48L6RIc4ygGHK9WGg9HZSZMUNRPVwNJGg5Hg2Qgqh4N3FsDsb6EmgYm07iwwvUxstdxJTwgmILf4CfZ6bb5OHANX8GN5x20IVxnG8ge94pt2xpwU3GnCwayF4Q2G2vgFLzHndFzQdk4q77nNfCdwL28qNyMtmEf3A1/QV5FjDiPWo5jrwf8TWZChTlgJvL4F9QL50/A43qVidTvLcuoM2wDQ1+IkgefgUpLcYwMVBqCKNJA2b0gKNocOIITOIef8C/F/CdMbh/GklynsSawKLHS8d9/B1x2LUqsfFyy3TMsWj5A1cLkotDbYO4JjWWZlZEGv8EbOIR1CAVN2eG8W5oNKgxaeC6DmTJjZs7ixUxpznLPLT+v4sXpoMLcLI3mzFSonDXIEI/M3QCIO4YuimBJ/gAAAABJRU5ErkJggg==" alt="Winget Version">
</a>
<a href="https://gurubase.io/g/sunshine">
<img src="https://img.shields.io/badge/Gurubase-Ask%20Guru-ef1a1b?style=for-the-badge&logo=data:image/jpeg;base64,/9j/2wCEAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDIBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIABgAGAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AOLqSO3mlilljido4QGkYDIQEgAn05IH41seFo7aS+uRKlrJci2Y2cd2QImlyOGyQPu7sA8ZxXapAlvpThbPRkv7nTQWhDoIZZRc/XaSAOmcZGOnFfP06XMr3P17F5iqE+Tl1uuvf9Lde55dRW74pit4r61EcdtFdG2U3kVqQY0lyeBgkD5duQOASawqykuV2O6jV9rTU0rXLNjf3Om3QubSXy5QCudoYEEYIIOQR7GnahqV3qk6zXk3mOqhFAUKqqOyqAAByeAKqUUXdrFezhz89lfv1+8KKKKRZ//Z" alt="Gurubase">
</a>
<a href="https://github.com/LizardByte/Sunshine/actions/workflows/CI.yml?query=branch%3Amaster">
<img src="https://img.shields.io/github/actions/workflow/status/lizardbyte/sunshine/CI.yml.svg?branch=master&label=CI%20build&logo=github&style=for-the-badge" alt="GitHub Workflow Status (CI)">
</a>
<a href="https://github.com/LizardByte/Sunshine/actions/workflows/localize.yml?query=branch%3Amaster">
<img src="https://img.shields.io/github/actions/workflow/status/lizardbyte/sunshine/localize.yml.svg?branch=master&label=localize%20build&logo=github&style=for-the-badge" alt="GitHub Workflow Status (localize)">
</a>
<a href="https://docs.lizardbyte.dev/projects/sunshine">
<img src="https://img.shields.io/readthedocs/sunshinestream.svg?label=Docs&style=for-the-badge&logo=readthedocs" alt="Read the Docs">
</a>
<a href="https://codecov.io/gh/LizardByte/Sunshine">
<img src="https://img.shields.io/codecov/c/gh/LizardByte/Sunshine?token=SMGXQ5NVMJ&style=for-the-badge&logo=codecov&label=codecov" alt="Codecov">
</a>
</div>
## About
@@ -164,34 +188,6 @@ LizardByte has the full documentation hosted on [Read the Docs](https://docs.liz
Our support methods are listed in our [LizardByte Docs](https://docs.lizardbyte.dev/latest/about/support.html).
## 💲 Sponsors and Supporters
<p align="center">
<a href="https://app.lizardbyte.dev" aria-label="Sponsor LizardByte">
<img src='https://raw.githubusercontent.com/LizardByte/contributors/refs/heads/dist/sponsors.svg'/>
</a>
</p>
## 👥 Contributors
Thank you to all the contributors who have helped make Sunshine better!
### GitHub
<p align="center">
<a href="https://github.com/LizardByte/Sunshine" aria-label="GitHub">
<img src='https://raw.githubusercontent.com/LizardByte/contributors/refs/heads/dist/github.Sunshine.svg'/>
</a>
</p>
### CrowdIn
<p align="center">
<a href="https://translate.lizardbyte.dev" aria-label="CrowdIn">
<img src='https://raw.githubusercontent.com/LizardByte/contributors/refs/heads/dist/crowdin.606145.svg'/>
</a>
</p>
<div class="section_buttons">
| Previous | Next |

View File

@@ -0,0 +1,17 @@
---
description: Bad Request - A parameter was not specified, or was specified incorrectly.
content:
application/json:
schema:
type: object
properties:
status_code:
type: string
status:
type: string
error:
type: string
example:
status_code: 400
status: false
error: "Bad Request"

View File

@@ -0,0 +1,17 @@
---
description: Unauthorized - The request requires user authentication.
content:
application/json:
schema:
type: object
properties:
status_code:
type: string
status:
type: string
error:
type: string
example:
status_code: 401
status: false
error: "Unauthorized"

View File

@@ -0,0 +1,7 @@
---
description: Forbidden - The server understood the request, but is refusing to fulfill it.
content:
# TODO: return JSON response.
text/plain:
schema:
type: string

View File

@@ -0,0 +1,15 @@
---
description: Not Found - The requested resource could not be found.
content:
application/json:
schema:
type: object
properties:
status_code:
type: integer
format: int32
error:
type: string
example:
status_code: 404
error: "Not Found"

View File

@@ -0,0 +1,48 @@
---
type: object
required:
- name
properties:
name:
type: string
description: Application Name, as shown on Moonlight
output:
type: string
description: The file where the output of the command is stored, if it is not specified, the output is ignored
cmd:
$ref: "./cmd.yml"
description: The main application to start. If blank, no application will be started.
exclude-global-prep-cmd:
type: boolean
description: Enable/Disable the execution of Global Prep Commands for this application.
elevated:
type: boolean
description: Run the application as an elevated process.
auto-detach:
type: boolean
description: Continue streaming if the application exits quickly
wait-all:
type: boolean
description: Continue streaming until all app processes exit
exit-timeout:
type: integer
description: Number of seconds to wait for all app processes to gracefully exit when requested to quit.
image-path:
type: string
description: |
Application icon/picture/image path that will be sent to client. Image must be a PNG file.
If not set, Sunshine will send default box image.
working-dir:
type: string
description: |
The working directory that should be passed to the process.
For example, some applications use the working directory to search for configuration files.
If not set, Sunshine will default to the parent directory of the command
prep-cmd:
type: array
items:
$ref: "./prep-cmd.yml"
detached:
type: array
items:
$ref: "./cmd.yml"

View File

@@ -0,0 +1,3 @@
---
type: string
description: Command to execute

View File

@@ -0,0 +1,16 @@
---
type: object
required:
- do
- undo
- elevated
properties:
do:
$ref: "./cmd.yml"
description: Command to run before the application starts.
undo:
$ref: "./cmd.yml"
description: Command to run after the application exits.
elevated:
type: boolean
description: Run the command as an elevated process.

44
api/openapi.yml Normal file
View File

@@ -0,0 +1,44 @@
---
# https://openapi.tools
openapi: 3.1.0
info:
title: Sunshine
summary: Self-hosted game stream host for Moonlight.
version: 0.0.0
contact:
name: LizardByte
url: https://app.lizardbyte.dev/support
license:
name: GNU General Public License v3.0 only
url: https://github.com/LizardByte/Sunshine/blob/master/LICENSE
servers:
- url: "https://{host}:{ui-port}"
description: Sunshine server
variables:
host:
default: "localhost"
ui-port:
default: 47990
security:
- basicAuth: []
components:
securitySchemes:
# TODO: update when JWT is implemented (https://github.com/LizardByte/Sunshine/pull/2995)
# https://swagger.io/specification/#security-scheme-object-examples
basicAuth:
description: HTTP Basic authentication
type: http
scheme: basic
paths:
/api/apps:
$ref: "./paths/confighttp/apps/apps.yml"
/api/apps/{index}:
$ref: "./paths/confighttp/apps/apps-by-index.yml"
/api/logs:
$ref: "./paths/confighttp/logs/logs.yml"

View File

@@ -0,0 +1,37 @@
---
delete:
summary: Delete an application.
description: |
Delete an application.
operationId: deleteApps
tags:
- Apps
parameters:
- name: index
in: path
description: The index of the application to delete.
required: true
schema:
type: integer
format: int32
responses:
'200':
description: The application was deleted successfully.
content:
application/json:
schema:
type: object
properties:
status:
type: string
result:
type: string
example:
status: true
result: "application 9999 deleted"
'400':
$ref: "../../../components/responses/400.yml"
'401':
$ref: "../../../components/responses/401.yml"
'403':
$ref: "../../../components/responses/403.yml"

View File

@@ -0,0 +1,151 @@
---
get:
summary: Get the list of available applications.
description: |
Get the list of available applications.
operationId: getApps
tags:
- Apps
responses:
'200':
description: A list of available applications.
content:
application/json:
schema:
type: array
items:
$ref: "../../../components/schemas/app.yml"
example:
- name: "Example App"
output: "/path/to/output.log"
cmd: "example-command"
exclude-global-prep-cmd: false
elevated: false
auto-detach: true
wait-all: false
exit-timeout: 30
image-path: "/path/to/image.png"
working-dir: "/path/to/working-dir"
prep-cmd:
- do: "prep-command-1"
undo: "undo-command-1"
elevated: false
detached:
- "detached-command-1"
'401':
$ref: "../../../components/responses/401.yml"
'403':
$ref: "../../../components/responses/403.yml"
post:
summary: Save an application.
description: |
Save an application.
To save a new application the index must be `-1`.
To update an existing application, you must provide the current index of the application.
operationId: postApps
tags:
- Apps
parameters:
- name: index
in: query
description: The index of the application to update. If the index is -1, a new application will be created.
required: true
schema:
type: integer
format: int32
- name: name
in: query
description: Application Name
required: false
schema:
type: string
- name: output
in: query
description: Log Output Path
required: false
schema:
type: string
- name: cmd
in: query
description: Command to run the application
required: false
schema:
$ref: "../../../components/schemas/cmd.yml"
- name: exclude-global-prep-cmd
in: query
description: Enable/Disable the execution of Global Prep Commands for this application.
required: false
schema:
type: boolean
- name: elevated
in: query
description: Run the application as an elevated process.
required: false
schema:
type: boolean
- name: auto-detach
in: query
description: Continue streaming if the application exits quickly
required: false
schema:
type: boolean
- name: wait-all
in: query
description: Continue streaming until all app processes exit
required: false
schema:
type: boolean
- name: exit-timeout
in: query
description: Number of seconds to wait for all app processes to gracefully exit when requested to quit.
required: false
schema:
type: integer
format: int32
- name: prep-cmd
in: query
description: Commands to run before the main application
required: false
schema:
type: array
items:
$ref: "../../../components/schemas/prep-cmd.yml"
- name: detached
in: query
description: Commands to run in detached processes
required: false
schema:
type: array
items:
$ref: "../../../components/schemas/cmd.yml"
- name: image-path
in: query
description: Full path to the application image. Must be a png file.
required: false
schema:
type: string
- name: working-dir
in: query
description: The working directory that should be passed to the process.
required: false
schema:
type: string
responses:
'200':
description: The application was saved successfully.
content:
application/json:
schema:
type: object
properties:
status:
type: string
example:
status: true
'400':
$ref: "../../../components/responses/400.yml"
'401':
$ref: "../../../components/responses/401.yml"
'403':
$ref: "../../../components/responses/403.yml"

View File

@@ -0,0 +1,20 @@
---
get:
summary: Get the logs from the log file.
description: |
Get the logs from the log file.
operationId: getLogs
tags:
- Logs
responses:
'200':
description: The contents of the log file.
content:
text/plain:
schema:
type: string
example: '[2025-01-15 17:07:58.131]: Info: Sunshine version: v...'
'401':
$ref: "../../../components/responses/401.yml"
'403':
$ref: "../../../components/responses/403.yml"

View File

@@ -137,8 +137,7 @@ if(WAYLAND_FOUND)
endif()
GEN_WAYLAND("${WAYLAND_PROTOCOLS_DIR}" "unstable/xdg-output" xdg-output-unstable-v1)
GEN_WAYLAND("${WAYLAND_PROTOCOLS_DIR}" "unstable/linux-dmabuf" linux-dmabuf-unstable-v1)
GEN_WAYLAND("${CMAKE_SOURCE_DIR}/third-party/wlr-protocols" "unstable" wlr-screencopy-unstable-v1)
GEN_WAYLAND("${CMAKE_SOURCE_DIR}/third-party/wlr-protocols" "unstable" wlr-export-dmabuf-unstable-v1)
include_directories(
SYSTEM
@@ -146,7 +145,7 @@ if(WAYLAND_FOUND)
${CMAKE_BINARY_DIR}/generated-src
)
list(APPEND PLATFORM_LIBRARIES ${WAYLAND_LIBRARIES} gbm)
list(APPEND PLATFORM_LIBRARIES ${WAYLAND_LIBRARIES})
list(APPEND PLATFORM_TARGET_FILES
"${CMAKE_SOURCE_DIR}/src/platform/linux/wlgrab.cpp"
"${CMAKE_SOURCE_DIR}/src/platform/linux/wayland.h"

View File

@@ -9,10 +9,6 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
# gcc complains about misleading indentation in some mingw includes
list(APPEND SUNSHINE_COMPILE_OPTIONS -Wno-misleading-indentation)
# gcc15 complains about non-template type 'coroutine_handle' used as a template in Windows.Foundation.h
# can remove after https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120495 is available in mingw-w64
list(APPEND SUNSHINE_COMPILE_OPTIONS -Wno-template-body)
# see gcc bug 98723
add_definitions(-DUSE_BOOST_REGEX)
@@ -42,7 +38,7 @@ if(NOT DEFINED SUNSHINE_ICON_PATH)
set(SUNSHINE_ICON_PATH "${CMAKE_SOURCE_DIR}/sunshine.ico")
endif()
configure_file("${CMAKE_SOURCE_DIR}/src/platform/windows/windows.rc.in" windows.rc @ONLY)
configure_file("${CMAKE_SOURCE_DIR}/src/platform/windows/windows.rs.in" windows.rc @ONLY)
set(PLATFORM_TARGET_FILES
"${CMAKE_CURRENT_BINARY_DIR}/windows.rc"

View File

@@ -3,43 +3,26 @@
#
include_guard(GLOBAL)
set(BOOST_VERSION "1.87.0")
set(BOOST_VERSION 1.86)
set(BOOST_COMPONENTS
filesystem
locale
log
program_options
system
)
# system is not used by Sunshine, but by Simple-Web-Server, added here for convenience
# algorithm, preprocessor, scope, and uuid are not used by Sunshine, but by libdisplaydevice, added here for convenience
if(WIN32)
list(APPEND BOOST_COMPONENTS
algorithm
preprocessor
scope
uuid
)
endif()
system) # system is not used by Sunshine, but by Simple-Web-Server, added here for convenience
if(BOOST_USE_STATIC)
set(Boost_USE_STATIC_LIBS ON) # cmake-lint: disable=C0103
endif()
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.30")
cmake_policy(SET CMP0167 NEW) # Get BoostConfig.cmake from upstream
endif()
find_package(Boost CONFIG ${BOOST_VERSION} EXACT COMPONENTS ${BOOST_COMPONENTS})
find_package(Boost CONFIG ${BOOST_VERSION} COMPONENTS ${BOOST_COMPONENTS})
if(NOT Boost_FOUND)
message(STATUS "Boost v${BOOST_VERSION} package not found in the system. Falling back to FetchContent.")
message(STATUS "Boost v${BOOST_VERSION}.x package not found in the system. Falling back to FetchContent.")
include(FetchContent)
# Avoid warning about DOWNLOAD_EXTRACT_TIMESTAMP in CMake 3.24:
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
cmake_policy(SET CMP0135 NEW) # Avoid warning about DOWNLOAD_EXTRACT_TIMESTAMP in CMake 3.24
endif()
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.31.0")
cmake_policy(SET CMP0174 NEW) # Handle empty variables
cmake_policy(SET CMP0135 NEW)
endif()
# more components required for compiling boost targets
@@ -53,9 +36,12 @@ if(NOT Boost_FOUND)
set(BOOST_ENABLE_CMAKE ON)
# Limit boost to the required libraries only
set(BOOST_INCLUDE_LIBRARIES ${BOOST_COMPONENTS})
set(BOOST_URL "https://github.com/boostorg/boost/releases/download/boost-${BOOST_VERSION}/boost-${BOOST_VERSION}-cmake.tar.xz") # cmake-lint: disable=C0301
set(BOOST_HASH "SHA256=7da75f171837577a52bbf217e17f8ea576c7c246e4594d617bfde7fafd408be5")
set(BOOST_INCLUDE_LIBRARIES
${BOOST_COMPONENTS})
set(BOOST_URL
"https://github.com/boostorg/boost/releases/download/boost-1.86.0/boost-1.86.0-cmake.tar.xz")
set(BOOST_HASH
"MD5=D02759931CEDC02ADED80402906C5EB6")
if(CMAKE_VERSION VERSION_LESS "3.24.0")
FetchContent_Declare(
@@ -86,7 +72,7 @@ if(NOT Boost_FOUND)
set(Boost_FOUND TRUE) # cmake-lint: disable=C0103
set(Boost_INCLUDE_DIRS # cmake-lint: disable=C0103
"$<BUILD_INTERFACE:${Boost_SOURCE_DIR}/libs/headers/include>")
"$<BUILD_INTERFACE:${Boost_SOURCE_DIR}/libs/headers/include>;$<INSTALL_INTERFACE:include/boost-1_85>")
if(WIN32)
# Windows build is failing to create .h file in this directory

View File

@@ -8,13 +8,6 @@ if(NOT nlohmann_json_FOUND)
message(STATUS "nlohmann_json v3.11.x package not found in the system. Falling back to FetchContent.")
include(FetchContent)
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
cmake_policy(SET CMP0135 NEW) # Avoid warning about DOWNLOAD_EXTRACT_TIMESTAMP in CMake 3.24
endif()
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.31.0")
cmake_policy(SET CMP0174 NEW) # Handle empty variables
endif()
FetchContent_Declare(
json
URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz

View File

@@ -136,13 +136,26 @@ if(${SUNSHINE_TRAY} STREQUAL 1)
endif()
# desktop file
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_FQDN}.desktop"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications")
# todo - validate desktop files with `desktop-file-validate`
if(NOT ${SUNSHINE_BUILD_FLATPAK})
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sunshine.desktop"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications")
else()
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sunshine.desktop"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications"
RENAME "${PROJECT_FQDN}.desktop")
endif()
if(NOT ${SUNSHINE_BUILD_APPIMAGE} AND NOT ${SUNSHINE_BUILD_FLATPAK})
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_FQDN}.terminal.desktop"
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sunshine_terminal.desktop"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications")
endif()
# metadata file
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_FQDN}.metainfo.xml"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/metainfo")
# todo - validate file with `appstream-util validate-relax`
if(NOT ${SUNSHINE_BUILD_FLATPAK})
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sunshine.appdata.xml"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/metainfo")
else()
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_FQDN}.metainfo.xml"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/metainfo")
endif()

View File

@@ -1,4 +1,6 @@
# windows specific packaging
# see options at: https://cmake.org/cmake/help/latest/cpack_gen/nsis.html
install(TARGETS sunshine RUNTIME DESTINATION "." COMPONENT application)
# Hardening: include zlib1.dll (loaded via LoadLibrary() in openssl's libcrypto.a)
@@ -18,9 +20,6 @@ install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/windows/misc/service/"
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/windows/misc/migration/"
DESTINATION "scripts"
COMPONENT assets)
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/windows/misc/path/"
DESTINATION "scripts"
COMPONENT assets)
# Configurable options for the service
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/windows/misc/autostart/"
@@ -50,11 +49,76 @@ cmake_path(CONVERT "${SUNSHINE_SOURCE_ASSETS_DIR}/windows/assets/shaders"
cmake_path(CONVERT "${CMAKE_BINARY_DIR}/assets/shaders" TO_NATIVE_PATH_LIST shaders_in_build_dest_native)
execute_process(COMMAND cmd.exe /c mklink /J "${shaders_in_build_dest_native}" "${shaders_in_build_src_native}")
# set(CPACK_NSIS_MUI_HEADERIMAGE "") # TODO: image should be 150x57 bmp
set(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}\\\\sunshine.ico")
set(CPACK_NSIS_INSTALLED_ICON_NAME "${PROJECT__DIR}\\\\${PROJECT_EXE}")
# The name of the directory that will be created in C:/Program files/
set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}")
# Extra install commands
# Restores permissions on the install directory
# Migrates config files from the root into the new config folder
# Install service
SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS
"${CPACK_NSIS_EXTRA_INSTALL_COMMANDS}
IfSilent +2 0
ExecShell 'open' 'https://docs.lizardbyte.dev/projects/sunshine'
nsExec::ExecToLog 'icacls \\\"$INSTDIR\\\" /reset'
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\migrate-config.bat\\\"'
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\add-firewall-rule.bat\\\"'
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\install-gamepad.bat\\\"'
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\install-service.bat\\\"'
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\autostart-service.bat\\\"'
NoController:
")
# Extra uninstall commands
# Uninstall service
set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS
"${CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS}
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\delete-firewall-rule.bat\\\"'
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\uninstall-service.bat\\\"'
nsExec::ExecToLog '\\\"$INSTDIR\\\\sunshine.exe\\\" --restore-nvprefs-undo'
MessageBox MB_YESNO|MB_ICONQUESTION \
'Do you want to remove Virtual Gamepad?' \
/SD IDNO IDNO NoGamepad
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\uninstall-gamepad.bat\\\"'; skipped if no
NoGamepad:
MessageBox MB_YESNO|MB_ICONQUESTION \
'Do you want to remove $INSTDIR (this includes the configuration, cover images, and settings)?' \
/SD IDNO IDNO NoDelete
RMDir /r \\\"$INSTDIR\\\"; skipped if no
NoDelete:
")
# Adding an option for the start menu
set(CPACK_NSIS_MODIFY_PATH "OFF")
set(CPACK_NSIS_EXECUTABLES_DIRECTORY ".")
# This will be shown on the installed apps Windows settings
set(CPACK_NSIS_INSTALLED_ICON_NAME "${CMAKE_PROJECT_NAME}.exe")
set(CPACK_NSIS_CREATE_ICONS_EXTRA
"${CPACK_NSIS_CREATE_ICONS_EXTRA}
CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\${CMAKE_PROJECT_NAME}.lnk' \
'\$INSTDIR\\\\${CMAKE_PROJECT_NAME}.exe' '--shortcut'
")
set(CPACK_NSIS_DELETE_ICONS_EXTRA
"${CPACK_NSIS_DELETE_ICONS_EXTRA}
Delete '\$SMPROGRAMS\\\\$MUI_TEMP\\\\${CMAKE_PROJECT_NAME}.lnk'
")
# Checking for previous installed versions
set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL "ON")
set(CPACK_NSIS_HELP_LINK "https://docs.lizardbyte.dev/projects/sunshine/latest/md_docs_2getting__started.html")
set(CPACK_NSIS_URL_INFO_ABOUT "${CMAKE_PROJECT_HOMEPAGE_URL}")
set(CPACK_NSIS_CONTACT "${CMAKE_PROJECT_HOMEPAGE_URL}/support")
set(CPACK_NSIS_MENU_LINKS
"https://docs.lizardbyte.dev/projects/sunshine" "Sunshine documentation"
"https://app.lizardbyte.dev" "LizardByte Web Site"
"https://app.lizardbyte.dev/support" "LizardByte Support")
set(CPACK_NSIS_MANIFEST_DPI_AWARE true)
# Setting components groups and dependencies
set(CPACK_COMPONENT_GROUP_CORE_EXPANDED true)
@@ -95,7 +159,3 @@ set(CPACK_COMPONENT_FIREWALL_GROUP "Scripts")
set(CPACK_COMPONENT_GAMEPAD_DISPLAY_NAME "Virtual Gamepad")
set(CPACK_COMPONENT_GAMEPAD_DESCRIPTION "Scripts to install and uninstall Virtual Gamepad.")
set(CPACK_COMPONENT_GAMEPAD_GROUP "Scripts")
# include specific packaging
include(${CMAKE_MODULE_PATH}/packaging/windows_nsis.cmake)
include(${CMAKE_MODULE_PATH}/packaging/windows_wix.cmake)

View File

@@ -1,71 +0,0 @@
# NSIS Packaging
# see options at: https://cmake.org/cmake/help/latest/cpack_gen/nsis.html
set(CPACK_NSIS_INSTALLED_ICON_NAME "${PROJECT__DIR}\\\\${PROJECT_EXE}")
# Extra install commands
# Restores permissions on the install directory
# Migrates config files from the root into the new config folder
# Install service
SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS
"${CPACK_NSIS_EXTRA_INSTALL_COMMANDS}
IfSilent +2 0
ExecShell 'open' 'https://docs.lizardbyte.dev/projects/sunshine'
nsExec::ExecToLog 'icacls \\\"$INSTDIR\\\" /reset'
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\update-path.bat\\\" add'
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\migrate-config.bat\\\"'
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\add-firewall-rule.bat\\\"'
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\install-gamepad.bat\\\"'
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\install-service.bat\\\"'
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\autostart-service.bat\\\"'
NoController:
")
# Extra uninstall commands
# Uninstall service
set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS
"${CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS}
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\delete-firewall-rule.bat\\\"'
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\uninstall-service.bat\\\"'
nsExec::ExecToLog '\\\"$INSTDIR\\\\${CMAKE_PROJECT_NAME}.exe\\\" --restore-nvprefs-undo'
MessageBox MB_YESNO|MB_ICONQUESTION \
'Do you want to remove Virtual Gamepad?' \
/SD IDNO IDNO NoGamepad
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\uninstall-gamepad.bat\\\"'; skipped if no
NoGamepad:
MessageBox MB_YESNO|MB_ICONQUESTION \
'Do you want to remove $INSTDIR (this includes the configuration, cover images, and settings)?' \
/SD IDNO IDNO NoDelete
RMDir /r \\\"$INSTDIR\\\"; skipped if no
nsExec::ExecToLog '\\\"$INSTDIR\\\\scripts\\\\update-path.bat\\\" remove'
NoDelete:
")
# Adding an option for the start menu
set(CPACK_NSIS_MODIFY_PATH OFF)
set(CPACK_NSIS_EXECUTABLES_DIRECTORY ".")
# This will be shown on the installed apps Windows settings
set(CPACK_NSIS_INSTALLED_ICON_NAME "${CMAKE_PROJECT_NAME}.exe")
set(CPACK_NSIS_CREATE_ICONS_EXTRA
"${CPACK_NSIS_CREATE_ICONS_EXTRA}
SetOutPath '\$INSTDIR'
CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\${CMAKE_PROJECT_NAME}.lnk' \
'\$INSTDIR\\\\${CMAKE_PROJECT_NAME}.exe' '--shortcut'
")
set(CPACK_NSIS_DELETE_ICONS_EXTRA
"${CPACK_NSIS_DELETE_ICONS_EXTRA}
Delete '\$SMPROGRAMS\\\\$MUI_TEMP\\\\${CMAKE_PROJECT_NAME}.lnk'
")
# Checking for previous installed versions
set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL "ON")
set(CPACK_NSIS_HELP_LINK "https://docs.lizardbyte.dev/projects/sunshine/latest/md_docs_2getting__started.html")
set(CPACK_NSIS_URL_INFO_ABOUT "${CMAKE_PROJECT_HOMEPAGE_URL}")
set(CPACK_NSIS_CONTACT "${CMAKE_PROJECT_HOMEPAGE_URL}/support")
set(CPACK_NSIS_MENU_LINKS
"https://docs.lizardbyte.dev/projects/sunshine" "Sunshine documentation"
"https://app.lizardbyte.dev" "LizardByte Web Site"
"https://app.lizardbyte.dev/support" "LizardByte Support")
set(CPACK_NSIS_MANIFEST_DPI_AWARE true)

View File

@@ -1,4 +0,0 @@
# WIX Packaging
# see options at: https://cmake.org/cmake/help/latest/cpack_gen/wix.html
# TODO: Replace nsis with wix

View File

@@ -54,34 +54,3 @@ else()
MESSAGE(WARNING ": Git not found, cannot find git version")
endif()
endif()
# set date variables
set(PROJECT_YEAR "1990")
set(PROJECT_MONTH "01")
set(PROJECT_DAY "01")
# Extract year, month, and day
if(PROJECT_VERSION MATCHES "^([0-9]{4})[.]([0-9]{3,4})")
# First capture group is the year
set(PROJECT_YEAR "${CMAKE_MATCH_1}")
# Second capture group is month/day
set(MONTH_DAY "${CMAKE_MATCH_2}")
string(LENGTH "${MONTH_DAY}" MONTH_DAY_LENGTH)
if(MONTH_DAY_LENGTH EQUAL 3)
string(SUBSTRING "${MONTH_DAY}" 0 1 PROJECT_MONTH)
string(SUBSTRING "${MONTH_DAY}" 1 2 PROJECT_DAY)
elseif(MONTH_DAY_LENGTH EQUAL 4)
string(SUBSTRING "${MONTH_DAY}" 0 2 PROJECT_MONTH)
string(SUBSTRING "${MONTH_DAY}" 2 2 PROJECT_DAY)
endif()
# Ensure month is two digits
if(PROJECT_MONTH LESS 10 AND NOT PROJECT_MONTH MATCHES "^0")
set(PROJECT_MONTH "0${PROJECT_MONTH}")
endif()
# Ensure day is two digits
if(PROJECT_DAY LESS 10 AND NOT PROJECT_DAY MATCHES "^0")
set(PROJECT_DAY "0${PROJECT_DAY}")
endif()
endif()

View File

@@ -10,6 +10,7 @@ set(SUNSHINE_PUBLISHER_ISSUE_URL "https://app.lizardbyte.dev/support"
option(BUILD_DOCS "Build documentation" ON)
option(BUILD_TESTS "Build tests" ON)
option(NPM_OFFLINE "Use offline npm packages. You must ensure packages are in your npm cache." OFF)
option(TESTS_ENABLE_PYTHON_TESTS "Enable Python tests" ON)
option(BUILD_WERROR "Enable -Werror flag." OFF)

View File

@@ -12,17 +12,19 @@ elseif(UNIX)
# configure the .desktop file
set(SUNSHINE_DESKTOP_ICON "sunshine")
if(${SUNSHINE_BUILD_APPIMAGE})
configure_file(packaging/linux/AppImage/${PROJECT_FQDN}.desktop ${PROJECT_FQDN}.desktop @ONLY)
configure_file(packaging/linux/AppImage/sunshine.desktop sunshine.desktop @ONLY)
elseif(${SUNSHINE_BUILD_FLATPAK})
set(SUNSHINE_DESKTOP_ICON "${PROJECT_FQDN}")
configure_file(packaging/linux/flatpak/${PROJECT_FQDN}.desktop ${PROJECT_FQDN}.desktop @ONLY)
configure_file(packaging/linux/flatpak/sunshine.desktop sunshine.desktop @ONLY)
configure_file(packaging/linux/flatpak/${PROJECT_FQDN}.metainfo.xml
${PROJECT_FQDN}.metainfo.xml @ONLY)
else()
configure_file(packaging/linux/${PROJECT_FQDN}.desktop ${PROJECT_FQDN}.desktop @ONLY)
configure_file(packaging/linux/${PROJECT_FQDN}.terminal.desktop ${PROJECT_FQDN}.terminal.desktop @ONLY)
configure_file(packaging/linux/sunshine.desktop sunshine.desktop @ONLY)
configure_file(packaging/linux/sunshine_terminal.desktop sunshine_terminal.desktop @ONLY)
endif()
# configure metadata file
configure_file(packaging/linux/${PROJECT_FQDN}.metainfo.xml ${PROJECT_FQDN}.metainfo.xml @ONLY)
configure_file(packaging/linux/sunshine.appdata.xml sunshine.appdata.xml @ONLY)
# configure service
configure_file(packaging/linux/sunshine.service.in sunshine.service @ONLY)
@@ -36,6 +38,8 @@ elseif(UNIX)
# configure the flatpak manifest
if(${SUNSHINE_CONFIGURE_FLATPAK_MAN})
configure_file(packaging/linux/flatpak/${PROJECT_FQDN}.yml ${PROJECT_FQDN}.yml @ONLY)
configure_file(packaging/linux/flatpak/${PROJECT_FQDN}.metainfo.xml
${PROJECT_FQDN}.metainfo.xml @ONLY)
file(COPY packaging/linux/flatpak/deps/ DESTINATION ${CMAKE_BINARY_DIR})
file(COPY packaging/linux/flatpak/modules DESTINATION ${CMAKE_BINARY_DIR})
file(COPY generated-sources.json DESTINATION ${CMAKE_BINARY_DIR})

View File

@@ -17,9 +17,7 @@
"two_letters_code": {
# map non-two letter codes here, left side is crowdin designation, right side is babel designation
"en-GB": "en_GB",
"en-US": "en_US",
"pt-BR": "pt_BR",
"zh-TW": "zh_TW"
"en-US": "en_US"
}
},
"update_option": "update_as_unapproved"

View File

@@ -49,7 +49,6 @@ INPUT = ../README.md \
legal.md \
configuration.md \
app_examples.md \
awesome_sunshine.md \
guides.md \
performance_tuning.md \
api.md \

View File

@@ -9,7 +9,7 @@ function generateExamples(endpoint, method, body = null) {
}
return {
cURL: `curl -u user:pass -H "Content-Type: application/json" -X ${method.trim()} -k https://localhost:47990${endpoint.trim()}${curlBodyString}`,
cURL: `curl -u user:pass -X ${method.trim()} -k https://localhost:47990${endpoint.trim()}${curlBodyString}`,
Python: `import json
import requests
from requests.auth import HTTPBasicAuth
@@ -30,7 +30,6 @@ requests.${method.trim().toLowerCase()}(
.then(data => console.log(data));`,
PowerShell: `Invoke-RestMethod \`
-SkipCertificateCheck \`
-ContentType 'application/json' \`
-Uri 'https://localhost:47990${endpoint.trim()}' \`
-Method ${method.trim()} \`
-Headers @{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes('user:pass'))}

View File

@@ -23,28 +23,25 @@ process is killed.}
@tabs{
@tab{Linux | <!-- -->
\| Field \| Value \|
\|------------------------------\|------------------------------------------------------\|
\| Application Name \| @code{}Steam Big Picture@endcode \|
\| Command Preporations -> Undo \| @code{}setsid steam steam://close/bigpicture@endcode \|
\| Detached Commands \| @code{}setsid steam steam://open/bigpicture@endcode \|
\| Image \| @code{}steam.png@endcode \|
\| Field \| Value \|
\|-------------------\|-----------------------------------------------------\|
\| Application Name \| @code{}Steam Big Picture@endcode \|
\| Detached Commands \| @code{}setsid steam steam://open/bigpicture@endcode \|
\| Image \| @code{}steam.png@endcode \|
}
@tab{macOS | <!-- -->
\| Field \| Value \|
\|------------------------------\|------------------------------------------------\|
\| Application Name \| @code{}Steam Big Picture@endcode \|
\| Command Preporations -> Undo \| @code{}open steam://close/bigpicture@endcode \|
\| Detached Commands \| @code{}open steam://open/bigpicture@endcode \|
\| Image \| @code{}steam.png@endcode \|
\| Field \| Value \|
\|-------------------\|---------------------------------------------------\|
\| Application Name \| @code{}Steam Big Picture@endcode \|
\| Detached Commands \| @code{}open steam steam://open/bigpicture@endcode \|
\| Image \| @code{}steam.png@endcode \|
}
@tab{Windows | <!-- -->
\| Field \| Value \|
\|------------------------------\|-------------------------------------------\|
\| Application Name \| @code{}Steam Big Picture@endcode \|
\| Command Preporations -> Undo \| @code{}steam://close/bigpicture@endcode \|
\| Detached Commands \| @code{}steam://open/bigpicture@endcode \|
\| Image \| @code{}steam.png@endcode \|
\| Field \| Value \|
\|-------------------\|----------------------------------------\|
\| Application Name \| @code{}Steam Big Picture@endcode \|
\| Detached Commands \| @code{}steam://open/bigpicture@endcode \|
\| Image \| @code{}steam.png@endcode \|
}
}
@@ -213,7 +210,7 @@ xrandr --output ${display_output} --primary --mode ${mode_alias} --pos 0x0 --rot
```
}
###### Wayland (wlroots, e.g. hyprland)
###### Wayland
| Prep Step | Command |
|-----------|------------------------------------------------------------------------------------------------------------------------------------------|
@@ -222,30 +219,17 @@ xrandr --output ${display_output} --primary --mode ${mode_alias} --pos 0x0 --rot
@hint{`wlr-xrandr` only works with wlroots-based compositors.}
###### Gnome (X11)
###### Gnome (Wayland, X11)
| Prep Step | Command |
|-----------|---------------------------------------------------------------------------------------------------------------------------------------|
| Do | @code{}sh -c "xrandr --output HDMI-1 --mode ${SUNSHINE_CLIENT_WIDTH}x${SUNSHINE_CLIENT_HEIGHT} --rate ${SUNSHINE_CLIENT_FPS}"@endcode |
| Undo | @code{}xrandr --output HDMI-1 --mode 3840x2160 --rate 120@endcode |
###### Gnome (Wayland)
| Prep Step | Command |
|-----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Do | @code{}sh -c "displayconfig-mutter set --connector HDMI-1 --resolution ${SUNSHINE_CLIENT_WIDTH}x${SUNSHINE_CLIENT_HEIGHT} --refresh-rate ${SUNSHINE_CLIENT_FPS} --hdr ${SUNSHINE_CLIENT_HDR}"@endcode |
| Undo | @code{}displayconfig-mutter set --connector HDMI-1 --resolution 3840x2160 --refresh-rate 120 --hdr false@endcode |
Installation instructions for displayconfig-mutter can be [found here](https://github.com/eaglesemanation/displayconfig-mutter). Alternatives include
[gnome-randr-rust](https://github.com/maxwellainatchi/gnome-randr-rust) and [gnome-randr.py](https://gitlab.com/Oschowa/gnome-randr), but both of those are
unmaintained and do not support newer Mutter features such as HDR and VRR.
@hint{HDR support has been added to Gnome 48, to check if your display supports it you can run this:
```
displayconfig-mutter list
```
If it doesn't, then remove ``--hdr`` flag from both ``Do`` and ``Undo`` steps.
}
The commands above are valid for an X11 session but won't work for
Wayland. In that case `xrandr` must be replaced by [gnome-randr.py](https://gitlab.com/Oschowa/gnome-randr).
This script is intended as a drop-in replacement with the same syntax. (It can be saved in
`/usr/local/bin` and needs to be made executable.)
###### KDE Plasma (Wayland, X11)
@@ -338,9 +322,9 @@ UAC prompt.
<div class="section_buttons">
| Previous | Next |
|:----------------------------------|----------------------------------------:|
| [Configuration](configuration.md) | [Awesome-Sunshine](awesome_sunshine.md) |
| Previous | Next |
|:----------------------------------|--------------------:|
| [Configuration](configuration.md) | [Guides](guides.md) |
</div>

View File

@@ -1,23 +0,0 @@
# Awesome-Sunshine
@htmlonly
<script type="module" src="https://md-block.verou.me/md-block.js"></script>
<md-block
hlinks=""
hmin="2"
src="https://raw.githubusercontent.com/LizardByte/awesome-sunshine/master/README.md">
</md-block>
@endhtmlonly
<div class="section_buttons">
| Previous | Next |
|:--------------------------------|--------------------:|
| [App Examples](app_examples.md) | [Guides](guides.md) |
</div>
<details style="display: none;">
<summary></summary>
[TOC]
</details>

View File

@@ -57,14 +57,10 @@ editing the `conf` file in a text editor. Use the examples as reference.
@endcode</td>
</tr>
<tr>
<td rowspan="20">Choices</td>
<td rowspan="18">Choices</td>
<td>bg</td>
<td>Bulgarian</td>
</tr>
<tr>
<td>cs</td>
<td>Czech</td>
</tr>
<tr>
<td>de</td>
<td>German</td>
@@ -133,10 +129,6 @@ editing the `conf` file in a text editor. Use the examples as reference.
<td>zh</td>
<td>Chinese (Simplified)</td>
</tr>
<tr>
<td>zh_TW</td>
<td>Chinese (Traditional)</td>
</tr>
</table>
### sunshine_name
@@ -778,29 +770,6 @@ editing the `conf` file in a text editor. Use the examples as reference.
</tr>
</table>
### stream_audio
<table>
<tr>
<td>Description</td>
<td colspan="2">
Whether to stream audio or not. Disabling this can be useful for streaming headless displays as second monitors.
</td>
</tr>
<tr>
<td>Default</td>
<td colspan="2">@code{}
enabled
@endcode</td>
</tr>
<tr>
<td>Example</td>
<td colspan="2">@code{}
stream_audio = disabled
@endcode</td>
</tr>
</table>
### install_steam_audio_drivers
<table>
@@ -1005,9 +974,7 @@ editing the `conf` file in a text editor. Use the examples as reference.
</tr>
<tr>
<td>Default</td>
<td colspan="2">@code{}
disabled
@endcode</td>
<td colspan="2">@code{}verify_only@endcode</td>
</tr>
<tr>
<td>Example</td>
@@ -1187,15 +1154,14 @@ editing the `conf` file in a text editor. Use the examples as reference.
</tr>
</table>
### dd_wa_hdr_toggle_delay
### dd_wa_hdr_toggle
<table>
<tr>
<td>Description</td>
<td colspan="2">
When using virtual display device (VDD) for streaming, it might incorrectly display HDR color. Sunshine can try to mitigate this issue, by turning HDR off and then on again.<br>
If the value is set to 0, the workaround is disabled (default). If the value is between 0 and 3000 milliseconds, Sunshine will turn off HDR, wait for the specified amount of time and then turn HDR on again. The recommended delay time is around 500 milliseconds in most cases.<br>
DO NOT use this workaround unless you actually have issues with HDR as it directly impacts stream start time!
When using virtual display device as for streaming, it might display incorrect (high-contrast) color.
With this option enabled, Sunshine will try to mitigate this issue.
@note{This option works independently of [dd_hdr_option](#dd_hdr_option)}
@note{Applies to Windows only.}
</td>
@@ -1203,13 +1169,13 @@ editing the `conf` file in a text editor. Use the examples as reference.
<tr>
<td>Default</td>
<td colspan="2">@code{}
0
disabled
@endcode</td>
</tr>
<tr>
<td>Example</td>
<td colspan="2">@code{}
dd_wa_hdr_toggle_delay = 500
dd_wa_hdr_toggle = enabled
@endcode</td>
</tr>
</table>
@@ -1348,25 +1314,31 @@ editing the `conf` file in a text editor. Use the examples as reference.
</tr>
</table>
### max_bitrate
### min_fps_factor
<table>
<tr>
<td>Description</td>
<td colspan="2">
The maximum bitrate (in Kbps) that Sunshine will encode the stream at. If set to 0, it will always use the bitrate requested by Moonlight.
Sunshine will use this factor to calculate the minimum time between frames. Increasing this value may help
when streaming mostly static content.
@warning{Higher values will consume more bandwidth.}
</td>
</tr>
<tr>
<td>Default</td>
<td colspan="2">@code{}
0
1
@endcode</td>
</tr>
<tr>
<td>Range</td>
<td colspan="2">1-3</td>
</tr>
<tr>
<td>Example</td>
<td colspan="2">@code{}
max_bitrate = 5000
min_fps_factor = 1
@endcode</td>
</tr>
</table>
@@ -1949,8 +1921,7 @@ editing the `conf` file in a text editor. Use the examples as reference.
</tr>
<tr>
<td>wlr</td>
<td>Capture for wlroots based Wayland compositors via wlr-screencopy-unstable-v1. It is possible to capture
virtual displays in e.g. Hyprland using this method.
<td>Capture for wlroots based Wayland compositors via DMA-BUF.
@note{Applies to Linux only.}</td>
</tr>
<tr>

View File

@@ -2,12 +2,6 @@
Read our contribution guide in our organization level
[docs](https://docs.lizardbyte.dev/latest/developers/contributing.html).
## Recommended Tools
| Tool | Description |
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------|
| <a href="https://www.jetbrains.com/clion/"><img src="https://resources.jetbrains.com/storage/products/company/brand/logos/CLion_icon.svg" width="30" height="30"></a><br>CLion | Recommended IDE for C and C++ development. Free for non-commercial use. |
## Project Patterns
### Web UI

View File

@@ -30,9 +30,7 @@ See [Docker](../DOCKER_README.md) for more information.
CUDA is used for NVFBC capture.
@tip{See [CUDA GPUS](https://developer.nvidia.com/cuda-gpus) to cross-reference Compute Capability to your GPU.
The table below applies to packages provided by LizardByte. If you use an official LizardByte package then you do not
need to install CUDA.}
@tip{See [CUDA GPUS](https://developer.nvidia.com/cuda-gpus) to cross-reference Compute Capability to your GPU.}
<table>
<caption>CUDA Compatibility</caption>
@@ -56,27 +54,21 @@ need to install CUDA.}
</tr>
<tr>
<td rowspan="1">12.0.0</td>
<td rowspan="1">525.60.13</td>
<td rowspan="5">50;52;60;61;62;70;72;75;80;86;87;89;90</td>
<td rowspan="2">525.60.13</td>
<td rowspan="4">50;52;60;61;62;70;72;75;80;86;87;89;90</td>
<td>sunshine-debian-bookworm-{arch}.deb</td>
</tr>
<tr>
<td rowspan="1">12.5.1</td>
<td>sunshine.pkg.tar.zst</td>
</tr>
<tr>
<td rowspan="2">12.6.2</td>
<td rowspan="2">560.35.03</td>
<td>sunshine_{arch}.flatpak</td>
</tr>
<tr>
<td>Sunshine (copr - Fedora 41)</td>
</tr>
<tr>
<td rowspan="1">12.8.1</td>
<td rowspan="1">570.124.06</td>
<td>Sunshine (copr - Fedora 42)</td>
</tr>
<tr>
<td rowspan="1">12.9.1</td>
<td rowspan="1">575.57.08</td>
<td>sunshine.pkg.tar.zst</td>
<td>Sunshine (copr)</td>
</tr>
</table>
@@ -343,6 +335,8 @@ recommended for most users. No support will be provided!}
scripts/uninstall-service.bat
```
To uninstall, delete the extracted directory which contains the `sunshine.exe` file.
## Initial Setup
After installation, some initial setup is required.
@@ -495,7 +489,6 @@ All shortcuts start with `Ctrl+Alt+Shift`, just like Moonlight.
instead it simply starts a stream. If you removed it and would like to get it back, just add a new application with
the name "Desktop" and "desktop.png" as the image path.
* For the Linux flatpak you must prepend commands with `flatpak-spawn --host`.
* If inputs (mouse, keyboard, gamepads...) aren't working after connecting, add the user running sunshine to the `input` group.
### HDR Support
Streaming HDR content is officially supported on Windows hosts and experimentally supported for Linux hosts.

View File

@@ -7,9 +7,9 @@ Feel free to contribute your own tips and trips by making a PR to
<div class="section_buttons">
| Previous | Next |
|:----------------------------------------|--------------------------------------------:|
| [Awesome-Sunshine](awesome_sunshine.md) | [Performance Tuning](performance_tuning.md) |
| Previous | Next |
|:--------------------------------|--------------------------------------------:|
| [App Examples](app_examples.md) | [Performance Tuning](performance_tuning.md) |
</div>

View File

@@ -118,16 +118,6 @@ system. You may also want to enable decoders, however that is not required for S
```
}
### Input not working
After installation, the `udev` rules need to be reloaded. Our post-install script tries to do this for you
automatically, but if it fails you may need to restart your system.
If the input is still not working, you may need to add your user to the `input` group.
```bash
sudo usermod -aG input $USER
```
@note{Other build options are listed in the
[meson options](https://gitlab.freedesktop.org/mesa/mesa/-/blob/main/meson_options.txt) file.}

View File

@@ -1,25 +0,0 @@
---
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
version: 2
build:
os: ubuntu-24.04
tools:
ruby: "3.3"
apt_packages:
- 7zip
- jq
jobs:
install:
- |
mkdir -p "./tmp"
branch="master"
base_url="https://raw.githubusercontent.com/LizardByte/LizardByte.github.io"
url="${base_url}/refs/heads/${branch}/scripts/readthedocs_build.sh"
curl -sSL -o "./tmp/readthedocs_build.sh" "${url}"
chmod +x "./tmp/readthedocs_build.sh"
build:
html:
- "./tmp/readthedocs_build.sh"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

View File

@@ -56,7 +56,7 @@ ext-js:
<div class="card-body p-4">
<div class="d-flex align-items-center">
<div class="icon text-white">
<img class="icon" src="https://moonlight-stream.org/images/moonlight.svg" alt="Moonlight"/>
<img class="icon" src="https://moonlight-stream.org/images/moonlight.svg" alt="Moonlight">
</div>
<div class="ms-3">
<h5 class="fw-bolder mb-0">Moonlight Support</h5>
@@ -163,7 +163,7 @@ ext-js:
<div class="card-body p-4">
<div class="d-flex align-items-center">
<div class="icon text-white">
<img class="invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/android.svg" alt="Android"/>
<i class="fa-fw fa-2x fab fa-android"></i>
</div>
<div class="ms-3">
<h5 class="fw-bolder mb-0">
@@ -182,7 +182,7 @@ ext-js:
<a href="https://play.google.com/store/apps/details?id=com.limelight" target="_blank">
<img alt="Get it on Google Play"
src="https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png"
height="60"/>
height="60">
</a>
</div>
<div>
@@ -190,14 +190,14 @@ ext-js:
<img alt="Available at Amazon Appstore"
src="https://images-na.ssl-images-amazon.com/images/G/01/mobile-apps/devportal2/res/images/amazon-appstore-badge-english-black.png"
height="60"
style="padding: 10px;"/>
style="padding: 10px;">
</a>
</div>
<div>
<a href="https://f-droid.org/packages/com.limelight" target="_blank">
<img alt="Get it on F-Droid"
src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
height="60"/>
height="60">
</a>
</div>
</div>
@@ -210,7 +210,7 @@ ext-js:
<div class="card-body p-4">
<div class="d-flex align-items-center">
<div class="icon text-white">
<img class="invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/chromewebstore.svg" alt="Chrome Web Store"/>
<i class="fa-fw fa-2x fab fa-chrome"></i>
</div>
<div class="ms-3">
<h5 class="fw-bolder mb-0">
@@ -229,7 +229,7 @@ ext-js:
<a href="https://chrome.google.com/webstore/detail/moonlight-game-streaming/gemamigbbenahjlfnmlfdjhdnkpbkfjj" target="_blank" class="btn btn-outline-light">
<img alt="Available in the Chrome Web Store"
src="https://developer.chrome.com/static/docs/webstore/branding/image/206x58-chrome-web-043497a3d766e.png"
height="30"/>
height="30">
</a>
</div>
</div>
@@ -242,8 +242,7 @@ ext-js:
<div class="card-body p-4">
<div class="d-flex align-items-center">
<div class="icon text-white">
<img class="invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/ios.svg" alt="iOS"/>
<img class="invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/appletv.svg" alt="Apple TV"/>
<i class="fa-fw fa-2x fab fa-apple"></i>
</div>
<div class="ms-3">
<h5 class="fw-bolder mb-0">
@@ -262,14 +261,14 @@ ext-js:
<a href="https://apps.apple.com/us/app/moonlight-game-streaming/id1000551566" target="_blank">
<img alt="Download on the App Store"
src="https://developer.apple.com/assets/elements/badges/download-on-the-app-store.svg"
height="40"/>
height="40">
</a>
</div>
<div class="pb-3">
<a href="https://apps.apple.com/us/app/moonlight-game-streaming/id1000551566" target="_blank">
<img alt="Download on Apple TV"
src="https://developer.apple.com/app-store/marketing/guidelines/images/badge-download-on-apple-tv.svg"
height="40"/>
height="40">
</a>
</div>
</div>
@@ -282,10 +281,10 @@ ext-js:
<div class="card-body p-4">
<div class="d-flex align-items-center">
<div class="icon text-white">
<img class="invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/linux.svg" alt="Linux"/>
<img class="invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/macos.svg" alt="macOS"/>
<img class="invert" src="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/icons/windows.svg" alt="Windows"/>
<img class="invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/steam.svg" alt="Steam"/>
<i class="fa-fw fa-2x fab fa-linux"></i>
<i class="fa-fw fa-2x fab fa-apple"></i>
<i class="fa-fw fa-2x fab fa-windows"></i>
<i class="fa-fw fa-2x fab fa-steam"></i>
</div>
<div class="ms-3">
<h5 class="fw-bolder mb-0">
@@ -315,7 +314,7 @@ ext-js:
<div class="card-body p-4">
<div class="d-flex align-items-center">
<div class="icon text-white">
<img class="invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/raspberrypi.svg" alt="Raspberry Pi"/>
<i class="fa-fw fa-2x fas fa-microchip"></i>
</div>
<div class="ms-3">
<h5 class="fw-bolder mb-0">
@@ -345,7 +344,7 @@ ext-js:
<div class="card-body p-4">
<div class="d-flex align-items-center">
<div class="icon text-white">
<img class="invert" src="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/icons/xbox.svg" alt="Xbox"/>
<i class="fa-fw fa-2x fab fa-xbox"></i>
</div>
<div class="ms-3">
<h5 class="fw-bolder mb-0">
@@ -364,7 +363,7 @@ ext-js:
<a href="https://apps.microsoft.com/store/detail/moonlight-uwp/9MW1BS08ZBTH" target="_blank">
<img alt="Get it from Microsoft"
src="https://get.microsoft.com/images/en-us%20dark.svg"
height="40"/>
height="40">
</a>
</div>
</div>
@@ -377,7 +376,7 @@ ext-js:
<div class="card-body p-4">
<div class="d-flex align-items-center">
<div class="icon text-white">
<img class="invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/playstationvita.svg" alt="PlayStation Vita"/>
<i class="fa-fw fa-2x fab fa-playstation"></i>
</div>
<div class="ms-3">
<h5 class="fw-bolder mb-0">
@@ -407,16 +406,12 @@ ext-js:
<div class="card-body p-4">
<div class="d-flex align-items-center">
<div class="icon text-white">
<img class="invert" src="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/icons/nintendo-switch.svg" alt="Nintendo Switch"/>
<img class="invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/android.svg" alt="Android"/>
<img class="invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/appletv.svg" alt="Apple TV"/>
<img class="invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/ios.svg" alt="iOS"/>
<img class="invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/macos.svg" alt="macOS"/>
<i class="fa-fw fa-2x fas fa-code"></i>
</div>
<div class="ms-3">
<h5 class="fw-bolder mb-0">
<a href="https://github.com/XITRIX/Moonlight-Switch" target="_blank" class="text-white text-decoration-none">
Moonlight Switch
Nintendo Switch
</a>
</h5>
</div>
@@ -441,7 +436,7 @@ ext-js:
<div class="card-body p-4">
<div class="d-flex align-items-center">
<div class="icon text-white">
<img class="invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v12/icons/wiiu.svg" alt="Wii U"/>
<i class="fa-fw fa-2x fas fa-code"></i>
</div>
<div class="ms-3">
<h5 class="fw-bolder mb-0">
@@ -465,43 +460,13 @@ ext-js:
</div>
</div>
<!-- New Nintendo 3DS -->
<div class="col-md-6 col-lg-4 mb-5">
<div class="card bg-dark text-white rounded-0">
<div class="card-body p-4">
<div class="d-flex align-items-center">
<div class="icon text-white">
<img class="invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v12/icons/nintendo3ds.svg" alt="3DS"/>
</div>
<div class="ms-3">
<h5 class="fw-bolder mb-0">
<a href="https://github.com/zoeyjodon/moonlight-N3DS" target="_blank" class="text-white text-decoration-none">
New Nintendo 3DS
</a>
</h5>
</div>
<div class="ms-auto">
<span class="badge text-bg-warning rounded-pill">Community</span>
</div>
</div>
</div>
<div class="card-footer p-3 px-4">
<div class="pb-3">
<a href="https://github.com/zoeyjodon/moonlight-N3DS" target="_blank" class="btn btn-info">
<i class="fas fa-download"></i> Download
</a>
</div>
</div>
</div>
</div>
<!-- LG webOS TV -->
<div class="col-md-6 col-lg-4 mb-5">
<div class="card bg-dark text-white rounded-0">
<div class="card-body p-4">
<div class="d-flex align-items-center">
<div class="icon text-white">
<img class="invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/lg.svg" alt="LG webOS TV"/>
<i class="fa-fw fa-2x fas fa-code"></i>
</div>
<div class="ms-3">
<h5 class="fw-bolder mb-0">
@@ -549,7 +514,7 @@ ext-js:
</div>
<div class="card-footer p-3 px-4">
<a class="btn btn-outline-light me-3 mb-3" href="https://docs.lizardbyte.dev/projects/sunshine" target="_blank">
<img class="icon-sm invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/readthedocs.svg" alt="ReadTheDocs"/>
<i class="fa-fw fas fa-book"></i>
Read the Docs
</a>
</div>
@@ -572,37 +537,27 @@ ext-js:
</div>
<div class="card-footer p-3 px-4">
<a class="latest-button btn btn-outline-light me-3 mb-3 d-none" href="https://github.com/LizardByte/Sunshine/releases/latest" target="_blank">
<img class="icon-sm invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/github.svg" alt="GitHub"/>
<img class="icon-sm invert" src="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/icons/windows.svg" alt="Windows"/>
<img class="icon-sm invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/debian.svg" alt="Debian"/>
<img class="icon-sm invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/ubuntu.svg" alt="Ubuntu"/>
<img class="icon-sm invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/flatpak.svg" alt="Flatpak"/>
<img class="icon-sm invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/linux.svg" alt="AppImage"/>
Latest: <span id="latest-version" class="crowdin-ignore"></span>
<i class="fa-fw fab fa-github"></i>
Latest: <span id="latest-version"></span>
</a>
<a class="beta-button btn btn-outline-light me-3 mb-3 d-none" href="#" target="_blank">
<i class="fa-fw fa-lg fas fa-flask"></i>
<img class="icon-sm invert" src="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/icons/windows.svg" alt="Windows"/>
<img class="icon-sm invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/debian.svg" alt="Debian"/>
<img class="icon-sm invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/ubuntu.svg" alt="Ubuntu"/>
<img class="icon-sm invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/flatpak.svg" alt="Flatpak"/>
<img class="icon-sm invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/linux.svg" alt="AppImage"/>
Beta: <span id="beta-version" class="crowdin-ignore"></span>
<i class="fa-fw fas fa-flask"></i>
Beta: <span id="beta-version"></span>
</a>
<a class="btn btn-outline-light me-3 mb-3" href="https://github.com/LizardByte/pacman-repo" target="_blank">
<img class="icon-sm invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/archlinux.svg" alt="Arch Linux"/>
Arch Linux
<i class="fa-fw fab fa-linux"></i>
ArchLinux
</a>
<a class="btn btn-outline-light me-3 mb-3" href="https://hub.docker.com/r/lizardbyte/sunshine" target="_blank">
<img class="icon-sm invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/docker.svg" alt="Docker"/>
<i class="fa-fw fab fa-docker"></i>
Docker
</a>
<a class="btn btn-outline-light me-3 mb-3" href="https://flathub.org/apps/dev.lizardbyte.app.Sunshine" target="_blank">
<img class="icon-sm invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/flathub.svg" alt="Flathub"/>
<i class="fa-fw fab fa-linux"></i>
Flathub
</a>
<a class="btn btn-outline-light me-3 mb-3" href="https://github.com/LizardByte/homebrew-homebrew" target="_blank">
<img class="icon-sm invert" src="https://cdn.jsdelivr.net/npm/simple-icons@v14/icons/homebrew.svg" alt="Homebrew"/>
<i class="fa-fw fas fa-beer-mug-empty"></i>
Homebrew
</a>
</div>
@@ -622,21 +577,16 @@ ext-js:
// Filter the releases to get only the stable releases
const stableReleases = data.filter(release => !release.prerelease);
const latestButton = document.querySelector('.latest-button');
const latestVersion = document.querySelector('#latest-version');
const betaButton = document.querySelector('.beta-button');
const betaVersion = document.querySelector('#beta-version');
// If there are no stable releases, hide the latest download button
if (stableReleases.length === 0) {
latestButton.classList.add('d-none');
document.querySelector('.latest-button').classList.add('d-none');
} else {
// Show the latest download button
latestButton.classList.remove('d-none');
document.querySelector('.latest-button').classList.remove('d-none');
// Get the latest stable release
const latestStableRelease = stableReleases[0];
latestVersion.textContent = latestStableRelease.tag_name;
document.querySelector('#latest-version').textContent = latestStableRelease.tag_name;
// If there is a pre-release, update the href attribute of the anchor tag
if (preReleases.length > 0) {
@@ -648,16 +598,16 @@ ext-js:
// If the pre-release is newer, update the href attribute of the anchor tag
if (preReleaseDate > stableReleaseDate) {
betaButton.href = latestPreRelease.html_url;
betaVersion.textContent = latestPreRelease.tag_name;
betaButton.classList.remove('d-none');
document.querySelector('.beta-button').href = latestPreRelease.html_url;
document.querySelector('#beta-version').textContent = latestPreRelease.tag_name;
document.querySelector('.beta-button').classList.remove('d-none');
} else {
// If the pre-release is older, hide the button
betaButton.classList.add('d-none');
document.querySelector('.beta-button').classList.add('d-none');
}
} else {
// If there is no pre-release, hide the button
betaButton.classList.add('d-none');
document.querySelector('.beta-button').classList.add('d-none');
}
}
});

View File

@@ -8,15 +8,14 @@
"serve": "serve ./tests/fixtures/http --no-port-switching"
},
"dependencies": {
"@lizardbyte/shared-web": "2025.626.181239",
"vue": "3.5.17",
"vue-i18n": "11.1.7"
"@lizardbyte/shared-web": "2024.921.191855",
"vue": "3.5.13",
"vue-i18n": "11.0.1"
},
"devDependencies": {
"@codecov/vite-plugin": "1.9.1",
"@vitejs/plugin-vue": "4.6.2",
"serve": "14.2.4",
"vite": "4.5.14",
"serve": "14.2.3",
"vite": "4.5.2",
"vite-plugin-ejs": "1.6.4"
}
}

View File

@@ -1,13 +1,13 @@
[Desktop Entry]
Categories=RemoteAccess;Network;
Comment=@PROJECT_DESCRIPTION@
Type=Application
Name=@PROJECT_NAME@
Exec=sunshine
Version=1.0
Comment=@PROJECT_DESCRIPTION@
Icon=sunshine
Keywords=gamestream;stream;moonlight;remote play;
Name=@PROJECT_NAME@
Categories=AudioVideo;Network;RemoteAccess;
Terminal=true
Type=Application
Version=1.0
X-AppImage-Arch=x86_64
X-AppImage-Name=sunshine
X-AppImage-Version=@PROJECT_VERSION@
X-AppImage-Arch=x86_64

View File

@@ -10,7 +10,7 @@ url=@PROJECT_HOMEPAGE_URL@
license=('GPL-3.0-only')
install=sunshine.install
_gcc_version=14
_gcc_version=13
depends=(
'avahi'
@@ -36,10 +36,7 @@ depends=(
)
makedepends=(
'appstream'
'appstream-glib'
'cmake'
'desktop-file-utils'
'cuda'
"gcc${_gcc_version}"
'git'
@@ -89,11 +86,6 @@ build() {
-D SUNSHINE_PUBLISHER_WEBSITE='https://app.lizardbyte.dev' \
-D SUNSHINE_PUBLISHER_ISSUE_URL='https://app.lizardbyte.dev/support'
appstreamcli validate "build/dev.lizardbyte.app.Sunshine.metainfo.xml"
appstream-util validate "build/dev.lizardbyte.app.Sunshine.metainfo.xml"
desktop-file-validate "build/dev.lizardbyte.app.Sunshine.desktop"
desktop-file-validate "build/dev.lizardbyte.app.Sunshine.terminal.desktop"
make -C build
}

View File

@@ -15,11 +15,10 @@ License: GPLv3-only
URL: https://github.com/LizardByte/Sunshine
Source0: tarball.tar.gz
BuildRequires: appstream
# BuildRequires: boost-devel >= 1.86.0
BuildRequires: cmake >= 3.25.0
BuildRequires: desktop-file-utils
BuildRequires: libappstream-glib
BuildRequires: gcc
BuildRequires: gcc-c++
BuildRequires: libayatana-appindicator3-devel
BuildRequires: libcap-devel
BuildRequires: libcurl-devel
@@ -38,7 +37,6 @@ BuildRequires: libXrandr-devel
BuildRequires: libXtst-devel
BuildRequires: git
BuildRequires: mesa-libGL-devel
BuildRequires: mesa-libgbm-devel
BuildRequires: miniupnpc-devel
BuildRequires: npm
BuildRequires: numactl-devel
@@ -56,22 +54,11 @@ BuildRequires: which
BuildRequires: xorg-x11-server-Xvfb
# Conditional BuildRequires for cuda-gcc based on Fedora version
%if 0%{?fedora} >= 40 && 0%{?fedora} <= 41
BuildRequires: gcc13
BuildRequires: gcc13-c++
%global gcc_version 13
%global cuda_version 12.6.3
%global cuda_build 560.35.05
%elif %{?fedora} >= 42
BuildRequires: gcc14
BuildRequires: gcc14-c++
%global gcc_version 14
%global cuda_version 12.8.1
%global cuda_build 570.124.06
%if 0%{?fedora} >= 40
# this package conflicts with gcc on f39
BuildRequires: cuda-gcc-c++
%endif
%global cuda_dir %{_builddir}/cuda
Requires: libcap >= 2.22
Requires: libcurl >= 7.0
Requires: libdrm > 2.4.97
@@ -101,14 +88,20 @@ ls -a %{_builddir}/Sunshine
%autopatch -p1
%build
# exit on error
set -e
# Detect the architecture and Fedora version
architecture=$(uname -m)
fedora_version=%{fedora}
cuda_supported_architectures=("x86_64" "aarch64")
# set cuda_version based on Fedora version
case "$fedora_version" in
*)
cuda_version="12.6.3"
cuda_build="560.35.05"
;;
esac
# prepare CMAKE args
cmake_args=(
"-B=%{_builddir}/Sunshine/build"
@@ -128,23 +121,27 @@ cmake_args=(
"-DSUNSHINE_PUBLISHER_ISSUE_URL=https://app.lizardbyte.dev/support"
)
export CC=gcc-%{gcc_version}
export CXX=g++-%{gcc_version}
function install_cuda() {
# check if we need to install cuda
if [ -f "%{cuda_dir}/bin/nvcc" ]; then
if [ -f "%{_builddir}/cuda/bin/nvcc" ]; then
echo "cuda already installed"
return
fi
if [ "$fedora_version" -ge 40 ]; then
# update environment variables for CUDA, necessary when using cuda-gcc-c++
export NVCC_PREPEND_FLAGS='-ccbin /usr/bin/g++-13'
export PATH=/usr/bin/cuda:"%{_builddir}/cuda/bin:${PATH}"
export LD_LIBRARY_PATH="%{_builddir}/cuda/lib64:${LD_LIBRARY_PATH}"
fi
local cuda_prefix="https://developer.download.nvidia.com/compute/cuda/"
local cuda_suffix=""
if [ "$architecture" == "aarch64" ]; then
local cuda_suffix="_sbsa"
fi
local url="${cuda_prefix}%{cuda_version}/local_installers/cuda_%{cuda_version}_%{cuda_build}_linux${cuda_suffix}.run"
local url="${cuda_prefix}${cuda_version}/local_installers/cuda_${cuda_version}_${cuda_build}_linux${cuda_suffix}.run"
echo "cuda url: ${url}"
wget \
"$url" \
@@ -160,31 +157,23 @@ function install_cuda() {
--override \
--silent \
--toolkit \
--toolkitpath="%{cuda_dir}"
--toolkitpath="%{_builddir}/cuda"
rm "%{_builddir}/cuda.run"
# we need to patch math_functions.h on fedora 42
# see https://forums.developer.nvidia.com/t/error-exception-specification-is-incompatible-for-cospi-sinpi-cospif-sinpif-with-glibc-2-41/323591/3
if [ "%{?fedora}" -eq 42 ]; then
echo "Original math_functions.h:"
find "%{cuda_dir}" -name math_functions.h -exec cat {} \;
# Apply the patch
patch -p2 \
--backup \
--directory="%{cuda_dir}" \
--verbose \
< "%{_builddir}/Sunshine/packaging/linux/fedora/patches/f42/${architecture}/01-math_functions.patch"
fi
}
if [ -n "%{cuda_version}" ] && [[ " ${cuda_supported_architectures[@]} " =~ " ${architecture} " ]]; then
# we need to clear these flags to avoid linkage errors with cuda-gcc-c++
export CFLAGS=""
export CXXFLAGS=""
export FFLAGS=""
export FCFLAGS=""
export LDFLAGS=""
export CC=gcc-13
export CXX=g++-13
if [ -n "$cuda_version" ] && [[ " ${cuda_supported_architectures[@]} " =~ " ${architecture} " ]]; then
install_cuda
cmake_args+=("-DSUNSHINE_ENABLE_CUDA=ON")
cmake_args+=("-DCMAKE_CUDA_COMPILER:PATH=%{cuda_dir}/bin/nvcc")
cmake_args+=("-DCMAKE_CUDA_HOST_COMPILER=gcc-%{gcc_version}")
else
cmake_args+=("-DSUNSHINE_ENABLE_CUDA=OFF")
cmake_args+=("-DCMAKE_CUDA_COMPILER:PATH=%{_builddir}/cuda/bin/nvcc")
fi
# setup the version
@@ -200,11 +189,6 @@ cmake "${cmake_args[@]}"
make -j$(nproc) -C "%{_builddir}/Sunshine/build"
%check
# validate the metainfo file
appstreamcli validate %{buildroot}%{_metainfodir}/*.metainfo.xml
appstream-util validate %{buildroot}%{_metainfodir}/*.metainfo.xml
desktop-file-validate %{buildroot}%{_datadir}/applications/*.desktop
# run tests
cd %{_builddir}/Sunshine/build
xvfb-run ./tests/test_sunshine
@@ -260,14 +244,14 @@ rm -f /usr/lib/modules-load.d/uhid.conf
%{_modulesloaddir}/uhid.conf
# Desktop entries
%{_datadir}/applications/*.desktop
%{_datadir}/applications/sunshine*.desktop
# Icons
%{_datadir}/icons/hicolor/scalable/apps/sunshine.svg
%{_datadir}/icons/hicolor/scalable/status/sunshine*.svg
# Metainfo
%{_datadir}/metainfo/*.metainfo.xml
%{_datadir}/metainfo/sunshine.appdata.xml
# Assets
%{_datadir}/sunshine/**

View File

@@ -1,39 +0,0 @@
diff '--color=auto' -ur a/cuda/targets/sbsa-linux/include/crt/math_functions.h b/cuda/targets/sbsa-linux/include/crt/math_functions.h
--- a/cuda/targets/sbsa-linux/include/crt/math_functions.h 2024-08-23 00:25:39.000000000 +0200
+++ b/cuda/targets/sbsa-linux/include/crt/math_functions.h 2025-02-17 01:19:44.270292640 +0100
@@ -2553,7 +2553,7 @@
*
* \note_accuracy_double
*/
-extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ double sinpi(double x);
+extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ double sinpi(double x) noexcept (true);
/**
* \ingroup CUDA_MATH_SINGLE
* \brief Calculate the sine of the input argument
@@ -2576,7 +2576,7 @@
*
* \note_accuracy_single
*/
-extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ float sinpif(float x);
+extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ float sinpif(float x) noexcept (true);
/**
* \ingroup CUDA_MATH_DOUBLE
* \brief Calculate the cosine of the input argument
@@ -2598,7 +2598,7 @@
*
* \note_accuracy_double
*/
-extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ double cospi(double x);
+extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ double cospi(double x) noexcept (true);
/**
* \ingroup CUDA_MATH_SINGLE
* \brief Calculate the cosine of the input argument
@@ -2620,7 +2620,7 @@
*
* \note_accuracy_single
*/
-extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ float cospif(float x);
+extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ float cospif(float x) noexcept (true);
/**
* \ingroup CUDA_MATH_DOUBLE
* \brief Calculate the sine and cosine of the first input argument

View File

@@ -1,39 +0,0 @@
diff '--color=auto' -ur a/cuda/targets/x86_64-linux/include/crt/math_functions.h b/cuda/targets/x86_64-linux/include/crt/math_functions.h
--- a/cuda/targets/x86_64-linux/include/crt/math_functions.h 2024-08-23 00:25:39.000000000 +0200
+++ b/cuda/targets/x86_64-linux/include/crt/math_functions.h 2025-02-17 01:19:44.270292640 +0100
@@ -2553,7 +2553,7 @@
*
* \note_accuracy_double
*/
-extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ double sinpi(double x);
+extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ double sinpi(double x) noexcept (true);
/**
* \ingroup CUDA_MATH_SINGLE
* \brief Calculate the sine of the input argument
@@ -2576,7 +2576,7 @@
*
* \note_accuracy_single
*/
-extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ float sinpif(float x);
+extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ float sinpif(float x) noexcept (true);
/**
* \ingroup CUDA_MATH_DOUBLE
* \brief Calculate the cosine of the input argument
@@ -2598,7 +2598,7 @@
*
* \note_accuracy_double
*/
-extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ double cospi(double x);
+extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ double cospi(double x) noexcept (true);
/**
* \ingroup CUDA_MATH_SINGLE
* \brief Calculate the cosine of the input argument
@@ -2620,7 +2620,7 @@
*
* \note_accuracy_single
*/
-extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ float cospif(float x);
+extern __DEVICE_FUNCTIONS_DECL__ __device_builtin__ float cospif(float x) noexcept (true);
/**
* \ingroup CUDA_MATH_DOUBLE
* \brief Calculate the sine and cosine of the first input argument

View File

@@ -1,22 +1,13 @@
<div align="center">
<img src="https://raw.githubusercontent.com/LizardByte/Sunshine/master/sunshine.png" />
<h1 align="center">Sunshine</h1>
<h4 align="center">Self-hosted game stream host for Moonlight.</h4>
</div>
# Overview
<div align="center">
<a href="https://flathub.org/apps/dev.lizardbyte.app.Sunshine"><img src="https://img.shields.io/flathub/downloads/dev.lizardbyte.app.Sunshine?style=for-the-badge&logo=flathub" alt="Flathub installs"></a>
<a href="https://flathub.org/apps/dev.lizardbyte.app.Sunshine"><img src="https://img.shields.io/flathub/v/dev.lizardbyte.app.Sunshine?style=for-the-badge&logo=flathub" alt="Flathub Version"></a>
</div>
[![Flathub installs](https://img.shields.io/flathub/downloads/dev.lizardbyte.app.Sunshine?style=for-the-badge&logo=flathub)](https://flathub.org/apps/dev.lizardbyte.app.Sunshine)
[![Flathub Version](https://img.shields.io/flathub/v/dev.lizardbyte.app.Sunshine?style=for-the-badge&logo=flathub)](https://flathub.org/apps/dev.lizardbyte.app.Sunshine)
## About
LizardByte has the full documentation hosted on [Read the Docs](https://docs.lizardbyte.dev/projects/sunshine).
## About
Sunshine is a self-hosted game stream host for Moonlight.
LizardByte has the full documentation hosted on [Read the Docs](https://docs.lizardbyte.dev/projects/sunshine)
* [Stable](https://docs.lizardbyte.dev/projects/sunshine/latest/)
* [Beta](https://docs.lizardbyte.dev/projects/sunshine/master/)
This repo is synced from the upstream [Sunshine](https://github.com/LizardByte/Sunshine) repo.
Please report issues and contribute to the upstream repo.

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop">
<component type="desktop-application">
<id>@PROJECT_FQDN@</id>
<name>@PROJECT_NAME@</name>
<name>@CMAKE_PROJECT_NAME@</name>
<summary>@PROJECT_BRIEF_DESCRIPTION@</summary>
<metadata_license>CC0-1.0</metadata_license>
@@ -15,49 +15,39 @@
<control>gamepad</control>
</supports>
<url type="homepage">@PROJECT_HOMEPAGE_URL@</url>
<url type="bugtracker">https://github.com/LizardByte/Sunshine/issues</url>
<url type="faq">https://docs.lizardbyte.dev/projects/sunshine/latest/md_docs_2troubleshooting.html</url>
<url type="help">https://docs.lizardbyte.dev/projects/sunshine</url>
<url type="homepage">@PROJECT_HOMEPAGE_URL@</url>
<url type="donation">https://app.lizardbyte.dev/#Donate</url>
<url type="translate">https://translate.lizardbyte.dev</url>
<url type="contact">https://app.lizardbyte.dev/support</url>
<url type="translate">https://translate.lizardbyte.dev</url>
<url type="contribute">https://docs.lizardbyte.dev</url>
<url type="vcs-browser">https://github.com/LizardByte/Sunshine</url>
<description>
<p>
@PROJECT_LONG_DESCRIPTION@
</p>
<p>NOTE: Sunshine requires additional installation steps (Flatpak).</p>
<p>NOTE: Sunshine requires additional installation steps.</p>
<p>
<code>flatpak run --command=additional-install.sh @PROJECT_FQDN@</code>
</p>
<p>NOTE: Sunshine uses a self-signed certificate. The web browser will report it as not secure, but it is safe.</p>
<p>NOTE: KMS Grab (Flatpak)</p>
<p>NOTE: KMS Grab (Optional)</p>
<p>
<code>sudo -i PULSE_SERVER=unix:/run/user/$(id -u $whoami)/pulse/native flatpak run @PROJECT_FQDN@</code>
</p>
</description>
<releases>
<release version="@PROJECT_VERSION@" date="@PROJECT_YEAR@-@PROJECT_MONTH@-@PROJECT_DAY@">
<description>
<p>
See the full changelog on GitHub
<!-- changelog -->
</p>
</description>
</release>
<release version="@PROJECT_VERSION@" date="1990-01-01"></release>
</releases>
<developer id="dev.lizardbyte">
<name>LizardByte</name>
</developer>
<developer_name>LizardByte</developer_name>
<screenshots>
<screenshot type="default">
<image>https://app.lizardbyte.dev/Sunshine/assets/img/screenshots/01-sunshine-welcome-page.png</image>
<caption>Sunshine welcome page</caption>
<image>https://app.lizardbyte.dev/Sunshine/assets/img/banners/AdobeStock_305732536_1920x1280.jpg</image>
<caption>Sunshine</caption>
</screenshot>
</screenshots>
<content_rating type="oars-1.0">

View File

@@ -1,9 +0,0 @@
{
"dev.lizardbyte.app.Sunshine": [
"appstream-external-screenshot-url",
"appstream-screenshots-not-mirrored-in-ostree",
"external-gitmodule-url-found",
"finish-args-flatpak-spawn-access",
"finish-args-home-filesystem-access"
]
}

View File

@@ -0,0 +1,9 @@
{
"errors": [
"finish-args-flatpak-spawn-access"
],
"info": [
"finish-args-flatpak-spawn-access: finish-args has a talk-name access for org.freedesktop.Flatpak"
],
"message": "Please consult the documentation at https://docs.flathub.org/docs/for-app-authors/linter"
}

View File

@@ -0,0 +1,11 @@
{
"errors": [
"appstream-missing-screenshots",
"finish-args-flatpak-spawn-access"
],
"info": [
"appstream-missing-screenshots: Catalogue file has no screenshots. Please check if screenshot URLs are reachable",
"finish-args-flatpak-spawn-access: finish-args has a talk-name access for org.freedesktop.Flatpak"
],
"message": "Please consult the documentation at https://docs.flathub.org/docs/for-app-authors/linter"
}

View File

@@ -9,8 +9,8 @@
"sources": [
{
"type": "archive",
"url": "https://github.com/boostorg/boost/releases/download/boost-1.87.0/boost-1.87.0-cmake.tar.xz",
"sha256": "7da75f171837577a52bbf217e17f8ea576c7c246e4594d617bfde7fafd408be5"
"url": "https://github.com/boostorg/boost/releases/download/boost-1.86.0/boost-1.86.0-cmake.tar.xz",
"sha256": "2c5ec5edcdff47ff55e27ed9560b0a0b94b07bd07ed9928b476150e16b0efc57"
}
]
}

View File

@@ -11,15 +11,14 @@
],
"sources": [
{
"type": "git",
"url": "https://github.com/LizardByte-infrastructure/xserver.git",
"tag": "xorg-server-21.1.13",
"commit": "be2767845d6ed3c6dbd25a151051294d0908a995",
"type": "archive",
"url": "https://gitlab.freedesktop.org/xorg/xserver/-/archive/xorg-server-21.1.13/xserver-xorg-server-21.1.13.tar.bz2",
"sha256": "ee2bf6d65f4b111ce86ca817c3327dc1e70d9c958aa16876f2820caf7bf7cffa",
"x-checker-data": {
"type": "anitya",
"project-id": 5250,
"stable-only": true,
"tag-template": "xorg-server-$version"
"url-template": "https://gitlab.freedesktop.org/xorg/xserver/-/archive/xorg-server-$version/xserver-xorg-server-$version.tar.bz2"
}
},
{
@@ -33,15 +32,14 @@
"buildsystem": "meson",
"sources": [
{
"type": "git",
"url": "https://github.com/LizardByte-infrastructure/libxcvt.git",
"tag": "libxcvt-0.1.2",
"commit": "d9ca87eea9eecddaccc3a77227bcb3acf84e89df",
"type": "archive",
"url": "https://gitlab.freedesktop.org/xorg/lib/libxcvt/-/archive/libxcvt-0.1.2/libxcvt-libxcvt-0.1.2.tar.bz2",
"sha256": "590e5a6da87ace7aa7857026b207a2c4d378620035441e20ea97efedd15d6d4a",
"x-checker-data": {
"type": "anitya",
"project-id": 235147,
"stable-only": true,
"tag-template": "libxcvt-$version"
"url-template": "https://gitlab.freedesktop.org/xorg/lib/libxcvt/-/archive/libxcvt-$version/libxcvt-libxcvt-$version.tar.bz2"
}
}
]
@@ -50,32 +48,14 @@
"name": "libXmu",
"sources": [
{
"type": "git",
"url": "https://github.com/LizardByte-infrastructure/libxmu.git",
"tag": "libXmu-1.2.1",
"commit": "792f80402ee06ce69bca3a8f2a84295999c3a170",
"type": "archive",
"url": "https://xorg.freedesktop.org/archive/individual/lib/libXmu-1.2.1.tar.gz",
"sha256": "bf0902583dd1123856c11e0a5085bd3c6e9886fbbd44954464975fd7d52eb599",
"x-checker-data": {
"type": "anitya",
"project-id": 1785,
"stable-only": true,
"tag-template": "libXmu-$version"
}
}
]
},
{
"name": "font-util",
"sources": [
{
"type": "git",
"url": "https://github.com/LizardByte-infrastructure/font-util.git",
"tag": "font-util-1.4.1",
"commit": "b5ca142f81a6f14eddb23be050291d1c25514777",
"x-checker-data": {
"type": "anitya",
"project-id": 15055,
"stable-only": true,
"tag-template": "font-util-$version"
"url-template": "https://xorg.freedesktop.org/archive/individual/lib/libXmu-$version.tar.gz"
}
}
]
@@ -84,15 +64,14 @@
"name": "libfontenc",
"sources": [
{
"type": "git",
"url": "https://github.com/LizardByte-infrastructure/libfontenc.git",
"tag": "libfontenc-1.1.8",
"commit": "92a85fda2acb4e14ec0b2f6d8fe3eaf2b687218c",
"type": "archive",
"url": "https://xorg.freedesktop.org/archive/individual/lib/libfontenc-1.1.8.tar.xz",
"sha256": "7b02c3d405236e0d86806b1de9d6868fe60c313628b38350b032914aa4fd14c6",
"x-checker-data": {
"type": "anitya",
"project-id": 1613,
"stable-only": true,
"tag-template": "libfontenc-$version"
"url-template": "https://xorg.freedesktop.org/archive/individual/lib/libfontenc-$version.tar.xz"
}
}
]
@@ -116,19 +95,34 @@
}
]
},
{
"name": "font-util",
"sources": [
{
"type": "archive",
"url": "https://xorg.freedesktop.org/archive/individual/font/font-util-1.4.1.tar.gz",
"sha256": "f029ae80cdd75d89bee7f7af61c21e07982adfb9f72344a158b99f91f77ef5ed",
"x-checker-data": {
"type": "anitya",
"project-id": 15055,
"stable-only": true,
"url-template": "https://xorg.freedesktop.org/archive/individual/font/font-util-$version.tar.gz"
}
}
]
},
{
"name": "xvfb-libXfont2",
"sources": [
{
"type": "git",
"url": "https://github.com/LizardByte-infrastructure/libxfont.git",
"tag": "libXfont2-2.0.6",
"commit": "d54aaf2483df6a1f98fadc09004157e657b7f73e",
"type": "archive",
"url": "https://xorg.freedesktop.org/archive/individual/lib/libXfont2-2.0.6.tar.gz",
"sha256": "a944df7b6837c8fa2067f6a5fc25d89b0acc4011cd0bc085106a03557fb502fc",
"x-checker-data": {
"type": "anitya",
"project-id": 17165,
"stable-only": true,
"tag-template": "libXfont2-$version"
"url-template": "https://xorg.freedesktop.org/archive/individual/lib/libXfont2-$version.tar.gz"
}
}
]
@@ -137,15 +131,14 @@
"name": "xvfb-xauth",
"sources": [
{
"type": "git",
"url": "https://github.com/LizardByte-infrastructure/xauth.git",
"tag": "xauth-1.1.3",
"commit": "c29eef23683f0e3575a3c60d9314de8156fbe2c2",
"type": "archive",
"url": "https://gitlab.freedesktop.org/xorg/app/xauth/-/archive/xauth-1.1.1/xauth-xauth-1.1.3.tar.bz2",
"sha256": "3cee16ebe9de0e85c62513f6d6353710407c8ebb1f855b18d03807c27d38a215",
"x-checker-data": {
"type": "anitya",
"project-id": 5253,
"stable-only": true,
"tag-template": "xauth-$version"
"url-template": "https://gitlab.freedesktop.org/xorg/app/xauth/-/archive/xauth-1.1.1/xauth-xauth-$version.tar.bz2"
}
}
]

View File

@@ -8,4 +8,4 @@ echo Sunshine User Service has been removed.
# Udev rule
flatpak-spawn --host pkexec sh -c "rm /etc/udev/rules.d/60-sunshine.rules"
echo Input rules removed. Restart computer to take effect.
echo Mouse permission removed. Restart computer to take effect.

View File

@@ -1,5 +1,5 @@
[Desktop Entry]
Categories=RemoteAccess;Network;
Categories=AudioVideo;Network;RemoteAccess;
Comment=@PROJECT_DESCRIPTION@
Exec=sunshine.sh
Icon=@SUNSHINE_DESKTOP_ICON@

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop">
<id>@PROJECT_NAME@.desktop</id>
<metadata_license>@PROJECT_LICENSE@</metadata_license>
<project_license>@PROJECT_LICENSE@</project_license>
<name>@PROJECT_NAME@</name>
<url type="homepage">@CMAKE_PROJECT_HOMEPAGE_URL@</url>
<summary>@PROJECT_BRIEF_DESCRIPTION@</summary>
<description>
<p>
@PROJECT_LONG_DESCRIPTION@
</p>
</description>
<screenshots>
<screenshot type="default">
<image>https://app.lizardbyte.dev/Sunshine/assets/images/AdobeStock_305732536_1920x1280.jpg</image>
<caption>Sunshine</caption>
</screenshot>
</screenshots>
</component>

View File

@@ -1,15 +1,15 @@
[Desktop Entry]
Actions=RunInTerminal;
Categories=RemoteAccess;Network;
Comment=@PROJECT_DESCRIPTION@
Type=Application
Name=@PROJECT_NAME@
Exec=/usr/bin/env systemctl start --u sunshine
Version=1.0
Comment=@PROJECT_DESCRIPTION@
Icon=@SUNSHINE_DESKTOP_ICON@
Keywords=gamestream;stream;moonlight;remote play;
Name=@PROJECT_NAME@
Type=Application
Version=1.0
Categories=AudioVideo;Network;RemoteAccess;
Actions=RunInTerminal;
[Desktop Action RunInTerminal]
Exec=gio launch @CMAKE_INSTALL_FULL_DATAROOTDIR@/applications/@PROJECT_FQDN@.terminal.desktop
Icon=application-x-executable
Name=Run in Terminal
Icon=application-x-executable
Exec=gio launch @CMAKE_INSTALL_FULL_DATAROOTDIR@/applications/sunshine_terminal.desktop

View File

@@ -29,34 +29,16 @@ class @PROJECT_NAME@ < Formula
depends_on "cmake" => :build
depends_on "doxygen" => :build
depends_on "graphviz" => :build
depends_on "ninja" => :build
depends_on "node" => :build
depends_on "pkg-config" => :build
depends_on "curl"
depends_on "miniupnpc"
depends_on "openssl"
depends_on "opus"
depends_on "boost" => :recommended
depends_on "icu4c" => :recommended
on_linux do
# the "build" dependencies are for libayatana-appindicator
depends_on "at-spi2-core" => :build
depends_on "cairo" => :build
depends_on "fontconfig" => :build
depends_on "freetype" => :build
depends_on "fribidi" => :build
depends_on "gettext" => :build
depends_on "gobject-introspection" => :build
depends_on "graphite2" => :build
depends_on "gtk+3" => :build
depends_on "harfbuzz" => :build
depends_on "intltool" => :build
depends_on "libepoxy" => :build
depends_on "libxdamage" => :build
depends_on "libxkbcommon" => :build
depends_on "pango" => :build
depends_on "perl" => :build
depends_on "pixman" => :build
depends_on "avahi"
depends_on "libcap"
depends_on "libdrm"
@@ -70,133 +52,10 @@ class @PROJECT_NAME@ < Formula
depends_on "libxinerama"
depends_on "libxrandr"
depends_on "libxtst"
depends_on "mesa"
depends_on "numactl"
depends_on "pulseaudio"
depends_on "systemd"
depends_on "wayland"
# resources that do not have brew packages
resource "libayatana-appindicator" do
url "https://github.com/AyatanaIndicators/libayatana-appindicator/archive/refs/tags/0.5.94.tar.gz"
sha256 "884a6bc77994c0b58c961613ca4c4b974dc91aa0f804e70e92f38a542d0d0f90"
end
resource "libdbusmenu" do
url "https://launchpad.net/libdbusmenu/16.04/16.04.0/+download/libdbusmenu-16.04.0.tar.gz"
sha256 "b9cc4a2acd74509435892823607d966d424bd9ad5d0b00938f27240a1bfa878a"
patch 'From 729546c51806a1b3ea6cb6efb7a115b1baa811f1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Br=C3=BCns?= <stefan.bruens@rwth-aachen.de>
Date: Mon, 18 Nov 2019 19:58:53 +0100
Subject: [PATCH 1/1] Fix HAVE_VALGRIND AM_CONDITIONAL
The AM_CONDITIONAL should also be run with --disable-tests, otherwise
HAVE_VALGRIND is undefined.
---
configure | 4 ++--
configure.ac | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/configure b/configure
index 831a3bb..8913b9b 100644
--- a/configure
+++ b/configure
@@ -14801,6 +14801,8 @@ else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
have_valgrind=yes
+fi
+
fi
if test "x$have_valgrind" = "xyes"; then
HAVE_VALGRIND_TRUE=
@@ -14811,8 +14813,6 @@ else
fi
-fi
-
diff --git a/configure.ac b/configure.ac
index ace54d1..cbd38a6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -120,8 +120,8 @@ PKG_CHECK_MODULES(DBUSMENUTESTS, json-glib-1.0 >= $JSON_GLIB_REQUIRED_VERSION
[have_tests=yes]
)
PKG_CHECK_MODULES(DBUSMENUTESTSVALGRIND, valgrind, have_valgrind=yes, have_valgrind=no)
-AM_CONDITIONAL([HAVE_VALGRIND], [test "x$have_valgrind" = "xyes"])
])
+AM_CONDITIONAL([HAVE_VALGRIND], [test "x$have_valgrind" = "xyes"])
AC_SUBST(DBUSMENUTESTS_CFLAGS)
AC_SUBST(DBUSMENUTESTS_LIBS)
--
2.46.2
'
end
resource "ayatana-ido" do
url "https://github.com/AyatanaIndicators/ayatana-ido/archive/refs/tags/0.10.4.tar.gz"
sha256 "bd59abd5f1314e411d0d55ce3643e91cef633271f58126be529de5fb71c5ab38"
patch 'From 8a09e6ad33c58c017c0c8fd756da036fc39428ea Mon Sep 17 00:00:00 2001
From: Alexander Koskovich <akoskovich@pm.me>
Date: Sun, 29 Sep 2024 13:47:54 -0400
Subject: [PATCH 1/1] Make introspection configurable
---
CMakeLists.txt | 1 +
src/CMakeLists.txt | 4 ++++
2 files changed, 5 insertions(+)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0e13fcd..f3e9ec0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,6 +12,7 @@ endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
option(ENABLE_TESTS "Enable all tests and checks" OFF)
option(ENABLE_COVERAGE "Enable coverage reports (includes enabling all tests and checks)" OFF)
option(ENABLE_WERROR "Treat all build warnings as errors" OFF)
+option(ENABLE_INTROSPECTION "Enable introspection" ON)
if(ENABLE_COVERAGE)
set(ENABLE_TESTS ON)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5b3638d..aca9481 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -108,6 +108,8 @@ install(TARGETS "ayatana-ido3-0.4" LIBRARY DESTINATION "${CMAKE_INSTALL_FULL_LIB
# AyatanaIdo3-0.4.gir
+if (ENABLE_INTROSPECTION)
+
find_package(GObjectIntrospection REQUIRED QUIET)
if (INTROSPECTION_FOUND)
@@ -183,3 +185,5 @@ if (INTROSPECTION_FOUND)
endif ()
endif ()
+
+endif ()
--
2.46.2
'
end
resource "libayatana-indicator" do
url "https://github.com/AyatanaIndicators/libayatana-indicator/archive/refs/tags/0.9.4.tar.gz"
sha256 "a18d3c682e29afd77db24366f8475b26bda22b0e16ff569a2ec71cd6eb4eac95"
end
end
def install
@@ -206,12 +65,12 @@ index 5b3638d..aca9481 100644
args = %W[
-DBUILD_WERROR=ON
-DCMAKE_CXX_STANDARD=20
-DCMAKE_INSTALL_PREFIX=#{prefix}
-DHOMEBREW_ALLOW_FETCHCONTENT=ON
-DOPENSSL_ROOT_DIR=#{Formula["openssl"].opt_prefix}
-DSUNSHINE_ASSETS_DIR=sunshine/assets
-DSUNSHINE_BUILD_HOMEBREW=ON
-DSUNSHINE_ENABLE_TRAY=OFF
-DSUNSHINE_PUBLISHER_NAME='LizardByte'
-DSUNSHINE_PUBLISHER_WEBSITE='https://app.lizardbyte.dev'
-DSUNSHINE_PUBLISHER_ISSUE_URL='https://app.lizardbyte.dev/support'
@@ -246,69 +105,16 @@ index 5b3638d..aca9481 100644
end
args << "-DCUDA_FAIL_ON_MISSING=OFF" if OS.linux?
args << "-DSUNSHINE_ENABLE_TRAY=OFF" if OS.mac?
# Handle system tray on Linux
if OS.linux?
# Build and install libayatana components
system "cmake", "-S", ".", "-B", "build", *std_cmake_args, *args
# Build libdbusmenu
resource("libdbusmenu").stage do
system "./configure",
"--prefix=#{prefix}",
"--with-gtk=3",
"--disable-dumper",
"--disable-static",
"--disable-tests",
"--disable-gtk-doc",
"--enable-introspection=no",
"--disable-vala"
system "make", "install"
end
cd "build" do
system "make"
system "make", "install"
# Build ayatana-ido
resource("ayatana-ido").stage do
system "cmake", "-S", ".", "-B", "build", "-G", "Ninja",
"-DCMAKE_INSTALL_PREFIX=#{prefix}",
"-DENABLE_INTROSPECTION=OFF",
*std_cmake_args
system "ninja", "-C", "build"
system "ninja", "-C", "build", "install"
end
# Build libayatana-indicator
resource("libayatana-indicator").stage do
ENV.append_path "PKG_CONFIG_PATH", "#{lib}/pkgconfig"
ENV.append "LDFLAGS", "-L#{lib}"
system "cmake", "-S", ".", "-B", "build", "-G", "Ninja",
"-DCMAKE_INSTALL_PREFIX=#{prefix}",
*std_cmake_args
system "ninja", "-C", "build"
system "ninja", "-C", "build", "install"
end
# Build libayatana-appindicator
resource("libayatana-appindicator").stage do
system "cmake", "-S", ".", "-B", "build", "-G", "Ninja",
"-DCMAKE_INSTALL_PREFIX=#{prefix}",
"-DENABLE_BINDINGS_MONO=OFF",
"-DENABLE_BINDINGS_VALA=OFF",
"-DENABLE_GTKDOC=OFF",
*std_cmake_args
system "ninja", "-C", "build"
system "ninja", "-C", "build", "install"
end
bin.install "tests/test_sunshine"
end
system "cmake", "-S", ".", "-B", "build", "-G", "Unix Makefiles",
*std_cmake_args,
*args
system "make", "-C", "build"
system "make", "-C", "build", "install"
bin.install "build/tests/test_sunshine"
# codesign the binary on intel macs
system "codesign", "-s", "-", "--force", "--deep", bin/"sunshine" if OS.mac? && Hardware::CPU.intel?
@@ -319,31 +125,31 @@ index 5b3638d..aca9481 100644
run [opt_bin/"sunshine", "~/.config/sunshine/sunshine.conf"]
end
def post_install
def caveats
caveats_message = <<~EOS
Thanks for installing @PROJECT_NAME@!
To get started, review the documentation at:
https://docs.lizardbyte.dev/projects/sunshine
EOS
if OS.linux?
opoo <<~EOS
caveats_message += <<~EOS
ATTENTION: To complete installation, you must run the following command:
`sudo #{bin}/postinst`
EOS
end
if OS.mac?
opoo <<~EOS
caveats_message += <<~EOS
Sunshine can only access microphones on macOS due to system limitations.
To stream system audio use "Soundflower" or "BlackHole".
Gamepads are not currently supported on macOS.
EOS
end
end
def caveats
<<~EOS
Thanks for installing @PROJECT_NAME@!
To get started, review the documentation at:
https://docs.lizardbyte.dev/projects/sunshine
EOS
caveats_message
end
test do
@@ -351,7 +157,6 @@ index 5b3638d..aca9481 100644
system bin/"sunshine", "--version"
# run the test suite
system bin/"test_sunshine", "--gtest_color=yes", "--gtest_output=xml:test_results.xml"
assert_path_exists testpath/"test_results.xml"
system bin/"test_sunshine", "--gtest_color=yes"
end
end

View File

@@ -25,7 +25,6 @@ year = datetime.datetime.now().year
# target locales
target_locales = [
'bg', # Bulgarian
'cs', # Czech
'de', # German
'en', # English
'en_GB', # English (United Kingdom)
@@ -43,7 +42,6 @@ target_locales = [
'tr', # Turkish
'uk', # Ukrainian
'zh', # Chinese
'zh_TW', # Chinese (Traditional)
]

183
scripts/linux_build.sh Executable file → Normal file
View File

@@ -3,7 +3,6 @@ set -e
# Default value for arguments
appimage_build=0
num_processors=$(nproc)
publisher_name="Third Party Publisher"
publisher_website=""
publisher_issue_url="https://app.lizardbyte.dev/support"
@@ -28,7 +27,6 @@ Options:
-h, --help Display this help message.
-s, --sudo-off Disable sudo command.
--appimage-build Compile for AppImage, this will not create the AppImage, just the executable.
--num-processors The number of processors to use for compilation. Default is the value of 'nproc'.
--publisher-name The name of the publisher (not developer) of the application.
--publisher-website The URL of the publisher's website.
--publisher-issue-url The URL of the publisher's support site or issue tracker.
@@ -55,9 +53,6 @@ while getopts ":hs-:" opt; do
appimage_build=1
skip_libva=1
;;
num-processors=*)
num_processors="${OPTARG#*=}"
;;
publisher-name=*)
publisher_name="${OPTARG#*=}"
;;
@@ -90,60 +85,11 @@ shift $((OPTIND -1))
# dependencies array to build out
dependencies=()
function add_arch_deps() {
function add_debain_based_deps() {
dependencies+=(
'avahi'
'base-devel'
'cmake'
'curl'
"gcc${gcc_version}"
"gcc${gcc_version}-libs"
'git'
'libayatana-appindicator'
'libcap'
'libdrm'
'libevdev'
'libmfx'
'libnotify'
'libpulse'
'libva'
'libx11'
'libxcb'
'libxfixes'
'libxrandr'
'libxtst'
'miniupnpc'
'ninja'
'nodejs'
'npm'
'numactl'
'openssl'
'opus'
'udev'
'wayland'
)
if [ "$skip_libva" == 0 ]; then
dependencies+=(
"libva" # VA-API
)
fi
if [ "$skip_cuda" == 0 ]; then
dependencies+=(
"cuda" # VA-API
)
fi
}
function add_debian_based_deps() {
dependencies+=(
"appstream"
"appstream-util"
"bison" # required if we need to compile doxygen
"build-essential"
"cmake"
"desktop-file-utils"
"doxygen"
"flex" # required if we need to compile doxygen
"gcc-${gcc_version}"
@@ -154,7 +100,6 @@ function add_debian_based_deps() {
"libcurl4-openssl-dev"
"libdrm-dev" # KMS
"libevdev-dev"
"libgbm-dev"
"libminiupnpc-dev"
"libnotify-dev"
"libnuma-dev"
@@ -183,8 +128,8 @@ function add_debian_based_deps() {
fi
}
function add_debian_deps() {
add_debian_based_deps
function add_debain_deps() {
add_debain_based_deps
dependencies+=(
"libayatana-appindicator3-dev"
)
@@ -196,7 +141,7 @@ function add_ubuntu_deps() {
${sudo_cmd} add-apt-repository ppa:ubuntu-toolchain-r/test -y
fi
add_debian_based_deps
add_debain_based_deps
dependencies+=(
"libappindicator3-dev"
)
@@ -204,16 +149,13 @@ function add_ubuntu_deps() {
function add_fedora_deps() {
dependencies+=(
"appstream"
"cmake"
"desktop-file-utils"
"doxygen"
"gcc${gcc_version}"
"gcc${gcc_version}-c++"
"gcc"
"g++"
"git"
"graphviz"
"libappindicator-gtk3-devel"
"libappstream-glib"
"libcap-devel"
"libcurl-devel"
"libdrm-devel"
@@ -228,7 +170,6 @@ function add_fedora_deps() {
"libXrandr-devel" # X11
"libXtst-devel" # X11
"mesa-libGL-devel"
"mesa-libgbm-devel"
"miniupnpc-devel"
"ninja-build"
"npm"
@@ -250,15 +191,9 @@ function add_fedora_deps() {
}
function install_cuda() {
nvcc_path=$(command -v nvcc 2>/dev/null) || true
if [ -n "$nvcc_path" ]; then
echo "found system cuda"
return
fi
# check if we need to install cuda
if [ -f "${build_dir}/cuda/bin/nvcc" ]; then
nvcc_path="${build_dir}/cuda/bin/nvcc"
echo "found local cuda"
echo "cuda already installed"
return
fi
@@ -295,13 +230,11 @@ function install_cuda() {
chmod a+x "${build_dir}/cuda.run"
"${build_dir}/cuda.run" --silent --toolkit --toolkitpath="${build_dir}/cuda" --no-opengl-libs --no-man-page --no-drm
rm "${build_dir}/cuda.run"
nvcc_path="${build_dir}/cuda/bin/nvcc"
}
function check_version() {
local package_name=$1
local min_version=$2
local max_version=$3
local installed_version
echo "Checking if $package_name is installed and at least version $min_version"
@@ -310,8 +243,6 @@ function check_version() {
installed_version=$(dpkg -s "$package_name" 2>/dev/null | grep '^Version:' | awk '{print $2}')
elif [ "$distro" == "fedora" ]; then
installed_version=$(rpm -q --queryformat '%{VERSION}' "$package_name" 2>/dev/null)
elif [ "$distro" == "arch" ]; then
installed_version=$(pacman -Q "$package_name" | awk '{print $2}' )
else
echo "Unsupported Distro"
return 1
@@ -322,12 +253,11 @@ function check_version() {
return 1
fi
if [[ "$(printf '%s\n' "$installed_version" "$min_version" | sort -V | head -n1)" = "$min_version" ]] && \
[[ "$(printf '%s\n' "$installed_version" "$max_version" | sort -V | head -n1)" = "$installed_version" ]]; then
echo "Installed version is within range"
if [ "$(printf '%s\n' "$installed_version" "$min_version" | sort -V | head -n1)" = "$min_version" ]; then
echo "$package_name version $installed_version is at least $min_version"
return 0
else
echo "$package_name version $installed_version is out of range"
echo "$package_name version $installed_version is less than $min_version"
return 1
fi
}
@@ -366,15 +296,13 @@ function run_install() {
# Update the package list
$package_update_command
if [ "$distro" == "arch" ]; then
add_arch_deps
elif [ "$distro" == "debian" ]; then
add_debian_deps
if [ "$distro" == "debian" ]; then
add_debain_deps
elif [ "$distro" == "ubuntu" ]; then
add_ubuntu_deps
elif [ "$distro" == "fedora" ]; then
add_fedora_deps
${sudo_cmd} dnf group install "$dev_tools_group" -y
${sudo_cmd} dnf group install "Development Tools" -y
fi
# Install the dependencies
@@ -392,11 +320,8 @@ function run_install() {
"gcc-ranlib"
)
#set gcc version based on distros
if [ "$distro" == "arch" ]; then
export CC=gcc-14
export CXX=g++-14
elif [ "$distro" == "debian" ] || [ "$distro" == "ubuntu" ]; then
# update alternatives for gcc and g++ if a debian based distro
if [ "$distro" == "debian" ] || [ "$distro" == "ubuntu" ]; then
for file in "${gcc_alternative_files[@]}"; do
file_path="/etc/alternatives/$file"
if [ -e "$file_path" ]; then
@@ -415,7 +340,7 @@ function run_install() {
# compile cmake if the version is too low
cmake_min="3.25.0"
target_cmake_version="3.30.1"
if ! check_version "cmake" "$cmake_min" "inf"; then
if ! check_version "cmake" "$cmake_min"; then
cmake_prefix="https://github.com/Kitware/CMake/releases/download/v"
if [ "$architecture" == "x86_64" ]; then
cmake_arch="x86_64"
@@ -433,8 +358,7 @@ function run_install() {
# compile doxygen if version is too low
doxygen_min="1.10.0"
_doxygen_min="1_10_0"
doxygen_max="1.12.0"
if ! check_version "doxygen" "$doxygen_min" "$doxygen_max"; then
if ! check_version "doxygen" "$doxygen_min"; then
if [ "${SUNSHINE_COMPILE_DOXYGEN}" == "true" ]; then
echo "Compiling doxygen"
doxygen_url="https://github.com/doxygen/doxygen/releases/download/Release_${_doxygen_min}/doxygen-${doxygen_min}.src.tar.gz"
@@ -443,10 +367,10 @@ function run_install() {
tar -xzf "${build_dir}/doxygen.tar.gz"
cd "doxygen-${doxygen_min}"
cmake -DCMAKE_BUILD_TYPE=Release -G="Ninja" -B="build" -S="."
ninja -C "build" -j"${num_processors}"
ninja -C "build"
ninja -C "build" install
else
echo "Doxygen version not in range, skipping docs"
echo "Doxygen version too low, skipping docs"
cmake_args+=("-DBUILD_DOCS=OFF")
fi
fi
@@ -462,12 +386,10 @@ function run_install() {
fi
# run the cuda install
if [ "$skip_cuda" == 0 ]; then
if [ -n "$cuda_version" ] && [ "$skip_cuda" == 0 ]; then
install_cuda
cmake_args+=("-DSUNSHINE_ENABLE_CUDA=ON")
cmake_args+=("-DCMAKE_CUDA_COMPILER:PATH=$nvcc_path")
else
cmake_args+=("-DSUNSHINE_ENABLE_CUDA=OFF")
cmake_args+=("-DCMAKE_CUDA_COMPILER:PATH=${build_dir}/cuda/bin/nvcc")
fi
# Cmake stuff here
@@ -475,16 +397,6 @@ function run_install() {
echo "cmake args:"
echo "${cmake_args[@]}"
cmake "${cmake_args[@]}"
# Run appstream validation, etc.
appstreamcli validate "build/dev.lizardbyte.app.Sunshine.metainfo.xml"
appstream-util validate "build/dev.lizardbyte.app.Sunshine.metainfo.xml"
desktop-file-validate "build/dev.lizardbyte.app.Sunshine.desktop"
if [ "$appimage_build" == 0 ]; then
desktop-file-validate "build/dev.lizardbyte.app.Sunshine.terminal.desktop"
fi
# Build the project
ninja -C "build"
# Create the package
@@ -517,15 +429,7 @@ function run_install() {
# Determine the OS and call the appropriate function
cat /etc/os-release
if grep -q "Arch Linux" /etc/os-release; then
distro="arch"
version=""
package_update_command="${sudo_cmd} pacman -Syu --noconfirm"
package_install_command="${sudo_cmd} pacman -Sy --needed"
nvm_node=0
gcc_version="14"
elif grep -q "Debian GNU/Linux 12 (bookworm)" /etc/os-release; then
if grep -q "Debian GNU/Linux 12 (bookworm)" /etc/os-release; then
distro="debian"
version="12"
package_update_command="${sudo_cmd} apt-get update"
@@ -534,36 +438,24 @@ elif grep -q "Debian GNU/Linux 12 (bookworm)" /etc/os-release; then
cuda_build="525.60.13"
gcc_version="12"
nvm_node=0
elif grep -q "PLATFORM_ID=\"platform:f39\"" /etc/os-release; then
distro="fedora"
version="39"
package_update_command="${sudo_cmd} dnf update -y"
package_install_command="${sudo_cmd} dnf install -y"
cuda_version="12.4.0"
cuda_build="550.54.14"
gcc_version="13"
nvm_node=0
elif grep -q "PLATFORM_ID=\"platform:f40\"" /etc/os-release; then
distro="fedora"
version="40"
package_update_command="${sudo_cmd} dnf update -y"
package_install_command="${sudo_cmd} dnf install -y"
cuda_version=12.6.3
cuda_build=560.35.05
cuda_version=
cuda_build=
gcc_version="13"
nvm_node=0
dev_tools_group="Development Tools"
elif grep -q "PLATFORM_ID=\"platform:f41\"" /etc/os-release; then
distro="fedora"
version="41"
package_update_command="${sudo_cmd} dnf update -y"
package_install_command="${sudo_cmd} dnf install -y"
cuda_version=12.6.3
cuda_build=560.35.05
gcc_version="13"
nvm_node=0
dev_tools_group="development-tools"
elif grep -q "PLATFORM_ID=\"platform:f42\"" /etc/os-release; then
distro="fedora"
version="42"
package_update_command="${sudo_cmd} dnf update -y"
package_install_command="${sudo_cmd} dnf install -y"
cuda_version=12.8.1
cuda_build=570.124.06
gcc_version="14"
nvm_node=0
dev_tools_group="development-tools"
elif grep -q "Ubuntu 22.04" /etc/os-release; then
distro="ubuntu"
version="22.04"
@@ -582,15 +474,6 @@ elif grep -q "Ubuntu 24.04" /etc/os-release; then
cuda_build="520.61.05"
gcc_version="11"
nvm_node=0
elif grep -q "Ubuntu 25.04" /etc/os-release; then
distro="ubuntu"
version="25.04"
package_update_command="${sudo_cmd} apt-get update"
package_install_command="${sudo_cmd} apt-get install -y"
cuda_version="11.8.0"
cuda_build="520.61.05"
gcc_version="11"
nvm_node=0
else
echo "Unsupported Distro or Version"
exit 1

View File

@@ -1,2 +1,2 @@
Babel==2.17.0
clang-format==20.*
Babel==2.16.0
clang-format

View File

@@ -129,10 +129,6 @@ namespace audio {
void capture(safe::mail_t mail, config_t config, void *channel_data) {
auto shutdown_event = mail->event<bool>(mail::shutdown);
if (!config::audio.stream) {
shutdown_event->view();
return;
}
auto stream = stream_configs[map_stream(config.channels, config.flags[config_t::HIGH_QUALITY])];
if (config.flags[config_t::CUSTOM_SURROUND_PARAMS]) {
apply_surround_params(stream, config.customStreamParams);

View File

@@ -414,7 +414,12 @@ namespace config {
auto final_resolution = entry.template get_optional<std::string>("final_resolution"s);
auto final_refresh_rate = entry.template get_optional<std::string>("final_refresh_rate"s);
output_field.push_back(video_t::dd_t::mode_remapping_entry_t {requested_resolution.value_or(""), requested_fps.value_or(""), final_resolution.value_or(""), final_refresh_rate.value_or("")});
output_field.push_back(video_t::dd_t::mode_remapping_entry_t {
requested_resolution.value_or(""),
requested_fps.value_or(""),
final_resolution.value_or(""),
final_refresh_rate.value_or("")
});
}
}};
@@ -492,7 +497,7 @@ namespace config {
{}, // output_name
{
video_t::dd_t::config_option_e::disabled, // configuration_option
video_t::dd_t::config_option_e::verify_only, // configuration_option
video_t::dd_t::resolution_option_e::automatic, // resolution_option
{}, // manual_resolution
video_t::dd_t::refresh_rate_option_e::automatic, // refresh_rate_option
@@ -504,13 +509,12 @@ namespace config {
{} // wa
}, // display_device
0 // max_bitrate
1 // min_fps_factor
};
audio_t audio {
{}, // audio_sink
{}, // virtual_sink
true, // stream audio
true, // install_steam_drivers
};
@@ -647,13 +651,9 @@ namespace config {
// Lists might contain newlines
if (*begin_val == '[') {
endl = skip_list(begin_val + 1, end);
if (endl == end) {
std::cout << "Warning: Config option ["sv << to_string(begin, end_name) << "] Missing ']'"sv;
// Check if we reached the end of the file without finding a closing bracket
// We know we have a valid closing bracket if:
// 1. We didn't reach the end, or
// 2. We reached the end but the last character was the matching closing bracket
if (endl == end && end == begin_val + 1) {
BOOST_LOG(warning) << "config: Missing ']' in config option: " << to_string(begin, end_name);
return std::make_pair(endl, std::nullopt);
}
}
@@ -987,7 +987,7 @@ namespace config {
// The list needs to be a multiple of 2
if (list.size() % 2) {
BOOST_LOG(warning) << "config: expected "sv << name << " to have a multiple of two elements --> not "sv << list.size();
std::cout << "Warning: expected "sv << name << " to have a multiple of two elements --> not "sv << list.size() << std::endl;
return;
}
@@ -1017,7 +1017,7 @@ namespace config {
config::sunshine.flags[config::flag::UPNP].flip();
break;
default:
BOOST_LOG(warning) << "config: Unrecognized flag: ["sv << *line << ']' << std::endl;
std::cout << "Warning: Unrecognized flag: ["sv << *line << ']' << std::endl;
ret = -1;
}
@@ -1043,8 +1043,7 @@ namespace config {
}
for (auto &[name, val] : vars) {
BOOST_LOG(info) << "config: '"sv << name << "' = "sv << val;
modified_config_settings[name] = val;
std::cout << "["sv << name << "] -- ["sv << val << ']' << std::endl;
}
int_f(vars, "qp", video.qp);
@@ -1136,13 +1135,9 @@ namespace config {
}
bool_f(vars, "dd_config_revert_on_disconnect", video.dd.config_revert_on_disconnect);
generic_f(vars, "dd_mode_remapping", video.dd.mode_remapping, dd::mode_remapping_from_view);
{
int value = 0;
int_between_f(vars, "dd_wa_hdr_toggle_delay", value, {0, 3000});
video.dd.wa.hdr_toggle_delay = std::chrono::milliseconds {value};
}
bool_f(vars, "dd_wa_hdr_toggle", video.dd.wa.hdr_toggle);
int_f(vars, "max_bitrate", video.max_bitrate);
int_between_f(vars, "min_fps_factor", video.min_fps_factor, {1, 3});
path_f(vars, "pkey", nvhttp.pkey);
path_f(vars, "cert", nvhttp.cert);
@@ -1159,7 +1154,6 @@ namespace config {
string_f(vars, "audio_sink", audio.sink);
string_f(vars, "virtual_sink", audio.virtual_sink);
bool_f(vars, "stream_audio", audio.stream);
bool_f(vars, "install_steam_audio_drivers", audio.install_steam_drivers);
string_restricted_f(vars, "origin_web_ui_allowed", nvhttp.origin_web_ui_allowed, {"pc"sv, "lan"sv, "wan"sv});
@@ -1238,7 +1232,6 @@ namespace config {
string_restricted_f(vars, "locale", config::sunshine.locale, {
"bg"sv, // Bulgarian
"cs"sv, // Czech
"de"sv, // German
"en"sv, // English
"en_GB"sv, // English (UK)
@@ -1256,7 +1249,6 @@ namespace config {
"tr"sv, // Turkish
"uk"sv, // Ukrainian
"zh"sv, // Chinese
"zh_TW"sv, // Chinese (Traditional)
});
std::string log_level_string;
@@ -1427,7 +1419,7 @@ namespace config {
shell_exec_info.nShow = SW_NORMAL;
if (!ShellExecuteExW(&shell_exec_info)) {
auto winerr = GetLastError();
BOOST_LOG(error) << "Failed executing shell command: " << winerr << std::endl;
std::cout << "Error: ShellExecuteEx() failed:"sv << winerr << std::endl;
return 1;
}

View File

@@ -16,9 +16,6 @@
#include "nvenc/nvenc_config.h"
namespace config {
// track modified config options
inline std::unordered_map<std::string, std::string> modified_config_settings;
struct video_t {
// ffmpeg params
int qp; // higher == more compression and less quality
@@ -87,7 +84,7 @@ namespace config {
struct dd_t {
struct workarounds_t {
std::chrono::milliseconds hdr_toggle_delay; ///< Specify whether to apply HDR high-contrast color workaround and what delay to use.
bool hdr_toggle; ///< Specify whether to apply HDR high-contrast color workaround.
};
enum class config_option_e {
@@ -140,13 +137,12 @@ namespace config {
workarounds_t wa;
} dd;
int max_bitrate; // Maximum bitrate, sets ceiling in kbps for bitrate requested from client
int min_fps_factor; // Minimum fps target, determines minimum frame time
};
struct audio_t {
std::string sink;
std::string virtual_sink;
bool stream;
bool install_steam_drivers;
};

View File

@@ -81,8 +81,7 @@ namespace confighttp {
void send_response(resp_https_t response, const nlohmann::json &output_tree) {
SimpleWeb::CaseInsensitiveMultimap headers;
headers.emplace("Content-Type", "application/json");
headers.emplace("X-Frame-Options", "DENY");
headers.emplace("Content-Security-Policy", "frame-ancestors 'none';");
response->write(output_tree.dump(), headers);
}
@@ -104,9 +103,7 @@ namespace confighttp {
const SimpleWeb::CaseInsensitiveMultimap headers {
{"Content-Type", "application/json"},
{"WWW-Authenticate", R"(Basic realm="Sunshine Gamestream Host", charset="UTF-8")"},
{"X-Frame-Options", "DENY"},
{"Content-Security-Policy", "frame-ancestors 'none';"}
{"WWW-Authenticate", R"(Basic realm="Sunshine Gamestream Host", charset="UTF-8")"}
};
response->write(code, tree.dump(), headers);
@@ -122,9 +119,7 @@ namespace confighttp {
auto address = net::addr_to_normalized_string(request->remote_endpoint().address());
BOOST_LOG(info) << "Web UI: ["sv << address << "] -- not authorized"sv;
const SimpleWeb::CaseInsensitiveMultimap headers {
{"Location", path},
{"X-Frame-Options", "DENY"},
{"Content-Security-Policy", "frame-ancestors 'none';"}
{"Location", path}
};
response->write(SimpleWeb::StatusCode::redirection_temporary_redirect, headers);
}
@@ -194,8 +189,6 @@ namespace confighttp {
SimpleWeb::CaseInsensitiveMultimap headers;
headers.emplace("Content-Type", "application/json");
headers.emplace("X-Frame-Options", "DENY");
headers.emplace("Content-Security-Policy", "frame-ancestors 'none';");
response->write(code, tree.dump(), headers);
}
@@ -216,45 +209,10 @@ namespace confighttp {
SimpleWeb::CaseInsensitiveMultimap headers;
headers.emplace("Content-Type", "application/json");
headers.emplace("X-Frame-Options", "DENY");
headers.emplace("Content-Security-Policy", "frame-ancestors 'none';");
response->write(code, tree.dump(), headers);
}
/**
* @brief Validate the request content type and send bad request when mismatch.
* @param response The HTTP response object.
* @param request The HTTP request object.
* @param contentType The expected content type
*/
bool check_content_type(resp_https_t response, req_https_t request, const std::string_view &contentType) {
auto requestContentType = request->header.find("content-type");
if (requestContentType == request->header.end()) {
bad_request(response, request, "Content type not provided");
return false;
}
// Extract the media type part before any parameters (e.g., charset)
std::string actualContentType = requestContentType->second;
size_t semicolonPos = actualContentType.find(';');
if (semicolonPos != std::string::npos) {
actualContentType = actualContentType.substr(0, semicolonPos);
}
// Trim whitespace and convert to lowercase for case-insensitive comparison
boost::algorithm::trim(actualContentType);
boost::algorithm::to_lower(actualContentType);
std::string expectedContentType(contentType);
boost::algorithm::to_lower(expectedContentType);
if (actualContentType != expectedContentType) {
bad_request(response, request, "Content type mismatch");
return false;
}
return true;
}
/**
* @brief Get the index page.
* @param response The HTTP response object.
@@ -271,8 +229,6 @@ namespace confighttp {
std::string content = file_handler::read_file(WEB_DIR "index.html");
SimpleWeb::CaseInsensitiveMultimap headers;
headers.emplace("Content-Type", "text/html; charset=utf-8");
headers.emplace("X-Frame-Options", "DENY");
headers.emplace("Content-Security-Policy", "frame-ancestors 'none';");
response->write(content, headers);
}
@@ -291,8 +247,6 @@ namespace confighttp {
std::string content = file_handler::read_file(WEB_DIR "pin.html");
SimpleWeb::CaseInsensitiveMultimap headers;
headers.emplace("Content-Type", "text/html; charset=utf-8");
headers.emplace("X-Frame-Options", "DENY");
headers.emplace("Content-Security-Policy", "frame-ancestors 'none';");
response->write(content, headers);
}
@@ -311,8 +265,6 @@ namespace confighttp {
std::string content = file_handler::read_file(WEB_DIR "apps.html");
SimpleWeb::CaseInsensitiveMultimap headers;
headers.emplace("Content-Type", "text/html; charset=utf-8");
headers.emplace("X-Frame-Options", "DENY");
headers.emplace("Content-Security-Policy", "frame-ancestors 'none';");
headers.emplace("Access-Control-Allow-Origin", "https://images.igdb.com/");
response->write(content, headers);
}
@@ -332,8 +284,6 @@ namespace confighttp {
std::string content = file_handler::read_file(WEB_DIR "clients.html");
SimpleWeb::CaseInsensitiveMultimap headers;
headers.emplace("Content-Type", "text/html; charset=utf-8");
headers.emplace("X-Frame-Options", "DENY");
headers.emplace("Content-Security-Policy", "frame-ancestors 'none';");
response->write(content, headers);
}
@@ -352,8 +302,6 @@ namespace confighttp {
std::string content = file_handler::read_file(WEB_DIR "config.html");
SimpleWeb::CaseInsensitiveMultimap headers;
headers.emplace("Content-Type", "text/html; charset=utf-8");
headers.emplace("X-Frame-Options", "DENY");
headers.emplace("Content-Security-Policy", "frame-ancestors 'none';");
response->write(content, headers);
}
@@ -372,8 +320,6 @@ namespace confighttp {
std::string content = file_handler::read_file(WEB_DIR "password.html");
SimpleWeb::CaseInsensitiveMultimap headers;
headers.emplace("Content-Type", "text/html; charset=utf-8");
headers.emplace("X-Frame-Options", "DENY");
headers.emplace("Content-Security-Policy", "frame-ancestors 'none';");
response->write(content, headers);
}
@@ -391,8 +337,6 @@ namespace confighttp {
std::string content = file_handler::read_file(WEB_DIR "welcome.html");
SimpleWeb::CaseInsensitiveMultimap headers;
headers.emplace("Content-Type", "text/html; charset=utf-8");
headers.emplace("X-Frame-Options", "DENY");
headers.emplace("Content-Security-Policy", "frame-ancestors 'none';");
response->write(content, headers);
}
@@ -411,8 +355,6 @@ namespace confighttp {
std::string content = file_handler::read_file(WEB_DIR "troubleshooting.html");
SimpleWeb::CaseInsensitiveMultimap headers;
headers.emplace("Content-Type", "text/html; charset=utf-8");
headers.emplace("X-Frame-Options", "DENY");
headers.emplace("Content-Security-Policy", "frame-ancestors 'none';");
response->write(content, headers);
}
@@ -429,8 +371,6 @@ namespace confighttp {
std::ifstream in(WEB_DIR "images/sunshine.ico", std::ios::binary);
SimpleWeb::CaseInsensitiveMultimap headers;
headers.emplace("Content-Type", "image/x-icon");
headers.emplace("X-Frame-Options", "DENY");
headers.emplace("Content-Security-Policy", "frame-ancestors 'none';");
response->write(SimpleWeb::StatusCode::success_ok, in, headers);
}
@@ -447,8 +387,6 @@ namespace confighttp {
std::ifstream in(WEB_DIR "images/logo-sunshine-45.png", std::ios::binary);
SimpleWeb::CaseInsensitiveMultimap headers;
headers.emplace("Content-Type", "image/png");
headers.emplace("X-Frame-Options", "DENY");
headers.emplace("Content-Security-Policy", "frame-ancestors 'none';");
response->write(SimpleWeb::StatusCode::success_ok, in, headers);
}
@@ -500,8 +438,6 @@ namespace confighttp {
// if it is, set the content type to the mime type
SimpleWeb::CaseInsensitiveMultimap headers;
headers.emplace("Content-Type", mimeType->second);
headers.emplace("X-Frame-Options", "DENY");
headers.emplace("Content-Security-Policy", "frame-ancestors 'none';");
std::ifstream in(filePath.string(), std::ios::binary);
response->write(SimpleWeb::StatusCode::success_ok, in, headers);
}
@@ -599,9 +535,6 @@ namespace confighttp {
* @api_examples{/api/apps| POST| {"name":"Hello, World!","index":-1}}
*/
void saveApp(resp_https_t response, req_https_t request) {
if (!check_content_type(response, request, "application/json")) {
return;
}
if (!authenticate(response, request)) {
return;
}
@@ -669,9 +602,6 @@ namespace confighttp {
* @api_examples{/api/apps/close| POST| null}
*/
void closeApp(resp_https_t response, req_https_t request) {
if (!check_content_type(response, request, "application/json")) {
return;
}
if (!authenticate(response, request)) {
return;
}
@@ -693,9 +623,6 @@ namespace confighttp {
* @api_examples{/api/apps/9999| DELETE| null}
*/
void deleteApp(resp_https_t response, req_https_t request) {
if (!check_content_type(response, request, "application/json")) {
return;
}
if (!authenticate(response, request)) {
return;
}
@@ -776,9 +703,6 @@ namespace confighttp {
* @api_examples{/api/unpair| POST| {"uuid":"1234"}}
*/
void unpair(resp_https_t response, req_https_t request) {
if (!check_content_type(response, request, "application/json")) {
return;
}
if (!authenticate(response, request)) {
return;
}
@@ -809,9 +733,6 @@ namespace confighttp {
* @api_examples{/api/clients/unpair-all| POST| null}
*/
void unpairAll(resp_https_t response, req_https_t request) {
if (!check_content_type(response, request, "application/json")) {
return;
}
if (!authenticate(response, request)) {
return;
}
@@ -888,9 +809,6 @@ namespace confighttp {
* @api_examples{/api/config| POST| {"key":"value"}}
*/
void saveConfig(resp_https_t response, req_https_t request) {
if (!check_content_type(response, request, "application/json")) {
return;
}
if (!authenticate(response, request)) {
return;
}
@@ -937,9 +855,6 @@ namespace confighttp {
* @api_examples{/api/covers/upload| POST| {"key":"igdb_1234","url":"https://images.igdb.com/igdb/image/upload/t_cover_big_2x/abc123.png"}}
*/
void uploadCover(resp_https_t response, req_https_t request) {
if (!check_content_type(response, request, "application/json")) {
return;
}
if (!authenticate(response, request)) {
return;
}
@@ -1002,8 +917,6 @@ namespace confighttp {
std::string content = file_handler::read_file(config::sunshine.log_file.c_str());
SimpleWeb::CaseInsensitiveMultimap headers;
headers.emplace("Content-Type", "text/plain");
headers.emplace("X-Frame-Options", "DENY");
headers.emplace("Content-Security-Policy", "frame-ancestors 'none';");
response->write(SimpleWeb::StatusCode::success_ok, content, headers);
}
@@ -1025,9 +938,6 @@ namespace confighttp {
* @api_examples{/api/password| POST| {"currentUsername":"admin","currentPassword":"admin","newUsername":"admin","newPassword":"admin","confirmNewPassword":"admin"}}
*/
void savePassword(resp_https_t response, req_https_t request) {
if (!check_content_type(response, request, "application/json")) {
return;
}
if (!config::sunshine.username.empty() && !authenticate(response, request)) {
return;
}
@@ -1098,9 +1008,6 @@ namespace confighttp {
* @api_examples{/api/pin| POST| {"pin":"1234","name":"My PC"}}
*/
void savePin(resp_https_t response, req_https_t request) {
if (!check_content_type(response, request, "application/json")) {
return;
}
if (!authenticate(response, request)) {
return;
}
@@ -1137,9 +1044,6 @@ namespace confighttp {
* @api_examples{/api/reset-display-device-persistence| POST| null}
*/
void resetDisplayDevicePersistence(resp_https_t response, req_https_t request) {
if (!check_content_type(response, request, "application/json")) {
return;
}
if (!authenticate(response, request)) {
return;
}
@@ -1159,9 +1063,6 @@ namespace confighttp {
* @api_examples{/api/restart| POST| null}
*/
void restart(resp_https_t response, req_https_t request) {
if (!check_content_type(response, request, "application/json")) {
return;
}
if (!authenticate(response, request)) {
return;
}

View File

@@ -621,7 +621,7 @@ namespace display_device {
std::make_shared<FileSettingsPersistence>(persistence_filepath)
),
WinWorkarounds {
.m_hdr_blank_delay = video_config.dd.wa.hdr_toggle_delay != std::chrono::milliseconds::zero() ? std::make_optional(video_config.dd.wa.hdr_toggle_delay) : std::nullopt
.m_hdr_blank_delay = video_config.dd.wa.hdr_toggle ? std::make_optional(500ms) : std::nullopt
}
);
#else

Some files were not shown because too many files have changed in this diff Show More