]> git.basschouten.com Git - openhab-addons.git/blob
3bbc4b7709afb8a781f06c55fd21711d08b22273
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.jellyfin.internal.discovery;
14
15 import static org.openhab.binding.jellyfin.internal.JellyfinBindingConstants.*;
16
17 import java.net.URI;
18 import java.net.URISyntaxException;
19 import java.util.HashMap;
20 import java.util.Map;
21 import java.util.Objects;
22 import java.util.Set;
23
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.jellyfin.sdk.Jellyfin;
27 import org.jellyfin.sdk.JellyfinOptions;
28 import org.jellyfin.sdk.api.client.exception.ApiClientException;
29 import org.jellyfin.sdk.api.operations.SystemApi;
30 import org.jellyfin.sdk.compatibility.JavaFlow;
31 import org.jellyfin.sdk.model.ClientInfo;
32 import org.jellyfin.sdk.model.DeviceInfo;
33 import org.jellyfin.sdk.model.api.PublicSystemInfo;
34 import org.jellyfin.sdk.model.api.ServerDiscoveryInfo;
35 import org.openhab.binding.jellyfin.internal.util.SyncCallback;
36 import org.openhab.binding.jellyfin.internal.util.SyncResponse;
37 import org.openhab.core.OpenHAB;
38 import org.openhab.core.config.discovery.AbstractDiscoveryService;
39 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
40 import org.openhab.core.config.discovery.DiscoveryService;
41 import org.openhab.core.thing.Thing;
42 import org.openhab.core.thing.ThingUID;
43 import org.osgi.service.component.annotations.Component;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 /**
48  * The {@link JellyfinServerDiscoveryService} discover Jellyfin servers in the network.
49  *
50  * @author Miguel Alvarez - Initial contribution
51  */
52 @NonNullByDefault
53 @Component(service = DiscoveryService.class, configurationPid = "discovery.jellyfin")
54 public class JellyfinServerDiscoveryService extends AbstractDiscoveryService {
55     private final Logger logger = LoggerFactory.getLogger(JellyfinServerDiscoveryService.class);
56     private JavaFlow.@Nullable FlowJob cancelDiscovery;
57
58     public JellyfinServerDiscoveryService() throws IllegalArgumentException {
59         super(Set.of(THING_TYPE_CLIENT), 60);
60     }
61
62     @Override
63     protected void startScan() {
64         var opts = new JellyfinOptions.Builder();
65         opts.setClientInfo(new ClientInfo("openHAB", OpenHAB.getVersion()));
66         opts.setDeviceInfo(new DeviceInfo("discovery", "openHAB"));
67         var jellyfin = new Jellyfin(opts.build());
68         var discoverySvc = new org.jellyfin.sdk.discovery.DiscoveryService(jellyfin);
69         logger.debug("Starting search");
70         cancelDiscovery = JavaFlow.collect(discoverySvc.discoverLocalServers(100, 10), null, (info) -> {
71             if (info == null) {
72                 return;
73             }
74             logger.debug("Server found: [{}] {}", info.getId(), info.getName());
75             processDiscoveryResult(jellyfin, info);
76         }, (throwable) -> {
77             if (throwable != null) {
78                 logger.warn("Discovery Error: {}", throwable.getMessage());
79             } else {
80                 logger.debug("Discovery ends");
81             }
82         });
83     }
84
85     @Override
86     protected synchronized void stopScan() {
87         super.stopScan();
88         var cancelDiscovery = this.cancelDiscovery;
89         if (cancelDiscovery != null) {
90             cancelDiscovery.close();
91             this.cancelDiscovery = null;
92         }
93     }
94
95     private void processDiscoveryResult(Jellyfin jellyfin, ServerDiscoveryInfo info) {
96         URI uri;
97         try {
98             uri = new URI(Objects.requireNonNull(info.getAddress()));
99         } catch (URISyntaxException e) {
100             logger.warn("Error parsing server url: {}", e.getMessage());
101             return;
102         }
103         var jellyClient = jellyfin.createApi(info.getAddress());
104         var asyncResponse = new SyncResponse<PublicSystemInfo>();
105         new SystemApi(jellyClient).getPublicSystemInfo(asyncResponse);
106         try {
107             var publicSystemInfo = asyncResponse.awaitContent();
108             discoverServer(uri.getHost(), uri.getPort(), uri.getScheme().equalsIgnoreCase("https"), publicSystemInfo);
109         } catch (SyncCallback.SyncCallbackError | ApiClientException e) {
110             logger.warn("Discovery error: {}", e.getMessage());
111         }
112     }
113
114     private void discoverServer(String hostname, int port, boolean ssl, PublicSystemInfo publicSystemInfo) {
115         logger.debug("Server discovered: [{}:{}] {}", hostname, port, publicSystemInfo.getServerName());
116         var id = Objects.requireNonNull(publicSystemInfo.getId());
117         Map<String, Object> properties = new HashMap<>();
118         properties.put("hostname", hostname);
119         properties.put("port", port);
120         properties.put("ssl", ssl);
121         properties.put(Thing.PROPERTY_SERIAL_NUMBER, id);
122         var productName = publicSystemInfo.getProductName();
123         if (productName != null) {
124             properties.put(Thing.PROPERTY_VENDOR, productName);
125         }
126         var version = publicSystemInfo.getVersion();
127         if (version != null) {
128             properties.put(Thing.PROPERTY_FIRMWARE_VERSION, version);
129         }
130         thingDiscovered(DiscoveryResultBuilder.create(new ThingUID(THING_TYPE_SERVER, publicSystemInfo.getId()))
131                 .withTTL(DISCOVERY_RESULT_TTL_SEC).withRepresentationProperty(Thing.PROPERTY_SERIAL_NUMBER)
132                 .withProperties(properties).withLabel(publicSystemInfo.getServerName()).build());
133     }
134 }