forked from j62/ctbrec
Add another playlist source for Cam4 models
This commit is contained in:
parent
c9cd6e825d
commit
672d2a77d4
|
@ -6,15 +6,12 @@ import static java.util.regex.Pattern.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.time.Duration;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@ -47,7 +44,6 @@ import okhttp3.Response;
|
||||||
public class Cam4Model extends AbstractModel {
|
public class Cam4Model extends AbstractModel {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(Cam4Model.class);
|
private static final Logger LOG = LoggerFactory.getLogger(Cam4Model.class);
|
||||||
private transient Instant playlistRequestTimestamp = Instant.EPOCH;
|
|
||||||
private String playlistUrl;
|
private String playlistUrl;
|
||||||
private int[] resolution = null;
|
private int[] resolution = null;
|
||||||
private boolean privateRoom = false;
|
private boolean privateRoom = false;
|
||||||
|
@ -121,34 +117,44 @@ public class Cam4Model extends AbstractModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getPlaylistUrl() throws IOException {
|
private String getPlaylistUrl() throws IOException {
|
||||||
if (playlistUrl == null || playlistUrl.trim().isEmpty() || playlistIsOutdated()) {
|
if (playlistUrl == null || playlistUrl.trim().isEmpty()) {
|
||||||
String page = loadModelPage();
|
String page = loadModelPage();
|
||||||
Matcher m = Pattern.compile("hlsUrl\\s*:\\s*'(.*?)'", DOTALL | MULTILINE).matcher(page);
|
Matcher m = Pattern.compile("hlsUrl\\s*:\\s*'(.*?)'", DOTALL | MULTILINE).matcher(page);
|
||||||
if (m.find()) {
|
if (m.find()) {
|
||||||
playlistUrl = m.group(1);
|
playlistUrl = m.group(1);
|
||||||
} else {
|
} else {
|
||||||
m = Pattern.compile("\"videoPlayUrl\"\\s*:\\s*\"(.*?)\"", DOTALL | MULTILINE).matcher(page);
|
getPlaylistUrlFromStreamUrl();
|
||||||
if (m.find()) {
|
|
||||||
generatePlaylistUrlFromStreamName(m.group(1));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (playlistUrl == null) {
|
if (playlistUrl == null) {
|
||||||
throw new IOException("Couldn't determine playlist url");
|
throw new IOException("Couldn't determine playlist url");
|
||||||
}
|
}
|
||||||
playlistRequestTimestamp = Instant.now();
|
|
||||||
}
|
}
|
||||||
return playlistUrl;
|
return playlistUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean playlistIsOutdated() {
|
private void getPlaylistUrlFromStreamUrl() throws IOException {
|
||||||
return Duration.between(playlistRequestTimestamp, Instant.now()).getSeconds() > TimeUnit.MINUTES.toSeconds(2);
|
String url = getSite().getBaseUrl() + "/_profile/streamURL?username=" + getName();
|
||||||
|
Request req = new Request.Builder() // @formatter:off
|
||||||
|
.url(url)
|
||||||
|
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
|
||||||
|
.header(ACCEPT, "*/*")
|
||||||
|
.header(ACCEPT_LANGUAGE, "*")
|
||||||
|
.header(REFERER, getUrl())
|
||||||
|
.build(); // @formatter:on
|
||||||
|
try (Response response = site.getHttpClient().execute(req)) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
JSONObject json = new JSONObject(response.body().string());
|
||||||
|
LOG.trace(json.toString(2));
|
||||||
|
if (json.has("canUseCDN")) {
|
||||||
|
if (json.getBoolean("canUseCDN")) {
|
||||||
|
playlistUrl = json.getString("cdnURL");
|
||||||
|
} else {
|
||||||
|
playlistUrl = json.getString("edgeURL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new HttpException(response.code(), response.message());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void generatePlaylistUrlFromStreamName(String streamName) {
|
|
||||||
Matcher 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";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,8 +190,9 @@ public class Cam4Model extends AbstractModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
private MasterPlaylist getMasterPlaylist() throws IOException, ParseException, PlaylistException {
|
private MasterPlaylist getMasterPlaylist() throws IOException, ParseException, PlaylistException {
|
||||||
LOG.trace("Loading master playlist [{}]", getPlaylistUrl());
|
String playlistUrl = getPlaylistUrl();
|
||||||
Request req = new Request.Builder().url(getPlaylistUrl()).build();
|
LOG.trace("Loading master playlist [{}]", playlistUrl);
|
||||||
|
Request req = new Request.Builder().url(playlistUrl).build();
|
||||||
|
|
||||||
try (Response response = site.getHttpClient().execute(req)) {
|
try (Response response = site.getHttpClient().execute(req)) {
|
||||||
if (response.isSuccessful()) {
|
if (response.isSuccessful()) {
|
||||||
|
@ -195,7 +202,7 @@ public class Cam4Model extends AbstractModel {
|
||||||
MasterPlaylist master = playlist.getMasterPlaylist();
|
MasterPlaylist master = playlist.getMasterPlaylist();
|
||||||
return master;
|
return master;
|
||||||
} else {
|
} else {
|
||||||
throw new HttpException(response.code(), "Couldn't download HLS playlist");
|
throw new HttpException(response.code(), "Couldn't download HLS playlist " + playlistUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue