Add HTTP header factory to Cam4Model

The edge URL requires a Referer header as @gohufrapoc@mastodon.cloud found out. Otherwise you get a HTTP 403 error.
We also set a few other standard headers.
This commit is contained in:
0xb00bface 2021-01-09 13:50:51 +01:00
parent 7a36f49896
commit dc12e12dc0
2 changed files with 65 additions and 66 deletions

View File

@ -1,17 +1,5 @@
package ctbrec.sites.cam4;
import static ctbrec.io.HttpConstants.*;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.json.JSONArray;
import org.json.JSONObject;
import ctbrec.Config;
import ctbrec.Model;
import ctbrec.StringUtil;
@ -20,6 +8,18 @@ import ctbrec.io.HttpException;
import ctbrec.sites.AbstractSite;
import okhttp3.Request;
import okhttp3.Response;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static ctbrec.io.HttpClient.bodyToJsonObject;
import static ctbrec.io.HttpConstants.USER_AGENT;
public class Cam4 extends AbstractSite {
@ -130,7 +130,7 @@ public class Cam4 extends AbstractSite {
.build();
try(Response response = getHttpClient().execute(req)) {
if(response.isSuccessful()) {
String body = response.body().string();
String body = bodyToJsonObject(response);
JSONArray results = new JSONArray(body);
for (int i = 0; i < results.length(); i++) {
JSONObject result = results.getJSONObject(i);

View File

@ -1,46 +1,39 @@
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;
import java.util.ArrayList;
import java.util.Collections;
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.JSONObject;
import org.jsoup.nodes.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.iheartradio.m3u8.Encoding;
import com.iheartradio.m3u8.Format;
import com.iheartradio.m3u8.ParseException;
import com.iheartradio.m3u8.ParsingMode;
import com.iheartradio.m3u8.PlaylistException;
import com.iheartradio.m3u8.PlaylistParser;
import com.iheartradio.m3u8.*;
import com.iheartradio.m3u8.data.MasterPlaylist;
import com.iheartradio.m3u8.data.Playlist;
import com.iheartradio.m3u8.data.PlaylistData;
import com.iheartradio.m3u8.data.StreamInfo;
import ctbrec.AbstractModel;
import ctbrec.Config;
import ctbrec.StringUtil;
import ctbrec.io.HtmlParser;
import ctbrec.io.HttpException;
import ctbrec.recorder.download.HttpHeaderFactory;
import ctbrec.recorder.download.HttpHeaderFactoryImpl;
import ctbrec.recorder.download.StreamSource;
import okhttp3.FormBody;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.json.JSONObject;
import org.jsoup.nodes.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static ctbrec.Model.State.*;
import static ctbrec.io.HttpClient.bodyToJsonObject;
import static ctbrec.io.HttpConstants.*;
import static java.util.regex.Pattern.DOTALL;
import static java.util.regex.Pattern.MULTILINE;
public class Cam4Model extends AbstractModel {
@ -103,10 +96,7 @@ public class Cam4Model extends AbstractModel {
@Override
public State getOnlineState(boolean failFast) throws IOException, ExecutionException {
if(failFast) {
return onlineState;
} else {
if(onlineState == UNKNOWN) {
if (!failFast && onlineState == UNKNOWN) {
try {
loadModelDetails();
} catch (Exception e) {
@ -115,7 +105,6 @@ public class Cam4Model extends AbstractModel {
}
return onlineState;
}
}
private String getPlaylistUrl() throws IOException {
String page = loadModelPage();
@ -146,8 +135,8 @@ public class Cam4Model extends AbstractModel {
.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));
JSONObject json = new JSONObject(bodyToJsonObject(response));
if (LOG.isTraceEnabled()) LOG.trace(json.toString(2));
if (json.has("canUseCDN")) {
if (json.getBoolean("canUseCDN")) {
playlistUrl = json.getString("cdnURL");
@ -191,8 +180,7 @@ public class Cam4Model extends AbstractModel {
src.height = Optional.ofNullable(playlist.getStreamInfo()).map(StreamInfo::getResolution).map(res -> res.height).orElse(0);
String masterUrl = getPlaylistUrl();
String baseUrl = masterUrl.substring(0, masterUrl.lastIndexOf('/') + 1);
String segmentUri = baseUrl + playlist.getUri();
src.mediaPlaylistUrl = segmentUri;
src.mediaPlaylistUrl = baseUrl + playlist.getUri();
LOG.trace("Media playlist {}", src.mediaPlaylistUrl);
sources.add(src);
}
@ -201,19 +189,18 @@ public class Cam4Model extends AbstractModel {
}
private MasterPlaylist getMasterPlaylist() throws IOException, ParseException, PlaylistException {
String playlistUrl = getPlaylistUrl();
LOG.trace("Loading master playlist [{}]", playlistUrl);
Request req = new Request.Builder().url(playlistUrl).build();
String masterPlaylistUrl = getPlaylistUrl();
LOG.trace("Loading master playlist [{}]", masterPlaylistUrl);
Request req = new Request.Builder().url(masterPlaylistUrl).build();
try (Response response = site.getHttpClient().execute(req)) {
if (response.isSuccessful()) {
InputStream inputStream = response.body().byteStream();
PlaylistParser parser = new PlaylistParser(inputStream, Format.EXT_M3U, Encoding.UTF_8, ParsingMode.LENIENT);
Playlist playlist = parser.parse();
MasterPlaylist master = playlist.getMasterPlaylist();
return master;
return playlist.getMasterPlaylist();
} else {
throw new HttpException(response.code(), "Couldn't download HLS playlist " + playlistUrl);
throw new HttpException(response.code(), "Couldn't download HLS playlist " + masterPlaylistUrl);
}
}
}
@ -321,12 +308,6 @@ public class Cam4Model extends AbstractModel {
this.playlistUrl = playlistUrl;
}
public class ModelDetailsEmptyException extends Exception {
public ModelDetailsEmptyException(String msg) {
super(msg);
}
}
@Override
public void setUrl(String url) {
String normalizedUrl = url.toLowerCase();
@ -335,4 +316,22 @@ public class Cam4Model extends AbstractModel {
}
super.setUrl(normalizedUrl);
}
@Override
public HttpHeaderFactory getHttpHeaderFactory() {
HttpHeaderFactoryImpl fac = new HttpHeaderFactoryImpl();
Map<String, String> headers = new HashMap<>();
headers.put(ACCEPT, "*/*");
headers.put(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage());
headers.put(CONNECTION, KEEP_ALIVE);
if (getSite() != null) {
headers.put(ORIGIN, getSite().getBaseUrl());
headers.put(REFERER, getSite().getBaseUrl());
}
headers.put(USER_AGENT, Config.getInstance().getSettings().httpUserAgent);
fac.setMasterPlaylistHeaders(headers);
fac.setSegmentPlaylistHeaders(headers);
fac.setSegmentHeaders(headers);
return fac;
}
}