diff --git a/CHANGELOG.md b/CHANGELOG.md index 226f2eee..f6a96470 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ * Added more category tabs for CamSoda * Added button to the "Recording" tab to go over all model URLs and check, if the account still exists +* Fix: some Cam4 models were not detected as online 3.10.8 ======================== diff --git a/common/src/main/java/ctbrec/sites/cam4/Cam4Model.java b/common/src/main/java/ctbrec/sites/cam4/Cam4Model.java index 239b5869..174cbc53 100644 --- a/common/src/main/java/ctbrec/sites/cam4/Cam4Model.java +++ b/common/src/main/java/ctbrec/sites/cam4/Cam4Model.java @@ -2,6 +2,7 @@ package ctbrec.sites.cam4; import static ctbrec.Model.State.*; import static ctbrec.io.HttpConstants.*; +import static java.util.regex.Pattern.*; import java.io.IOException; import java.io.InputStream; @@ -10,6 +11,8 @@ import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.concurrent.ExecutionException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.json.JSONArray; import org.json.JSONObject; @@ -51,7 +54,15 @@ public class Cam4Model extends AbstractModel { try { loadModelDetails(); } catch (ModelDetailsEmptyException e) { - return false; + // nothing to do, keep going + } + if (playlistUrl == null || onlineState == OFFLINE) { + try { + getPlaylistUrl(); + onlineState = ONLINE; + } catch (IOException e) { + return false; + } } } return onlineState == ONLINE && !privateRoom && playlistUrl != null && !playlistUrl.isEmpty(); @@ -126,19 +137,40 @@ public class Cam4Model extends AbstractModel { } private String getPlaylistUrl() throws IOException { - if(playlistUrl == null || playlistUrl.trim().isEmpty()) { - try { - loadModelDetails(); - if (playlistUrl == null) { - throw new IOException("Couldn't determine playlist url"); + if (playlistUrl == null || playlistUrl.trim().isEmpty()) { + String page = loadModelPage(); + Matcher m = Pattern.compile("hlsUrl\\s*:\\s*'(.*?)'", DOTALL | MULTILINE).matcher(page); + if (m.find()) { + playlistUrl = m.group(1); + } else { + m = Pattern.compile("\"videoPlayUrl\"\\s*:\\s*\"(.*?)\"", DOTALL | MULTILINE).matcher(page); + if (m.find()) { + String streamName = m.group(1); + m = Pattern.compile(".*?-(\\d{3,})-.*?").matcher(streamName); + if (m.find()) { + String number = m.group(1); + playlistUrl = "https://cam4-hls.xcdnpro.com/" + number + "/cam4-origin-live/ngrp:" + streamName + "_all/playlist.m3u8"; + } } - } catch (ModelDetailsEmptyException e) { - throw new IOException(e); + } + if (playlistUrl == null) { + throw new IOException("Couldn't determine playlist url"); } } return playlistUrl; } + private String loadModelPage() throws IOException { + Request req = new Request.Builder().url(getUrl()).build(); + try (Response response = site.getHttpClient().execute(req)) { + if (response.isSuccessful()) { + return response.body().string(); + } else { + throw new HttpException(response.code(), response.message()); + } + } + } + @Override public List getStreamSources() throws IOException, ExecutionException, ParseException, PlaylistException { MasterPlaylist masterPlaylist = getMasterPlaylist();