mirror of
https://github.com/LizardByte/Sunshine.git
synced 2025-08-10 00:52:16 +00:00
Compare commits
1 Commits
fix/packag
...
feat/api/a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b863f760b |
@@ -1,10 +1,6 @@
|
||||
# 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"
|
||||
|
||||
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
|
||||
|
||||
95
.github/workflows/CI.yml
vendored
95
.github/workflows/CI.yml
vendored
@@ -45,22 +45,43 @@ jobs:
|
||||
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:
|
||||
env:
|
||||
APP_ID: dev.lizardbyte.app.Sunshine
|
||||
NODE_VERSION: "20"
|
||||
PLATFORM_VERSION: "23.08"
|
||||
name: Linux Flatpak
|
||||
needs: [setup_release]
|
||||
runs-on: ${{ matrix.runner }}
|
||||
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
|
||||
@@ -105,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"
|
||||
@@ -205,23 +227,52 @@ 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
|
||||
@@ -503,16 +554,12 @@ 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
|
||||
|
||||
2
.github/workflows/ci-docker.yml
vendored
2
.github/workflows/ci-docker.yml
vendored
@@ -123,7 +123,7 @@ jobs:
|
||||
docker:
|
||||
needs: [check_dockerfiles, setup_release]
|
||||
if: ${{ needs.check_dockerfiles.outputs.dockerfiles }}
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
packages: write
|
||||
contents: write
|
||||
|
||||
33
.github/workflows/codeql.yml
vendored
33
.github/workflows/codeql.yml
vendored
@@ -51,39 +51,32 @@ jobs:
|
||||
"include": []
|
||||
}
|
||||
|
||||
// Track languages we've already added to avoid duplicates
|
||||
const addedLanguages = new Set()
|
||||
|
||||
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}`
|
||||
if (osList.length == 1) {
|
||||
name = key.toLowerCase()
|
||||
} else {
|
||||
name = `${key.toLowerCase()}, ${os}`
|
||||
}
|
||||
|
||||
// add to matrix
|
||||
matrix['include'].push({
|
||||
"language": normalizedKey,
|
||||
"os": os,
|
||||
"name": name
|
||||
})
|
||||
matrix['include'].push({"language": key.toLowerCase(), "os": os, "name": name})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
2
.github/workflows/update-flathub-repo.yml
vendored
2
.github/workflows/update-flathub-repo.yml
vendored
@@ -104,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 }}"
|
||||
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
id: download
|
||||
if: >-
|
||||
steps.check-label.outputs.hasTopic == 'true'
|
||||
uses: robinraju/release-downloader@v1.12
|
||||
uses: robinraju/release-downloader@v1.11
|
||||
with:
|
||||
repository: "${{ github.repository }}"
|
||||
tag: "${{ github.event.release.tag_name }}"
|
||||
|
||||
2
.github/workflows/update-pacman-repo.yml
vendored
2
.github/workflows/update-pacman-repo.yml
vendored
@@ -77,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 }}"
|
||||
|
||||
2
.github/workflows/update-winget-release.yml
vendored
2
.github/workflows/update-winget-release.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
id: download
|
||||
if: >-
|
||||
steps.check-label.outputs.hasTopic == 'true'
|
||||
uses: robinraju/release-downloader@v1.12
|
||||
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.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"
|
||||
@@ -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'
|
||||
")
|
||||
|
||||
@@ -974,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>
|
||||
@@ -1156,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>
|
||||
@@ -1172,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>
|
||||
@@ -1317,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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -335,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.
|
||||
|
||||
|
||||
@@ -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"
|
||||
@@ -538,11 +538,11 @@ ext-js:
|
||||
<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">
|
||||
<i class="fa-fw fab fa-github"></i>
|
||||
Latest: <span id="latest-version" class="crowdin-ignore"></span>
|
||||
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 fas fa-flask"></i>
|
||||
Beta: <span id="beta-version" class="crowdin-ignore"></span>
|
||||
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">
|
||||
<i class="fa-fw fab fa-linux"></i>
|
||||
@@ -577,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) {
|
||||
@@ -603,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,14 +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.2"
|
||||
"vue-i18n": "11.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "4.6.2",
|
||||
"serve": "14.2.3",
|
||||
"vite": "4.5.9",
|
||||
"vite": "4.5.2",
|
||||
"vite-plugin-ejs": "1.6.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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: aac65cf44c...a1eb29c5f3
Submodule packaging/linux/flatpak/deps/shared-modules updated: a6c788b38f...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"
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -2,23 +2,12 @@
|
||||
|
||||
# User Service
|
||||
mkdir -p ~/.config/systemd/user
|
||||
cp /app/share/sunshine/systemd/user/sunshine.service "${HOME}/.config/systemd/user/sunshine.service"
|
||||
cp /app/share/sunshine/systemd/user/sunshine.service $HOME/.config/systemd/user/sunshine.service
|
||||
echo Sunshine User Service has been installed.
|
||||
echo Use [systemctl --user enable sunshine] once to autostart Sunshine on login.
|
||||
|
||||
# Udev rule
|
||||
UDEV=$(cat /app/share/sunshine/udev/rules.d/60-sunshine.rules)
|
||||
echo Configuring input permissions.
|
||||
echo Configuring mouse permission.
|
||||
flatpak-spawn --host pkexec sh -c "echo '$UDEV' > /etc/udev/rules.d/60-sunshine.rules"
|
||||
|
||||
# Reload udev rules
|
||||
path_to_udevadm=$(flatpak-spawn --host which udevadm)
|
||||
if [ -x "$path_to_udevadm" ] ; then
|
||||
echo "Reloading udev rules."
|
||||
flatpak-spawn --host "$path_to_udevadm" control --reload-rules
|
||||
flatpak-spawn --host "$path_to_udevadm" trigger --property-match=DEVNAME=/dev/uinput
|
||||
flatpak-spawn --host "$path_to_udevadm" trigger --property-match=DEVNAME=/dev/uhid
|
||||
echo "Udev rules reloadeded successfully."
|
||||
else
|
||||
echo "error: udevadm not found or not executable."
|
||||
fi
|
||||
echo Restart computer for mouse permission to take effect.
|
||||
|
||||
@@ -2,22 +2,10 @@
|
||||
|
||||
# User Service
|
||||
systemctl --user stop sunshine
|
||||
rm "${HOME}/.config/systemd/user/sunshine.service"
|
||||
rm $HOME/.config/systemd/user/sunshine.service
|
||||
systemctl --user daemon-reload
|
||||
echo Sunshine User Service has been removed.
|
||||
|
||||
# Udev rule
|
||||
echo Removing input permissions.
|
||||
flatpak-spawn --host pkexec sh -c "rm /etc/udev/rules.d/60-sunshine.rules"
|
||||
|
||||
# Reload udev rules
|
||||
path_to_udevadm=$(flatpak-spawn --host which udevadm)
|
||||
if [ -x "$path_to_udevadm" ] ; then
|
||||
echo "Reloading udev rules."
|
||||
flatpak-spawn --host "$path_to_udevadm" control --reload-rules
|
||||
flatpak-spawn --host "$path_to_udevadm" trigger --property-match=DEVNAME=/dev/uinput
|
||||
flatpak-spawn --host "$path_to_udevadm" trigger --property-match=DEVNAME=/dev/uhid
|
||||
echo "Udev rules reloadeded successfully."
|
||||
else
|
||||
echo "error: udevadm not found or not executable."
|
||||
fi
|
||||
echo Mouse permission removed. Restart computer to take effect.
|
||||
|
||||
@@ -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#*=}"
|
||||
;;
|
||||
@@ -372,7 +367,7 @@ 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 too low, skipping docs"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
Babel==2.17.0
|
||||
Babel==2.16.0
|
||||
clang-format
|
||||
|
||||
@@ -497,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
|
||||
@@ -509,8 +509,7 @@ namespace config {
|
||||
{} // wa
|
||||
}, // display_device
|
||||
|
||||
1, // min_fps_factor
|
||||
0 // max_bitrate
|
||||
1 // min_fps_factor
|
||||
};
|
||||
|
||||
audio_t audio {
|
||||
@@ -1136,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);
|
||||
|
||||
@@ -84,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 {
|
||||
@@ -138,7 +138,6 @@ 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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,11 +1,2 @@
|
||||
# Allows Sunshine to acces /dev/uinput
|
||||
KERNEL=="uinput", SUBSYSTEM=="misc", OPTIONS+="static_node=uinput", TAG+="uaccess"
|
||||
|
||||
# Allows Sunshine to access /dev/uhid
|
||||
KERNEL=="uhid", TAG+="uaccess"
|
||||
|
||||
# Joypads
|
||||
KERNEL=="hidraw*" ATTRS{name}=="Sunshine PS5 (virtual) pad" MODE="0660", TAG+="uaccess"
|
||||
SUBSYSTEMS=="input", ATTRS{name}=="Sunshine X-Box One (virtual) pad", MODE="0660", TAG+="uaccess"
|
||||
SUBSYSTEMS=="input", ATTRS{name}=="Sunshine gamepad (virtual) motion sensors", MODE="0660", TAG+="uaccess"
|
||||
SUBSYSTEMS=="input", ATTRS{name}=="Sunshine Nintendo (virtual) pad", MODE="0660", TAG+="uaccess"
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
@echo off
|
||||
setlocal EnableDelayedExpansion
|
||||
|
||||
rem Check if parameter is provided
|
||||
if "%~1"=="" (
|
||||
echo Usage: %0 [add^|remove]
|
||||
echo add - Adds Sunshine directories to system PATH
|
||||
echo remove - Removes Sunshine directories from system PATH
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
rem Get sunshine root directory
|
||||
for %%I in ("%~dp0\..") do set "ROOT_DIR=%%~fI"
|
||||
echo Sunshine root directory: !ROOT_DIR!
|
||||
|
||||
rem Define directories to add to path
|
||||
set "PATHS_TO_MANAGE[0]=!ROOT_DIR!"
|
||||
set "PATHS_TO_MANAGE[1]=!ROOT_DIR!\tools"
|
||||
|
||||
rem System path registry location
|
||||
set "KEY_NAME=HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment"
|
||||
set "VALUE_NAME=Path"
|
||||
|
||||
rem Get the current path
|
||||
for /f "tokens=2*" %%A in ('reg query "%KEY_NAME%" /v "%VALUE_NAME%"') do set "CURRENT_PATH=%%B"
|
||||
echo Current path: !CURRENT_PATH!
|
||||
|
||||
rem Check if adding to path
|
||||
if /i "%~1"=="add" (
|
||||
set "NEW_PATH=!CURRENT_PATH!"
|
||||
|
||||
rem Process each directory to add
|
||||
for /L %%i in (0,1,1) do (
|
||||
set "DIR_TO_ADD=!PATHS_TO_MANAGE[%%i]!"
|
||||
|
||||
rem Check if path already contains this directory
|
||||
echo "!CURRENT_PATH!" | findstr /i /c:"!DIR_TO_ADD!" > nul
|
||||
if !ERRORLEVEL!==0 (
|
||||
echo !DIR_TO_ADD! already in path
|
||||
) else (
|
||||
echo Adding to path: !DIR_TO_ADD!
|
||||
set "NEW_PATH=!NEW_PATH!;!DIR_TO_ADD!"
|
||||
)
|
||||
)
|
||||
|
||||
rem Only update if path was changed
|
||||
if "!NEW_PATH!" neq "!CURRENT_PATH!" (
|
||||
rem Set the new path in the registry
|
||||
reg add "%KEY_NAME%" /v "%VALUE_NAME%" /t REG_EXPAND_SZ /d "!NEW_PATH!" /f
|
||||
if !ERRORLEVEL!==0 (
|
||||
echo Successfully added Sunshine directories to PATH
|
||||
) else (
|
||||
echo Failed to add Sunshine directories to PATH
|
||||
)
|
||||
) else (
|
||||
echo No changes needed to PATH
|
||||
)
|
||||
exit /b !ERRORLEVEL!
|
||||
)
|
||||
|
||||
rem Check if removing from path
|
||||
if /i "%~1"=="remove" (
|
||||
set "CHANGES_MADE=0"
|
||||
|
||||
rem Process each directory to remove
|
||||
for /L %%i in (0,1,1) do (
|
||||
set "DIR_TO_REMOVE=!PATHS_TO_MANAGE[%%i]!"
|
||||
|
||||
rem Check if path contains this directory
|
||||
echo "!CURRENT_PATH!" | findstr /i /c:"!DIR_TO_REMOVE!" > nul
|
||||
if !ERRORLEVEL!==0 (
|
||||
echo Removing from path: !DIR_TO_REMOVE!
|
||||
|
||||
rem Build a new path by parsing and filtering the current path
|
||||
set "NEW_PATH="
|
||||
for %%p in ("!CURRENT_PATH:;=" "!") do (
|
||||
set "PART=%%~p"
|
||||
if /i "!PART!" NEQ "!DIR_TO_REMOVE!" (
|
||||
if defined NEW_PATH (
|
||||
set "NEW_PATH=!NEW_PATH!;!PART!"
|
||||
) else (
|
||||
set "NEW_PATH=!PART!"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
set "CURRENT_PATH=!NEW_PATH!"
|
||||
set "CHANGES_MADE=1"
|
||||
) else (
|
||||
echo !DIR_TO_REMOVE! not found in path
|
||||
)
|
||||
)
|
||||
|
||||
rem Only update if path was changed
|
||||
if "!CHANGES_MADE!"=="1" (
|
||||
rem Set the new path in the registry
|
||||
reg add "%KEY_NAME%" /v "%VALUE_NAME%" /t REG_EXPAND_SZ /d "!CURRENT_PATH!" /f
|
||||
if !ERRORLEVEL!==0 (
|
||||
echo Successfully removed Sunshine directories from PATH
|
||||
) else (
|
||||
echo Failed to remove Sunshine directories from PATH
|
||||
)
|
||||
) else (
|
||||
echo No changes needed to PATH
|
||||
)
|
||||
exit /b !ERRORLEVEL!
|
||||
)
|
||||
|
||||
echo Unknown parameter: %~1
|
||||
echo Usage: %0 [add^|remove]
|
||||
exit /b 1
|
||||
2
third-party/build-deps
vendored
2
third-party/build-deps
vendored
Submodule third-party/build-deps updated: b567d3c479...249a313844
2
third-party/googletest
vendored
2
third-party/googletest
vendored
Submodule third-party/googletest updated: 6910c9d916...b514bdc898
2
third-party/inputtino
vendored
2
third-party/inputtino
vendored
Submodule third-party/inputtino updated: fd136cfe49...8065aeb46e
2
third-party/libdisplaydevice
vendored
2
third-party/libdisplaydevice
vendored
Submodule third-party/libdisplaydevice updated: 591387c584...53a0ea5317
2
third-party/moonlight-common-c
vendored
2
third-party/moonlight-common-c
vendored
Submodule third-party/moonlight-common-c updated: e95feaf495...d3d3e6cf01
Reference in New Issue
Block a user