diff --git a/client/pom.xml b/client/pom.xml index d6191b83..739486ca 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -80,6 +80,11 @@ org.eclipse.jetty jetty-servlet + + com.twelvemonkeys.imageio + imageio-webp + 3.10.1 + diff --git a/client/src/main/java/ctbrec/ui/sites/streamray/AbstractStreamrayUpdateService.java b/client/src/main/java/ctbrec/ui/sites/streamray/AbstractStreamrayUpdateService.java index f38a04eb..0ae1f535 100644 --- a/client/src/main/java/ctbrec/ui/sites/streamray/AbstractStreamrayUpdateService.java +++ b/client/src/main/java/ctbrec/ui/sites/streamray/AbstractStreamrayUpdateService.java @@ -27,7 +27,7 @@ public abstract class AbstractStreamrayUpdateService extends PaginatedScheduledS protected String getPreviewURL(String name) { String lname = name.toLowerCase(); - String url = MessageFormat.format("https://images4.streamray.com/images/streamray/won/jpg/{0}/{1}/{2}_640.jpg", lname.substring(0, 1), lname.substring(lname.length() - 1), lname); + String url = MessageFormat.format("https://s3root.prod.cams.run/cams-d-com-production-model-snapshot/won/jpg/{0}/{1}/{2}.jpg", lname.substring(0,1), lname.substring(lname.length()-1), lname); try { return MessageFormat.format("https://dynimages.securedataimages.com/unsigned/rs:fill:640::0/g:no/plain/{0}@jpg", URLEncoder.encode(url, UTF_8)); } catch (Exception ex) { diff --git a/client/src/main/java/ctbrec/ui/tabs/ThumbCell.java b/client/src/main/java/ctbrec/ui/tabs/ThumbCell.java index 14d035eb..5784a3b9 100644 --- a/client/src/main/java/ctbrec/ui/tabs/ThumbCell.java +++ b/client/src/main/java/ctbrec/ui/tabs/ThumbCell.java @@ -47,6 +47,7 @@ import javafx.scene.shape.Shape; import javafx.scene.text.Text; import javafx.scene.text.TextAlignment; import javafx.util.Duration; +import javafx.embed.swing.SwingFXUtils; import okhttp3.Request; import okhttp3.Response; import org.slf4j.Logger; @@ -61,6 +62,9 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; + import static ctbrec.Model.State.OFFLINE; import static ctbrec.Model.State.ONLINE; import static ctbrec.io.HttpConstants.*; @@ -434,7 +438,8 @@ public class ThumbCell extends StackPane { double width = 480; double height = width * imgAspectRatio; InputStream bodyStream = Objects.requireNonNull(resp.body(), "HTTP body is null").byteStream(); - var img = new Image(bodyStream, width, height, preserveAspectRatio.get(), true); + BufferedImage bimg = ImageIO.read(bodyStream); + Image img = SwingFXUtils.toFXImage(bimg, null); if (img.progressProperty().get() == 1.0) { Platform.runLater(() -> { iv.setImage(img); diff --git a/common/src/main/java/ctbrec/sites/streamray/StreamrayModel.java b/common/src/main/java/ctbrec/sites/streamray/StreamrayModel.java index f5d1b4c4..0ddbe6f8 100644 --- a/common/src/main/java/ctbrec/sites/streamray/StreamrayModel.java +++ b/common/src/main/java/ctbrec/sites/streamray/StreamrayModel.java @@ -27,11 +27,14 @@ import java.time.LocalDate; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.concurrent.ExecutionException; +import java.net.URLEncoder; import static ctbrec.Model.State.*; import static ctbrec.io.HttpConstants.*; import static ctbrec.sites.streamray.Streamray.API_URL; +import static java.nio.charset.StandardCharsets.UTF_8; @Slf4j public class StreamrayModel extends AbstractModel { @@ -52,6 +55,9 @@ public class StreamrayModel extends AbstractModel { private transient JSONObject modelInfo; private transient Instant lastInfoRequest = Instant.EPOCH; + private transient JSONObject apiInfo; + private transient Instant lastApiRequest = Instant.EPOCH; + @Override public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException { if (ignoreCache) { @@ -101,10 +107,45 @@ public class StreamrayModel extends AbstractModel { } private String getMasterPlaylistUrl() throws IOException { - JSONObject json = getModelInfo(); - String mpp = json.getString("mpp"); String lname = getName().toLowerCase(); - return MessageFormat.format("https://stream14.cams.com/h5live/http/playlist.m3u8?url=rtmp%3A%2F%2F{0}%3A1935%2Fcams%2F{1}%3Fcams%2F{1}_720p&stream={2}", mpp, lname, getName()); + JSONObject apiInfo = getApiInfo(); + if (apiInfo.has("origin")) { + String origin = apiInfo.optString("origin"); + String appName = apiInfo.optString("applicationName", "origin"); + String token = apiInfo.optString("token"); + String streamUrl = MessageFormat.format("rtmp://{0}:1935/{1}/{2}?token={3}&site=cams.com", origin, appName, lname, token); + String streamName = lname; + if (appName.equals("webrtc")) { + streamName = lname + "_720p"; + } + String playlistURL = MessageFormat.format("https://stream14cdn.securedataimages.com/h5live/http/playlist.m3u8?url={0}&stream={1}", URLEncoder.encode(streamUrl, UTF_8), URLEncoder.encode(streamName, UTF_8)); + return playlistURL; + } else { + throw new IOException("Can not get master playlist url"); + } + } + + private JSONObject getApiInfo() throws IOException { + if (Objects.nonNull(apiInfo) && Duration.between(lastApiRequest, Instant.now()).getSeconds() < 5) { + return apiInfo; + } + lastApiRequest = Instant.now(); + String url = MessageFormat.format(API_URL + "/broadcasting/api/urls/anonymous/{0}/", URLEncoder.encode(getName().toLowerCase(), UTF_8)); + Request req = new Request.Builder().url(url) + .header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent) + .header(ACCEPT_LANGUAGE, "en") + .header(ORIGIN, getSite().getBaseUrl()) + .header(REFERER, getSite().getBaseUrl() + '/' + getName()) + .build(); + try (Response response = site.getHttpClient().execute(req)) { + if (response.isSuccessful()) { + JSONObject jsonResponse = new JSONObject(response.body().string()); + apiInfo = jsonResponse; + return apiInfo; + } else { + throw new HttpException(response.code(), response.message()); + } + } } @Override @@ -157,7 +198,7 @@ public class StreamrayModel extends AbstractModel { @Override public RecordingProcess createDownload() { - return new FfmpegHlsDownload(getSite().getHttpClient()); + return new FfmpegHlsDownload(new StreamrayHttpClient(Config.getInstance())); } @Override @@ -238,6 +279,8 @@ public class StreamrayModel extends AbstractModel { status = null; lastInfoRequest = Instant.EPOCH; modelInfo = null; + lastApiRequest = Instant.EPOCH; + apiInfo = null; } public boolean isNew() {