diff --git a/docs/guide/authentication.md b/docs/guide/authentication.md index 9c07fd6a9..593bfe0b1 100644 --- a/docs/guide/authentication.md +++ b/docs/guide/authentication.md @@ -24,7 +24,7 @@ val api = jellyfin.createApi( Change the token in an existing API client instance like so: ```kotlin -api.accessToken = "02a7174a4d1843448b6d177d8288efd0" +api.update(accessToken = "02a7174a4d1843448b6d177d8288efd0") ``` ## Password login @@ -43,7 +43,7 @@ try { ) // Use access token in api instance - api.accessToken = authenticationResult.accessToken + api.update(accessToken = authenticationResult.accessToken) // Print session information println(authenticationResult.sessionInfo) @@ -70,19 +70,19 @@ the new one. The Quick Connect functionality may be disabled by a server. In those cases the server responds with an HTTP 401 response. You can check if QuickConnect is enabled first or deal with it when trying to use it. -To start a Quick Connect session you need to request a Quick Connect code with the initiate function. This returns a -state object which can be updated by calling the connect method. +To start a Quick Connect session you need to request a Quick Connect code with the initiateQuickConnect function. This +returns a state object which can be updated by calling the getQuickConnectState method. ```kotlin val api = jellyfin.createApi(/* .. */) // Check if Quick Connect is enabled (this is optional) -val enabled by api.quickConnectApi.getEnabled() +val enabled by api.quickConnectApi.getQuickConnectEnabled() if (!enabled) println("QuickConnect is disabled in the server!") // Create a Quick Connect session and store the state try { - var quickConnectState by api.quickConnectApi.initiate() + val quickConnectState by api.quickConnectApi.initiateQuickConnect() } catch (err: InvalidStatusException) { if (err.status == 401) { // Quick Connect is disabled @@ -99,13 +99,12 @@ The Quick Connect state contains a few values that are of interest: - The `code` is for the user to input in a different app The next step is to show the code to the user. Depending on your app you might want to either show a "next" button to -press -when the user authorized the app or automatically update the Quick Connect state. In the latter example we recommend -updating every 5 seconds. +press when the user authorized the app or automatically update the Quick Connect state. In the latter example we +recommend updating every 5 seconds. ```kotlin // Update the Quick Connect session state -quickConnectState = api.quickConnectApi.connect( +quickConnectState = api.quickConnectApi.getQuickConnectState( secret = quickConnectState.secret, ) ``` @@ -119,7 +118,7 @@ val authenticationResult by api.userApi.authenticateWithQuickConnect( ) // Use access token in api instance -api.accessToken = authenticationResult.accessToken +api.update(accessToken = authenticationResult.accessToken) // Print session information println(authenticationResult.sessionInfo) diff --git a/docs/guide/getting-started.md b/docs/guide/getting-started.md index 687bbff97..d59c8e1ca 100644 --- a/docs/guide/getting-started.md +++ b/docs/guide/getting-started.md @@ -106,7 +106,7 @@ try { ) // Use access token in api instance - api.accessToken = authenticationResult.accessToken + api.update(accessToken = authenticationResult.accessToken) // Print session information println(authenticationResult.sessionInfo) @@ -122,9 +122,7 @@ Jellyfin uses WebSockets to communicate events like library changes and activiti used with the SocketApi. ```kotlin -val instance = api.ws() - -instance.addGlobalListener { message -> +api.webSocket.subscribeAll().collect { message -> println(message) } ``` @@ -162,4 +160,4 @@ val recommended = jellyfin.discovery.getRecommendedServers(candidates, Recommend and series. - [Homedia](https://github.com/valmnt/homedia) provides a native user interface for Android TV using Jetpack Compose. -_Want to add your project? We'd love to know about it, open an issue or create pull request!_ +_Want to add your project? We'd love to know about it, please open a pull request to add it!_ diff --git a/docs/guide/websockets.md b/docs/guide/websockets.md index 53c31544f..bc0fcbf6a 100644 --- a/docs/guide/websockets.md +++ b/docs/guide/websockets.md @@ -1,92 +1,77 @@ # Using WebSockets -Added in v1.2.0, the new WebSocket implementation can be used to interact with the Jellyfin WebSocket server. This API -is not supported with the Java language because it heavily relies on coroutines and inline functions. +The WebSocket API can be used to interact with the Jellyfin WebSocket server. Get started by creating a new +authenticated API instance using the `createApi` function in the Jellyfin class. -Get started by creating a new authenticated API instance using the `createApi` function in the Jellyfin class. +Listening the WebSocket messages is done using subscriptions. Whenever one or multiple subscriptions are active the +WebSocket will automatically connect to the server. Credentials changes via the `update()` function will cause the +WebSocket to reconnect. There is a single WebSocket API for each ApiClient. ```kotlin +// Create an API instance val api = jellyfin.createApi(baseUrl = "https://demo.jellyfin.org/stable/") -``` - -## Connecting - -The socket connection is managed by an "instance". You can have multiple of these instances at the same time. However, -it is recommended to use a single instance during the lifecycle of your application. Use the `ws()` -function from the ApiClient class to create a new instance. - -```kotlin -val instance = api.ws() -``` -You can close an instance when it's no longer in use with the `stop()` function. - -```kotlin -instance.stop() +// Create a subscription for WebSocket all messages +api.webSocket.subscribeAll().collect { message -> + println(message) +} ``` ## Updating credentials -An instance does not automatically refresh credentials. You'll need to manually refresh the instance when the access -token, server or device info change. Use the `updateCredentials()` function to apply these changes. The instance -automatically reconnects when required. - -```kotlin -instance.updateCredentials() -``` +The WebSocket connection will reconnect when the server URL, access token, client information of device information +changes. All existing subscriptions stay active and automatically switch to the new credentials. -## Listen for messages +## Subscribe to messages -Listeners are used to receive the various types of websocket messages. A connection is automatically started and/or -closed depending on the active listeners. Multiple helper functions can be used to register a listener. They all return -a `SocketListener` object that can be used to remove the listener later with the `removeListener()` function on the -instance or the `stop()` on the listener. +Subscriptions are used to receive the various types of websocket messages. A connection is automatically started and/or +closed depending on the availability of subscriptions. Multiple extension functions can be used to create a +subscription. They all return a flow that emits each message as soon as it is received. -## Listen for specific messages +## Subscribe to specific messages -Use the `addListener()` function to create a listener that receives a single type. +Use the `subscribe()` function to create a listener that receives a single message type. ```kotlin -instance.addListener { message -> +api.webSocket.subscribe().collect { message -> // type of message is UserDataChangedMessage println("Received a message: $message") } ``` -## Listen for all messages +## Subscribe to all messages -If you want to listen for all types of messages instead. Use the `addGlobalListener` function. +Use the `subscribeAll` function if you want to subscribe to all types of messages instead. This is not recommended if +you only want to receive a subset of message types. ```kotlin -instance.addGlobalListener { message -> - // type of message is IncomingSocketMessage +api.webSocket.subscribeAll().collect { message -> + // type of message is OutboundWebSocketMessage println("Received a message: $message") } ``` -## Listen for grouped message types +## Subscribe to grouped message types -Some incoming messages are used for multiple kinds of information. These are the general, play state and SyncPlay -commands. To filter the types of commands there are a few helper functions available. All of them support a "commands" -parameter to define the message types to receive. All types will be sent when the commands parameter is omitted. This is -the same behavior as using `addListener`. +Some incoming messages are used for multiple kinds of information. These are the general commands, play state and +SyncPlay command messages. To filter the types of commands there are extensions functions available. All of them support +filtering for one or multiple commands to receive. All types will be sent when the commands parameter is omitted. This is +the same behavior as using the `subscribe` function. ```kotlin -instance.addGeneralCommandsListener( - commands = setOf(GeneralCommandType.DISPLAY_MESSAGE) -) { message -> +api.webSocket.subscribeGeneralCommand(GeneralCommandType.DISPLAY_MESSAGE).collect { message -> // type of message is GeneralCommandMessage println("Received a message: $message") } -instance.addPlayStateCommandsListener( +api.webSocket.subscribePlayStateCommands( commands = setOf(PlaystateCommand.NEXT_TRACK, PlaystateCommand.PREVIOUS_TRACK) -) { message -> - // type of message is PlayStateMessage +).collect { message -> + // type of message is PlaystateMessage println("Received a message: $message") } -instance.addSyncPlayCommandsListener( +api.webSocket.subscribeSyncPlayCommands( commands = setOf(SendCommandType.PAUSE, SendCommandType.UNPAUSE) ) { message -> // type of message is SyncPlayCommandMessage @@ -94,79 +79,10 @@ instance.addSyncPlayCommandsListener( } ``` -## Advanced listeners - -All previously mentioned functions to add listeners use the `addListenerDefinition` function under the hood. This -function is not recommended being used directly. Use the other functions instead. The function receives a listener -definition. - -An example for listening to both LibraryChangedMessage and UserDataChangedMessage messages: - -```kotlin -instance.addListenerDefinition( - SocketListenerDefinition( - subscribesTo = emptySet(), - filterTypes = setOf(LibraryChangedMessage::class, UserDataChangedMessage::class), - stopOnCredentialsChange = false, - listener = { message -> - // type of message is IncomingSocketMessage - println("Received a message: $message") - } - ) -) -``` - ## Sending messages -The Jellyfin server uses HTTP endpoints, mostly in the SessionApi, to manipulate state. The only messages send by a -client are to enable subscriptions. These subscriptions are automatically managed by the SDK. The `publish()` function -can still be used if you need to send your own messages. The function receives a `OutgoingSocketMessage` type and sends -it to the server. - -```kotlin -instance.publish(SessionsStartMessage()) -``` - -> **Note**: Do not send start and stop messages manually. This can confuse the SDK and cause unknown behavior. - -## Message Types - -The following messages types are supported in the SDK. - -### Incoming - -- GeneralCommandMessage -- UserDataChangedMessage -- SessionsMessage -- PlayMessage -- SyncPlayCommandMessage -- SyncPlayGroupUpdateMessage -- PlayStateMessage -- RestartRequiredMessage -- ServerShuttingDownMessage -- ServerRestartingMessage -- LibraryChangedMessage -- UserDeletedMessage -- UserUpdatedMessage -- SeriesTimerCreatedMessage -- TimerCreatedMessage -- SeriesTimerCancelledMessage -- TimerCancelledMessage -- RefreshProgressMessage -- ScheduledTaskEndedMessage -- PackageInstallationCancelledMessage -- PackageInstallationFailedMessage -- PackageInstallationCompletedMessage -- PackageInstallingMessage -- PackageUninstalledMessage -- ActivityLogEntryMessage -- ScheduledTasksInfoMessage - -### Outgoing - -- ActivityLogEntryStartMessage and ActivityLogEntryStopMessage -- SessionsStartMessage and SessionsStopMessage -- ScheduledTasksInfoStartMessage and ScheduledTasksInfoStopMessage +The SDK does not expose any functionality to send messages. Publishing messages is only used to keep the connection +alive or to request for certain message types to be sent. This is all managed by the SDK. ## Sample usage