Compare commits

...

11 Commits

Author SHA1 Message Date
restitux 8570d7f356 add debugging
CodeQL / Get language matrix (push) Successful in -6s
CodeQL / Analyze (${{ matrix.name }}) (push) Failing after 1m56s
2025-06-29 20:08:11 -06:00
Cody Maness 64544e7960 fix(httpcommon): sonarqube warning cleanup (#3558)
Co-authored-by: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com>
2025-01-22 09:16:14 -05:00
LizardByte-bot 2a31ee5422 chore(l10n): update translations (#3563) 2025-01-22 02:45:44 +00:00
dependabot[bot] 8263d8976f build(deps): bump packaging/linux/flatpak/deps/shared-modules from f5d368a to 26def5f (#3568)
build(deps): bump packaging/linux/flatpak/deps/shared-modules

Bumps [packaging/linux/flatpak/deps/shared-modules](https://github.com/flathub/shared-modules) from `f5d368a` to `26def5f`.
- [Commits](https://github.com/flathub/shared-modules/compare/f5d368a31d6ef046eb2955c74ec6f54f32ed5c4e...26def5f1d263653f9b9f93399ca9c6f2118964f5)

---
updated-dependencies:
- dependency-name: packaging/linux/flatpak/deps/shared-modules
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-21 20:38:20 -05:00
ReenigneArcher eb6916ef34 fix(web-ui): fix new version notification conditions (#3577) 2025-01-22 00:46:04 +00:00
dependabot[bot] 5af21bde88 build(deps): bump third-party/tray from e80058b to d45306e (#3574)
Bumps [third-party/tray](https://github.com/LizardByte/tray) from `e80058b` to `d45306e`.
- [Commits](https://github.com/LizardByte/tray/compare/e80058b9a9f3a1574775a57b6eb9159aa3299bf5...d45306e686c90a18f5792a1541783d7bc8555bc6)

---
updated-dependencies:
- dependency-name: third-party/tray
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-21 09:15:26 -05:00
dependabot[bot] 31866fde35 build(deps): bump third-party/libdisplaydevice from 63599b0 to 1975f75 (#3576)
build(deps): bump third-party/libdisplaydevice

Bumps [third-party/libdisplaydevice](https://github.com/LizardByte/libdisplaydevice) from `63599b0` to `1975f75`.
- [Release notes](https://github.com/LizardByte/libdisplaydevice/releases)
- [Commits](https://github.com/LizardByte/libdisplaydevice/compare/63599b07659a5d1dd554a24bd0c8e96b21e21112...1975f75add5812afa1ec82b1553c9d830757687a)

---
updated-dependencies:
- dependency-name: third-party/libdisplaydevice
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-21 09:14:58 -05:00
dependabot[bot] 299b12347f build(deps): bump third-party/doxyconfig from 4c94524 to 4501c7b (#3573)
Bumps [third-party/doxyconfig](https://github.com/LizardByte/doxyconfig) from `4c94524` to `4501c7b`.
- [Commits](https://github.com/LizardByte/doxyconfig/compare/4c9452482bd01cb36764dc914d4537b278ad4218...4501c7b191170cd2adcc12336821b65449186d85)

---
updated-dependencies:
- dependency-name: third-party/doxyconfig
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-21 05:06:24 +00:00
LizardByte-bot 2ac87fdc36 chore: update global workflows (#3570) 2025-01-21 02:30:06 +00:00
dependabot[bot] a88c01f3b8 build(deps): bump third-party/tray from ebbd14f to e80058b (#3567)
Bumps [third-party/tray](https://github.com/LizardByte/tray) from `ebbd14f` to `e80058b`.
- [Commits](https://github.com/LizardByte/tray/compare/ebbd14fe6af30e61ddbb710251f612d32e371d98...e80058b9a9f3a1574775a57b6eb9159aa3299bf5)

---
updated-dependencies:
- dependency-name: third-party/tray
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-20 20:19:36 -05:00
ReenigneArcher f5b923c406 fix(flatpak): fix broken desktop file, icons, and service (#3561) 2025-01-21 00:15:23 +00:00
21 changed files with 171 additions and 132 deletions
+2 -1
View File
@@ -80,13 +80,14 @@ jobs:
month_day=$(printf "%04d" "$month_day")
# create the filename
file_name="_posts/releases/${year}-${month_day:0:2}-${month_day:2:2}-v${semver}.md"
file_name="_posts/releases/${repo_lower}/${year}-${month_day:0:2}-${month_day:2:2}-v${semver}.md"
mkdir -p "$(dirname "${file_name}")"
# create jekyll blog post
echo "---" > "${file_name}"
echo "layout: release" >> "${file_name}"
echo "title: ${{ github.event.repository.name }} ${tag_name} Released" >> "${file_name}"
echo "release-tag: ${tag_name}" >> "${file_name}"
echo "gh-repo: ${{ github.repository }}" >> "${file_name}"
echo "gh-badge: [follow, fork, star]" >> "${file_name}"
echo "tags: [release, ${repo_lower}]" >> "${file_name}"
+8 -1
View File
@@ -81,9 +81,16 @@ jobs:
--arg description "${{ github.event.repository.description }}" \
'{default_branch: $default_branch}')
# change the default branch to the latest release
curl \
-X PATCH \
-H "Authorization: Token ${RTD_TOKEN}" \
https://readthedocs.org/api/v3/projects/${RTD_SLUG}/ \
-H "Content-Type: application/json" \
https://readthedocs.org/api/v3/projects/${RTD_SLUG}/ \
-d "$json_body"
# trigger a build for the latest version
curl \
-X POST \
-H "Authorization: Token ${RTD_TOKEN}" \
https://readthedocs.org/api/v3/projects/${RTD_SLUG}/versions/latest/builds/
+8
View File
@@ -198,6 +198,14 @@ if(${SUNSHINE_ENABLE_TRAY})
list(APPEND PLATFORM_TARGET_FILES "${CMAKE_SOURCE_DIR}/third-party/tray/src/tray_linux.c")
list(APPEND SUNSHINE_EXTERNAL_LIBRARIES ${APPINDICATOR_LIBRARIES} ${LIBNOTIFY_LIBRARIES})
endif()
# flatpak icons must be prefixed with the app id or they will not be included in the flatpak
if(${SUNSHINE_BUILD_FLATPAK})
set(SUNSHINE_TRAY_PREFIX "${PROJECT_FQDN}")
else()
set(SUNSHINE_TRAY_PREFIX "sunshine")
endif()
list(APPEND SUNSHINE_DEFINITIONS SUNSHINE_TRAY_PREFIX="${SUNSHINE_TRAY_PREFIX}")
else()
set(SUNSHINE_TRAY 0)
message(STATUS "Tray icon disabled")
+17 -8
View File
@@ -100,6 +100,7 @@ endif()
# tray icon
if(${SUNSHINE_TRAY} STREQUAL 1)
if(NOT ${SUNSHINE_BUILD_FLATPAK})
install(FILES "${CMAKE_SOURCE_DIR}/sunshine.svg"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/status"
RENAME "sunshine-tray.svg")
@@ -109,6 +110,21 @@ if(${SUNSHINE_TRAY} STREQUAL 1)
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/status")
install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/web/public/images/sunshine-locked.svg"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/status")
else()
# flatpak icons must be prefixed with the app id or they will not be included in the flatpak
install(FILES "${CMAKE_SOURCE_DIR}/sunshine.svg"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/status"
RENAME "${PROJECT_FQDN}-tray.svg")
install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/web/public/images/sunshine-playing.svg"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/status"
RENAME "${PROJECT_FQDN}-playing.svg")
install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/web/public/images/sunshine-pausing.svg"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/status"
RENAME "${PROJECT_FQDN}-pausing.svg")
install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/web/public/images/sunshine-locked.svg"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/status"
RENAME "${PROJECT_FQDN}-locked.svg")
endif()
set(CPACK_DEBIAN_PACKAGE_DEPENDS "\
${CPACK_DEBIAN_PACKAGE_DEPENDS}, \
@@ -128,15 +144,8 @@ else()
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sunshine.desktop"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications"
RENAME "${PROJECT_FQDN}.desktop")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sunshine_kms.desktop"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications"
RENAME "${PROJECT_FQDN}_kms.desktop")
endif()
if(${SUNSHINE_BUILD_FLATPAK})
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sunshine_terminal.desktop"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications"
RENAME "${PROJECT_FQDN}_terminal.desktop")
elseif(NOT ${SUNSHINE_BUILD_APPIMAGE})
if(NOT ${SUNSHINE_BUILD_APPIMAGE} AND NOT ${SUNSHINE_BUILD_FLATPAK})
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sunshine_terminal.desktop"
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/applications")
endif()
+2 -2
View File
@@ -8,10 +8,10 @@ elseif (UNIX)
endif()
if(SUNSHINE_BUILD_FLATPAK)
set(SUNSHINE_SERVICE_START_COMMAND "ExecStart=${PROJECT_FQDN}")
set(SUNSHINE_SERVICE_START_COMMAND "ExecStart=flatpak run --command=sunshine ${PROJECT_FQDN}")
set(SUNSHINE_SERVICE_STOP_COMMAND "ExecStop=flatpak kill ${PROJECT_FQDN}")
else()
set(SUNSHINE_SERVICE_START_COMMAND "ExecStart=${SUNSHINE_EXECUTABLE_PATH}")
set(SUNSHINE_SERVICE_STOP_COMMAND "")
endif()
endif ()
endif()
@@ -10,14 +10,12 @@ if(APPLE)
endif()
elseif(UNIX)
# configure the .desktop file
set(SUNSHINE_DESKTOP_ICON "sunshine.svg")
set(SUNSHINE_DESKTOP_ICON "sunshine")
if(${SUNSHINE_BUILD_APPIMAGE})
configure_file(packaging/linux/AppImage/sunshine.desktop sunshine.desktop @ONLY)
elseif(${SUNSHINE_BUILD_FLATPAK})
set(SUNSHINE_DESKTOP_ICON "${PROJECT_FQDN}.svg")
set(SUNSHINE_DESKTOP_ICON "${PROJECT_FQDN}")
configure_file(packaging/linux/flatpak/sunshine.desktop sunshine.desktop @ONLY)
configure_file(packaging/linux/flatpak/sunshine_kms.desktop sunshine_kms.desktop @ONLY)
configure_file(packaging/linux/sunshine_terminal.desktop sunshine_terminal.desktop @ONLY)
configure_file(packaging/linux/flatpak/${PROJECT_FQDN}.metainfo.xml
${PROJECT_FQDN}.metainfo.xml @ONLY)
else()
@@ -0,0 +1,11 @@
#!/bin/sh
PORT=47990
if ! curl -k https://localhost:$PORT > /dev/null 2>&1; then
(sleep 3 && xdg-open https://localhost:$PORT) &
exec sunshine "$@"
else
echo "Sunshine is already running, opening the web interface..."
xdg-open https://localhost:$PORT
fi
+5 -16
View File
@@ -1,20 +1,9 @@
[Desktop Entry]
Type=Application
Name=@PROJECT_NAME@
Exec=@PROJECT_FQDN@
Version=1.0
Categories=AudioVideo;Network;RemoteAccess;
Comment=@PROJECT_DESCRIPTION@
Exec=sunshine.sh
Icon=@SUNSHINE_DESKTOP_ICON@
Keywords=gamestream;stream;moonlight;remote play;
Categories=AudioVideo;Network;RemoteAccess;
Actions=RunInTerminal;KMS;
[Desktop Action RunInTerminal]
Name=Run in Terminal
Icon=application-x-executable
Exec=gio launch @CMAKE_INSTALL_FULL_DATAROOTDIR@/applications/@PROJECT_FQDN@_terminal.desktop
[Desktop Action KMS]
Name=Run in Terminal (KMS)
Icon=application-x-executable
Exec=gio launch @CMAKE_INSTALL_FULL_DATAROOTDIR@/applications/@PROJECT_FQDN@_kms.desktop
Name=@PROJECT_NAME@
Type=Application
Version=1.0
@@ -1,6 +0,0 @@
[Desktop Entry]
Name=@PROJECT_NAME@ (KMS)
Exec=sudo -i PULSE_SERVER=unix:$(pactl info | awk '/Server String/{print$3}') flatpak run @PROJECT_FQDN@
Terminal=true
Type=Application
NoDisplay=true
+13 -22
View File
@@ -54,17 +54,14 @@ namespace http {
config::nvhttp.pkey = (dir / ("pkey-"s + unique_id)).string();
}
if (!fs::exists(config::nvhttp.pkey) || !fs::exists(config::nvhttp.cert)) {
if (create_creds(config::nvhttp.pkey, config::nvhttp.cert)) {
if ((!fs::exists(config::nvhttp.pkey) || !fs::exists(config::nvhttp.cert)) &&
create_creds(config::nvhttp.pkey, config::nvhttp.cert)) {
return -1;
}
}
if (user_creds_exist(config::sunshine.credentials_file)) {
if (reload_user_creds(config::sunshine.credentials_file)) {
return -1;
}
} else {
if (!user_creds_exist(config::sunshine.credentials_file)) {
BOOST_LOG(info) << "Open the Web UI to set your new username and password and getting started";
} else if (reload_user_creds(config::sunshine.credentials_file)) {
return -1;
}
return 0;
}
@@ -179,19 +176,15 @@ namespace http {
return 0;
}
bool download_file(const std::string &url, const std::string &file) {
CURL *curl = curl_easy_init();
if (curl) {
// sonar complains about weak ssl and tls versions
// ideally, the setopts should go after the early returns; however sonar cannot detect the fix
curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
} else {
bool download_file(const std::string &url, const std::string &file, long ssl_version) {
// sonar complains about weak ssl and tls versions; however sonar cannot detect the fix
CURL *curl = curl_easy_init(); // NOSONAR
if (!curl) {
BOOST_LOG(error) << "Couldn't create CURL instance";
return false;
}
std::string file_dir = file_handler::get_parent_directory(file);
if (!file_handler::make_directory(file_dir)) {
if (std::string file_dir = file_handler::get_parent_directory(file); !file_handler::make_directory(file_dir)) {
BOOST_LOG(error) << "Couldn't create directory ["sv << file_dir << ']';
curl_easy_cleanup(curl);
return false;
@@ -204,6 +197,7 @@ namespace http {
return false;
}
curl_easy_setopt(curl, CURLOPT_SSLVERSION, ssl_version); // NOSONAR
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
@@ -219,17 +213,15 @@ namespace http {
}
std::string url_escape(const std::string &url) {
CURL *curl = curl_easy_init();
char *string = curl_easy_escape(curl, url.c_str(), url.length());
char *string = curl_easy_escape(nullptr, url.c_str(), static_cast<int>(url.length()));
std::string result(string);
curl_free(string);
curl_easy_cleanup(curl);
return result;
}
std::string url_get_host(const std::string &url) {
CURLU *curlu = curl_url();
curl_url_set(curlu, CURLUPART_URL, url.c_str(), url.length());
curl_url_set(curlu, CURLUPART_URL, url.c_str(), static_cast<unsigned int>(url.length()));
char *host;
if (curl_url_get(curlu, CURLUPART_HOST, &host, 0) != CURLUE_OK) {
curl_url_cleanup(curlu);
@@ -240,5 +232,4 @@ namespace http {
curl_url_cleanup(curlu);
return result;
}
} // namespace http
+4 -1
View File
@@ -4,6 +4,9 @@
*/
#pragma once
// lib includes
#include <curl/curl.h>
// local includes
#include "network.h"
#include "thread_safe.h"
@@ -20,7 +23,7 @@ namespace http {
);
int reload_user_creds(const std::string &file);
bool download_file(const std::string &url, const std::string &file);
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);
+23
View File
@@ -361,8 +361,19 @@ namespace nvhttp {
auto salt = util::from_hex<std::array<uint8_t, 16>>(salt_view, true);
auto key = crypto::gen_aes_key(salt, pin);
std::ostringstream cipher_key_hex;
for (auto b = key.begin(); b != key.end(); ++b) {
cipher_key_hex << std::hex // Output in hexadecimal
<< std::setw(2) // Each byte prints as two characters
<< std::setfill('0') // Fill with '0' if less than two characters
<< static_cast<unsigned int>(*b); // Cast to unsigned int for correct printing
}
BOOST_LOG(debug) << "cipher_key_hex: " << cipher_key_hex.str();
sess.cipher_key = std::make_unique<crypto::aes_t>(key);
tree.put("root.paired", 1);
tree.put("root.plaincert", util::hex_vec(conf_intern.servercert, true));
tree.put("root.<xmlattr>.status_code", 200);
@@ -471,11 +482,23 @@ namespace nvhttp {
data.insert(std::end(data), std::begin(x509_sign), std::end(x509_sign));
data.insert(std::end(data), std::begin(secret), std::end(secret));
std::ostringstream data_hex;
for (auto d = data.begin(); d != data.end(); ++d) {
data_hex << std::hex // Output in hexadecimal
<< std::setw(2) // Each byte prints as two characters
<< std::setfill('0') // Fill with '0' if less than two characters
<< static_cast<unsigned int>(*d); // Cast to unsigned int for correct printing
}
BOOST_LOG(debug) << "data_hex: " << data_hex.str();
auto hash = crypto::hash(data);
// if hash not correct, probably MITM
bool same_hash = hash.size() == sess.clienthash.size() && std::equal(hash.begin(), hash.end(), sess.clienthash.begin());
auto verify = crypto::verify256(crypto::x509(client.cert), secret, sign);
BOOST_LOG(debug) << "same_hash: " << same_hash;
BOOST_LOG(debug) << "verify: " << verify;
if (same_hash && verify) {
tree.put("root.paired", 1);
add_cert->raise(crypto::x509(client.cert));
+4 -4
View File
@@ -14,10 +14,10 @@
#define TRAY_ICON_PAUSING WEB_DIR "images/sunshine-pausing.ico"
#define TRAY_ICON_LOCKED WEB_DIR "images/sunshine-locked.ico"
#elif defined(__linux__) || defined(linux) || defined(__linux)
#define TRAY_ICON "sunshine-tray"
#define TRAY_ICON_PLAYING "sunshine-playing"
#define TRAY_ICON_PAUSING "sunshine-pausing"
#define TRAY_ICON_LOCKED "sunshine-locked"
#define TRAY_ICON SUNSHINE_TRAY_PREFIX "-tray"
#define TRAY_ICON_PLAYING SUNSHINE_TRAY_PREFIX "-playing"
#define TRAY_ICON_PAUSING SUNSHINE_TRAY_PREFIX "-pausing"
#define TRAY_ICON_LOCKED SUNSHINE_TRAY_PREFIX "-locked"
#elif defined(__APPLE__) || defined(__MACH__)
#define TRAY_ICON WEB_DIR "images/logo-sunshine-16.png"
#define TRAY_ICON_PLAYING WEB_DIR "images/sunshine-playing-16.png"
@@ -10,7 +10,7 @@
"disabled_def_cbox": "기본값: 선택 안 함",
"dismiss": "해제",
"do_cmd": "명령 수행",
"elevated": "상승",
"elevated": "관리자 권한으로 실행",
"enabled": "활성화됨",
"enabled_def": "활성화됨 (기본값)",
"enabled_def_cbox": "기본값: 확인됨",
@@ -208,11 +208,11 @@
"gamepad_desc": "호스트에서 에뮬레이트할 게임패드 유형을 선택합니다.",
"gamepad_ds4": "DS4 (PS4)",
"gamepad_ds4_manual": "DS4 선택 옵션",
"gamepad_ds5": "DS5(PS5)",
"gamepad_switch": "닌텐도 프로(스위치)",
"gamepad_ds5": "DS5 (PS5)",
"gamepad_switch": "닌텐도 프로 (스위치 컨트롤러)",
"gamepad_manual": "DS4 수동 옵션",
"gamepad_x360": "X360(Xbox 360)",
"gamepad_xone": "XOne(Xbox One)",
"gamepad_x360": "X360 (Xbox 360)",
"gamepad_xone": "XOne (Xbox One)",
"global_prep_cmd": "명령 준비",
"global_prep_cmd_desc": "애플리케이션 실행 전 또는 실행 후에 실행할 명령 목록을 구성합니다. 지정된 준비 명령 중 하나라도 실패하면 애플리케이션 실행 프로세스가 중단됩니다.",
"hevc_mode": "HEVC 지원",
@@ -224,18 +224,18 @@
"high_resolution_scrolling": "고해상도 스크롤 지원",
"high_resolution_scrolling_desc": "이 옵션을 활성화하면 Sunshine은 Moonlight 클라이언트의 고해상도 스크롤 이벤트를 통과합니다. 고해상도 스크롤 이벤트로 너무 빠르게 스크롤하는 구형 애플리케이션의 경우 이 옵션을 비활성화하면 유용할 수 있습니다.",
"install_steam_audio_drivers": "Steam 오디오 드라이버 설치",
"install_steam_audio_drivers_desc": "Steam이 설치되어 있으면 5.1/7.1 서라운드 사운드와 호스트 오디오 음소거를 지원하는 Steam 스트리밍 스피커 드라이버가 자동으로 설치됩니다.",
"install_steam_audio_drivers_desc": "Steam이 설치되어 있으면 5.1/7.1 서라운드 사운드와 호스트 오디오 음소거를 지원하는 Steam Streaming Speakers 드라이버가 자동으로 설치됩니다.",
"key_repeat_delay": "키 반복 지연",
"key_repeat_delay_desc": "키가 반복되는 속도를 제어합니다. 키가 반복되기 전 초기 지연 시간(밀리초)입니다.",
"key_repeat_delay_desc": "키가 반복되는 속도를 제어합니다. 키가 반복되기 전 초기 지연 시간 (ms) 입니다.",
"key_repeat_frequency": "키 반복 빈도",
"key_repeat_frequency_desc": "매 초마다 키가 반복되는 빈도. 이 구성 가능한 옵션은 소수를 지원합니다.",
"key_repeat_frequency_desc": "매 초마다 키가 반복되는 빈도입니다. (이 옵션은 소수점 입력이 가능합니다.)",
"key_rightalt_to_key_win": "오른쪽 Alt 키를 Windows 키로 매핑",
"key_rightalt_to_key_win_desc": "달빛에서 Windows 키를 직접 보낼 수 없는 경우가 있을 수 있습니다. 이러한 경우 Sunshine이 오른쪽 Alt 키를 Windows 키로 인식하도록 하는 것이 유용할 수 있습니다.",
"keyboard": "키보드 입력 활성화",
"keyboard_desc": "게스트가 키보드로 호스트 시스템을 제어할 수 있습니다.",
"lan_encryption_mode": "LAN 암호화 모드",
"lan_encryption_mode_1": "지원되는 클라이언트에서 사용 가능",
"lan_encryption_mode_2": "모든 고객에게 필수",
"lan_encryption_mode_2": "모든 사용자에게 필수",
"lan_encryption_mode_desc": "로컬 네트워크를 통해 스트리밍할 때 암호화를 사용할 시기를 결정합니다. 암호화는 특히 성능이 낮은 호스트와 클라이언트에서 스트리밍 성능을 저하시킬 수 있습니다.",
"locale": "로캘",
"locale_desc": "Sunshine의 사용자 인터페이스에 사용되는 로캘입니다.",
@@ -255,8 +255,8 @@
"min_threads": "최소 CPU 스레드 수",
"min_threads_desc": "이 값을 높이면 인코딩 효율이 약간 떨어지지만, 일반적으로 인코딩에 더 많은 CPU 코어를 사용할 수 있다는 점에서 그만한 가치가 있습니다. 이상적인 값은 하드웨어에서 원하는 스트리밍 설정으로 안정적으로 인코딩할 수 있는 가장 낮은 값입니다.",
"misc": "기타 옵션",
"motion_as_ds4": "클라이언트 게임패드가 모션 센서가 있다고 보고하는 경우 DS4 게임패드 에뮬레이",
"motion_as_ds4_desc": "비활성화하면 게임패드 유형을 선택할 때 모션 센서가 고려되지 않습니다.",
"motion_as_ds4": "클라이언트 게임패드가 모션 기능을 보유중인 경우 DS4 게임패드 에뮬레이",
"motion_as_ds4_desc": "비활성화시, 게임패드 선택할 때 모션 센서 유무를 확인하지 않습니다.",
"mouse": "마우스 입력 활성화",
"mouse_desc": "게스트가 마우스로 호스트 시스템을 제어할 수 있습니다.",
"native_pen_touch": "기본 펜/터치 지원",
@@ -300,10 +300,10 @@
"pkey": "개인 키",
"pkey_desc": "웹 UI와 Moonlight 클라이언트 페어링에 사용되는 개인 키입니다. 최상의 호환성을 위해 RSA-2048 개인키를 사용해야 합니다.",
"port": "포트",
"port_alert_1": "선샤인은 1024 이하의 포트를 사용할 수 없습니다!",
"port_alert_2": "65535 이상의 포트는 사용할 수 없습니다!",
"port_alert_1": "Sunshine은 1024 이하의 포트를 사용할 수 없습니다, 다시 확인하세요.",
"port_alert_2": "65535 이상의 포트는 사용할 수 없습니다, 다시 확인하세요.",
"port_desc": "Sunshine에서 사용하는 포트 제품군 설정",
"port_http_port_note": "이 포트를 사용하여 문라이트에 연결하세요.",
"port_http_port_note": "이 포트를 사용하여 Moonlight에 연결하세요.",
"port_note": "참고",
"port_port": "포트",
"port_protocol": "프로토콜",
@@ -315,27 +315,27 @@
"qp_desc": "일부 디바이스는 고정 비트 전송률을 지원하지 않을 수 있습니다. 이러한 디바이스에서는 대신 QP가 사용됩니다. 값이 높을수록 압축률이 높아지지만 품질은 떨어집니다.",
"qsv_coder": "퀵싱크 코더(H264)",
"qsv_preset": "퀵싱크 프리셋",
"qsv_preset_fast": "빠름(낮은 품질)",
"qsv_preset_faster": "더 빠름(품질 저하)",
"qsv_preset_medium": "중간(기본값)",
"qsv_preset_slow": "느림(좋은 품질)",
"qsv_preset_slower": "느림(더 은 품질)",
"qsv_preset_slowest": "가장 느림(최고 품질)",
"qsv_preset_veryfast": "가장 빠름(최저 품질)",
"qsv_preset_fast": "빠름 (낮은 품질)",
"qsv_preset_faster": "더 빠름 (더 낮은 품질)",
"qsv_preset_medium": "중간 (기본값)",
"qsv_preset_slow": "느림 (좋은 품질)",
"qsv_preset_slower": "느림 (더 은 품질)",
"qsv_preset_slowest": "가장 느림 (최고 품질)",
"qsv_preset_veryfast": "가장 빠름 (최저 품질)",
"qsv_slow_hevc": "느린 HEVC 인코딩 허용",
"qsv_slow_hevc_desc": "이렇게 하면 구형 인텔 GPU에서 HEVC 인코딩이 가능하지만, GPU 사용량이 증가하고 성능이 저하될 수 있습니다.",
"restart_note": "변경 사항을 적용하기 위해 Sunshine이 다시 시작됩니다.",
"sunshine_name": "선샤인 이름",
"sunshine_name_desc": "달빛이 표시는 이름입니다. 지정하지 않으면 PC의 호스트 이름이 사용됩니다.",
"sunshine_name": "Sunshine 이름",
"sunshine_name_desc": "Moonlight에서 표시는 이름입니다. 지정하지 않으면 PC의 이름이 사용됩니다.",
"sw_preset": "SW 프리셋",
"sw_preset_desc": "인코딩 속도(초당 인코딩 프레임 수)와 압축 효율성(비트스트림의 비트당 품질) 간의 절충점을 최적화합니다. 기본값은 초고속입니다.",
"sw_preset_fast": "빠",
"sw_preset_faster": "더 빠르게",
"sw_preset_medium": "medium",
"sw_preset_slow": "slow",
"sw_preset_slower": "느린",
"sw_preset_superfast": "초고속(기본값)",
"sw_preset_ultrafast": "초고속",
"sw_preset_fast": "빠",
"sw_preset_faster": "더 빠",
"sw_preset_medium": "중간",
"sw_preset_slow": "느림",
"sw_preset_slower": "더 느림",
"sw_preset_superfast": "엄청 빠름 (기본값)",
"sw_preset_ultrafast": "엄청 빠름",
"sw_preset_veryfast": "매우 빠름",
"sw_preset_veryslow": "매우 느림",
"sw_tune": "SW Tune",
@@ -353,8 +353,8 @@
"vaapi_strict_rc_buffer": "AMD GPU에서 H.264/HEVC에 대한 프레임 비트레이트 제한을 엄격하게 적용합니다.",
"vaapi_strict_rc_buffer_desc": "이 옵션을 활성화하면 장면이 변경되는 동안 네트워크를 통해 프레임이 끊기는 것을 방지할 수 있지만 움직이는 동안 동영상 품질이 저하될 수 있습니다.",
"virtual_sink": "가상 싱크",
"virtual_sink_desc": "사용할 가상 오디오 장치를 수동으로 지정합니다. 설정하지 않으면 장치가 자동으로 선택됩니다. 자동 장치 선택을 사용하려면 이 필드를 비워 두는 것이 좋습니다!",
"virtual_sink_placeholder": "Steam 스트리밍 스피커",
"virtual_sink_desc": "사용할 가상 오디오 장치를 수동으로 지정합니다. 설정하지 않으면 자동으로 장치가 선택됩니다. 자동으로 장치 선택할려면 이 칸을 비우는 것을 권장드립니다.",
"virtual_sink_placeholder": "Steam Streaming Speakers",
"vt_coder": "비디오 툴박스 코더",
"vt_realtime": "비디오툴박스 실시간 인코딩",
"vt_software": "비디오툴박스 소프트웨어 인코딩",
@@ -362,30 +362,30 @@
"vt_software_forced": "강제",
"wan_encryption_mode": "WAN 암호화 모드",
"wan_encryption_mode_1": "지원되는 클라이언트에 사용(기본값)",
"wan_encryption_mode_2": "모든 고객에게 필수",
"wan_encryption_mode_2": "모든 사용자에게 필수",
"wan_encryption_mode_desc": "인터넷을 통해 스트리밍할 때 암호화를 사용할 시기를 결정합니다. 암호화는 특히 성능이 낮은 호스트와 클라이언트에서 스트리밍 성능을 저하시킬 수 있습니다."
},
"index": {
"description": "선샤인은 문라이트의 자체 호스팅 게임 스트림 호스트입니다.",
"description": "Sunshine은 Moonlight의 게임 스트리밍 프로그램 입니다.",
"download": "다운로드",
"installed_version_not_stable": "선샤인 시험판 버전을 실행 중입니다. 버그나 기타 문제가 발생할 수 있습니다. 문제가 발생하면 신고해 주세요. Sunshine을 더 나은 소프트웨어로 만드는 데 도움을 주셔서 감사합니다!",
"loading_latest": "최신 릴리스 로드 중...",
"installed_version_not_stable": "Sunshine의 정식 출시 이전 버전을 실행 중입니다. 버그나 기타 문제가 발생할 수 있습니다. 문제가 발생하면 신고해 주세요. Sunshine을 더 나은 소프트웨어로 만드는 데 도움을 주셔서 감사합니다!",
"loading_latest": "새로운 업데이트를 확인하는 중...",
"new_pre_release": "새로운 사전 출시 버전이 출시되었습니다!",
"new_stable": "새로운 안정 버전이 출시되었습니다!",
"startup_errors": "<b>주의!</b> 시작 중에 이러한 오류가 감지되었습니다. 스트리밍하기 전에 이 오류를 수정할 <b>것을 강력히 권장합니다</b>.",
"version_dirty": "선샤인이 더 나은 소프트웨어가 될 수 있도록 도와주셔서 감사합니다!",
"startup_errors": "<b>주의!</b> 시작하는 중에 오류가 감지되었습니다. 스트리밍하기 전에 이 오류를 수정할 것을 <b>강력히 권장합니다.</b>",
"version_dirty": "Sunshine이 더 나은 소프트웨어가 될 수 있도록 도와주셔서 감사합니다!",
"version_latest": "최신 버전의 Sunshine을 실행 중입니다.",
"welcome": "안녕하세요, 선샤인!"
"welcome": "반가워요, Sunshine!"
},
"navbar": {
"applications": "애플리케이션",
"configuration": "구성",
"configuration": "설정",
"home": "홈",
"password": "비밀번호 변경",
"pin": "핀",
"theme_auto": "자동",
"theme_dark": "Dark",
"theme_light": "",
"theme_dark": "다크 테마",
"theme_light": "라이트 테마",
"toggle_theme": "테마",
"troubleshoot": "문제 해결"
},
@@ -444,8 +444,8 @@
"confirm_password": "비밀번호 확인",
"create_creds": "시작하기 전에 웹 UI에 액세스하기 위한 새 사용자 아이디와 비밀번호를 만들어야 합니다.",
"create_creds_alert": "선샤인의 웹 UI에 액세스하려면 아래 자격 증명이 필요합니다. 다시는 볼 수 없으니 안전하게 보관하세요!",
"greeting": "선샤인에 오신 것을 환영합니다!",
"greeting": "Sunshine에 오신 것을 환영합니다!",
"login": "로그인",
"welcome_success": "이 페이지다시 로드되며 브라우저에서 새 자격 증명을 입력하라는 메시지가 표시됩니다."
"welcome_success": "이 페이지새로고침 될 것이며, 브라우저에서 다시 로그인을 해야 합니다."
}
}
@@ -172,9 +172,9 @@
"dd_mode_remapping_desc_5_sops_mixed_only": "\"优化游戏设置\"选项必须在 Moonlight 客户端启用,否则将跳过指定任何分辨率字段的条目。",
"dd_mode_remapping_desc_5_sops_resolution_only": "\"优化游戏设置\"选项必须在 Moonlight 客户端启用,否则将跳过映射。",
"dd_mode_remapping_final_refresh_rate": "最终刷新率",
"dd_mode_remapping_final_resolution": "最后决议",
"dd_mode_remapping_final_resolution": "最终分辨率",
"dd_mode_remapping_requested_fps": "请求FPS",
"dd_mode_remapping_requested_resolution": "请求的决议",
"dd_mode_remapping_requested_resolution": "请求的分辨率",
"dd_options_header": "高级显示设备选项",
"dd_refresh_rate_option": "刷新率",
"dd_refresh_rate_option_auto": "使用客户端提供的 FPS 值 (默认)",
@@ -44,8 +44,8 @@ class SunshineVersion {
return false;
}
for (let i = 0; i < Math.min(3, this.versionParts.length, otherVersionParts.length); i++) {
if (this.versionParts[i] > otherVersionParts[i]) {
return true;
if (this.versionParts[i] !== otherVersionParts[i]) {
return this.versionParts[i] > otherVersionParts[i];
}
}
return false;
+10 -5
View File
@@ -2,14 +2,19 @@
* @file tests/unit/test_httpcommon.cpp
* @brief Test src/httpcommon.*.
*/
// test imports
#include "../tests_common.h"
// lib imports
#include <curl/curl.h>
// local imports
#include <src/httpcommon.h>
struct UrlEscapeTest: testing::TestWithParam<std::tuple<std::string, std::string>> {};
TEST_P(UrlEscapeTest, Run) {
auto [input, expected] = GetParam();
const auto &[input, expected] = GetParam();
ASSERT_EQ(http::url_escape(input), expected);
}
@@ -26,7 +31,7 @@ INSTANTIATE_TEST_SUITE_P(
struct UrlGetHostTest: testing::TestWithParam<std::tuple<std::string, std::string>> {};
TEST_P(UrlGetHostTest, Run) {
auto [input, expected] = GetParam();
const auto &[input, expected] = GetParam();
ASSERT_EQ(http::url_get_host(input), expected);
}
@@ -43,10 +48,10 @@ INSTANTIATE_TEST_SUITE_P(
struct DownloadFileTest: testing::TestWithParam<std::tuple<std::string, std::string>> {};
TEST_P(DownloadFileTest, Run) {
auto [url, filename] = GetParam();
const auto &[url, filename] = GetParam();
const std::string test_dir = platf::appdata().string() + "/tests/";
std::basic_string path = test_dir + filename;
ASSERT_TRUE(http::download_file(url, path));
std::string path = test_dir + filename;
ASSERT_TRUE(http::download_file(url, path, CURL_SSLVERSION_TLSv1_0));
}
#ifdef SUNSHINE_BUILD_FLATPAK