mirror of
https://github.com/LizardByte/Sunshine.git
synced 2025-08-10 00:52:16 +00:00
Compare commits
1 Commits
ci/homebre
...
feat/api/a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b863f760b |
@@ -4,31 +4,10 @@ set -e
|
||||
# update pacman
|
||||
pacman --noconfirm -Syu
|
||||
|
||||
gcc_version="14.2.0-3"
|
||||
|
||||
broken_deps=(
|
||||
"mingw-w64-ucrt-x86_64-gcc"
|
||||
"mingw-w64-ucrt-x86_64-gcc-libs"
|
||||
)
|
||||
|
||||
tarballs=""
|
||||
for dep in "${broken_deps[@]}"; do
|
||||
tarball="${dep}-${gcc_version}-any.pkg.tar.zst"
|
||||
|
||||
# download and install working version
|
||||
wget https://repo.msys2.org/mingw/ucrt64/${tarball}
|
||||
|
||||
tarballs="${tarballs} ${tarball}"
|
||||
done
|
||||
|
||||
# install broken dependencies
|
||||
if [ -n "$tarballs" ]; then
|
||||
pacman -U --noconfirm ${tarballs}
|
||||
fi
|
||||
|
||||
# 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"
|
||||
@@ -42,8 +21,7 @@ dependencies=(
|
||||
"mingw-w64-ucrt-x86_64-opus"
|
||||
"mingw-w64-ucrt-x86_64-toolchain"
|
||||
)
|
||||
|
||||
pacman -Syu --noconfirm --ignore="$(IFS=,; echo "${broken_deps[*]}")" "${dependencies[@]}"
|
||||
pacman -S --noconfirm "${dependencies[@]}"
|
||||
|
||||
# build
|
||||
mkdir -p build
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
# install dependencies for C++ analysis
|
||||
set -e
|
||||
|
||||
# setup homebrew for x86_64
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
eval "$(/usr/local/bin/brew shellenv)"
|
||||
|
||||
# install dependencies
|
||||
dependencies=(
|
||||
"boost"
|
||||
"cmake"
|
||||
"miniupnpc"
|
||||
"ninja"
|
||||
|
||||
12
.github/ISSUE_TEMPLATE/config.yml
vendored
12
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -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
|
||||
|
||||
381
.github/workflows/CI.yml
vendored
381
.github/workflows/CI.yml
vendored
@@ -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.426.225
|
||||
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.426.1549
|
||||
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 }}
|
||||
@@ -265,7 +312,7 @@ jobs:
|
||||
build_linux:
|
||||
name: Linux ${{ matrix.type }}
|
||||
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:
|
||||
@@ -273,6 +320,7 @@ jobs:
|
||||
- type: AppImage
|
||||
EXTRA_ARGS: '--appimage-build'
|
||||
dist: 22.04
|
||||
|
||||
steps:
|
||||
- name: Maximize build space
|
||||
uses: easimon/maximize-build-space@v10
|
||||
@@ -347,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
|
||||
@@ -398,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
|
||||
@@ -410,7 +459,6 @@ jobs:
|
||||
with:
|
||||
name: sunshine-linux-${{ matrix.type }}-${{ matrix.dist }}
|
||||
path: artifacts/
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Install test deps
|
||||
run: |
|
||||
@@ -431,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
|
||||
@@ -450,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: >-
|
||||
@@ -482,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.426.1549
|
||||
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 }}
|
||||
@@ -494,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:
|
||||
@@ -511,7 +540,9 @@ jobs:
|
||||
- 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
|
||||
@@ -523,18 +554,20 @@ 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/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 python
|
||||
|
||||
- name: Setup python
|
||||
id: python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Configure formula
|
||||
run: |
|
||||
# variables for formula
|
||||
@@ -593,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 \
|
||||
@@ -614,8 +648,9 @@ jobs:
|
||||
|
||||
- name: Validate Homebrew Formula
|
||||
id: test
|
||||
if: matrix.release != true
|
||||
uses: LizardByte/homebrew-release-action@v2025.506.15440
|
||||
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 }}
|
||||
@@ -624,56 +659,52 @@ jobs:
|
||||
token: ${{ secrets.GH_BOT_TOKEN }}
|
||||
validate: true
|
||||
|
||||
- name: Debug upload gcda artifact
|
||||
if: always() && matrix.release != true
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: homebrew-gcda-${{ matrix.os_name }}-${{ matrix.os_version }}
|
||||
path: ${{ steps.test.outputs.buildpath }}/build/tests/CMakeFiles/test_sunshine.dir/__/src/audio.cpp.gcda
|
||||
|
||||
- name: Debug homebrew buildpath
|
||||
if: always() && matrix.release != true
|
||||
run: |
|
||||
# print the build path
|
||||
echo "Build path: ${{ steps.test.outputs.buildpath }}"
|
||||
echo "contents:"
|
||||
ls -Ra
|
||||
|
||||
# print the test path
|
||||
echo "----"
|
||||
echo "Test path: ${{ steps.test.outputs.testpath }}"
|
||||
echo "contents:"
|
||||
ls -Ra
|
||||
|
||||
- name: Upload test results to Codecov
|
||||
- name: Generate gcov report
|
||||
# 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
|
||||
# TODO: fix coverage, no .gcno files are being created
|
||||
# TODO: .gcno files are supposed to be created next to .o files
|
||||
if: false
|
||||
# if: >-
|
||||
# always() &&
|
||||
# matrix.release != true &&
|
||||
# (steps.test.outcome == 'success' || steps.test.outcome == 'failure')
|
||||
id: test_report
|
||||
run: |
|
||||
# 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
|
||||
|
||||
${{ steps.python.outputs.python-path }} -m pip install gcovr
|
||||
${{ steps.python.outputs.python-path }} -m gcovr . -r ../src \
|
||||
--exclude-noncode-lines \
|
||||
--exclude-throw-branches \
|
||||
--exclude-unreachable-branches \
|
||||
--verbose \
|
||||
--xml-pretty \
|
||||
-o coverage.xml
|
||||
|
||||
- name: Upload coverage
|
||||
# any except canceled or skipped
|
||||
if: >-
|
||||
always() &&
|
||||
matrix.release != true &&
|
||||
(steps.test_report.outcome == 'success') &&
|
||||
startsWith(github.repository, 'LizardByte/')
|
||||
# TODO: enable this once coverage report is fixed
|
||||
if: false
|
||||
# if: >-
|
||||
# always() &&
|
||||
# matrix.release != true &&
|
||||
# (steps.test_report.outcome == 'success') &&
|
||||
# startsWith(github.repository, 'LizardByte/')
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
disable_search: true
|
||||
fail_ci_if_error: true
|
||||
files: ${{ steps.test.outputs.testpath }}/build/coverage.xml
|
||||
files: ./build/coverage.xml
|
||||
flags: ${{ matrix.os_name }}-${{ matrix.os_version }} (Homebrew)
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
verbose: true
|
||||
@@ -682,7 +713,7 @@ jobs:
|
||||
if: >-
|
||||
matrix.release &&
|
||||
needs.setup_release.outputs.publish_release == 'true'
|
||||
uses: LizardByte/create-release-action@v2025.426.1549
|
||||
uses: LizardByte/create-release-action@v2025.102.13208
|
||||
with:
|
||||
allowUpdates: true
|
||||
artifacts: '${{ github.workspace }}/homebrew/*'
|
||||
@@ -696,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"
|
||||
@@ -717,7 +749,7 @@ jobs:
|
||||
github.repository_owner == 'LizardByte' &&
|
||||
matrix.release &&
|
||||
needs.setup_release.outputs.publish_release == 'true'
|
||||
uses: LizardByte/homebrew-release-action@v2025.503.165455
|
||||
uses: LizardByte/homebrew-release-action@v2024.1115.14934
|
||||
with:
|
||||
formula_file: ${{ github.workspace }}/homebrew/sunshine-beta.rb
|
||||
git_email: ${{ secrets.GH_BOT_EMAIL }}
|
||||
@@ -728,8 +760,9 @@ jobs:
|
||||
|
||||
build_win:
|
||||
name: Windows
|
||||
needs: setup_release
|
||||
runs-on: windows-2019
|
||||
needs: [setup_release]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -841,59 +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:
|
||||
gcc_version: "14.2.0-3"
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
broken_deps=(
|
||||
"mingw-w64-ucrt-x86_64-gcc"
|
||||
"mingw-w64-ucrt-x86_64-gcc-libs"
|
||||
)
|
||||
|
||||
tarballs=""
|
||||
for dep in "${broken_deps[@]}"; do
|
||||
tarball="${dep}-${gcc_version}-any.pkg.tar.zst"
|
||||
|
||||
# download and install working version
|
||||
wget https://repo.msys2.org/mingw/ucrt64/${tarball}
|
||||
|
||||
tarballs="${tarballs} ${tarball}"
|
||||
done
|
||||
|
||||
# install broken dependencies
|
||||
if [ -n "$tarballs" ]; then
|
||||
pacman -U --noconfirm ${tarballs}
|
||||
fi
|
||||
|
||||
# install dependencies
|
||||
dependencies=(
|
||||
"git"
|
||||
"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-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 -Syu --noconfirm --ignore="$(IFS=,; echo "${broken_deps[*]}")" "${dependencies[@]}"
|
||||
|
||||
- name: Install Doxygen
|
||||
# GCC compiled doxygen has issues when running graphviz
|
||||
env:
|
||||
@@ -941,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
|
||||
@@ -976,14 +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')
|
||||
if: always() && (steps.test.outcome == 'success' || steps.test.outcome == 'failure')
|
||||
id: test_report
|
||||
shell: msys2 {0}
|
||||
working-directory: build
|
||||
run: |
|
||||
@@ -996,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: >-
|
||||
@@ -1045,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.426.1549
|
||||
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 }}
|
||||
|
||||
4
.github/workflows/ci-copr.yml
vendored
4
.github/workflows/ci-copr.yml
vendored
@@ -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 }}
|
||||
|
||||
56
.github/workflows/ci-docker.yml
vendored
56
.github/workflows/ci-docker.yml
vendored
@@ -1,5 +1,5 @@
|
||||
---
|
||||
# This workflow is centrally managed in https://github.com/<organization>/.github/
|
||||
# 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.
|
||||
|
||||
@@ -19,20 +19,13 @@
|
||||
# GitHub runner.
|
||||
|
||||
name: CI Docker
|
||||
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:
|
||||
@@ -104,9 +97,10 @@ jobs:
|
||||
solution: ${{ steps.find_dotnet.outputs.solution }}
|
||||
|
||||
setup_release:
|
||||
if: ${{ needs.check_dockerfiles.outputs.dockerfiles }}
|
||||
name: Setup Release
|
||||
if: needs.check_dockerfiles.outputs.dockerfiles
|
||||
needs: check_dockerfiles
|
||||
needs:
|
||||
- check_dockerfiles
|
||||
outputs:
|
||||
publish_release: ${{ steps.setup_release.outputs.publish_release }}
|
||||
release_body: ${{ steps.setup_release.outputs.release_body }}
|
||||
@@ -114,8 +108,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
|
||||
@@ -123,24 +115,23 @@ jobs:
|
||||
|
||||
- name: Setup Release
|
||||
id: setup_release
|
||||
uses: LizardByte/setup-release-action@v2025.426.225
|
||||
uses: LizardByte/setup-release-action@v2025.102.14715
|
||||
with:
|
||||
dotnet: ${{ needs.check_dockerfiles.outputs.dotnet }}
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
docker:
|
||||
name: Docker${{ matrix.tag }}
|
||||
if: needs.check_dockerfiles.outputs.dockerfiles
|
||||
needs:
|
||||
- check_dockerfiles
|
||||
- setup_release
|
||||
needs: [check_dockerfiles, setup_release]
|
||||
if: ${{ needs.check_dockerfiles.outputs.dockerfiles }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
packages: write
|
||||
contents: write
|
||||
runs-on: ubuntu-22.04
|
||||
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
|
||||
@@ -265,14 +256,14 @@ jobs:
|
||||
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
|
||||
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
|
||||
if: ${{ needs.setup_release.outputs.publish_release == 'true' }} # PRs do not have access to secrets
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
@@ -280,7 +271,7 @@ jobs:
|
||||
password: ${{ secrets.GH_BOT_TOKEN }}
|
||||
|
||||
- name: Build artifacts
|
||||
if: steps.prepare.outputs.artifacts == 'true'
|
||||
if: ${{ steps.prepare.outputs.artifacts == 'true' }}
|
||||
id: build_artifacts
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
@@ -323,7 +314,7 @@ jobs:
|
||||
no-cache-filters: ${{ steps.prepare.outputs.no_cache_filters }}
|
||||
|
||||
- name: Arrange Artifacts
|
||||
if: steps.prepare.outputs.artifacts == 'true'
|
||||
if: ${{ steps.prepare.outputs.artifacts == 'true' }}
|
||||
working-directory: artifacts
|
||||
run: |
|
||||
# debug directory
|
||||
@@ -345,18 +336,15 @@ jobs:
|
||||
rm -f ./provenance.json
|
||||
|
||||
- name: Upload Artifacts
|
||||
if: steps.prepare.outputs.artifacts == 'true'
|
||||
if: ${{ steps.prepare.outputs.artifacts == 'true' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Docker${{ matrix.tag }}
|
||||
path: artifacts/
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Create/Update GitHub Release
|
||||
if: >
|
||||
needs.setup_release.outputs.publish_release == 'true' &&
|
||||
steps.prepare.outputs.artifacts == 'true'
|
||||
uses: LizardByte/create-release-action@v2025.426.1549
|
||||
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/*"
|
||||
@@ -368,9 +356,7 @@ jobs:
|
||||
token: ${{ secrets.GH_BOT_TOKEN }}
|
||||
|
||||
- name: Update Docker Hub Description
|
||||
if: >
|
||||
github.event_name == 'push' &&
|
||||
github.ref == 'refs/heads/master'
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
uses: peter-evans/dockerhub-description@v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
|
||||
90
.github/workflows/codeql.yml
vendored
90
.github/workflows/codeql.yml
vendored
@@ -1,21 +1,17 @@
|
||||
---
|
||||
# This workflow is centrally managed in https://github.com/<organization>/.github/
|
||||
# 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"
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
branches: ["master"]
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
branches: ["master"]
|
||||
schedule:
|
||||
- cron: '00 12 * * 0' # every Sunday at 12:00 UTC
|
||||
|
||||
@@ -26,17 +22,14 @@ concurrency:
|
||||
jobs:
|
||||
languages:
|
||||
name: Get language matrix
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.lang.outputs.result }}
|
||||
continue: ${{ steps.continue.outputs.result }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Get repo languages
|
||||
id: lang
|
||||
uses: actions/github-script@v7
|
||||
id: lang
|
||||
with:
|
||||
script: |
|
||||
// CodeQL supports ['cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby', 'swift']
|
||||
@@ -58,62 +51,32 @@ jobs:
|
||||
"include": []
|
||||
}
|
||||
|
||||
// Track languages we've already added to avoid duplicates
|
||||
const addedLanguages = new Set()
|
||||
|
||||
// Check if workflow files exist to determine if we should add actions language
|
||||
const fs = require('fs');
|
||||
const hasYmlFiles = fs.existsSync('.github/workflows') &&
|
||||
fs.readdirSync('.github/workflows').some(file => file.endsWith('.yml') || file.endsWith('.yaml'));
|
||||
|
||||
// Add actions language if workflow files exist
|
||||
if (hasYmlFiles) {
|
||||
console.log('Found GitHub Actions workflow files. Adding actions to the matrix.');
|
||||
matrix['include'].push({
|
||||
"category": "/language:actions",
|
||||
"language": "actions",
|
||||
"name": "actions",
|
||||
"os": "ubuntu-latest"
|
||||
});
|
||||
}
|
||||
|
||||
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()]
|
||||
}
|
||||
|
||||
const normalizedKey = key.toLowerCase()
|
||||
|
||||
if (supported_languages.includes(normalizedKey) && !addedLanguages.has(normalizedKey)) {
|
||||
// Mark this language as added
|
||||
addedLanguages.add(normalizedKey)
|
||||
|
||||
console.log(`Found supported language: ${normalizedKey}`)
|
||||
if (supported_languages.includes(key.toLowerCase())) {
|
||||
console.log(`Found supported language: ${key}`)
|
||||
let osList = ['ubuntu-latest'];
|
||||
if (normalizedKey === 'swift') {
|
||||
if (key.toLowerCase() === 'swift') {
|
||||
osList = ['macos-latest'];
|
||||
} else if (normalizedKey === 'cpp') {
|
||||
osList = ['macos-latest', 'ubuntu-latest', 'windows-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
|
||||
let name = osList.length === 1 ? normalizedKey : `${normalizedKey}, ${os}`
|
||||
|
||||
// set category for matrix
|
||||
let category = `/language:${normalizedKey}`
|
||||
if (normalizedKey === 'cpp') {
|
||||
category = `/language:cpp-${os.split('-')[0]}`
|
||||
if (osList.length == 1) {
|
||||
name = key.toLowerCase()
|
||||
} else {
|
||||
name = `${key.toLowerCase()}, ${os}`
|
||||
}
|
||||
|
||||
// add to matrix
|
||||
matrix['include'].push({
|
||||
"category": category,
|
||||
"language": normalizedKey,
|
||||
"name": name,
|
||||
"os": os
|
||||
})
|
||||
matrix['include'].push({"language": key.toLowerCase(), "os": os, "name": name})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,8 +87,8 @@ jobs:
|
||||
return matrix
|
||||
|
||||
- name: Continue
|
||||
id: continue
|
||||
uses: actions/github-script@v7
|
||||
id: continue
|
||||
with:
|
||||
script: |
|
||||
// if matrix['include'] is an empty list return false, otherwise true
|
||||
@@ -139,22 +102,24 @@ jobs:
|
||||
|
||||
analyze:
|
||||
name: Analyze (${{ matrix.name }})
|
||||
if: needs.languages.outputs.continue == 'true'
|
||||
if: ${{ needs.languages.outputs.continue == 'true' }}
|
||||
defaults:
|
||||
run:
|
||||
shell: ${{ matrix.os == 'windows-latest' && 'msys2 {0}' || 'bash' }}
|
||||
env:
|
||||
GITHUB_CODEQL_BUILD: true
|
||||
needs: languages
|
||||
needs: [languages]
|
||||
runs-on: ${{ matrix.os || 'ubuntu-latest' }}
|
||||
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
runs-on: ${{ matrix.os || 'ubuntu-latest' }}
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJson(needs.languages.outputs.matrix) }}
|
||||
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
|
||||
|
||||
steps:
|
||||
- name: Maximize build space
|
||||
if: >-
|
||||
@@ -202,7 +167,8 @@ jobs:
|
||||
- third-party
|
||||
|
||||
# Pre autobuild
|
||||
# create a file named .codeql-prebuild-${{ matrix.language }}-${{ runner.os }}.sh in the root of your repository
|
||||
# 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: |
|
||||
@@ -221,7 +187,7 @@ jobs:
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
with:
|
||||
category: "${{ matrix.category }}"
|
||||
category: "/language:${{matrix.language}}"
|
||||
output: sarif-results
|
||||
upload: failure-only
|
||||
|
||||
@@ -238,7 +204,6 @@ jobs:
|
||||
- name: Upload SARIF
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
category: "${{ matrix.category }}"
|
||||
sarif_file: sarif-results/${{ matrix.language }}.sarif
|
||||
|
||||
- name: Upload loc as a Build Artifact
|
||||
@@ -246,5 +211,4 @@ jobs:
|
||||
with:
|
||||
name: sarif-results-${{ matrix.language }}-${{ runner.os }}
|
||||
path: sarif-results
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
18
.github/workflows/common-lint.yml
vendored
18
.github/workflows/common-lint.yml
vendored
@@ -1,22 +1,16 @@
|
||||
---
|
||||
# This workflow is centrally managed in https://github.com/<organization>/.github/
|
||||
# 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
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
branches: [master]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
concurrency:
|
||||
group: "${{ github.workflow }}-${{ github.ref }}"
|
||||
@@ -83,10 +77,9 @@ jobs:
|
||||
|
||||
- name: C++ - Clang format lint
|
||||
if: always() && steps.cpp_files.outputs.found_files
|
||||
uses: DoozyX/clang-format-lint-action@v0.20
|
||||
uses: DoozyX/clang-format-lint-action@v0.18
|
||||
with:
|
||||
source: ${{ steps.cpp_files.outputs.found_files }}
|
||||
clangFormatVersion: '20'
|
||||
extensions: 'c,cpp,h,hpp,m,mm'
|
||||
style: file
|
||||
inplace: false
|
||||
@@ -270,4 +263,5 @@ jobs:
|
||||
|
||||
- name: YAML - log
|
||||
if: always() && steps.yamllint.outcome == 'failure'
|
||||
run: cat "${{ steps.yamllint.outputs.logfile }}" >> $GITHUB_STEP_SUMMARY
|
||||
run: |
|
||||
cat "${{ steps.yamllint.outputs.logfile }}" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
11
.github/workflows/issues.yml
vendored
11
.github/workflows/issues.yml
vendored
@@ -1,22 +1,17 @@
|
||||
---
|
||||
# This workflow is centrally managed in https://github.com/<organization>/.github/
|
||||
# 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
|
||||
permissions: {}
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- labeled
|
||||
- unlabeled
|
||||
types: [labeled, unlabeled]
|
||||
discussion:
|
||||
types:
|
||||
- labeled
|
||||
- unlabeled
|
||||
types: [labeled, unlabeled]
|
||||
|
||||
jobs:
|
||||
label:
|
||||
|
||||
13
.github/workflows/localize.yml
vendored
13
.github/workflows/localize.yml
vendored
@@ -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
|
||||
|
||||
|
||||
31
.github/workflows/release-notifier-moonlight.yml
vendored
31
.github/workflows/release-notifier-moonlight.yml
vendored
@@ -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
|
||||
|
||||
15
.github/workflows/release-notifier.yml
vendored
15
.github/workflows/release-notifier.yml
vendored
@@ -1,13 +1,11 @@
|
||||
---
|
||||
# This workflow is centrally managed in https://github.com/<organization>/.github/
|
||||
# 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
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
release:
|
||||
@@ -16,8 +14,8 @@ on:
|
||||
|
||||
jobs:
|
||||
update-blog:
|
||||
name: Update blog
|
||||
if: github.repository_owner == 'LizardByte'
|
||||
if: >-
|
||||
github.repository_owner == 'LizardByte'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check topics
|
||||
@@ -43,7 +41,8 @@ jobs:
|
||||
|
||||
- name: Check if latest GitHub release
|
||||
id: check-release
|
||||
if: steps.check-label.outputs.hasTopic == 'true'
|
||||
if: >-
|
||||
steps.check-label.outputs.hasTopic == 'true'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
@@ -129,7 +128,9 @@ jobs:
|
||||
steps.check-label.outputs.hasTopic == 'true' &&
|
||||
steps.check-release.outputs.isLatestRelease == 'true'
|
||||
run: |
|
||||
gh pr merge \
|
||||
gh \
|
||||
pr \
|
||||
merge \
|
||||
--auto \
|
||||
--delete-branch \
|
||||
--repo "LizardByte/LizardByte.github.io" \
|
||||
|
||||
10
.github/workflows/update-changelog.yml
vendored
10
.github/workflows/update-changelog.yml
vendored
@@ -1,20 +1,15 @@
|
||||
---
|
||||
# This workflow is centrally managed in https://github.com/<organization>/.github/
|
||||
# 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
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- created
|
||||
- edited
|
||||
- deleted
|
||||
types: [created, edited, deleted]
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
@@ -23,7 +18,6 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
update-changelog:
|
||||
name: Update Changelog
|
||||
if: >-
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
(!github.event.release.prerelease && !github.event.release.draft)
|
||||
|
||||
13
.github/workflows/update-docs.yml
vendored
13
.github/workflows/update-docs.yml
vendored
@@ -1,23 +1,19 @@
|
||||
---
|
||||
# This workflow is centrally managed in https://github.com/<organization>/.github/
|
||||
# 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.
|
||||
|
||||
# To use, add the `rtd` repository label to identify repositories that should trigger this workflow.
|
||||
# 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
|
||||
permissions: {}
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- created
|
||||
- edited
|
||||
- deleted
|
||||
types: [created, edited, deleted]
|
||||
|
||||
concurrency:
|
||||
group: "${{ github.workflow }}-${{ github.event.release.tag_name }}"
|
||||
@@ -77,7 +73,8 @@ jobs:
|
||||
- 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'
|
||||
if: >-
|
||||
steps.check.outputs.isLatestRelease == 'true'
|
||||
run: |
|
||||
json_body=$(jq -n \
|
||||
--arg default_branch "${TAG}" \
|
||||
|
||||
41
.github/workflows/update-flathub-repo.yml
vendored
41
.github/workflows/update-flathub-repo.yml
vendored
@@ -1,20 +1,15 @@
|
||||
---
|
||||
# This workflow 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.
|
||||
|
||||
# To use, add the `flathub-pkg` repository label to identify repositories that should trigger this workflow.
|
||||
# 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
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- released
|
||||
types: [released]
|
||||
|
||||
concurrency:
|
||||
group: "${{ github.workflow }}-${{ github.event.release.tag_name }}"
|
||||
@@ -24,13 +19,14 @@ jobs:
|
||||
update-flathub-repo:
|
||||
env:
|
||||
FLATHUB_PKG: dev.lizardbyte.app.${{ github.event.repository.name }}
|
||||
if: github.repository_owner == 'LizardByte'
|
||||
if: >-
|
||||
github.repository_owner == 'LizardByte'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check if flathub repo
|
||||
id: check-label
|
||||
env:
|
||||
TOPIC: flathub-pkg
|
||||
id: check-label
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
@@ -50,7 +46,8 @@ jobs:
|
||||
|
||||
- name: Check if latest GitHub release
|
||||
id: check-release
|
||||
if: steps.check-label.outputs.hasTopic == 'true'
|
||||
if: >-
|
||||
steps.check-label.outputs.hasTopic == 'true'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
@@ -107,7 +104,7 @@ jobs:
|
||||
if: >-
|
||||
steps.check-label.outputs.hasTopic == 'true' &&
|
||||
steps.check-release.outputs.isLatestRelease == 'true'
|
||||
uses: robinraju/release-downloader@v1.12
|
||||
uses: robinraju/release-downloader@v1.11
|
||||
with:
|
||||
repository: "${{ github.repository }}"
|
||||
tag: "${{ github.event.release.tag_name }}"
|
||||
@@ -117,7 +114,7 @@ jobs:
|
||||
out-file-path: "flathub/${{ env.FLATHUB_PKG }}"
|
||||
extract: true
|
||||
|
||||
- name: Delete archive
|
||||
- name: Delete arhive
|
||||
if: >-
|
||||
steps.check-label.outputs.hasTopic == 'true' &&
|
||||
steps.check-release.outputs.isLatestRelease == 'true'
|
||||
@@ -175,7 +172,6 @@ jobs:
|
||||
git checkout $main_commit
|
||||
|
||||
- name: Create/Update Pull Request
|
||||
id: create-pr
|
||||
if: >-
|
||||
steps.check-label.outputs.hasTopic == 'true' &&
|
||||
steps.check-release.outputs.isLatestRelease == 'true' &&
|
||||
@@ -189,18 +185,3 @@ jobs:
|
||||
delete-branch: true
|
||||
title: "chore: Update ${{ env.FLATHUB_PKG }} to ${{ github.event.release.tag_name }}"
|
||||
body: ${{ github.event.release.body }}
|
||||
|
||||
- name: Automerge PR
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }}
|
||||
if: >-
|
||||
steps.check-label.outputs.hasTopic == 'true' &&
|
||||
steps.check-release.outputs.isLatestRelease == 'true' &&
|
||||
fromJson(steps.download.outputs.downloaded_files)[0]
|
||||
run: |
|
||||
gh pr merge \
|
||||
--auto \
|
||||
--delete-branch \
|
||||
--repo "flathub/${{ env.FLATHUB_PKG }}" \
|
||||
--squash \
|
||||
"${{ steps.create-pr.outputs.pull-request-number }}"
|
||||
|
||||
23
.github/workflows/update-homebrew-release.yml
vendored
23
.github/workflows/update-homebrew-release.yml
vendored
@@ -1,20 +1,15 @@
|
||||
---
|
||||
# This workflow 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.
|
||||
|
||||
# To use, add the `homebrew-pkg` repository label to identify repositories that should trigger this workflow.
|
||||
# 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
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- released
|
||||
types: [released]
|
||||
|
||||
concurrency:
|
||||
group: "${{ github.workflow }}-${{ github.event.release.tag_name }}"
|
||||
@@ -22,13 +17,14 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
update-homebrew-release:
|
||||
if: github.repository_owner == 'LizardByte'
|
||||
if: >-
|
||||
github.repository_owner == 'LizardByte'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check if Homebrew repo
|
||||
id: check-label
|
||||
env:
|
||||
TOPIC: homebrew-pkg
|
||||
id: check-label
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
@@ -48,8 +44,9 @@ jobs:
|
||||
|
||||
- name: Download release asset
|
||||
id: download
|
||||
if: steps.check-label.outputs.hasTopic == 'true'
|
||||
uses: robinraju/release-downloader@v1.12
|
||||
if: >-
|
||||
steps.check-label.outputs.hasTopic == 'true'
|
||||
uses: robinraju/release-downloader@v1.11
|
||||
with:
|
||||
repository: "${{ github.repository }}"
|
||||
tag: "${{ github.event.release.tag_name }}"
|
||||
|
||||
43
.github/workflows/update-pacman-repo.yml
vendored
43
.github/workflows/update-pacman-repo.yml
vendored
@@ -1,20 +1,15 @@
|
||||
---
|
||||
# This workflow 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.
|
||||
|
||||
# To use, add the `pacman-pkg` repository label to identify repositories that should trigger this workflow.
|
||||
# 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
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- released
|
||||
types: [released]
|
||||
|
||||
concurrency:
|
||||
group: "${{ github.workflow }}-${{ github.event.release.tag_name }}"
|
||||
@@ -22,13 +17,14 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
update-homebrew-release:
|
||||
if: github.repository_owner == 'LizardByte'
|
||||
if: >-
|
||||
github.repository_owner == 'LizardByte'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check if pacman repo
|
||||
id: check-label
|
||||
env:
|
||||
TOPIC: pacman-pkg
|
||||
id: check-label
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
@@ -81,7 +77,7 @@ jobs:
|
||||
if: >-
|
||||
steps.check-label.outputs.hasTopic == 'true' &&
|
||||
steps.check-release.outputs.isLatestRelease == 'true'
|
||||
uses: robinraju/release-downloader@v1.12
|
||||
uses: robinraju/release-downloader@v1.11
|
||||
with:
|
||||
repository: "${{ github.repository }}"
|
||||
tag: "${{ github.event.release.tag_name }}"
|
||||
@@ -91,16 +87,7 @@ jobs:
|
||||
out-file-path: "pkgbuilds/${{ steps.prep.outputs.pkg_name }}"
|
||||
extract: true
|
||||
|
||||
- name: Remove pkg.tar.gz
|
||||
if: >-
|
||||
steps.check-label.outputs.hasTopic == 'true' &&
|
||||
steps.check-release.outputs.isLatestRelease == 'true' &&
|
||||
fromJson(steps.download.outputs.downloaded_files)[0]
|
||||
run: |
|
||||
rm -f "pkgbuilds/${{ steps.prep.outputs.pkg_name }}"
|
||||
|
||||
- name: Create/Update Pull Request
|
||||
id: create-pr
|
||||
if: >-
|
||||
steps.check-label.outputs.hasTopic == 'true' &&
|
||||
steps.check-release.outputs.isLatestRelease == 'true' &&
|
||||
@@ -118,17 +105,3 @@ jobs:
|
||||
labels: |
|
||||
auto-approve
|
||||
auto-merge
|
||||
|
||||
- name: Automerge PR
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }}
|
||||
if: >-
|
||||
steps.check-label.outputs.hasTopic == 'true' &&
|
||||
steps.check-release.outputs.isLatestRelease == 'true' &&
|
||||
fromJson(steps.download.outputs.downloaded_files)[0]
|
||||
run: |
|
||||
gh pr merge \
|
||||
--auto \
|
||||
--delete-branch \
|
||||
--squash \
|
||||
"${{ steps.create-pr.outputs.pull-request-number }}"
|
||||
|
||||
10
.github/workflows/update-pages.yml
vendored
10
.github/workflows/update-pages.yml
vendored
@@ -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'
|
||||
|
||||
23
.github/workflows/update-winget-release.yml
vendored
23
.github/workflows/update-winget-release.yml
vendored
@@ -1,20 +1,15 @@
|
||||
---
|
||||
# This workflow 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.
|
||||
|
||||
# To use, add the `winget-pkg` repository label to identify repositories that should trigger this workflow.
|
||||
# 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
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- released
|
||||
types: [released]
|
||||
|
||||
concurrency:
|
||||
group: "${{ github.workflow }}-${{ github.event.release.tag_name }}"
|
||||
@@ -22,13 +17,14 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
update-winget-release:
|
||||
if: github.repository_owner == 'LizardByte'
|
||||
if: >-
|
||||
github.repository_owner == 'LizardByte'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check if Winget repo
|
||||
id: check-label
|
||||
env:
|
||||
TOPIC: winget-pkg
|
||||
id: check-label
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
@@ -48,8 +44,9 @@ jobs:
|
||||
|
||||
- name: Download release asset
|
||||
id: download
|
||||
if: steps.check-label.outputs.hasTopic == 'true'
|
||||
uses: robinraju/release-downloader@v1.12
|
||||
if: >-
|
||||
steps.check-label.outputs.hasTopic == 'true'
|
||||
uses: robinraju/release-downloader@v1.11
|
||||
with:
|
||||
repository: "${{ github.repository }}"
|
||||
tag: "${{ github.event.release.tag_name }}"
|
||||
|
||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -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
|
||||
|
||||
76
README.md
76
README.md
@@ -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 |
|
||||
|
||||
17
api/components/responses/400.yml
Normal file
17
api/components/responses/400.yml
Normal 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"
|
||||
17
api/components/responses/401.yml
Normal file
17
api/components/responses/401.yml
Normal 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"
|
||||
7
api/components/responses/403.yml
Normal file
7
api/components/responses/403.yml
Normal 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
|
||||
15
api/components/responses/404.yml
Normal file
15
api/components/responses/404.yml
Normal 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"
|
||||
48
api/components/schemas/app.yml
Normal file
48
api/components/schemas/app.yml
Normal 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"
|
||||
3
api/components/schemas/cmd.yml
Normal file
3
api/components/schemas/cmd.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
---
|
||||
type: string
|
||||
description: Command to execute
|
||||
16
api/components/schemas/prep-cmd.yml
Normal file
16
api/components/schemas/prep-cmd.yml
Normal 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
44
api/openapi.yml
Normal 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"
|
||||
37
api/paths/confighttp/apps/apps-by-index.yml
Normal file
37
api/paths/confighttp/apps/apps-by-index.yml
Normal 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"
|
||||
151
api/paths/confighttp/apps/apps.yml
Normal file
151
api/paths/confighttp/apps/apps.yml
Normal 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"
|
||||
20
api/paths/confighttp/logs/logs.yml
Normal file
20
api/paths/confighttp/logs/logs.yml
Normal 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"
|
||||
@@ -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"
|
||||
|
||||
@@ -38,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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -20,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/"
|
||||
@@ -67,7 +64,6 @@ SET(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\\\"'
|
||||
@@ -82,7 +78,7 @@ 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'
|
||||
nsExec::ExecToLog '\\\"$INSTDIR\\\\sunshine.exe\\\" --restore-nvprefs-undo'
|
||||
MessageBox MB_YESNO|MB_ICONQUESTION \
|
||||
'Do you want to remove Virtual Gamepad?' \
|
||||
/SD IDNO IDNO NoGamepad
|
||||
@@ -92,18 +88,16 @@ set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS
|
||||
'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_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'
|
||||
")
|
||||
|
||||
@@ -49,7 +49,6 @@ INPUT = ../README.md \
|
||||
legal.md \
|
||||
configuration.md \
|
||||
app_examples.md \
|
||||
awesome_sunshine.md \
|
||||
guides.md \
|
||||
performance_tuning.md \
|
||||
api.md \
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -770,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>
|
||||
@@ -997,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>
|
||||
@@ -1179,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>
|
||||
@@ -1195,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>
|
||||
@@ -1340,29 +1314,6 @@ editing the `conf` file in a text editor. Use the examples as reference.
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### max_bitrate
|
||||
|
||||
<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.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Default</td>
|
||||
<td colspan="2">@code{}
|
||||
0
|
||||
@endcode</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Example</td>
|
||||
<td colspan="2">@code{}
|
||||
max_bitrate = 5000
|
||||
@endcode</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### min_fps_factor
|
||||
|
||||
<table>
|
||||
@@ -1970,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>
|
||||
|
||||
@@ -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++ development. Free licenses available for open source developers through the [JetBrains Open Source Program](https://www.jetbrains.com/community/opensource/). |
|
||||
|
||||
## Project Patterns
|
||||
|
||||
### Web UI
|
||||
|
||||
@@ -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>
|
||||
@@ -57,7 +55,7 @@ need to install CUDA.}
|
||||
<tr>
|
||||
<td rowspan="1">12.0.0</td>
|
||||
<td rowspan="2">525.60.13</td>
|
||||
<td rowspan="5">50;52;60;61;62;70;72;75;80;86;87;89;90</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>
|
||||
@@ -70,12 +68,7 @@ need to install CUDA.}
|
||||
<td>sunshine_{arch}.flatpak</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sunshine (copr - Fedora 40/41)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td rowspan="1">12.8.1</td>
|
||||
<td rowspan="1">570.124.06</td>
|
||||
<td>Sunshine (copr - Fedora 42)</td>
|
||||
<td>Sunshine (copr)</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -342,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.
|
||||
|
||||
@@ -494,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.
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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.}
|
||||
|
||||
|
||||
@@ -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"
|
||||
@@ -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">
|
||||
@@ -471,7 +466,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/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">
|
||||
@@ -519,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>
|
||||
@@ -542,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>
|
||||
@@ -592,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) {
|
||||
@@ -618,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');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -8,15 +8,14 @@
|
||||
"serve": "serve ./tests/fixtures/http --no-port-switching"
|
||||
},
|
||||
"dependencies": {
|
||||
"@lizardbyte/shared-web": "2025.326.11214",
|
||||
"@lizardbyte/shared-web": "2024.921.191855",
|
||||
"vue": "3.5.13",
|
||||
"vue-i18n": "11.1.3"
|
||||
"vue-i18n": "11.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@codecov/vite-plugin": "1.9.0",
|
||||
"@vitejs/plugin-vue": "4.6.2",
|
||||
"serve": "14.2.3",
|
||||
"vite": "4.5.9",
|
||||
"vite": "4.5.2",
|
||||
"vite-plugin-ejs": "1.6.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ Source0: tarball.tar.gz
|
||||
|
||||
# BuildRequires: boost-devel >= 1.86.0
|
||||
BuildRequires: cmake >= 3.25.0
|
||||
BuildRequires: gcc
|
||||
BuildRequires: gcc-c++
|
||||
BuildRequires: libayatana-appindicator3-devel
|
||||
BuildRequires: libcap-devel
|
||||
BuildRequires: libcurl-devel
|
||||
@@ -35,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
|
||||
@@ -53,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
|
||||
@@ -98,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"
|
||||
@@ -125,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" \
|
||||
@@ -157,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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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>
|
||||
[](https://flathub.org/apps/dev.lizardbyte.app.Sunshine)
|
||||
[](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.
|
||||
|
||||
Submodule packaging/linux/flatpak/deps/flatpak-builder-tools updated: bf91cb0bee...a1eb29c5f3
Submodule packaging/linux/flatpak/deps/shared-modules updated: 1f8e591b26...26def5f1d2
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"dev.lizardbyte.app.Sunshine": [
|
||||
"appstream-missing-screenshots",
|
||||
"appstream-screenshots-not-mirrored-in-ostree",
|
||||
"external-gitmodule-url-found",
|
||||
"finish-args-flatpak-spawn-access"
|
||||
]
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
11
packaging/linux/flatpak/flatpak-lint-baseline_repo.json
Normal file
11
packaging/linux/flatpak/flatpak-lint-baseline_repo.json
Normal 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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -29,35 +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 "gcovr" => :test
|
||||
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"
|
||||
@@ -71,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
|
||||
@@ -207,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'
|
||||
@@ -247,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?
|
||||
|
||||
@@ -352,23 +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"
|
||||
|
||||
# create gcovr report
|
||||
if ENV["HOMEBREW_BUILDPATH"]
|
||||
|
||||
cd File.join(ENV["HOMEBREW_BUILDPATH"], "build") do
|
||||
system "gcovr", ".",
|
||||
"-r", "../src",
|
||||
"--exclude-noncode-lines",
|
||||
"--exclude-throw-branches",
|
||||
"--exclude-unreachable-branches",
|
||||
"--verbose",
|
||||
"--xml-pretty",
|
||||
"-o=coverage.xml"
|
||||
end
|
||||
assert_path_exists File.join(ENV["HOMEBREW_BUILDPATH"], "build", "coverage.xml")
|
||||
end
|
||||
system bin/"test_sunshine", "--gtest_color=yes"
|
||||
end
|
||||
end
|
||||
|
||||
156
scripts/linux_build.sh
Executable file → Normal file
156
scripts/linux_build.sh
Executable file → Normal 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,53 +85,7 @@ shift $((OPTIND -1))
|
||||
# dependencies array to build out
|
||||
dependencies=()
|
||||
|
||||
function add_arch_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() {
|
||||
function add_debain_based_deps() {
|
||||
dependencies+=(
|
||||
"bison" # required if we need to compile doxygen
|
||||
"build-essential"
|
||||
@@ -151,7 +100,6 @@ function add_debian_based_deps() {
|
||||
"libcurl4-openssl-dev"
|
||||
"libdrm-dev" # KMS
|
||||
"libevdev-dev"
|
||||
"libgbm-dev"
|
||||
"libminiupnpc-dev"
|
||||
"libnotify-dev"
|
||||
"libnuma-dev"
|
||||
@@ -180,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"
|
||||
)
|
||||
@@ -193,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"
|
||||
)
|
||||
@@ -203,8 +151,8 @@ function add_fedora_deps() {
|
||||
dependencies+=(
|
||||
"cmake"
|
||||
"doxygen"
|
||||
"gcc${gcc_version}"
|
||||
"gcc${gcc_version}-c++"
|
||||
"gcc"
|
||||
"g++"
|
||||
"git"
|
||||
"graphviz"
|
||||
"libappindicator-gtk3-devel"
|
||||
@@ -222,7 +170,6 @@ function add_fedora_deps() {
|
||||
"libXrandr-devel" # X11
|
||||
"libXtst-devel" # X11
|
||||
"mesa-libGL-devel"
|
||||
"mesa-libgbm-devel"
|
||||
"miniupnpc-devel"
|
||||
"ninja-build"
|
||||
"npm"
|
||||
@@ -244,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
|
||||
|
||||
@@ -289,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"
|
||||
@@ -304,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
|
||||
@@ -316,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
|
||||
}
|
||||
@@ -360,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
|
||||
@@ -386,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
|
||||
@@ -409,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"
|
||||
@@ -427,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"
|
||||
@@ -437,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
|
||||
@@ -456,10 +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")
|
||||
cmake_args+=("-DCMAKE_CUDA_COMPILER:PATH=${build_dir}/cuda/bin/nvcc")
|
||||
fi
|
||||
|
||||
# Cmake stuff here
|
||||
@@ -499,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"
|
||||
@@ -516,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"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
Babel==2.17.0
|
||||
clang-format==20.*
|
||||
Babel==2.16.0
|
||||
clang-format
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,14 +509,12 @@ namespace config {
|
||||
{} // wa
|
||||
}, // display_device
|
||||
|
||||
1, // min_fps_factor
|
||||
0 // max_bitrate
|
||||
1 // min_fps_factor
|
||||
};
|
||||
|
||||
audio_t audio {
|
||||
{}, // audio_sink
|
||||
{}, // virtual_sink
|
||||
true, // stream audio
|
||||
true, // install_steam_drivers
|
||||
};
|
||||
|
||||
@@ -648,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);
|
||||
}
|
||||
}
|
||||
@@ -988,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;
|
||||
}
|
||||
|
||||
@@ -1018,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;
|
||||
}
|
||||
|
||||
@@ -1044,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);
|
||||
@@ -1137,14 +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_between_f(vars, "min_fps_factor", video.min_fps_factor, {1, 3});
|
||||
int_f(vars, "max_bitrate", video.max_bitrate);
|
||||
|
||||
path_f(vars, "pkey", nvhttp.pkey);
|
||||
path_f(vars, "cert", nvhttp.cert);
|
||||
@@ -1161,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});
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
@@ -141,13 +138,11 @@ namespace config {
|
||||
} dd;
|
||||
|
||||
int min_fps_factor; // Minimum fps target, determines minimum frame time
|
||||
int max_bitrate; // Maximum bitrate, sets ceiling in kbps for bitrate requested from client
|
||||
};
|
||||
|
||||
struct audio_t {
|
||||
std::string sink;
|
||||
std::string virtual_sink;
|
||||
bool stream;
|
||||
bool install_steam_drivers;
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace http {
|
||||
);
|
||||
|
||||
int reload_user_creds(const std::string &file);
|
||||
bool download_file(const std::string &url, const std::string &file, long ssl_version = CURL_SSLVERSION_TLSv1_2);
|
||||
bool download_file(const std::string &url, const std::string &file, long ssl_version = CURL_SSLVERSION_TLSv1_3);
|
||||
std::string url_escape(const std::string &url);
|
||||
std::string url_get_host(const std::string &url);
|
||||
|
||||
|
||||
@@ -106,7 +106,6 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
mail::man = std::make_shared<safe::mail_raw_t>();
|
||||
|
||||
// parse config file
|
||||
if (config::parse(argc, argv)) {
|
||||
return 0;
|
||||
}
|
||||
@@ -124,12 +123,6 @@ int main(int argc, char *argv[]) {
|
||||
// Log publisher metadata
|
||||
log_publisher_data();
|
||||
|
||||
// Log modified_config_settings
|
||||
for (auto &[name, val] : config::modified_config_settings) {
|
||||
BOOST_LOG(info) << "config: '"sv << name << "' = "sv << val;
|
||||
}
|
||||
config::modified_config_settings.clear();
|
||||
|
||||
if (!config::sunshine.cmd.name.empty()) {
|
||||
auto fn = cmd_to_func.find(config::sunshine.cmd.name);
|
||||
if (fn == std::end(cmd_to_func)) {
|
||||
|
||||
@@ -186,7 +186,7 @@ namespace net {
|
||||
|
||||
std::uint16_t map_port(int port) {
|
||||
// calculate the port from the config port
|
||||
auto mapped_port = (std::uint16_t) ((int) config::sunshine.port + port);
|
||||
auto mapped_port = (std::uint16_t)((int) config::sunshine.port + port);
|
||||
|
||||
// Ensure port is in the range of 1024-65535
|
||||
if (mapped_port < 1024 || mapped_port > 65535) {
|
||||
|
||||
@@ -528,7 +528,7 @@ namespace nvenc {
|
||||
|
||||
NV_ENC_LOCK_BITSTREAM lock_bitstream = {min_struct_version(NV_ENC_LOCK_BITSTREAM_VER, 1, 2)};
|
||||
lock_bitstream.outputBitstream = output_bitstream;
|
||||
lock_bitstream.doNotWait = async_event_handle ? 1 : 0;
|
||||
lock_bitstream.doNotWait = 0;
|
||||
|
||||
if (async_event_handle && !wait_for_async_event(100)) {
|
||||
BOOST_LOG(error) << "NvEnc: frame " << frame_index << " encode wait timeout";
|
||||
|
||||
@@ -10,19 +10,11 @@
|
||||
|
||||
namespace nvenc {
|
||||
|
||||
nvenc_d3d11::nvenc_d3d11(NV_ENC_DEVICE_TYPE device_type):
|
||||
nvenc_base(device_type) {
|
||||
async_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
}
|
||||
|
||||
nvenc_d3d11::~nvenc_d3d11() {
|
||||
if (dll) {
|
||||
FreeLibrary(dll);
|
||||
dll = NULL;
|
||||
}
|
||||
if (async_event_handle) {
|
||||
CloseHandle(async_event_handle);
|
||||
}
|
||||
}
|
||||
|
||||
bool nvenc_d3d11::init_library() {
|
||||
@@ -61,9 +53,5 @@ namespace nvenc {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool nvenc_d3d11::wait_for_async_event(uint32_t timeout_ms) {
|
||||
return WaitForSingleObject(async_event_handle, timeout_ms) == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
} // namespace nvenc
|
||||
#endif
|
||||
|
||||
@@ -25,7 +25,10 @@ namespace nvenc {
|
||||
*/
|
||||
class nvenc_d3d11: public nvenc_base {
|
||||
public:
|
||||
explicit nvenc_d3d11(NV_ENC_DEVICE_TYPE device_type);
|
||||
explicit nvenc_d3d11(NV_ENC_DEVICE_TYPE device_type):
|
||||
nvenc_base(device_type) {
|
||||
}
|
||||
|
||||
~nvenc_d3d11();
|
||||
|
||||
/**
|
||||
@@ -36,7 +39,6 @@ namespace nvenc {
|
||||
|
||||
protected:
|
||||
bool init_library() override;
|
||||
bool wait_for_async_event(uint32_t timeout_ms) override;
|
||||
|
||||
private:
|
||||
HMODULE dll = NULL;
|
||||
|
||||
@@ -106,7 +106,6 @@ namespace platf {
|
||||
rumble_triggers, ///< Rumble triggers
|
||||
set_motion_event_state, ///< Set motion event state
|
||||
set_rgb_led, ///< Set RGB LED
|
||||
set_adaptive_triggers, ///< Set adaptive triggers
|
||||
};
|
||||
|
||||
struct gamepad_feedback_msg_t {
|
||||
@@ -143,14 +142,6 @@ namespace platf {
|
||||
return msg;
|
||||
}
|
||||
|
||||
static gamepad_feedback_msg_t make_adaptive_triggers(std::uint16_t id, uint8_t event_flags, uint8_t type_left, uint8_t type_right, const std::array<uint8_t, 10> &left, const std::array<uint8_t, 10> &right) {
|
||||
gamepad_feedback_msg_t msg;
|
||||
msg.type = gamepad_feedback_e::set_adaptive_triggers;
|
||||
msg.id = id;
|
||||
msg.data.adaptive_triggers = {.event_flags = event_flags, .type_left = type_left, .type_right = type_right, .left = left, .right = right};
|
||||
return msg;
|
||||
}
|
||||
|
||||
gamepad_feedback_e type;
|
||||
std::uint16_t id;
|
||||
|
||||
@@ -175,15 +166,6 @@ namespace platf {
|
||||
std::uint8_t g;
|
||||
std::uint8_t b;
|
||||
} rgb_led;
|
||||
|
||||
struct {
|
||||
uint16_t controllerNumber;
|
||||
uint8_t event_flags;
|
||||
uint8_t type_left;
|
||||
uint8_t type_right;
|
||||
std::array<uint8_t, 10> left;
|
||||
std::array<uint8_t, 10> right;
|
||||
} adaptive_triggers;
|
||||
} data;
|
||||
};
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ extern "C" {
|
||||
// There aren't that many DRM_FORMAT I need to use, so define them here
|
||||
//
|
||||
// They aren't likely to change any time soon.
|
||||
#define fourcc_code(a, b, c, d) ((std::uint32_t) (a) | ((std::uint32_t) (b) << 8) | ((std::uint32_t) (c) << 16) | ((std::uint32_t) (d) << 24))
|
||||
#define fourcc_code(a, b, c, d) ((std::uint32_t)(a) | ((std::uint32_t)(b) << 8) | ((std::uint32_t)(c) << 16) | ((std::uint32_t)(d) << 24))
|
||||
#define fourcc_mod_code(vendor, val) ((((uint64_t) vendor) << 56) | ((val) & 0x00ffffffffffffffULL))
|
||||
#define DRM_FORMAT_MOD_INVALID fourcc_mod_code(0, ((1ULL << 56) - 1))
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace platf::gamepad {
|
||||
}
|
||||
|
||||
auto create_ds5() {
|
||||
return inputtino::PS5Joypad::create({.name = "Sunshine PS5 (virtual) pad", .vendor_id = 0x054C, .product_id = 0x0CE6, .version = 0x8111});
|
||||
return inputtino::PS5Joypad::create({.name = "Sunshine DualSense (virtual) pad", .vendor_id = 0x054C, .product_id = 0x0CE6, .version = 0x8111});
|
||||
}
|
||||
|
||||
int alloc(input_raw_t *raw, const gamepad_id_t &id, const gamepad_arrival_t &metadata, feedback_queue_t feedback_queue) {
|
||||
@@ -152,10 +152,6 @@ namespace platf::gamepad {
|
||||
gamepad->last_rgb_led = msg;
|
||||
});
|
||||
|
||||
(*ds5).set_on_trigger_effect([feedback_queue, idx = id.clientRelativeIndex](const inputtino::PS5Joypad::TriggerEffect &trigger_effect) {
|
||||
feedback_queue->raise(gamepad_feedback_msg_t::make_adaptive_triggers(idx, trigger_effect.event_flags, trigger_effect.type_left, trigger_effect.type_right, trigger_effect.left, trigger_effect.right));
|
||||
});
|
||||
|
||||
// Activate the motion sensors
|
||||
feedback_queue->raise(gamepad_feedback_msg_t::make_motion_event_state(id.clientRelativeIndex, LI_MOTION_TYPE_ACCEL, 100));
|
||||
feedback_queue->raise(gamepad_feedback_msg_t::make_motion_event_state(id.clientRelativeIndex, LI_MOTION_TYPE_GYRO, 100));
|
||||
|
||||
@@ -6,14 +6,9 @@
|
||||
#include <cstdlib>
|
||||
|
||||
// platform includes
|
||||
#include <drm_fourcc.h>
|
||||
#include <fcntl.h>
|
||||
#include <gbm.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <wayland-client.h>
|
||||
#include <wayland-util.h>
|
||||
#include <xf86drm.h>
|
||||
|
||||
// local includes
|
||||
#include "graphics.h"
|
||||
@@ -42,12 +37,6 @@ namespace wl {
|
||||
|
||||
#define CLASS_CALL(c, m) classCall<c, decltype(&c::m), &c::m>
|
||||
|
||||
// Define buffer params listener
|
||||
static const struct zwp_linux_buffer_params_v1_listener params_listener = {
|
||||
.created = dmabuf_t::buffer_params_created,
|
||||
.failed = dmabuf_t::buffer_params_failed
|
||||
};
|
||||
|
||||
int display_t::init(const char *display_name) {
|
||||
if (!display_name) {
|
||||
display_name = std::getenv("WAYLAND_DISPLAY");
|
||||
@@ -147,13 +136,7 @@ namespace wl {
|
||||
BOOST_LOG(info) << "Logical size: "sv << width << 'x' << height;
|
||||
}
|
||||
|
||||
void monitor_t::wl_mode(
|
||||
wl_output *wl_output,
|
||||
std::uint32_t flags,
|
||||
std::int32_t width,
|
||||
std::int32_t height,
|
||||
std::int32_t refresh
|
||||
) {
|
||||
void monitor_t::wl_mode(wl_output *wl_output, std::uint32_t flags, std::int32_t width, std::int32_t height, std::int32_t refresh) {
|
||||
viewport.width = width;
|
||||
viewport.height = height;
|
||||
|
||||
@@ -168,8 +151,6 @@ namespace wl {
|
||||
|
||||
interface_t::interface_t() noexcept
|
||||
:
|
||||
screencopy_manager {nullptr},
|
||||
dmabuf_interface {nullptr},
|
||||
output_manager {nullptr},
|
||||
listener {
|
||||
&CLASS_CALL(interface_t, add_interface),
|
||||
@@ -181,12 +162,7 @@ namespace wl {
|
||||
wl_registry_add_listener(registry, &listener, this);
|
||||
}
|
||||
|
||||
void interface_t::add_interface(
|
||||
wl_registry *registry,
|
||||
std::uint32_t id,
|
||||
const char *interface,
|
||||
std::uint32_t version
|
||||
) {
|
||||
void interface_t::add_interface(wl_registry *registry, std::uint32_t id, const char *interface, std::uint32_t version) {
|
||||
BOOST_LOG(debug) << "Available interface: "sv << interface << '(' << id << ") version "sv << version;
|
||||
|
||||
if (!std::strcmp(interface, wl_output_interface.name)) {
|
||||
@@ -201,16 +177,11 @@ namespace wl {
|
||||
output_manager = (zxdg_output_manager_v1 *) wl_registry_bind(registry, id, &zxdg_output_manager_v1_interface, version);
|
||||
|
||||
this->interface[XDG_OUTPUT] = true;
|
||||
} else if (!std::strcmp(interface, zwlr_screencopy_manager_v1_interface.name)) {
|
||||
} else if (!std::strcmp(interface, zwlr_export_dmabuf_manager_v1_interface.name)) {
|
||||
BOOST_LOG(info) << "Found interface: "sv << interface << '(' << id << ") version "sv << version;
|
||||
screencopy_manager = (zwlr_screencopy_manager_v1 *) wl_registry_bind(registry, id, &zwlr_screencopy_manager_v1_interface, version);
|
||||
dmabuf_manager = (zwlr_export_dmabuf_manager_v1 *) wl_registry_bind(registry, id, &zwlr_export_dmabuf_manager_v1_interface, version);
|
||||
|
||||
this->interface[WLR_EXPORT_DMABUF] = true;
|
||||
} else if (!std::strcmp(interface, zwp_linux_dmabuf_v1_interface.name)) {
|
||||
BOOST_LOG(info) << "Found interface: "sv << interface << '(' << id << ") version "sv << version;
|
||||
dmabuf_interface = (zwp_linux_dmabuf_v1 *) wl_registry_bind(registry, id, &zwp_linux_dmabuf_v1_interface, version);
|
||||
|
||||
this->interface[LINUX_DMABUF] = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,306 +189,94 @@ namespace wl {
|
||||
BOOST_LOG(info) << "Delete: "sv << id;
|
||||
}
|
||||
|
||||
// Initialize GBM
|
||||
bool dmabuf_t::init_gbm() {
|
||||
if (gbm_device) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Find render node
|
||||
drmDevice *devices[16];
|
||||
int n = drmGetDevices2(0, devices, 16);
|
||||
if (n <= 0) {
|
||||
BOOST_LOG(error) << "No DRM devices found"sv;
|
||||
return false;
|
||||
}
|
||||
|
||||
int drm_fd = -1;
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (devices[i]->available_nodes & (1 << DRM_NODE_RENDER)) {
|
||||
drm_fd = open(devices[i]->nodes[DRM_NODE_RENDER], O_RDWR);
|
||||
if (drm_fd >= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
drmFreeDevices(devices, n);
|
||||
|
||||
if (drm_fd < 0) {
|
||||
BOOST_LOG(error) << "Failed to open DRM render node"sv;
|
||||
return false;
|
||||
}
|
||||
|
||||
gbm_device = gbm_create_device(drm_fd);
|
||||
if (!gbm_device) {
|
||||
close(drm_fd);
|
||||
BOOST_LOG(error) << "Failed to create GBM device"sv;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Cleanup GBM
|
||||
void dmabuf_t::cleanup_gbm() {
|
||||
if (current_bo) {
|
||||
gbm_bo_destroy(current_bo);
|
||||
current_bo = nullptr;
|
||||
}
|
||||
|
||||
if (current_wl_buffer) {
|
||||
wl_buffer_destroy(current_wl_buffer);
|
||||
current_wl_buffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
dmabuf_t::dmabuf_t():
|
||||
status {READY},
|
||||
frames {},
|
||||
current_frame {&frames[0]},
|
||||
listener {
|
||||
&CLASS_CALL(dmabuf_t, buffer),
|
||||
&CLASS_CALL(dmabuf_t, flags),
|
||||
&CLASS_CALL(dmabuf_t, frame),
|
||||
&CLASS_CALL(dmabuf_t, object),
|
||||
&CLASS_CALL(dmabuf_t, ready),
|
||||
&CLASS_CALL(dmabuf_t, failed),
|
||||
&CLASS_CALL(dmabuf_t, damage),
|
||||
&CLASS_CALL(dmabuf_t, linux_dmabuf),
|
||||
&CLASS_CALL(dmabuf_t, buffer_done),
|
||||
&CLASS_CALL(dmabuf_t, cancel)
|
||||
} {
|
||||
}
|
||||
|
||||
// Start capture
|
||||
void dmabuf_t::listen(
|
||||
zwlr_screencopy_manager_v1 *screencopy_manager,
|
||||
zwp_linux_dmabuf_v1 *dmabuf_interface,
|
||||
wl_output *output,
|
||||
bool blend_cursor
|
||||
) {
|
||||
this->dmabuf_interface = dmabuf_interface;
|
||||
// Reset state
|
||||
shm_info.supported = false;
|
||||
dmabuf_info.supported = false;
|
||||
|
||||
// Create new frame
|
||||
auto frame = zwlr_screencopy_manager_v1_capture_output(
|
||||
screencopy_manager,
|
||||
blend_cursor ? 1 : 0,
|
||||
output
|
||||
);
|
||||
|
||||
// Store frame data pointer for callbacks
|
||||
zwlr_screencopy_frame_v1_set_user_data(frame, this);
|
||||
|
||||
// Add listener
|
||||
zwlr_screencopy_frame_v1_add_listener(frame, &listener, this);
|
||||
void dmabuf_t::listen(zwlr_export_dmabuf_manager_v1 *dmabuf_manager, wl_output *output, bool blend_cursor) {
|
||||
auto frame = zwlr_export_dmabuf_manager_v1_capture_output(dmabuf_manager, blend_cursor, output);
|
||||
zwlr_export_dmabuf_frame_v1_add_listener(frame, &listener, this);
|
||||
|
||||
status = WAITING;
|
||||
}
|
||||
|
||||
dmabuf_t::~dmabuf_t() {
|
||||
cleanup_gbm();
|
||||
|
||||
for (auto &frame : frames) {
|
||||
frame.destroy();
|
||||
}
|
||||
|
||||
if (gbm_device) {
|
||||
// We should close the DRM FD, but it's owned by GBM
|
||||
gbm_device_destroy(gbm_device);
|
||||
gbm_device = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Buffer format callback
|
||||
void dmabuf_t::buffer(
|
||||
zwlr_screencopy_frame_v1 *frame,
|
||||
uint32_t format,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
uint32_t stride
|
||||
) {
|
||||
shm_info.supported = true;
|
||||
shm_info.format = format;
|
||||
shm_info.width = width;
|
||||
shm_info.height = height;
|
||||
shm_info.stride = stride;
|
||||
|
||||
BOOST_LOG(debug) << "Screencopy supports SHM format: "sv << format;
|
||||
}
|
||||
|
||||
// DMA-BUF format callback
|
||||
void dmabuf_t::linux_dmabuf(
|
||||
zwlr_screencopy_frame_v1 *frame,
|
||||
std::uint32_t format,
|
||||
void dmabuf_t::frame(
|
||||
zwlr_export_dmabuf_frame_v1 *frame,
|
||||
std::uint32_t width,
|
||||
std::uint32_t height
|
||||
std::uint32_t height,
|
||||
std::uint32_t x,
|
||||
std::uint32_t y,
|
||||
std::uint32_t buffer_flags,
|
||||
std::uint32_t flags,
|
||||
std::uint32_t format,
|
||||
std::uint32_t high,
|
||||
std::uint32_t low,
|
||||
std::uint32_t obj_count
|
||||
) {
|
||||
dmabuf_info.supported = true;
|
||||
dmabuf_info.format = format;
|
||||
dmabuf_info.width = width;
|
||||
dmabuf_info.height = height;
|
||||
|
||||
BOOST_LOG(debug) << "Screencopy supports DMA-BUF format: "sv << format;
|
||||
}
|
||||
|
||||
// Flags callback
|
||||
void dmabuf_t::flags(zwlr_screencopy_frame_v1 *frame, std::uint32_t flags) {
|
||||
y_invert = flags & ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT;
|
||||
BOOST_LOG(debug) << "Frame flags: "sv << flags << (y_invert ? " (y_invert)" : "");
|
||||
}
|
||||
|
||||
// DMA-BUF creation helper
|
||||
void dmabuf_t::create_and_copy_dmabuf(zwlr_screencopy_frame_v1 *frame) {
|
||||
if (!init_gbm()) {
|
||||
BOOST_LOG(error) << "Failed to initialize GBM"sv;
|
||||
zwlr_screencopy_frame_v1_destroy(frame);
|
||||
status = REINIT;
|
||||
return;
|
||||
}
|
||||
|
||||
// Create GBM buffer
|
||||
current_bo = gbm_bo_create(gbm_device, dmabuf_info.width, dmabuf_info.height, dmabuf_info.format, GBM_BO_USE_RENDERING);
|
||||
if (!current_bo) {
|
||||
BOOST_LOG(error) << "Failed to create GBM buffer"sv;
|
||||
zwlr_screencopy_frame_v1_destroy(frame);
|
||||
status = REINIT;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get buffer info
|
||||
int fd = gbm_bo_get_fd(current_bo);
|
||||
if (fd < 0) {
|
||||
BOOST_LOG(error) << "Failed to get buffer FD"sv;
|
||||
gbm_bo_destroy(current_bo);
|
||||
current_bo = nullptr;
|
||||
zwlr_screencopy_frame_v1_destroy(frame);
|
||||
status = REINIT;
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t stride = gbm_bo_get_stride(current_bo);
|
||||
uint64_t modifier = gbm_bo_get_modifier(current_bo);
|
||||
|
||||
// Store in surface descriptor for later use
|
||||
auto next_frame = get_next_frame();
|
||||
next_frame->sd.fds[0] = fd;
|
||||
next_frame->sd.pitches[0] = stride;
|
||||
next_frame->sd.offsets[0] = 0;
|
||||
next_frame->sd.modifier = modifier;
|
||||
|
||||
// Create linux-dmabuf buffer
|
||||
auto params = zwp_linux_dmabuf_v1_create_params(dmabuf_interface);
|
||||
zwp_linux_buffer_params_v1_add(params, fd, 0, 0, stride, modifier >> 32, modifier & 0xffffffff);
|
||||
|
||||
// Add listener for buffer creation
|
||||
zwp_linux_buffer_params_v1_add_listener(params, ¶ms_listener, frame);
|
||||
|
||||
// Create Wayland buffer (async - callback will handle copy)
|
||||
zwp_linux_buffer_params_v1_create(params, dmabuf_info.width, dmabuf_info.height, dmabuf_info.format, 0);
|
||||
}
|
||||
|
||||
// Buffer done callback - time to create buffer
|
||||
void dmabuf_t::buffer_done(zwlr_screencopy_frame_v1 *frame) {
|
||||
auto next_frame = get_next_frame();
|
||||
|
||||
// Prefer DMA-BUF if supported
|
||||
if (dmabuf_info.supported && dmabuf_interface) {
|
||||
// Store format info first
|
||||
next_frame->sd.fourcc = dmabuf_info.format;
|
||||
next_frame->sd.width = dmabuf_info.width;
|
||||
next_frame->sd.height = dmabuf_info.height;
|
||||
|
||||
// Create and start copy
|
||||
create_and_copy_dmabuf(frame);
|
||||
} else if (shm_info.supported) {
|
||||
// SHM fallback would go here
|
||||
BOOST_LOG(warning) << "SHM capture not implemented"sv;
|
||||
zwlr_screencopy_frame_v1_destroy(frame);
|
||||
status = REINIT;
|
||||
} else {
|
||||
BOOST_LOG(error) << "No supported buffer types"sv;
|
||||
zwlr_screencopy_frame_v1_destroy(frame);
|
||||
status = REINIT;
|
||||
}
|
||||
next_frame->sd.fourcc = format;
|
||||
next_frame->sd.width = width;
|
||||
next_frame->sd.height = height;
|
||||
next_frame->sd.modifier = (((std::uint64_t) high) << 32) | low;
|
||||
}
|
||||
|
||||
// Buffer params created callback
|
||||
void dmabuf_t::buffer_params_created(
|
||||
void *data,
|
||||
struct zwp_linux_buffer_params_v1 *params,
|
||||
struct wl_buffer *buffer
|
||||
void dmabuf_t::object(
|
||||
zwlr_export_dmabuf_frame_v1 *frame,
|
||||
std::uint32_t index,
|
||||
std::int32_t fd,
|
||||
std::uint32_t size,
|
||||
std::uint32_t offset,
|
||||
std::uint32_t stride,
|
||||
std::uint32_t plane_index
|
||||
) {
|
||||
auto frame = static_cast<zwlr_screencopy_frame_v1 *>(data);
|
||||
auto self = static_cast<dmabuf_t *>(zwlr_screencopy_frame_v1_get_user_data(frame));
|
||||
auto next_frame = get_next_frame();
|
||||
|
||||
// Store for cleanup
|
||||
self->current_wl_buffer = buffer;
|
||||
|
||||
// Start the actual copy
|
||||
zwlr_screencopy_frame_v1_copy(frame, buffer);
|
||||
next_frame->sd.fds[plane_index] = fd;
|
||||
next_frame->sd.pitches[plane_index] = stride;
|
||||
next_frame->sd.offsets[plane_index] = offset;
|
||||
}
|
||||
|
||||
// Buffer params failed callback
|
||||
void dmabuf_t::buffer_params_failed(
|
||||
void *data,
|
||||
struct zwp_linux_buffer_params_v1 *params
|
||||
) {
|
||||
auto frame = static_cast<zwlr_screencopy_frame_v1 *>(data);
|
||||
auto self = static_cast<dmabuf_t *>(zwlr_screencopy_frame_v1_get_user_data(frame));
|
||||
|
||||
BOOST_LOG(error) << "Failed to create buffer from params"sv;
|
||||
self->cleanup_gbm();
|
||||
|
||||
zwlr_screencopy_frame_v1_destroy(frame);
|
||||
self->status = REINIT;
|
||||
}
|
||||
|
||||
// Ready callback
|
||||
void dmabuf_t::ready(
|
||||
zwlr_screencopy_frame_v1 *frame,
|
||||
zwlr_export_dmabuf_frame_v1 *frame,
|
||||
std::uint32_t tv_sec_hi,
|
||||
std::uint32_t tv_sec_lo,
|
||||
std::uint32_t tv_nsec
|
||||
) {
|
||||
BOOST_LOG(debug) << "Frame ready"sv;
|
||||
zwlr_export_dmabuf_frame_v1_destroy(frame);
|
||||
|
||||
// Frame is ready for use, GBM buffer now contains screen content
|
||||
current_frame->destroy();
|
||||
current_frame = get_next_frame();
|
||||
|
||||
// Keep the GBM buffer alive but destroy the Wayland objects
|
||||
if (current_wl_buffer) {
|
||||
wl_buffer_destroy(current_wl_buffer);
|
||||
current_wl_buffer = nullptr;
|
||||
}
|
||||
|
||||
cleanup_gbm();
|
||||
|
||||
zwlr_screencopy_frame_v1_destroy(frame);
|
||||
status = READY;
|
||||
}
|
||||
|
||||
// Failed callback
|
||||
void dmabuf_t::failed(zwlr_screencopy_frame_v1 *frame) {
|
||||
BOOST_LOG(error) << "Frame capture failed"sv;
|
||||
void dmabuf_t::cancel(
|
||||
zwlr_export_dmabuf_frame_v1 *frame,
|
||||
std::uint32_t reason
|
||||
) {
|
||||
zwlr_export_dmabuf_frame_v1_destroy(frame);
|
||||
|
||||
// Clean up resources
|
||||
cleanup_gbm();
|
||||
auto next_frame = get_next_frame();
|
||||
next_frame->destroy();
|
||||
|
||||
zwlr_screencopy_frame_v1_destroy(frame);
|
||||
status = REINIT;
|
||||
}
|
||||
|
||||
void dmabuf_t::damage(
|
||||
zwlr_screencopy_frame_v1 *frame,
|
||||
std::uint32_t x,
|
||||
std::uint32_t y,
|
||||
std::uint32_t width,
|
||||
std::uint32_t height
|
||||
) {};
|
||||
|
||||
void frame_t::destroy() {
|
||||
for (auto x = 0; x < 4; ++x) {
|
||||
if (sd.fds[x] >= 0) {
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
#include <bitset>
|
||||
|
||||
#ifdef SUNSHINE_BUILD_WAYLAND
|
||||
#include <linux-dmabuf-unstable-v1.h>
|
||||
#include <wlr-screencopy-unstable-v1.h>
|
||||
#include <wlr-export-dmabuf-unstable-v1.h>
|
||||
#include <xdg-output-unstable-v1.h>
|
||||
#endif
|
||||
|
||||
@@ -28,9 +27,9 @@ namespace wl {
|
||||
class frame_t {
|
||||
public:
|
||||
frame_t();
|
||||
void destroy();
|
||||
|
||||
egl::surface_descriptor_t sd;
|
||||
|
||||
void destroy();
|
||||
};
|
||||
|
||||
class dmabuf_t {
|
||||
@@ -41,91 +40,104 @@ namespace wl {
|
||||
REINIT, ///< Reinitialize the frame
|
||||
};
|
||||
|
||||
dmabuf_t();
|
||||
~dmabuf_t();
|
||||
|
||||
dmabuf_t(dmabuf_t &&) = delete;
|
||||
dmabuf_t(const dmabuf_t &) = delete;
|
||||
|
||||
dmabuf_t &operator=(const dmabuf_t &) = delete;
|
||||
dmabuf_t &operator=(dmabuf_t &&) = delete;
|
||||
|
||||
void listen(zwlr_screencopy_manager_v1 *screencopy_manager, zwp_linux_dmabuf_v1 *dmabuf_interface, wl_output *output, bool blend_cursor = false);
|
||||
static void buffer_params_created(void *data, struct zwp_linux_buffer_params_v1 *params, struct wl_buffer *wl_buffer);
|
||||
static void buffer_params_failed(void *data, struct zwp_linux_buffer_params_v1 *params);
|
||||
void buffer(zwlr_screencopy_frame_v1 *frame, std::uint32_t format, std::uint32_t width, std::uint32_t height, std::uint32_t stride);
|
||||
void linux_dmabuf(zwlr_screencopy_frame_v1 *frame, std::uint32_t format, std::uint32_t width, std::uint32_t height);
|
||||
void buffer_done(zwlr_screencopy_frame_v1 *frame);
|
||||
void flags(zwlr_screencopy_frame_v1 *frame, std::uint32_t flags);
|
||||
void damage(zwlr_screencopy_frame_v1 *frame, std::uint32_t x, std::uint32_t y, std::uint32_t width, std::uint32_t height);
|
||||
void ready(zwlr_screencopy_frame_v1 *frame, std::uint32_t tv_sec_hi, std::uint32_t tv_sec_lo, std::uint32_t tv_nsec);
|
||||
void failed(zwlr_screencopy_frame_v1 *frame);
|
||||
dmabuf_t();
|
||||
|
||||
frame_t *get_next_frame() {
|
||||
void listen(zwlr_export_dmabuf_manager_v1 *dmabuf_manager, wl_output *output, bool blend_cursor = false);
|
||||
|
||||
~dmabuf_t();
|
||||
|
||||
void frame(
|
||||
zwlr_export_dmabuf_frame_v1 *frame,
|
||||
std::uint32_t width,
|
||||
std::uint32_t height,
|
||||
std::uint32_t x,
|
||||
std::uint32_t y,
|
||||
std::uint32_t buffer_flags,
|
||||
std::uint32_t flags,
|
||||
std::uint32_t format,
|
||||
std::uint32_t high,
|
||||
std::uint32_t low,
|
||||
std::uint32_t obj_count
|
||||
);
|
||||
|
||||
void object(
|
||||
zwlr_export_dmabuf_frame_v1 *frame,
|
||||
std::uint32_t index,
|
||||
std::int32_t fd,
|
||||
std::uint32_t size,
|
||||
std::uint32_t offset,
|
||||
std::uint32_t stride,
|
||||
std::uint32_t plane_index
|
||||
);
|
||||
|
||||
void ready(
|
||||
zwlr_export_dmabuf_frame_v1 *frame,
|
||||
std::uint32_t tv_sec_hi,
|
||||
std::uint32_t tv_sec_lo,
|
||||
std::uint32_t tv_nsec
|
||||
);
|
||||
|
||||
void cancel(
|
||||
zwlr_export_dmabuf_frame_v1 *frame,
|
||||
std::uint32_t reason
|
||||
);
|
||||
|
||||
inline frame_t *get_next_frame() {
|
||||
return current_frame == &frames[0] ? &frames[1] : &frames[0];
|
||||
}
|
||||
|
||||
status_e status;
|
||||
|
||||
std::array<frame_t, 2> frames;
|
||||
frame_t *current_frame;
|
||||
zwlr_screencopy_frame_v1_listener listener;
|
||||
|
||||
private:
|
||||
bool init_gbm();
|
||||
void cleanup_gbm();
|
||||
void create_and_copy_dmabuf(zwlr_screencopy_frame_v1 *frame);
|
||||
|
||||
zwp_linux_dmabuf_v1 *dmabuf_interface {nullptr};
|
||||
|
||||
struct {
|
||||
bool supported {false};
|
||||
std::uint32_t format;
|
||||
std::uint32_t width;
|
||||
std::uint32_t height;
|
||||
std::uint32_t stride;
|
||||
} shm_info;
|
||||
|
||||
struct {
|
||||
bool supported {false};
|
||||
std::uint32_t format;
|
||||
std::uint32_t width;
|
||||
std::uint32_t height;
|
||||
} dmabuf_info;
|
||||
|
||||
struct gbm_device *gbm_device {nullptr};
|
||||
struct gbm_bo *current_bo {nullptr};
|
||||
struct wl_buffer *current_wl_buffer {nullptr};
|
||||
bool y_invert {false};
|
||||
zwlr_export_dmabuf_frame_v1_listener listener;
|
||||
};
|
||||
|
||||
class monitor_t {
|
||||
public:
|
||||
explicit monitor_t(wl_output *output);
|
||||
|
||||
monitor_t(monitor_t &&) = delete;
|
||||
monitor_t(const monitor_t &) = delete;
|
||||
|
||||
monitor_t &operator=(const monitor_t &) = delete;
|
||||
monitor_t &operator=(monitor_t &&) = delete;
|
||||
|
||||
void listen(zxdg_output_manager_v1 *output_manager);
|
||||
monitor_t(wl_output *output);
|
||||
|
||||
void xdg_name(zxdg_output_v1 *, const char *name);
|
||||
void xdg_description(zxdg_output_v1 *, const char *description);
|
||||
void xdg_position(zxdg_output_v1 *, std::int32_t x, std::int32_t y);
|
||||
void xdg_size(zxdg_output_v1 *, std::int32_t width, std::int32_t height);
|
||||
|
||||
void xdg_done(zxdg_output_v1 *) {}
|
||||
void xdg_done(zxdg_output_v1 *) {
|
||||
}
|
||||
|
||||
void wl_geometry(wl_output *wl_output, std::int32_t x, std::int32_t y, std::int32_t physical_width, std::int32_t physical_height, std::int32_t subpixel, const char *make, const char *model, std::int32_t transform) {}
|
||||
void wl_geometry(wl_output *wl_output, std::int32_t x, std::int32_t y, std::int32_t physical_width, std::int32_t physical_height, std::int32_t subpixel, const char *make, const char *model, std::int32_t transform) {
|
||||
}
|
||||
|
||||
void wl_mode(wl_output *wl_output, std::uint32_t flags, std::int32_t width, std::int32_t height, std::int32_t refresh);
|
||||
|
||||
void wl_done(wl_output *wl_output) {}
|
||||
void wl_done(wl_output *wl_output) {
|
||||
}
|
||||
|
||||
void wl_scale(wl_output *wl_output, std::int32_t factor) {}
|
||||
void wl_scale(wl_output *wl_output, std::int32_t factor) {
|
||||
}
|
||||
|
||||
void listen(zxdg_output_manager_v1 *output_manager);
|
||||
|
||||
wl_output *output;
|
||||
|
||||
std::string name;
|
||||
std::string description;
|
||||
|
||||
platf::touch_port_t viewport;
|
||||
|
||||
wl_output_listener wl_listener;
|
||||
zxdg_output_v1_listener xdg_listener;
|
||||
};
|
||||
@@ -139,34 +151,35 @@ namespace wl {
|
||||
public:
|
||||
enum interface_e {
|
||||
XDG_OUTPUT, ///< xdg-output
|
||||
WLR_EXPORT_DMABUF, ///< screencopy manager
|
||||
LINUX_DMABUF, ///< linux-dmabuf protocol
|
||||
WLR_EXPORT_DMABUF, ///< Export dmabuf
|
||||
MAX_INTERFACES, ///< Maximum number of interfaces
|
||||
};
|
||||
|
||||
interface_t() noexcept;
|
||||
|
||||
interface_t(interface_t &&) = delete;
|
||||
interface_t(const interface_t &) = delete;
|
||||
|
||||
interface_t &operator=(const interface_t &) = delete;
|
||||
interface_t &operator=(interface_t &&) = delete;
|
||||
|
||||
interface_t() noexcept;
|
||||
|
||||
void listen(wl_registry *registry);
|
||||
|
||||
std::vector<std::unique_ptr<monitor_t>> monitors;
|
||||
|
||||
zwlr_export_dmabuf_manager_v1 *dmabuf_manager;
|
||||
zxdg_output_manager_v1 *output_manager;
|
||||
|
||||
bool operator[](interface_e bit) const {
|
||||
return interface[bit];
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<monitor_t>> monitors;
|
||||
zwlr_screencopy_manager_v1 *screencopy_manager {nullptr};
|
||||
zwp_linux_dmabuf_v1 *dmabuf_interface {nullptr};
|
||||
zxdg_output_manager_v1 *output_manager {nullptr};
|
||||
|
||||
private:
|
||||
void add_interface(wl_registry *registry, std::uint32_t id, const char *interface, std::uint32_t version);
|
||||
void del_interface(wl_registry *registry, uint32_t id);
|
||||
|
||||
std::bitset<MAX_INTERFACES> interface;
|
||||
|
||||
wl_registry_listener listener;
|
||||
};
|
||||
|
||||
@@ -199,6 +212,7 @@ namespace wl {
|
||||
};
|
||||
|
||||
std::vector<std::unique_ptr<monitor_t>> monitors(const char *display_name = nullptr);
|
||||
|
||||
int init();
|
||||
} // namespace wl
|
||||
#else
|
||||
@@ -209,18 +223,21 @@ struct zxdg_output_manager_v1;
|
||||
namespace wl {
|
||||
class monitor_t {
|
||||
public:
|
||||
monitor_t(wl_output *output);
|
||||
|
||||
monitor_t(monitor_t &&) = delete;
|
||||
monitor_t(const monitor_t &) = delete;
|
||||
|
||||
monitor_t &operator=(const monitor_t &) = delete;
|
||||
monitor_t &operator=(monitor_t &&) = delete;
|
||||
|
||||
monitor_t(wl_output *output);
|
||||
|
||||
void listen(zxdg_output_manager_v1 *output_manager);
|
||||
|
||||
wl_output *output;
|
||||
|
||||
std::string name;
|
||||
std::string description;
|
||||
|
||||
platf::touch_port_t viewport;
|
||||
};
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ namespace wl {
|
||||
auto to = std::chrono::steady_clock::now() + timeout;
|
||||
|
||||
// Dispatch events until we get a new frame or the timeout expires
|
||||
dmabuf.listen(interface.screencopy_manager, interface.dmabuf_interface, output, cursor);
|
||||
dmabuf.listen(interface.dmabuf_manager, output, cursor);
|
||||
do {
|
||||
auto remaining_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(to - std::chrono::steady_clock::now());
|
||||
if (remaining_time_ms.count() < 0 || !display.dispatch(remaining_time_ms)) {
|
||||
|
||||
@@ -117,26 +117,15 @@ namespace {
|
||||
|
||||
using virtual_sink_waveformats_t = std::vector<WAVEFORMATEXTENSIBLE>;
|
||||
|
||||
/**
|
||||
* @brief List of supported waveformats for an N-channel virtual audio device
|
||||
* @tparam channel_count Number of virtual audio channels
|
||||
* @returns std::vector<WAVEFORMATEXTENSIBLE>
|
||||
* @note The list of virtual formats returned are sorted in preference order and the first valid
|
||||
* format will be used. All bits-per-sample options are listed because we try to match
|
||||
* this to the default audio device. See also: set_format() below.
|
||||
*/
|
||||
template<WORD channel_count>
|
||||
virtual_sink_waveformats_t create_virtual_sink_waveformats() {
|
||||
if constexpr (channel_count == 2) {
|
||||
auto channel_mask = waveformat_mask_stereo;
|
||||
// The 32-bit formats are a lower priority for stereo because using one will disable Dolby/DTS
|
||||
// spatial audio mode if the user enabled it on the Steam speaker.
|
||||
// only choose 24 or 16-bit formats to avoid clobbering existing Dolby/DTS spatial audio settings
|
||||
return {
|
||||
create_waveformat(sample_format_e::s24in32, channel_count, channel_mask),
|
||||
create_waveformat(sample_format_e::s24, channel_count, channel_mask),
|
||||
create_waveformat(sample_format_e::s16, channel_count, channel_mask),
|
||||
create_waveformat(sample_format_e::f32, channel_count, channel_mask),
|
||||
create_waveformat(sample_format_e::s32, channel_count, channel_mask),
|
||||
};
|
||||
} else if (channel_count == 6) {
|
||||
auto channel_mask1 = waveformat_mask_surround51_with_backspeakers;
|
||||
@@ -309,10 +298,6 @@ namespace platf::audio {
|
||||
auto waveformatext_pointer = reinterpret_cast<const WAVEFORMATEXTENSIBLE *>(mixer_waveformat.get());
|
||||
capture_waveformat.dwChannelMask = waveformatext_pointer->dwChannelMask;
|
||||
}
|
||||
|
||||
BOOST_LOG(info) << "Audio mixer format is "sv << mixer_waveformat->wBitsPerSample << "-bit, "sv
|
||||
<< mixer_waveformat->nSamplesPerSec << " Hz, "sv
|
||||
<< ((mixer_waveformat->nSamplesPerSec != 48000) ? "will be resampled to 48000 by Windows"sv : "no resampling needed"sv);
|
||||
}
|
||||
|
||||
status = audio_client->Initialize(
|
||||
@@ -330,7 +315,7 @@ namespace platf::audio {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BOOST_LOG(info) << "Audio capture format is "sv << logging::bracket(waveformat_to_pretty_string(capture_waveformat));
|
||||
BOOST_LOG(info) << "Audio capture format is " << logging::bracket(waveformat_to_pretty_string(capture_waveformat));
|
||||
|
||||
return audio_client;
|
||||
}
|
||||
@@ -808,22 +793,6 @@ namespace platf::audio {
|
||||
}
|
||||
}
|
||||
|
||||
// When switching to a Steam virtual speaker device, try to retain the bit depth of the
|
||||
// default audio device. Switching from a 16-bit device to a 24-bit one has been known to
|
||||
// cause glitches for some users.
|
||||
int wanted_bits_per_sample = 32;
|
||||
auto current_default_dev = default_device(device_enum);
|
||||
if (current_default_dev) {
|
||||
audio::prop_t prop;
|
||||
prop_var_t current_device_format;
|
||||
|
||||
if (SUCCEEDED(current_default_dev->OpenPropertyStore(STGM_READ, &prop)) && SUCCEEDED(prop->GetValue(PKEY_AudioEngine_DeviceFormat, ¤t_device_format.prop))) {
|
||||
auto *format = (WAVEFORMATEXTENSIBLE *) current_device_format.prop.blob.pBlobData;
|
||||
wanted_bits_per_sample = format->Samples.wValidBitsPerSample;
|
||||
BOOST_LOG(info) << "Virtual audio device will use "sv << wanted_bits_per_sample << "-bit to match default device"sv;
|
||||
}
|
||||
}
|
||||
|
||||
auto &device_id = virtual_sink_info->first;
|
||||
auto &waveformats = virtual_sink_info->second.get().virtual_sink_waveformats;
|
||||
for (const auto &waveformat : waveformats) {
|
||||
@@ -833,10 +802,6 @@ namespace platf::audio {
|
||||
auto waveformat_copy = waveformat;
|
||||
auto waveformat_copy_pointer = reinterpret_cast<WAVEFORMATEX *>(&waveformat_copy);
|
||||
|
||||
if (wanted_bits_per_sample != waveformat.Samples.wValidBitsPerSample) {
|
||||
continue;
|
||||
}
|
||||
|
||||
WAVEFORMATEXTENSIBLE p {};
|
||||
if (SUCCEEDED(policy->SetDeviceFormat(device_id_copy.c_str(), waveformat_copy_pointer, (WAVEFORMATEX *) &p))) {
|
||||
BOOST_LOG(info) << "Changed virtual audio sink format to " << logging::bracket(waveformat_to_pretty_string(waveformat));
|
||||
|
||||
@@ -219,7 +219,7 @@ namespace platf::dxgi {
|
||||
{
|
||||
util::buffer_t<std::uint8_t> cursor_img = img_data;
|
||||
std::for_each((std::uint32_t *) std::begin(cursor_img), (std::uint32_t *) std::end(cursor_img), [](auto &pixel) {
|
||||
auto alpha = (std::uint8_t) ((pixel >> 24) & 0xFF);
|
||||
auto alpha = (std::uint8_t)((pixel >> 24) & 0xFF);
|
||||
if (alpha == 0xFF) {
|
||||
// Pixels with 0xFF alpha will be XOR-blended as is.
|
||||
} else if (alpha == 0x00) {
|
||||
@@ -286,7 +286,7 @@ namespace platf::dxgi {
|
||||
{
|
||||
util::buffer_t<std::uint8_t> cursor_img = img_data;
|
||||
std::for_each((std::uint32_t *) std::begin(cursor_img), (std::uint32_t *) std::end(cursor_img), [](auto &pixel) {
|
||||
auto alpha = (std::uint8_t) ((pixel >> 24) & 0xFF);
|
||||
auto alpha = (std::uint8_t)((pixel >> 24) & 0xFF);
|
||||
if (alpha == 0xFF) {
|
||||
// Pixels with 0xFF alpha will be XOR-blended by make_cursor_xor_image().
|
||||
// We make them transparent for the alpha-blended cursor image.
|
||||
|
||||
@@ -92,10 +92,10 @@ namespace platf {
|
||||
|
||||
constexpr float EARTH_G = 9.80665f;
|
||||
|
||||
#define MPS2_TO_DS4_ACCEL(x) (int32_t) (((x) / EARTH_G) * 8192)
|
||||
#define DPS_TO_DS4_GYRO(x) (int32_t) ((x) * (1024 / 64))
|
||||
#define MPS2_TO_DS4_ACCEL(x) (int32_t)(((x) / EARTH_G) * 8192)
|
||||
#define DPS_TO_DS4_GYRO(x) (int32_t)((x) * (1024 / 64))
|
||||
|
||||
#define APPLY_CALIBRATION(val, bias, scale) (int32_t) (((float) (val) + (bias)) / (scale))
|
||||
#define APPLY_CALIBRATION(val, bias, scale) (int32_t)(((float) (val) + (bias)) / (scale))
|
||||
|
||||
constexpr DS4_TOUCH ds4_touch_unused = {
|
||||
.bPacketCounter = 0,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file src/platform/windows/windows.rc.in
|
||||
* @file src/platform/windows/windows.rs.in
|
||||
* @brief Windows resource file template.
|
||||
* @note The final `windows.rc` is generated from this file during the CMake build.
|
||||
* @note The final `windows.rs` is generated from this file during the CMake build.
|
||||
* @todo Use CMake definitions directly, instead of configuring this file.
|
||||
*/
|
||||
#include "winver.h"
|
||||
@@ -112,7 +112,7 @@ namespace rtsp_stream {
|
||||
boost::asio::async_read(sock, boost::asio::buffer(begin, sizeof(encrypted_rtsp_header_t)), boost::bind(&socket_t::handle_read_encrypted_header, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
|
||||
} else {
|
||||
sock.async_read_some(
|
||||
boost::asio::buffer(begin, (std::size_t) (std::end(msg_buf) - begin)),
|
||||
boost::asio::buffer(begin, (std::size_t)(std::end(msg_buf) - begin)),
|
||||
boost::bind(
|
||||
&socket_t::handle_read_plaintext,
|
||||
shared_from_this(),
|
||||
@@ -253,7 +253,7 @@ namespace rtsp_stream {
|
||||
}
|
||||
|
||||
sock.async_read_some(
|
||||
boost::asio::buffer(begin, (std::size_t) (std::end(msg_buf) - begin)),
|
||||
boost::asio::buffer(begin, (std::size_t)(std::end(msg_buf) - begin)),
|
||||
boost::bind(
|
||||
&socket_t::handle_plaintext_payload,
|
||||
shared_from_this(),
|
||||
@@ -289,7 +289,7 @@ namespace rtsp_stream {
|
||||
|
||||
auto end = socket->begin + bytes;
|
||||
msg_t req {new msg_t::element_type {}};
|
||||
if (auto status = parseRtspMessage(req.get(), socket->msg_buf.data(), (std::size_t) (end - socket->msg_buf.data()))) {
|
||||
if (auto status = parseRtspMessage(req.get(), socket->msg_buf.data(), (std::size_t)(end - socket->msg_buf.data()))) {
|
||||
BOOST_LOG(error) << "Malformed RTSP message: ["sv << status << ']';
|
||||
|
||||
respond(socket->sock, *socket->session, nullptr, 400, "BAD REQUEST", 0, {});
|
||||
@@ -321,7 +321,7 @@ namespace rtsp_stream {
|
||||
|
||||
if (end - socket->crlf >= content_length) {
|
||||
if (end - socket->crlf > content_length) {
|
||||
BOOST_LOG(warning) << "(end - socket->crlf) > content_length -- "sv << (std::size_t) (end - socket->crlf) << " > "sv << content_length;
|
||||
BOOST_LOG(warning) << "(end - socket->crlf) > content_length -- "sv << (std::size_t)(end - socket->crlf) << " > "sv << content_length;
|
||||
}
|
||||
|
||||
fg.disable();
|
||||
|
||||
@@ -48,7 +48,6 @@ extern "C" {
|
||||
#define IDX_RUMBLE_TRIGGER_DATA 12
|
||||
#define IDX_SET_MOTION_EVENT 13
|
||||
#define IDX_SET_RGB_LED 14
|
||||
#define IDX_SET_ADAPTIVE_TRIGGERS 15
|
||||
|
||||
static const short packetTypes[] = {
|
||||
0x0305, // Start A
|
||||
@@ -66,7 +65,6 @@ static const short packetTypes[] = {
|
||||
0x5500, // Rumble triggers (Sunshine protocol extension)
|
||||
0x5501, // Set motion event (Sunshine protocol extension)
|
||||
0x5502, // Set RGB LED (Sunshine protocol extension)
|
||||
0x5503, // Set Adaptive triggers (Sunshine protocol extension)
|
||||
};
|
||||
|
||||
namespace asio = boost::asio;
|
||||
@@ -188,21 +186,6 @@ namespace stream {
|
||||
std::uint8_t b;
|
||||
};
|
||||
|
||||
struct control_adaptive_triggers_t {
|
||||
control_header_v2 header;
|
||||
|
||||
std::uint16_t id;
|
||||
/**
|
||||
* 0x04 - Right trigger
|
||||
* 0x08 - Left trigger
|
||||
*/
|
||||
std::uint8_t event_flags;
|
||||
std::uint8_t type_left;
|
||||
std::uint8_t type_right;
|
||||
std::uint8_t left[DS_EFFECT_PAYLOAD_SIZE];
|
||||
std::uint8_t right[DS_EFFECT_PAYLOAD_SIZE];
|
||||
};
|
||||
|
||||
struct control_hdr_mode_t {
|
||||
control_header_v2 header;
|
||||
|
||||
@@ -850,22 +833,6 @@ namespace stream {
|
||||
plaintext.b = data.b;
|
||||
|
||||
BOOST_LOG(verbose) << "RGB: "sv << msg.id << " :: "sv << util::hex(data.r).to_string_view() << util::hex(data.g).to_string_view() << util::hex(data.b).to_string_view();
|
||||
std::array<std::uint8_t, sizeof(control_encrypted_t) + crypto::cipher::round_to_pkcs7_padded(sizeof(plaintext)) + crypto::cipher::tag_size>
|
||||
encrypted_payload;
|
||||
|
||||
payload = encode_control(session, util::view(plaintext), encrypted_payload);
|
||||
} else if (msg.type == platf::gamepad_feedback_e::set_adaptive_triggers) {
|
||||
control_adaptive_triggers_t plaintext;
|
||||
plaintext.header.type = packetTypes[IDX_SET_ADAPTIVE_TRIGGERS];
|
||||
plaintext.header.payloadLength = sizeof(plaintext) - sizeof(control_header_v2);
|
||||
|
||||
plaintext.id = util::endian::little(msg.id);
|
||||
plaintext.event_flags = msg.data.adaptive_triggers.event_flags;
|
||||
plaintext.type_left = msg.data.adaptive_triggers.type_left;
|
||||
std::ranges::copy(msg.data.adaptive_triggers.left, plaintext.left);
|
||||
plaintext.type_right = msg.data.adaptive_triggers.type_right;
|
||||
std::ranges::copy(msg.data.adaptive_triggers.right, plaintext.right);
|
||||
|
||||
std::array<std::uint8_t, sizeof(control_encrypted_t) + crypto::cipher::round_to_pkcs7_padded(sizeof(plaintext)) + crypto::cipher::tag_size>
|
||||
encrypted_payload;
|
||||
|
||||
|
||||
@@ -375,7 +375,7 @@ namespace util {
|
||||
return (std::uint8_t) ch - '0';
|
||||
}
|
||||
|
||||
return (std::uint8_t) (ch | (char) 32) - 'a' + (char) 10;
|
||||
return (std::uint8_t)(ch | (char) 32) - 'a' + (char) 10;
|
||||
};
|
||||
|
||||
std::fill_n(buf + buf_size, padding, 0);
|
||||
@@ -429,7 +429,7 @@ namespace util {
|
||||
return (std::uint8_t) ch - '0';
|
||||
}
|
||||
|
||||
return (std::uint8_t) (ch | (char) 32) - 'a' + (char) 10;
|
||||
return (std::uint8_t)(ch | (char) 32) - 'a' + (char) 10;
|
||||
};
|
||||
|
||||
for (auto &el : buf) {
|
||||
@@ -483,12 +483,12 @@ namespace util {
|
||||
std::int64_t res {};
|
||||
std::int64_t mul = 1;
|
||||
while (begin != --end) {
|
||||
res += (std::int64_t) (*end - '0') * mul;
|
||||
res += (std::int64_t)(*end - '0') * mul;
|
||||
|
||||
mul *= 10;
|
||||
}
|
||||
|
||||
return *begin != '-' ? res + (std::int64_t) (*begin - '0') * mul : -res;
|
||||
return *begin != '-' ? res + (std::int64_t)(*begin - '0') * mul : -res;
|
||||
}
|
||||
|
||||
inline std::int64_t from_view(const std::string_view &number) {
|
||||
@@ -955,7 +955,7 @@ namespace util {
|
||||
|
||||
template<class It>
|
||||
std::string_view view(It begin, It end) {
|
||||
return std::string_view {(const char *) begin, (std::size_t) (end - begin)};
|
||||
return std::string_view {(const char *) begin, (std::size_t)(end - begin)};
|
||||
}
|
||||
|
||||
template<class T>
|
||||
|
||||
@@ -299,7 +299,6 @@ namespace video {
|
||||
REF_FRAMES_INVALIDATION = 1 << 8, ///< Support reference frames invalidation
|
||||
ALWAYS_REPROBE = 1 << 9, ///< This is an encoder of last resort and we want to aggressively probe for a better one
|
||||
YUV444_SUPPORT = 1 << 10, ///< Encoder may support 4:4:4 chroma sampling depending on hardware
|
||||
ASYNC_TEARDOWN = 1 << 11, ///< Encoder supports async teardown on a different thread
|
||||
};
|
||||
|
||||
class avcodec_encode_session_t: public encode_session_t {
|
||||
@@ -504,7 +503,7 @@ namespace video {
|
||||
{}, // Fallback options
|
||||
"h264_nvenc"s,
|
||||
},
|
||||
PARALLEL_ENCODING | REF_FRAMES_INVALIDATION | YUV444_SUPPORT | ASYNC_TEARDOWN // flags
|
||||
PARALLEL_ENCODING | REF_FRAMES_INVALIDATION | YUV444_SUPPORT // flags
|
||||
};
|
||||
#elif !defined(__APPLE__)
|
||||
encoder_t nvenc {
|
||||
@@ -1687,8 +1686,7 @@ namespace video {
|
||||
}
|
||||
}
|
||||
|
||||
auto bitrate = ((config::video.max_bitrate > 0) ? std::min(config.bitrate, config::video.max_bitrate) : config.bitrate) * 1000;
|
||||
BOOST_LOG(info) << "Streaming bitrate is " << bitrate;
|
||||
auto bitrate = config.bitrate * 1000;
|
||||
ctx->rc_max_rate = bitrate;
|
||||
ctx->bit_rate = bitrate;
|
||||
|
||||
@@ -1858,23 +1856,6 @@ namespace video {
|
||||
return;
|
||||
}
|
||||
|
||||
// As a workaround for NVENC hangs and to generally speed up encoder reinit,
|
||||
// we will complete the encoder teardown in a separate thread if supported.
|
||||
// This will move expensive processing off the encoder thread to allow us
|
||||
// to restart encoding as soon as possible. For cases where the NVENC driver
|
||||
// hang occurs, this thread may probably never exit, but it will allow
|
||||
// streaming to continue without requiring a full restart of Sunshine.
|
||||
auto fail_guard = util::fail_guard([&encoder, &session] {
|
||||
if (encoder.flags & ASYNC_TEARDOWN) {
|
||||
std::thread encoder_teardown_thread {[session = std::move(session)]() mutable {
|
||||
BOOST_LOG(info) << "Starting async encoder teardown";
|
||||
session.reset();
|
||||
BOOST_LOG(info) << "Async encoder teardown complete";
|
||||
}};
|
||||
encoder_teardown_thread.detach();
|
||||
}
|
||||
});
|
||||
|
||||
// set minimum frame time, avoiding violation of client-requested target framerate
|
||||
auto minimum_frame_time = std::chrono::milliseconds(1000 / std::min(config.framerate, (config::video.min_fps_factor * 10)));
|
||||
BOOST_LOG(debug) << "Minimum frame time set to "sv << minimum_frame_time.count() << "ms, based on min fps factor of "sv << config::video.min_fps_factor << "."sv;
|
||||
|
||||
@@ -441,7 +441,7 @@
|
||||
);
|
||||
if (resp) {
|
||||
fetch("./api/apps/" + id, { method: "DELETE" }).then((r) => {
|
||||
if (r.status === 200) document.location.reload();
|
||||
if (r.status == 200) document.location.reload();
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -557,7 +557,7 @@
|
||||
method: "POST",
|
||||
body: JSON.stringify(this.editForm),
|
||||
}).then((r) => {
|
||||
if (r.status === 200) document.location.reload();
|
||||
if (r.status == 200) document.location.reload();
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
<b>{{ $t('_common.success') }}</b> {{ $t('config.restart_note') }}
|
||||
</div>
|
||||
<div class="mb-3 buttons">
|
||||
<button class="btn btn-primary mr-3" @click="save">{{ $t('_common.save') }}</button>
|
||||
<button class="btn btn-primary" @click="save">{{ $t('_common.save') }}</button>
|
||||
<button class="btn btn-success" @click="apply" v-if="saved && !restarted">{{ $t('_common.apply') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -168,7 +168,7 @@
|
||||
"install_steam_audio_drivers": "enabled",
|
||||
"adapter_name": "",
|
||||
"output_name": "",
|
||||
"dd_configuration_option": "disabled",
|
||||
"dd_configuration_option": "verify_only",
|
||||
"dd_resolution_option": "auto",
|
||||
"dd_manual_resolution": "",
|
||||
"dd_refresh_rate_option": "auto",
|
||||
@@ -177,9 +177,8 @@
|
||||
"dd_config_revert_delay": 3000,
|
||||
"dd_config_revert_on_disconnect": "disabled",
|
||||
"dd_mode_remapping": {"mixed": [], "resolution_only": [], "refresh_rate_only": []},
|
||||
"dd_wa_hdr_toggle_delay": 0,
|
||||
"dd_wa_hdr_toggle": "disabled",
|
||||
"min_fps_factor": 1,
|
||||
"max_bitrate": 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -63,14 +63,6 @@ const config = ref(props.config)
|
||||
</template>
|
||||
</PlatformLayout>
|
||||
|
||||
<!-- Disable Audio -->
|
||||
<Checkbox class="mb-3"
|
||||
id="stream_audio"
|
||||
locale-prefix="config"
|
||||
v-model="config.stream_audio"
|
||||
default="true"
|
||||
></Checkbox>
|
||||
|
||||
<AdapterNameSelector
|
||||
:platform="platform"
|
||||
:config="config"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import PlatformLayout from '../../../PlatformLayout.vue'
|
||||
import Checkbox from "../../../Checkbox.vue";
|
||||
|
||||
const props = defineProps({
|
||||
platform: String,
|
||||
@@ -67,7 +68,7 @@ function addRemappingEntry() {
|
||||
{{ $t('config.dd_config_label') }}
|
||||
</label>
|
||||
<select id="dd_configuration_option" class="form-select" v-model="config.dd_configuration_option">
|
||||
<option value="disabled">{{ $t('_common.disabled_def') }}</option>
|
||||
<option value="disabled">{{ $t('_common.disabled') }}</option>
|
||||
<option value="verify_only">{{ $t('config.dd_config_verify_only') }}</option>
|
||||
<option value="ensure_active">{{ $t('config.dd_config_ensure_active') }}</option>
|
||||
<option value="ensure_primary">{{ $t('config.dd_config_ensure_primary') }}</option>
|
||||
@@ -131,18 +132,11 @@ function addRemappingEntry() {
|
||||
<option value="auto">{{ $t('config.dd_hdr_option_auto') }}</option>
|
||||
</select>
|
||||
<!-- HDR toggle -->
|
||||
<label for="dd_wa_hdr_toggle_delay" class="form-label">
|
||||
{{ $t('config.dd_wa_hdr_toggle_delay') }}
|
||||
</label>
|
||||
<input type="number" class="form-control" id="dd_wa_hdr_toggle_delay" placeholder="0" min="0" max="3000"
|
||||
v-model="config.dd_wa_hdr_toggle_delay" />
|
||||
<div class="form-text">
|
||||
{{ $t('config.dd_wa_hdr_toggle_delay_desc_1') }}
|
||||
<br>
|
||||
{{ $t('config.dd_wa_hdr_toggle_delay_desc_2') }}
|
||||
<br>
|
||||
{{ $t('config.dd_wa_hdr_toggle_delay_desc_3') }}
|
||||
</div>
|
||||
<Checkbox id="dd_wa_hdr_toggle"
|
||||
locale-prefix="config"
|
||||
v-model="config.dd_wa_hdr_toggle"
|
||||
default="false"
|
||||
></Checkbox>
|
||||
</div>
|
||||
|
||||
<!-- Config revert delay -->
|
||||
|
||||
@@ -17,13 +17,6 @@ const config = ref(props.config)
|
||||
<input type="number" min="1" max="3" class="form-control" id="min_fps_factor" placeholder="1" v-model="config.min_fps_factor" />
|
||||
<div class="form-text">{{ $t('config.min_fps_factor_desc') }}</div>
|
||||
</div>
|
||||
|
||||
<!--max_bitrate-->
|
||||
<div class="mb-3">
|
||||
<label for="max_bitrate" class="form-label">{{ $t("config.max_bitrate") }}</label>
|
||||
<input type="number" class="form-control" id="max_bitrate" placeholder="0" v-model="config.max_bitrate" />
|
||||
<div class="form-text">{{ $t("config.max_bitrate_desc") }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -94,10 +94,10 @@
|
||||
method: "POST",
|
||||
body: JSON.stringify(this.passwordData),
|
||||
}).then((r) => {
|
||||
if (r.status === 200) {
|
||||
if (r.status == 200) {
|
||||
r.json().then((rj) => {
|
||||
this.success = rj.status;
|
||||
if (this.success === true) {
|
||||
if (rj.status.toString() === "true") {
|
||||
this.success = true;
|
||||
setTimeout(() => {
|
||||
document.location.reload();
|
||||
}, 5000);
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
fetch("./api/pin", {method: "POST", body: b})
|
||||
.then((response) => response.json())
|
||||
.then((response) => {
|
||||
if (response.status === true) {
|
||||
if (response.status.toString().toLowerCase() === "true") {
|
||||
document.querySelector(
|
||||
"#status"
|
||||
).innerHTML = `<div class="alert alert-success" role="alert">${this.i18n.t('pin.pair_success')}</div>`;
|
||||
|
||||
@@ -160,7 +160,7 @@
|
||||
"dd_config_revert_delay_desc": "Additional delay in milliseconds to wait before reverting configuration when the app has been closed or the last session terminated. Main purpose is to provide a smoother transition when quickly switching between apps.",
|
||||
"dd_config_revert_on_disconnect": "Config revert on disconnect",
|
||||
"dd_config_revert_on_disconnect_desc": "Revert configuration upon disconnect of all clients instead of app close or last session termination.",
|
||||
"dd_config_verify_only": "Verify that the display is enabled",
|
||||
"dd_config_verify_only": "Verify that the display is enabled (default)",
|
||||
"dd_hdr_option": "HDR",
|
||||
"dd_hdr_option_auto": "Switch on/off the HDR mode as requested by the client (default)",
|
||||
"dd_hdr_option_disabled": "Do not change HDR settings",
|
||||
@@ -189,10 +189,8 @@
|
||||
"dd_resolution_option_manual": "Use manually entered resolution",
|
||||
"dd_resolution_option_manual_desc": "Enter the resolution to be used",
|
||||
"dd_resolution_option_ogs_desc": "\"Optimize game settings\" option must be enabled on the Moonlight client for this to work.",
|
||||
"dd_wa_hdr_toggle_delay_desc_1": "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.",
|
||||
"dd_wa_hdr_toggle_delay_desc_2": "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.",
|
||||
"dd_wa_hdr_toggle_delay_desc_3": "DO NOT use this workaround unless you actually have issues with HDR as it directly impacts stream start time!",
|
||||
"dd_wa_hdr_toggle_delay": "High-contrast workaround for HDR",
|
||||
"dd_wa_hdr_toggle_desc": "When using virtual display device as for streaming, it might display incorrect HDR color. With this option enabled, Sunshine will try to mitigate this issue.",
|
||||
"dd_wa_hdr_toggle": "Enable high-contrast workaround for HDR",
|
||||
"ds4_back_as_touchpad_click": "Map Back/Select to Touchpad Click",
|
||||
"ds4_back_as_touchpad_click_desc": "When forcing DS4 emulation, map Back/Select to Touchpad Click",
|
||||
"encoder": "Force a Specific Encoder",
|
||||
@@ -254,8 +252,6 @@
|
||||
"log_level_desc": "The minimum log level printed to standard out",
|
||||
"log_path": "Logfile Path",
|
||||
"log_path_desc": "The file where the current logs of Sunshine are stored.",
|
||||
"max_bitrate": "Maximum Bitrate",
|
||||
"max_bitrate_desc": "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.",
|
||||
"min_fps_factor": "Minimum FPS Factor",
|
||||
"min_fps_factor_desc": "Sunshine will use this factor to calculate the minimum time between frames. Increasing this value slightly may help when streaming mostly static content. Higher values will consume more bandwidth.",
|
||||
"min_threads": "Minimum CPU Thread Count",
|
||||
@@ -329,8 +325,6 @@
|
||||
"qsv_slow_hevc": "Allow Slow HEVC Encoding",
|
||||
"qsv_slow_hevc_desc": "This can enable HEVC encoding on older Intel GPUs, at the cost of higher GPU usage and worse performance.",
|
||||
"restart_note": "Sunshine is restarting to apply changes.",
|
||||
"stream_audio": "Stream Audio",
|
||||
"stream_audio_desc": "Whether to stream audio or not. Disabling this can be useful for streaming headless displays as second monitors.",
|
||||
"sunshine_name": "Sunshine Name",
|
||||
"sunshine_name_desc": "The name displayed by Moonlight. If not specified, the PC's hostname is used",
|
||||
"sw_preset": "SW Presets",
|
||||
|
||||
@@ -120,14 +120,13 @@
|
||||
</div>
|
||||
<ul id="client-list" class="list-group list-group-flush list-group-item-light" v-if="clients && clients.length > 0">
|
||||
<div v-for="client in clients" class="list-group-item d-flex">
|
||||
<div class="p-2 flex-grow-1">{{ client.name !== "" ? client.name : $t('troubleshooting.unpair_single_unknown') }}</div>
|
||||
<div class="me-2 ms-auto btn btn-danger" @click="unpairSingle(client.uuid)"><i class="fas fa-trash"></i></div>
|
||||
<div class="p-2 flex-grow-1">{{client.name != "" ? client.name : $t('troubleshooting.unpair_single_unknown')}}</div><div class="me-2 ms-auto btn btn-danger" @click="unpairSingle(client.uuid)"><i class="fas fa-trash"></i></div>
|
||||
</div>
|
||||
</ul>
|
||||
<ul v-else class="list-group list-group-flush list-group-item-light">
|
||||
<div class="list-group-item p-3 text-center"><em>{{ $t('troubleshooting.unpair_single_no_devices') }}</em></div>
|
||||
</ul>
|
||||
|
||||
|
||||
</div>
|
||||
<!-- Logs -->
|
||||
<div class="card p-2 my-4">
|
||||
@@ -177,7 +176,7 @@
|
||||
actualLogs() {
|
||||
if (!this.logFilter) return this.logs;
|
||||
let lines = this.logs.split("\n");
|
||||
lines = lines.filter(x => x.indexOf(this.logFilter) !== -1);
|
||||
lines = lines.filter(x => x.indexOf(this.logFilter) != -1);
|
||||
return lines.join("\n");
|
||||
}
|
||||
},
|
||||
@@ -211,7 +210,7 @@
|
||||
.then((r) => r.json())
|
||||
.then((r) => {
|
||||
this.closeAppPressed = false;
|
||||
this.closeAppStatus = r.status;
|
||||
this.closeAppStatus = r.status.toString() === "true";
|
||||
setTimeout(() => {
|
||||
this.closeAppStatus = null;
|
||||
}, 5000);
|
||||
@@ -223,7 +222,7 @@
|
||||
.then((r) => r.json())
|
||||
.then((r) => {
|
||||
this.unpairAllPressed = false;
|
||||
this.unpairAllStatus = r.status;
|
||||
this.unpairAllStatus = r.status.toString() === "true";
|
||||
setTimeout(() => {
|
||||
this.unpairAllStatus = null;
|
||||
}, 5000);
|
||||
@@ -241,9 +240,9 @@
|
||||
.then((response) => response.json())
|
||||
.then((response) => {
|
||||
const clientList = document.querySelector("#client-list");
|
||||
if (response.status === true && response.named_certs && response.named_certs.length) {
|
||||
if (response.status === 'true' && response.named_certs && response.named_certs.length) {
|
||||
this.clients = response.named_certs.sort((a, b) => {
|
||||
return (a.name.toLowerCase() > b.name.toLowerCase() || a.name === "" ? 1 : -1)
|
||||
return (a.name.toLowerCase() > b.name.toLowerCase() || a.name == "" ? 1 : -1)
|
||||
});
|
||||
} else {
|
||||
this.clients = [];
|
||||
@@ -271,7 +270,7 @@
|
||||
.then((r) => r.json())
|
||||
.then((r) => {
|
||||
this.ddResetPressed = false;
|
||||
this.ddResetStatus = r.status;
|
||||
this.ddResetStatus = r.status.toString() === "true";
|
||||
setTimeout(() => {
|
||||
this.ddResetStatus = null;
|
||||
}, 5000);
|
||||
|
||||
@@ -81,10 +81,10 @@
|
||||
body: JSON.stringify(this.passwordData),
|
||||
}).then((r) => {
|
||||
this.loading = false;
|
||||
if (r.status === 200) {
|
||||
if (r.status == 200) {
|
||||
r.json().then((rj) => {
|
||||
this.success = rj.status;
|
||||
if (this.success === true) {
|
||||
if (rj.status.toString() === "true") {
|
||||
this.success = true;
|
||||
setTimeout(() => {
|
||||
document.location.reload();
|
||||
}, 5000);
|
||||
|
||||
@@ -22,12 +22,6 @@
|
||||
"detached": [
|
||||
"setsid steam steam://open/bigpicture"
|
||||
],
|
||||
"prep-cmd": [
|
||||
{
|
||||
"do": "",
|
||||
"undo": "setsid steam steam://close/bigpicture"
|
||||
}
|
||||
],
|
||||
"image-path": "steam.png"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,11 +1,2 @@
|
||||
# Allows Sunshine to acces /dev/uinput
|
||||
KERNEL=="uinput", SUBSYSTEM=="misc", OPTIONS+="static_node=uinput", GROUP="input", MODE="0660", TAG+="uaccess"
|
||||
|
||||
# Allows Sunshine to access /dev/uhid
|
||||
KERNEL=="uhid", GROUP="input", MODE="0660", TAG+="uaccess"
|
||||
|
||||
# Joypads
|
||||
KERNEL=="hidraw*" ATTRS{name}=="Sunshine PS5 (virtual) pad" GROUP="input", MODE="0660", TAG+="uaccess"
|
||||
SUBSYSTEMS=="input", ATTRS{name}=="Sunshine X-Box One (virtual) pad", GROUP="input", MODE="0660", TAG+="uaccess"
|
||||
SUBSYSTEMS=="input", ATTRS{name}=="Sunshine gamepad (virtual) motion sensors", GROUP="input", MODE="0660", TAG+="uaccess"
|
||||
SUBSYSTEMS=="input", ATTRS{name}=="Sunshine Nintendo (virtual) pad", GROUP="input", MODE="0660", TAG+="uaccess"
|
||||
KERNEL=="uinput", SUBSYSTEM=="misc", OPTIONS+="static_node=uinput", TAG+="uaccess"
|
||||
KERNEL=="uhid", TAG+="uaccess"
|
||||
|
||||
@@ -12,12 +12,6 @@
|
||||
"detached": [
|
||||
"open steam://open/bigpicture"
|
||||
],
|
||||
"prep-cmd": [
|
||||
{
|
||||
"do": "",
|
||||
"undo": "open steam://close/bigpicture"
|
||||
}
|
||||
],
|
||||
"image-path": "steam.png"
|
||||
}
|
||||
]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user