feat(jellyfin): support Jellyfin 12.x authentication headers and capabilities schema
This commit is contained in:
+16
-9
@@ -40,11 +40,14 @@ class JellyfinClient:
|
||||
|
||||
def _get_headers(self) -> Dict[str, str]:
|
||||
headers = {
|
||||
"Authorization": self.auth_header,
|
||||
"X-Emby-Authorization": self.auth_header,
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json",
|
||||
}
|
||||
if self.auth_token:
|
||||
headers["X-Emby-Token"] = self.auth_token
|
||||
headers["Authorization"] = f'{self.auth_header}, Token="{self.auth_token}"'
|
||||
return headers
|
||||
|
||||
async def start(self) -> None:
|
||||
@@ -64,7 +67,6 @@ class JellyfinClient:
|
||||
self._ws_task = asyncio.create_task(self._connection_manager())
|
||||
self._report_task = asyncio.create_task(self._progress_reporter())
|
||||
|
||||
|
||||
async def _connection_manager(self) -> None:
|
||||
"""Keeps the connection and WebSocket session alive with auto-reconnect."""
|
||||
while self._running:
|
||||
@@ -90,7 +92,7 @@ class JellyfinClient:
|
||||
"Pw": self.config.password or "",
|
||||
}
|
||||
logger.info("Authenticating to Jellyfin server: %s as %s", self.config.server_url, self.config.username)
|
||||
async with self.session.post(url, json=payload) as resp:
|
||||
async with self.session.post(url, json=payload, headers=self._get_headers()) as resp:
|
||||
if resp.status != 200:
|
||||
err_text = await resp.text()
|
||||
raise RuntimeError(f"Authentication failed ({resp.status}): {err_text}")
|
||||
@@ -98,6 +100,7 @@ class JellyfinClient:
|
||||
self.auth_token = data.get("AccessToken")
|
||||
self.user_id = data.get("User", {}).get("Id")
|
||||
self.session.headers["X-Emby-Token"] = self.auth_token
|
||||
self.session.headers["Authorization"] = f'{self.auth_header}, Token="{self.auth_token}"'
|
||||
logger.info("Authenticated successfully with Jellyfin (UserId: %s)", self.user_id)
|
||||
|
||||
async def _report_capabilities(self) -> None:
|
||||
@@ -106,19 +109,18 @@ class JellyfinClient:
|
||||
capabilities = {
|
||||
"PlayableMediaTypes": ["Video", "Audio"],
|
||||
"SupportedCommands": [
|
||||
"Play",
|
||||
"Playstate",
|
||||
"PlayNext",
|
||||
"SetVolume",
|
||||
"VolumeUp",
|
||||
"VolumeDown",
|
||||
"Mute",
|
||||
"Unmute",
|
||||
"ToggleMute",
|
||||
"SetVolume",
|
||||
"SetAudioStreamIndex",
|
||||
"SetSubtitleStreamIndex",
|
||||
"Seek",
|
||||
"DisplayMessage",
|
||||
],
|
||||
"SupportsMediaControl": true if True else True,
|
||||
"SupportsMediaControl": True,
|
||||
"SupportsPersistentIdentifier": True,
|
||||
"DeviceProfile": {
|
||||
"Name": "HTPC MPV Player",
|
||||
"DirectPlayProfiles": [
|
||||
@@ -139,8 +141,13 @@ class JellyfinClient:
|
||||
f"{self.config.server_url.replace('http://', 'ws://').replace('https://', 'wss://')}"
|
||||
f"/socket?api_key={self.auth_token}&deviceId={self.config.device_id}"
|
||||
)
|
||||
ws_headers = {
|
||||
"Authorization": f'MediaBrowser Token="{self.auth_token}"',
|
||||
"X-Emby-Token": self.auth_token,
|
||||
}
|
||||
logger.info("Connecting to Jellyfin WebSocket: %s", ws_url)
|
||||
async with self.session.ws_connect(ws_url) as ws:
|
||||
async with self.session.ws_connect(ws_url, headers=ws_headers) as ws:
|
||||
|
||||
self.ws = ws
|
||||
logger.info("Jellyfin WebSocket connected; waiting for remote control commands")
|
||||
async for msg in ws:
|
||||
|
||||
Reference in New Issue
Block a user