mirror of
https://github.com/home-assistant/core
synced 2024-09-03 08:14:07 +02:00
![j-stienstra](/assets/img/avatar_default.png)
* Initial commit after scaffold setup * Add initial config flow * Create initial entity * Ready for testing * Can browse, no result yet * Further improvements. Browsing is working. Now need to work on proper stream URL * Two valid URLs. Do not play in HA * First working version for music * Add thumbnail * Includes Artist->Album hierarchy * Add sorting of artists, albums and tracks * Remove code for video libraries * Improved code styling * Optimize configuration flow * Fix unit tests for config flow * Fix import order * Conform to style requirements * Use empty string as media type for non playables * 100% code coverage config_flow * Type async_get_media_source * Final docsctring fix after rebase * Add __init__ and media_source files to .coveragerc * Fix testing issues after rebase * Fix string format issues and relative const import * Remove unused manifest entries * Raise ConfigEntry exceptions, not log errors * Upgrade dependency to avoid WARNING on startup * Change to builtin tuple and list (deprecation) * Log broad exceptions * Add strict typing * Further type fixes after rebase * Retry when cannot connect, otherwise fail setup * Remove unused CONFIG_SCHEMA * Enable strict typing checks * FlowResultDict -> FlowResult * Code quality improvements * Resolve mypy.ini merge conflict * Use unique userid generated by Jellyfin * Update homeassistant/components/jellyfin/config_flow.py Remove connection class from config flow Co-authored-by: Milan Meulemans <milan.meulemans@live.be> * Minor changes for additional checks after rebase * Remove title from string and translations * Changes wrt review * Fixes based on rebase and review suggestions * Move client initialization to separate file * Remove persistent_notification, add test const.py Co-authored-by: Milan Meulemans <milan.meulemans@live.be>
95 lines
2.8 KiB
Python
95 lines
2.8 KiB
Python
"""Utility methods for initializing a Jellyfin client."""
|
|
from __future__ import annotations
|
|
|
|
import socket
|
|
from typing import Any
|
|
import uuid
|
|
|
|
from jellyfin_apiclient_python import Jellyfin, JellyfinClient
|
|
from jellyfin_apiclient_python.api import API
|
|
from jellyfin_apiclient_python.connection_manager import (
|
|
CONNECTION_STATE,
|
|
ConnectionManager,
|
|
)
|
|
|
|
from homeassistant import exceptions
|
|
from homeassistant.const import CONF_PASSWORD, CONF_URL, CONF_USERNAME
|
|
from homeassistant.core import HomeAssistant
|
|
|
|
from .const import CLIENT_VERSION, USER_AGENT, USER_APP_NAME
|
|
|
|
|
|
async def validate_input(
|
|
hass: HomeAssistant, user_input: dict[str, Any], client: JellyfinClient
|
|
) -> str:
|
|
"""Validate that the provided url and credentials can be used to connect."""
|
|
url = user_input[CONF_URL]
|
|
username = user_input[CONF_USERNAME]
|
|
password = user_input[CONF_PASSWORD]
|
|
|
|
userid = await hass.async_add_executor_job(
|
|
_connect, client, url, username, password
|
|
)
|
|
|
|
return userid
|
|
|
|
|
|
def create_client() -> JellyfinClient:
|
|
"""Create a new Jellyfin client."""
|
|
jellyfin = Jellyfin()
|
|
client = jellyfin.get_client()
|
|
_setup_client(client)
|
|
return client
|
|
|
|
|
|
def _setup_client(client: JellyfinClient) -> None:
|
|
"""Configure the Jellyfin client with a number of required properties."""
|
|
player_name = socket.gethostname()
|
|
client_uuid = str(uuid.uuid4())
|
|
|
|
client.config.app(USER_APP_NAME, CLIENT_VERSION, player_name, client_uuid)
|
|
client.config.http(USER_AGENT)
|
|
|
|
|
|
def _connect(client: JellyfinClient, url: str, username: str, password: str) -> str:
|
|
"""Connect to the Jellyfin server and assert that the user can login."""
|
|
client.config.data["auth.ssl"] = url.startswith("https")
|
|
|
|
_connect_to_address(client.auth, url)
|
|
_login(client.auth, url, username, password)
|
|
return _get_id(client.jellyfin)
|
|
|
|
|
|
def _connect_to_address(connection_manager: ConnectionManager, url: str) -> None:
|
|
"""Connect to the Jellyfin server."""
|
|
state = connection_manager.connect_to_address(url)
|
|
if state["State"] != CONNECTION_STATE["ServerSignIn"]:
|
|
raise CannotConnect
|
|
|
|
|
|
def _login(
|
|
connection_manager: ConnectionManager,
|
|
url: str,
|
|
username: str,
|
|
password: str,
|
|
) -> None:
|
|
"""Assert that the user can log in to the Jellyfin server."""
|
|
response = connection_manager.login(url, username, password)
|
|
if "AccessToken" not in response:
|
|
raise InvalidAuth
|
|
|
|
|
|
def _get_id(api: API) -> str:
|
|
"""Set the unique userid from a Jellyfin server."""
|
|
settings: dict[str, Any] = api.get_user_settings()
|
|
userid: str = settings["Id"]
|
|
return userid
|
|
|
|
|
|
class CannotConnect(exceptions.HomeAssistantError):
|
|
"""Error to indicate the server is unreachable."""
|
|
|
|
|
|
class InvalidAuth(exceptions.HomeAssistantError):
|
|
"""Error to indicate the credentials are invalid."""
|