mirror of
https://github.com/Andre-Bzk/twitch4steamdeck.git
synced 2026-11-15 09:33:09 +01:00
style: translate all remaining German code comments to English
German comments had survived the earlier translation pass. Mixing languages in comments creates inconsistency and makes the codebase harder to read for non-German contributors.
This commit is contained in:
@@ -49,8 +49,8 @@ export class AuthService extends EventEmitter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Startet den Device Code Flow. Liefert die Anzeigedaten sofort zurück
|
||||
* und pollt im Hintergrund. Statuswechsel werden als 'auth-event' emittiert.
|
||||
* Starts the Device Code Flow. Returns display data immediately
|
||||
* and polls in the background. Status changes are emitted as 'auth-event'.
|
||||
*/
|
||||
async startDeviceFlow(): Promise<DeviceFlowStartInfo> {
|
||||
if (!this.isConfigured()) {
|
||||
@@ -86,8 +86,8 @@ export class AuthService extends EventEmitter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Liefert ein gültiges Access-Token, refresht falls nötig.
|
||||
* Wird vom Helix-Client benutzt.
|
||||
* Returns a valid access token, refreshing it if necessary.
|
||||
* Used by the Helix client.
|
||||
*/
|
||||
async getValidAccessToken(): Promise<string | null> {
|
||||
if (!this.tokens) return null
|
||||
@@ -100,7 +100,7 @@ export class AuthService extends EventEmitter {
|
||||
await saveTokens(this.tokens)
|
||||
return this.tokens.accessToken
|
||||
} catch {
|
||||
// Refresh fehlgeschlagen → User muss sich neu einloggen.
|
||||
// Refresh failed — user must log in again.
|
||||
this.tokens = null
|
||||
await clearTokens()
|
||||
return null
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Twitch OAuth 2.0 Device Code Flow.
|
||||
// Doku: https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#device-code-grant-flow
|
||||
// Docs: https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#device-code-grant-flow
|
||||
|
||||
const DEVICE_ENDPOINT = 'https://id.twitch.tv/oauth2/device'
|
||||
const TOKEN_ENDPOINT = 'https://id.twitch.tv/oauth2/token'
|
||||
@@ -100,7 +100,7 @@ export async function pollForToken(opts: PollOptions): Promise<PollOutcome> {
|
||||
payload = json as ErrorResponse
|
||||
}
|
||||
} catch {
|
||||
/* nicht-JSON Antwort, ignorieren */
|
||||
/* non-JSON response, ignore */
|
||||
}
|
||||
const msg = (payload.message ?? '').toLowerCase()
|
||||
|
||||
|
||||
+8
-8
@@ -64,15 +64,15 @@ function createWindow(): BrowserWindow {
|
||||
}
|
||||
|
||||
/**
|
||||
* CORS-Bypass für Twitch CDN und HLS-Streams.
|
||||
* hls.js im Renderer sendet Requests von localhost/file:// — Twitch CDN erwartet
|
||||
* Origin: https://www.twitch.tv. Wir setzen Origin + Referer auf ausgehenden Requests
|
||||
* und ergänzen CORS-Response-Header, damit Chromium die Antworten akzeptiert.
|
||||
* CORS bypass for Twitch CDN and HLS streams.
|
||||
* hls.js in the renderer sends requests from localhost/file:// — Twitch CDN expects
|
||||
* Origin: https://www.twitch.tv. We set Origin + Referer on outgoing requests
|
||||
* and inject CORS response headers so Chromium accepts the responses.
|
||||
*
|
||||
* HLS-Cache-Unterdrückung: xhrSetup in hls.js setzt Cache-Control: no-store auf jedem
|
||||
* XHR. Das löst einen CORS-Preflight aus (Cache-Control ist kein safelisted header).
|
||||
* Damit der Preflight durchkommt, muss onHeadersReceived auch ttvnw.net-Domains abdecken
|
||||
* (Segment-CDN: *.j.cloudfront.hls.ttvnw.net — enthält nicht "cloudfront.net").
|
||||
* HLS cache suppression: xhrSetup in hls.js sets Cache-Control: no-store on every
|
||||
* XHR. This triggers a CORS preflight (Cache-Control is not a safelisted header).
|
||||
* For the preflight to pass, onHeadersReceived must also cover ttvnw.net domains
|
||||
* (segment CDN: *.j.cloudfront.hls.ttvnw.net — does not contain "cloudfront.net").
|
||||
*/
|
||||
function setupTwitchCors(): void {
|
||||
const isTwitchCdn = (url: string): boolean =>
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
/**
|
||||
* Liest Gamepad-Events via Linux evdev (/dev/input/event*).
|
||||
* Reads gamepad events via Linux evdev (/dev/input/event*).
|
||||
*
|
||||
* Erkennt Controller über /dev/input/js* und öffnet deren zugehöriges
|
||||
* event*-Interface. Das evdev-Interface liefert standardisierte, benannte
|
||||
* Button-Codes (BTN_SOUTH, BTN_NORTH, …) die über alle Controller-Typen
|
||||
* (Xbox, PlayStation, Nintendo) und Verbindungsarten (USB, Bluetooth)
|
||||
* konsistent sind – unabhängig davon, welchen Treiber der Kernel nutzt.
|
||||
* Detects controllers via /dev/input/js* and opens their corresponding
|
||||
* event* interface. The evdev interface provides standardized, named
|
||||
* button codes (BTN_SOUTH, BTN_NORTH, …) that are consistent across all
|
||||
* controller types (Xbox, PlayStation, Nintendo) and connection methods
|
||||
* (USB, Bluetooth), regardless of which driver the kernel uses.
|
||||
*
|
||||
* Damit entfällt das alte Problem mit der button-Nummerierung im Joystick-API,
|
||||
* bei dem Xbox-One-Controller via Bluetooth (Share-Button verschiebt die
|
||||
* Nummerierung) X-Button als Nummer 3 statt 2 lieferten.
|
||||
* This eliminates the old button-numbering problem in the Joystick API,
|
||||
* where Xbox One controllers via Bluetooth (Share button shifts the
|
||||
* numbering) reported the X button as number 3 instead of 2.
|
||||
*
|
||||
* Unterstützt mehrere Gamepads gleichzeitig (Steam Deck + Bluetooth Xbox).
|
||||
* Hotplug wird durch periodisches Scannen von /dev/input/ abgedeckt.
|
||||
* Supports multiple gamepads simultaneously (Steam Deck + Bluetooth Xbox).
|
||||
* Hotplug is handled by periodically scanning /dev/input/.
|
||||
*
|
||||
* BTN_*-Codes sind konsistent für alle Controller:
|
||||
* BTN_* codes are consistent across all controllers:
|
||||
* BTN_SOUTH (0x130) = A / Cross
|
||||
* BTN_EAST (0x131) = B / Circle
|
||||
* BTN_NORTH (0x133) = X / Square
|
||||
* BTN_WEST (0x134) = Y / Triangle
|
||||
* BTN_TL (0x136) = LB / L1
|
||||
* BTN_TR (0x137) = RB / R1
|
||||
* BTN_TL2 (0x138) = LT / L2 (als Button bei manchen Controllern)
|
||||
* BTN_TR2 (0x139) = RT / R2 (als Button bei manchen Controllern)
|
||||
* ABS_HAT0X (16) = D-Pad X-Achse
|
||||
* ABS_HAT0Y (17) = D-Pad Y-Achse
|
||||
* ABS_X/Y (0/1) = Linker Stick
|
||||
* ABS_Z/RZ (2/5) = LT/RT als Analog-Achse
|
||||
* BTN_TL2 (0x138) = LT / L2 (as button on some controllers)
|
||||
* BTN_TR2 (0x139) = RT / R2 (as button on some controllers)
|
||||
* ABS_HAT0X (16) = D-Pad X-axis
|
||||
* ABS_HAT0Y (17) = D-Pad Y-axis
|
||||
* ABS_X/Y (0/1) = Left stick
|
||||
* ABS_Z/RZ (2/5) = LT/RT as analog axis
|
||||
*/
|
||||
|
||||
import * as fs from 'node:fs'
|
||||
@@ -35,8 +35,8 @@ import type { BrowserWindow } from 'electron'
|
||||
import { DEDUP_WINDOW_MS, HOTPLUG_SCAN_INTERVAL_MS, TRIGGER_THRESHOLD } from '../constants/input'
|
||||
import log from 'electron-log/main'
|
||||
|
||||
// evdev input_event auf 64-bit Linux:
|
||||
// { u64 tv_sec (8 Bytes), u64 tv_usec (8 Bytes), u16 type (2), u16 code (2), s32 value (4) } = 24 Bytes
|
||||
// evdev input_event on 64-bit Linux:
|
||||
// { u64 tv_sec (8 bytes), u64 tv_usec (8 bytes), u16 type (2), u16 code (2), s32 value (4) } = 24 bytes
|
||||
const INPUT_EVENT_SIZE = 24
|
||||
|
||||
const EV_KEY = 0x01
|
||||
@@ -52,7 +52,7 @@ const BTN_TR = 0x137
|
||||
const BTN_TL2 = 0x138
|
||||
const BTN_TR2 = 0x139
|
||||
|
||||
// ABS-Achsen-Codes
|
||||
// ABS axis codes
|
||||
const ABS_X = 0
|
||||
const ABS_Y = 1
|
||||
const ABS_Z = 2 // LT / L2
|
||||
@@ -84,8 +84,8 @@ interface AxisState {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sucht das zugehörige evdev-Device (/dev/input/eventN) für ein
|
||||
* Joystick-Device (/dev/input/jsN) über den /sys-Dateisystem-Pfad.
|
||||
* Finds the corresponding evdev device (/dev/input/eventN) for a
|
||||
* joystick device (/dev/input/jsN) via the /sys filesystem path.
|
||||
*/
|
||||
function findEventDevice(jsDevicePath: string): string | null {
|
||||
try {
|
||||
@@ -223,9 +223,9 @@ class EvdevReader {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fallback-Reader für den Fall, dass kein evdev-Device gefunden wird.
|
||||
* Nutzt das alte Joystick-API (8-Byte-Events, Joystick-Nummern-Mapping).
|
||||
* Deckt Controller ab, die kein /sys-Event-Device-Mapping haben.
|
||||
* Fallback reader used when no evdev device is found.
|
||||
* Uses the legacy Joystick API (8-byte events, numeric button mapping).
|
||||
* Covers controllers that have no /sys event device mapping.
|
||||
*/
|
||||
class JoystickFallbackReader {
|
||||
private stream: fs.ReadStream | null = null
|
||||
@@ -350,13 +350,13 @@ class JoystickFallbackReader {
|
||||
}
|
||||
|
||||
/**
|
||||
* Startet das Lesen aller /dev/input/js* Devices (evdev-Interface bevorzugt).
|
||||
* Gibt eine Cleanup-Funktion zurück.
|
||||
* Starts reading all /dev/input/js* devices (evdev interface preferred).
|
||||
* Returns a cleanup function.
|
||||
*/
|
||||
export function startGamepadReader(getWindow: () => BrowserWindow | null): () => void {
|
||||
if (process.platform !== 'linux') return () => {}
|
||||
|
||||
// Keyed by js-Device-Pfad
|
||||
// Keyed by js device path
|
||||
const readers = new Map<string, EvdevReader | JoystickFallbackReader>()
|
||||
const lastKeyAt = new Map<string, number>()
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ function sortQualities(qualities: string[]): string[] {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fragt streamlink nach allen verfügbaren Qualitätsstufen für eine URL (--json).
|
||||
* Gibt eine sortierte Liste zurück; bei Fehler leeres Array.
|
||||
* Queries streamlink for all available quality levels for a URL (--json).
|
||||
* Returns a sorted list; empty array on error.
|
||||
*/
|
||||
export function getAvailableQualities(url: string): Promise<string[]> {
|
||||
return new Promise((resolve) => {
|
||||
@@ -56,8 +56,8 @@ export function getAvailableQualities(url: string): Promise<string[]> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fragt streamlink nach der direkten HLS-URL für einen Stream oder VOD.
|
||||
* Wird für Live-Streams (twitch.tv/<login>) und VODs (twitch.tv/videos/<id>) verwendet.
|
||||
* Queries streamlink for the direct HLS URL of a stream or VOD.
|
||||
* Used for live streams (twitch.tv/<login>) and VODs (twitch.tv/videos/<id>).
|
||||
*/
|
||||
export function getStreamUrl(url: string, quality: string): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
@@ -157,7 +157,7 @@ export class HelixClient {
|
||||
boxArtUrl: g.box_art_url.replace('{width}', '285').replace('{height}', '380')
|
||||
}))
|
||||
|
||||
// Zuschauerzahlen: pro Kategorie die Top-100-Streams abrufen (parallel)
|
||||
// Viewer counts: fetch the top 100 streams per category in parallel
|
||||
const headers = await this.authHeaders()
|
||||
const viewerCounts = await Promise.all(
|
||||
games.map(async (g) => {
|
||||
|
||||
@@ -20,14 +20,14 @@ export default function App(): JSX.Element {
|
||||
return off
|
||||
}, [refresh])
|
||||
|
||||
// Browser Gamepad API (funktioniert im Desktop-Modus / Windows)
|
||||
// Browser Gamepad API (works in desktop mode / Windows)
|
||||
useEffect(() => {
|
||||
if (navigator.userAgent.toLowerCase().includes('linux')) return
|
||||
gamepadService.start()
|
||||
return () => gamepadService.stop()
|
||||
}, [])
|
||||
|
||||
// Main-Process Gamepad Reader (liest /dev/input/js* direkt, funktioniert in Gaming Mode)
|
||||
// Main-process gamepad reader (reads /dev/input/js* directly, works in Gaming Mode)
|
||||
useEffect(() => {
|
||||
return window.t4sd.gamepad.onInput((key) => {
|
||||
const target = document.activeElement ?? document.body
|
||||
|
||||
@@ -588,7 +588,7 @@ export default function ChannelScreen({ channel, onBack }: Props): JSX.Element {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* HTML5 Video Player — rendert innerhalb des Electron-Fensters */}
|
||||
{/* HTML5 video player — renders inside the Electron window */}
|
||||
{hlsPayload && (
|
||||
<VideoPlayer
|
||||
ref={videoRef}
|
||||
|
||||
Reference in New Issue
Block a user