Added URL path support. (#13436)

Changes:
Fix: Now using KTOR instead of building the url by simple string concad. This fixes the https and port 443 bug that existed prier to this change. (https://example.com would look like: https://example.com:443)
Added: Support for jellyfins Base URL option. This allows the addon to be used on installations were jellyfin uses a base path.

Signed-off-by: tliese <mail@tobiasliese.me>
pull/13476/head
Tobias Liese 2022-10-01 15:32:11 +02:00 committed by GitHub
parent cc50497f31
commit 8b4607a4f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 60 additions and 34 deletions

View File

@ -33,41 +33,42 @@ In order to assist you with this process the binding expose a simple login form
## Server Thing Configuration ## Server Thing Configuration
| Config | Type | description | | Config | Type | description |
|----------|----------|------------------------------| |---------------------------|---------|----------------------------------------------------------------------------------------------|
| hostname | text | Hostname or IP address of the server (required) | | hostname | text | Hostname or IP address of the server (required) |
| port | integer | Port of the server (required) | | port | integer | Port of the server (required) |
| ssl | boolean | Connect through https (required) | | ssl | boolean | Connect through https (required) |
| refreshSeconds | integer | Interval to pull devices state from the server | | path | text | Base path of the server |
| refreshSeconds | integer | Interval to pull devices state from the server |
| clientActiveWithInSeconds | integer | Amount off seconds allowed since the last client activity to assert it's online (0 disabled) | | clientActiveWithInSeconds | integer | Amount off seconds allowed since the last client activity to assert it's online (0 disabled) |
| userId | text | The user id | | userId | text | The user id |
| token | text | The user access token | | token | text | The user access token |
## Channels ## Channels
| channel | type | description | | channel | type | description |
|----------|--------|------------------------------| |----------------------------|--------|-----------------------------------------------------------------------------------------------------------------|
| send-notification | String | Display message in client | | send-notification | String | Display message in client |
| media-control | Player | Control media playback | | media-control | Player | Control media playback |
| playing-item-id | String | Id of the item currently playing (readonly) | | playing-item-id | String | Id of the item currently playing (readonly) |
| playing-item-name | String | Name of the item currently playing (readonly) | | playing-item-name | String | Name of the item currently playing (readonly) |
| playing-item-series-name | String | Name of the item's series currently playing, only have value when item is an episode (readonly) | | playing-item-series-name | String | Name of the item's series currently playing, only have value when item is an episode (readonly) |
| playing-item-season-name | String | Name of the item's season currently playing, only have value when item is an episode (readonly) | | playing-item-season-name | String | Name of the item's season currently playing, only have value when item is an episode (readonly) |
| playing-item-season | Number | Number of the item's season currently playing, only have value when item is an episode (readonly) | | playing-item-season | Number | Number of the item's season currently playing, only have value when item is an episode (readonly) |
| playing-item-episode | Number | Number of the episode item currently playing, only have value when item is an episode (readonly) | | playing-item-episode | Number | Number of the episode item currently playing, only have value when item is an episode (readonly) |
| playing-item-genders | String | Coma separate list genders of the item currently playing (readonly) | | playing-item-genders | String | Coma separate list genders of the item currently playing (readonly) |
| playing-item-type | String | Type of the item currently playing (readonly) | | playing-item-type | String | Type of the item currently playing (readonly) |
| playing-item-percentage | Dimmer | Played percentage for the item currently playing, allow seek | | playing-item-percentage | Dimmer | Played percentage for the item currently playing, allow seek |
| playing-item-second | Number | Current second for the item currently playing, allow seek | | playing-item-second | Number | Current second for the item currently playing, allow seek |
| playing-item-total-seconds | Number | Total seconds for the item currently playing (readonly) | | playing-item-total-seconds | Number | Total seconds for the item currently playing (readonly) |
| play-by-terms | String | Play media by terms, works for series, episodes and movies; terms search is explained bellow | | play-by-terms | String | Play media by terms, works for series, episodes and movies; terms search is explained bellow |
| play-next-by-terms | String | Add to playback queue as next by terms, works for series, episodes and movies; terms search is explained bellow | | play-next-by-terms | String | Add to playback queue as next by terms, works for series, episodes and movies; terms search is explained bellow |
| play-last-by-terms | String | Add to playback queue as last by terms, works for series, episodes and movies; terms search is explained bellow | | play-last-by-terms | String | Add to playback queue as last by terms, works for series, episodes and movies; terms search is explained bellow |
| browse-by-terms | String | Browse media by terms, works for series, episodes and movies; terms search is explained bellow | | browse-by-terms | String | Browse media by terms, works for series, episodes and movies; terms search is explained bellow |
| play-by-id | String | Play media by id, works for series, episodes and movies; id search is explained bellow | | play-by-id | String | Play media by id, works for series, episodes and movies; id search is explained bellow |
| play-next-by-id | String | Add to playback queue as next by id, works for series, episodes and movies | | play-next-by-id | String | Add to playback queue as next by id, works for series, episodes and movies |
| play-last-by-id | String | Add to playback queue as last by id, works for series, episodes and movies | | play-last-by-id | String | Add to playback queue as last by id, works for series, episodes and movies |
| browse-by-id | String | Browse media by id, works for series, episodes and movies | | browse-by-id | String | Browse media by id, works for series, episodes and movies |
### Terms search: ### Terms search:
The terms search has a default behavior that can be modified sending some predefined prefixes. The terms search has a default behavior that can be modified sending some predefined prefixes.

View File

@ -33,6 +33,10 @@ public class JellyfinServerConfiguration {
* Use Https * Use Https
*/ */
public Boolean ssl = true; public Boolean ssl = true;
/**
* Jellyfin base url
*/
public String path = "";
/** /**
* Interval to pull devices state from the server * Interval to pull devices state from the server
*/ */

View File

@ -107,19 +107,22 @@ public class JellyfinServerDiscoveryService extends AbstractDiscoveryService {
new SystemApi(jellyClient).getPublicSystemInfo(asyncResponse); new SystemApi(jellyClient).getPublicSystemInfo(asyncResponse);
try { try {
var publicSystemInfo = asyncResponse.awaitContent(); var publicSystemInfo = asyncResponse.awaitContent();
discoverServer(uri.getHost(), uri.getPort(), uri.getScheme().equalsIgnoreCase("https"), publicSystemInfo); discoverServer(uri.getHost(), uri.getPort(), uri.getScheme().equalsIgnoreCase("https"), uri.getPath(),
publicSystemInfo);
} catch (SyncCallback.SyncCallbackError | ApiClientException e) { } catch (SyncCallback.SyncCallbackError | ApiClientException e) {
logger.warn("Discovery error: {}", e.getMessage()); logger.warn("Discovery error: {}", e.getMessage());
} }
} }
private void discoverServer(String hostname, int port, boolean ssl, PublicSystemInfo publicSystemInfo) { private void discoverServer(String hostname, int port, boolean ssl, String path,
PublicSystemInfo publicSystemInfo) {
logger.debug("Server discovered: [{}:{}] {}", hostname, port, publicSystemInfo.getServerName()); logger.debug("Server discovered: [{}:{}] {}", hostname, port, publicSystemInfo.getServerName());
var id = Objects.requireNonNull(publicSystemInfo.getId()); var id = Objects.requireNonNull(publicSystemInfo.getId());
Map<String, Object> properties = new HashMap<>(); Map<String, Object> properties = new HashMap<>();
properties.put("hostname", hostname); properties.put("hostname", hostname);
properties.put("port", port); properties.put("port", port);
properties.put("ssl", ssl); properties.put("ssl", ssl);
properties.put("path", path);
properties.put(Thing.PROPERTY_SERIAL_NUMBER, id); properties.put(Thing.PROPERTY_SERIAL_NUMBER, id);
var productName = publicSystemInfo.getProductName(); var productName = publicSystemInfo.getProductName();
if (productName != null) { if (productName != null) {

View File

@ -65,6 +65,9 @@ import org.openhab.core.types.Command;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import io.ktor.http.URLBuilder;
import io.ktor.http.URLProtocol;
/** /**
* The {@link JellyfinServerHandler} is responsible for handling commands, which are * The {@link JellyfinServerHandler} is responsible for handling commands, which are
* sent to one of the channels. * sent to one of the channels.
@ -119,7 +122,16 @@ public class JellyfinServerHandler extends BaseBridgeHandler {
} }
public String getServerUrl() { public String getServerUrl() {
return (config.ssl ? "https" : "http") + "://" + config.hostname + ":" + config.port; var builder = new URLBuilder();
builder.setHost(config.hostname);
if (config.ssl) {
builder.setProtocol(URLProtocol.Companion.getHTTPS());
} else {
builder.setProtocol(URLProtocol.Companion.getHTTP());
}
builder.setPort(config.port);
builder.setEncodedPath(config.path);
return builder.buildString();
} }
public boolean isOnline() { public boolean isOnline() {

View File

@ -18,6 +18,8 @@ thing-type.config.jellyfin.server.hostname.label = Hostname/IP
thing-type.config.jellyfin.server.hostname.description = Hostname or IP address of the server thing-type.config.jellyfin.server.hostname.description = Hostname or IP address of the server
thing-type.config.jellyfin.server.port.label = Port thing-type.config.jellyfin.server.port.label = Port
thing-type.config.jellyfin.server.port.description = Port of the server thing-type.config.jellyfin.server.port.description = Port of the server
thing-type.config.jellyfin.server.path.label = Base Path
thing-type.config.jellyfin.server.path.description = Base path of the server
thing-type.config.jellyfin.server.refreshSeconds.label = Refresh Seconds thing-type.config.jellyfin.server.refreshSeconds.label = Refresh Seconds
thing-type.config.jellyfin.server.refreshSeconds.description = Interval to pull devices state from the server thing-type.config.jellyfin.server.refreshSeconds.description = Interval to pull devices state from the server
thing-type.config.jellyfin.server.ssl.label = SSL thing-type.config.jellyfin.server.ssl.label = SSL

View File

@ -23,6 +23,10 @@
<description>Connect through https</description> <description>Connect through https</description>
<default>false</default> <default>false</default>
</parameter> </parameter>
<parameter name="path" type="text" required="false">
<label>Base Path</label>
<description>Base path of the server</description>
</parameter>
<parameter name="refreshSeconds" type="integer" min="10" max="300" required="true"> <parameter name="refreshSeconds" type="integer" min="10" max="300" required="true">
<label>Refresh Seconds</label> <label>Refresh Seconds</label>
<description>Interval to pull devices state from the server</description> <description>Interval to pull devices state from the server</description>