Fix BongaCams online check

This commit is contained in:
0xb00bface 2022-10-15 14:13:51 +02:00
parent a3fc1e31d4
commit 3ed7fd1aff
7 changed files with 271 additions and 313 deletions

View File

@ -1,16 +1,5 @@
package ctbrec.ui.sites.bonga;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.Objects;
import java.util.function.Consumer;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ctbrec.Config;
import ctbrec.sites.bonga.BongaCams;
import ctbrec.ui.ExternalBrowser;
@ -18,21 +7,32 @@ import okhttp3.Cookie;
import okhttp3.Cookie.Builder;
import okhttp3.CookieJar;
import okhttp3.HttpUrl;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Collections;
import java.util.Objects;
import java.util.function.Consumer;
public class BongaCamsElectronLoginDialog {
private static final Logger LOG = LoggerFactory.getLogger(BongaCamsElectronLoginDialog.class);
public static final String DOMAIN = "bongacams.com";
public static final String URL = BongaCams.baseUrl + "/login";
private final BongaCams site;
private CookieJar cookieJar;
private ExternalBrowser browser;
public BongaCamsElectronLoginDialog(CookieJar cookieJar) throws IOException {
public BongaCamsElectronLoginDialog(BongaCams site, CookieJar cookieJar) throws IOException {
this.site = site;
this.cookieJar = cookieJar;
browser = ExternalBrowser.getInstance();
try {
var config = new JSONObject();
config.put("url", URL);
config.put("url", site.getBaseUrl() + "/login");
config.put("w", 640);
config.put("h", 480);
var msg = new JSONObject();
@ -46,14 +46,14 @@ public class BongaCamsElectronLoginDialog {
}
}
private Consumer<String> msgHandler = line -> {
if(!line.startsWith("{")) {
private final Consumer<String> msgHandler = line -> {
if (!line.startsWith("{")) {
LOG.error("Didn't received a JSON object {}", line);
} else {
var json = new JSONObject(line);
if(json.has("url")) {
if (json.has("url")) {
var url = json.getString("url");
if(url.endsWith("/login")) {
if (url.endsWith("/login")) {
try {
Thread.sleep(500);
String username = Config.getInstance().getSettings().bongaUsername;
@ -65,7 +65,7 @@ public class BongaCamsElectronLoginDialog {
password = password.replace("'", "\\'");
browser.executeJavaScript("document.getElementById('log_in_password').value = '" + password + "';");
}
var simplify = new String[] {
var simplify = new String[]{
"$('div[class~=\"page_header\"]').css('display','none');",
"$('div[class~=\"header_bar\"]').css('display','none')",
"$('footer').css('display','none');",
@ -75,36 +75,36 @@ public class BongaCamsElectronLoginDialog {
for (String js : simplify) {
browser.executeJavaScript(js);
}
} catch(InterruptedException e) {
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LOG.warn("Couldn't auto fill username and password for BongaCams", e);
} catch(Exception e) {
} catch (Exception e) {
LOG.warn("Couldn't auto fill username and password for BongaCams", e);
}
}
if(json.has("cookies")) {
if (json.has("cookies")) {
var cookiesFromBrowser = json.getJSONArray("cookies");
for (var i = 0; i < cookiesFromBrowser.length(); i++) {
var cookie = cookiesFromBrowser.getJSONObject(i);
if(cookie.getString("domain").contains(DOMAIN)) {
if (cookie.getString("domain").contains(DOMAIN)) {
Builder b = new Cookie.Builder()
.path(cookie.getString("path"))
.domain(DOMAIN)
.name(cookie.getString("name"))
.value(cookie.getString("value"))
.expiresAt((long) cookie.optDouble("expirationDate"));
if(cookie.optBoolean("hostOnly")) {
if (cookie.optBoolean("hostOnly")) {
b.hostOnlyDomain(DOMAIN);
}
if(cookie.optBoolean("httpOnly")) {
if (cookie.optBoolean("httpOnly")) {
b.httpOnly();
}
if(cookie.optBoolean("secure")) {
if (cookie.optBoolean("secure")) {
b.secure();
}
Cookie c = b.build();
cookieJar.saveFromResponse(HttpUrl.parse(BongaCams.baseUrl), Collections.singletonList(c));
cookieJar.saveFromResponse(HttpUrl.parse(BongaCamsElectronLoginDialog.this.site.getBaseUrl()), Collections.singletonList(c));
}
}
}

View File

@ -1,16 +1,15 @@
package ctbrec.ui.sites.bonga;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ctbrec.sites.bonga.BongaCams;
import ctbrec.sites.bonga.BongaCamsHttpClient;
import ctbrec.ui.controls.Dialogs;
import ctbrec.ui.sites.AbstractSiteUi;
import ctbrec.ui.sites.ConfigUI;
import ctbrec.ui.tabs.TabProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
public class BongaCamsSiteUi extends AbstractSiteUi {
@ -47,7 +46,7 @@ public class BongaCamsSiteUi extends AbstractSiteUi {
} else {
// login with external browser window
try {
new BongaCamsElectronLoginDialog(bongaCams.getHttpClient().getCookieJar());
new BongaCamsElectronLoginDialog(bongaCams, bongaCams.getHttpClient().getCookieJar());
} catch (Exception e1) {
LOG.error("Error logging in with external browser", e1);
Dialogs.showError("Login error", "Couldn't login to " + bongaCams.getName(), e1);

View File

@ -23,32 +23,32 @@ public class BongaCamsTabProvider extends AbstractTabProvider {
List<Tab> tabs = new ArrayList<>();
// female
String url = BongaCams.baseUrl + "/tools/listing_v3.php?livetab=female&online_only=true&is_mobile=true&offset=";
String url = site.getBaseUrl() + "/tools/listing_v3.php?livetab=female&online_only=true&is_mobile=true&offset=";
var updateService = new BongaCamsUpdateService((BongaCams) site, url);
tabs.add(createTab("Female", updateService));
// male
url = BongaCams.baseUrl + "/tools/listing_v3.php?livetab=male&online_only=true&is_mobile=true&offset=";
url = site.getBaseUrl() + "/tools/listing_v3.php?livetab=male&online_only=true&is_mobile=true&offset=";
updateService = new BongaCamsUpdateService((BongaCams) site, url);
tabs.add(createTab("Male", updateService));
// couples
url = BongaCams.baseUrl + "/tools/listing_v3.php?livetab=couples&online_only=true&is_mobile=true&offset=";
url = site.getBaseUrl() + "/tools/listing_v3.php?livetab=couples&online_only=true&is_mobile=true&offset=";
updateService = new BongaCamsUpdateService((BongaCams) site, url);
tabs.add(createTab("Couples", updateService));
// trans
url = BongaCams.baseUrl + "/tools/listing_v3.php?livetab=transsexual&online_only=true&is_mobile=true&offset=";
url = site.getBaseUrl() + "/tools/listing_v3.php?livetab=transsexual&online_only=true&is_mobile=true&offset=";
updateService = new BongaCamsUpdateService((BongaCams) site, url);
tabs.add(createTab("Transsexual", updateService));
// new
url = BongaCams.baseUrl + "/tools/listing_v3.php?livetab=new&online_only=true&is_mobile=true&offset=";
url = site.getBaseUrl() + "/tools/listing_v3.php?livetab=new&online_only=true&is_mobile=true&offset=";
updateService = new BongaCamsUpdateService((BongaCams) site, url);
tabs.add(createTab("New", updateService));
// friends
url = BongaCams.baseUrl + "/tools/listing_v3.php?livetab=friends&online_only=true&offset=";
url = site.getBaseUrl() + "/tools/listing_v3.php?livetab=friends&online_only=true&offset=";
updateService = new BongaCamsUpdateService((BongaCams) site, url, true);
friendsTab = new BongaCamsFriendsTab("Friends", updateService, site);
friendsTab.setRecorder(recorder);

View File

@ -6,6 +6,7 @@ public class HttpConstants {
public static final String ACCEPT_ENCODING = "Accept-Encoding";
public static final String ACCEPT_ENCODING_GZIP = "gzip";
public static final String ACCEPT_LANGUAGE = "Accept-Language";
public static final String ALL = "*";
public static final String AUTHORIZATION = "Authorization";
public static final String CACHE_CONTROL = "Cache-Control";
public static final String CONNECTION = "Connection";

View File

@ -1,21 +1,5 @@
package ctbrec.sites.bonga;
import static ctbrec.io.HttpConstants.*;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ctbrec.Model;
import ctbrec.io.HttpClient;
import ctbrec.io.HttpException;
@ -24,12 +8,26 @@ import okhttp3.FormBody;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static ctbrec.ErrorMessages.HTTP_RESPONSE_BODY_IS_NULL;
import static ctbrec.io.HttpConstants.*;
import static java.nio.charset.StandardCharsets.UTF_8;
public class BongaCams extends AbstractSite {
private static final Logger LOG = LoggerFactory.getLogger(BongaCams.class);
public static String baseUrl = "https://bongacams.com";
private String baseUrl = "https://bongacams.com";
private BongaCamsHttpClient httpClient;
@ -50,7 +48,7 @@ public class BongaCams extends AbstractSite {
@Override
public String getAffiliateLink() {
return "http://bongacams2.com/track?c=610249";
return "https://bongacams10.com/track?c=610249";
}
@Override
@ -65,8 +63,8 @@ public class BongaCams extends AbstractSite {
@Override
public Double getTokenBalance() throws IOException {
int userId = ((BongaCamsHttpClient)getHttpClient()).getUserId();
String url = BongaCams.baseUrl + "/tools/amf.php";
int userId = ((BongaCamsHttpClient) getHttpClient()).getUserId();
String url = getBaseUrl() + "/tools/amf.php";
RequestBody body = new FormBody.Builder()
.add("method", "ping")
.add("args[]", Integer.toString(userId))
@ -76,14 +74,14 @@ public class BongaCams extends AbstractSite {
.addHeader(USER_AGENT, getConfig().getSettings().httpUserAgent)
.addHeader(ACCEPT, MIMETYPE_APPLICATION_JSON)
.addHeader(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage())
.addHeader(REFERER, BongaCams.baseUrl)
.addHeader(REFERER, getBaseUrl())
.addHeader(X_REQUESTED_WITH, XML_HTTP_REQUEST)
.post(body)
.build();
try(Response response = getHttpClient().execute(request)) {
if(response.isSuccessful()) {
JSONObject json = new JSONObject(response.body().string());
if(json.optString("status").equals("online")) {
try (Response response = getHttpClient().execute(request)) {
if (response.isSuccessful()) {
JSONObject json = new JSONObject(Objects.requireNonNull(response.body(), HTTP_RESPONSE_BODY_IS_NULL).string());
if (json.optString("status").equals("online")) {
JSONObject userData = json.getJSONObject("userData");
return (double) userData.getInt("balance");
} else {
@ -108,7 +106,7 @@ public class BongaCams extends AbstractSite {
@Override
public HttpClient getHttpClient() {
if (httpClient == null) {
httpClient = new BongaCamsHttpClient(getConfig());
httpClient = new BongaCamsHttpClient(this, getConfig());
}
return httpClient;
}
@ -142,39 +140,25 @@ public class BongaCams extends AbstractSite {
@Override
public List<Model> search(String q) throws IOException, InterruptedException {
String url = baseUrl + "/tools/listing_v3.php?offset=0&model_search[display_name][text]=" + URLEncoder.encode(q, "utf-8");
String url = baseUrl + "/tools/listing_v3.php?offset=0&model_search[display_name][text]=" + URLEncoder.encode(q, UTF_8);
Request req = new Request.Builder()
.url(url)
.addHeader(USER_AGENT, getConfig().getSettings().httpUserAgent)
.addHeader(ACCEPT, MIMETYPE_APPLICATION_JSON)
.addHeader(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage())
.addHeader(REFERER, BongaCams.baseUrl)
.addHeader(REFERER, getBaseUrl())
.addHeader(X_REQUESTED_WITH, XML_HTTP_REQUEST)
.build();
try(Response response = getHttpClient().execute(req)) {
if(response.isSuccessful()) {
String body = response.body().string();
try (Response response = getHttpClient().execute(req)) {
if (response.isSuccessful()) {
String body = Objects.requireNonNull(response.body(), HTTP_RESPONSE_BODY_IS_NULL).string();
JSONObject json = new JSONObject(body);
if(json.optString("status").equals("success")) {
if (json.optString("status").equals("success")) {
List<Model> models = new ArrayList<>();
JSONArray results = json.getJSONArray("models");
for (int i = 0; i < results.length(); i++) {
JSONObject result = results.getJSONObject(i);
if(result.has("username")) {
Model model = createModel(result.getString("username"));
String thumb = result.getString("thumb_image").replace("{ext}", "jpg");
if(thumb != null) {
model.setPreview("https:" + thumb);
}
if(result.has("display_name")) {
model.setDisplayName(result.getString("display_name"));
}
models.add(model);
}
}
parseModelList(models, json);
return models;
} else {
LOG.warn("Search result: " + json.toString(2));
LOG.warn("Search result: {}", json.toString(2));
return Collections.emptyList();
}
} else {
@ -183,6 +167,24 @@ public class BongaCams extends AbstractSite {
}
}
private void parseModelList(List<Model> models, JSONObject json) {
JSONArray results = json.getJSONArray("models");
for (int i = 0; i < results.length(); i++) {
JSONObject result = results.getJSONObject(i);
if (result.has("username")) {
Model model = createModel(result.getString("username"));
String thumb = result.getString("thumb_image").replace("{ext}", "jpg");
if (thumb != null) {
model.setPreview("https:" + thumb);
}
if (result.has("display_name")) {
model.setDisplayName(result.getString("display_name"));
}
models.add(model);
}
}
}
@Override
public boolean isSiteForModel(Model m) {
return m instanceof BongaCamsModel;
@ -197,7 +199,7 @@ public class BongaCams extends AbstractSite {
@Override
public Model createModelFromUrl(String url) {
Matcher m = Pattern.compile("https?://.*?bongacams.com(?:/profile)?/([^/]*?)/?").matcher(url);
if(m.matches()) {
if (m.matches()) {
String modelName = m.group(1);
return createModel(modelName);
} else {

View File

@ -1,36 +1,34 @@
package ctbrec.sites.bonga;
import static ctbrec.io.HttpConstants.*;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import ctbrec.Config;
import ctbrec.io.HttpClient;
import ctbrec.io.HttpException;
import okhttp3.*;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ctbrec.Config;
import ctbrec.io.HttpClient;
import ctbrec.io.HttpException;
import okhttp3.Cookie;
import okhttp3.FormBody;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import static ctbrec.ErrorMessages.HTTP_RESPONSE_BODY_IS_NULL;
import static ctbrec.io.HttpConstants.*;
public class BongaCamsHttpClient extends HttpClient {
private static final Logger LOG = LoggerFactory.getLogger(BongaCamsHttpClient.class);
private static final String SORT_COOKIE = "ls01";
private final BongaCams site;
private int userId = 0;
public BongaCamsHttpClient(Config config) {
public BongaCamsHttpClient(BongaCams site, Config config) {
super("bongacams", config);
this.site = site;
addSortByPopularCookie();
}
@ -48,24 +46,19 @@ public class BongaCamsHttpClient extends HttpClient {
Map<String, List<Cookie>> cookies = cookieJar.getCookies();
for (Entry<String, List<Cookie>> entry : cookies.entrySet()) {
List<Cookie> cookieList = entry.getValue();
for (Iterator<Cookie> iterator = cookieList.iterator(); iterator.hasNext();) {
Cookie cookie = iterator.next();
if(cookie.name().equals(SORT_COOKIE)) {
iterator.remove();
}
}
cookieList.removeIf(cookie -> cookie.name().equals(SORT_COOKIE));
entry.getValue().add(sortByCookie);
}
}
@Override
public synchronized boolean login() throws IOException {
if(loggedIn) {
if (loggedIn) {
return true;
}
boolean cookiesWorked = checkLoginSuccess();
if(cookiesWorked) {
if (cookiesWorked) {
loggedIn = true;
LOG.debug("Logged in with cookies");
return true;
@ -76,33 +69,32 @@ public class BongaCamsHttpClient extends HttpClient {
/**
* Check, if the login worked by requesting roomdata and looking
* @throws IOException
*
* @throws IOException if the roomdata couldn't be loaded
*/
public boolean checkLoginSuccess() throws IOException {
String modelName = getAnyModelName();
// we request the roomData of a random model, because it contains
// user data, if the user is logged in, which we can use to verify, that the login worked
String url = BongaCams.baseUrl + "/tools/amf.php";
String url = site.getBaseUrl() + "/tools/amf.php";
RequestBody body = new FormBody.Builder()
.add("method", "getRoomData")
.add("args[]", modelName)
.add("args[]", "false")
//.add("method", "ping") // TODO alternative request, but
//.add("args[]", <userId>) // where to get the userId
.build();
Request request = new Request.Builder()
.url(url)
.addHeader(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
.addHeader(ACCEPT, MIMETYPE_APPLICATION_JSON)
.addHeader(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage())
.addHeader(REFERER, BongaCams.baseUrl)
.addHeader(REFERER, site.getBaseUrl())
.addHeader(X_REQUESTED_WITH, XML_HTTP_REQUEST)
.post(body)
.build();
try(Response response = execute(request)) {
if(response.isSuccessful()) {
JSONObject json = new JSONObject(response.body().string());
if(json.optString("status").equals("success")) {
try (Response response = execute(request)) {
if (response.isSuccessful()) {
JSONObject json = new JSONObject(Objects.requireNonNull(response.body(), HTTP_RESPONSE_BODY_IS_NULL).string());
if (json.optString("status").equals("success")) {
JSONObject userData = json.getJSONObject("userData");
userId = userData.optInt("userId");
return userId > 0;
@ -120,23 +112,23 @@ public class BongaCamsHttpClient extends HttpClient {
*/
private String getAnyModelName() throws IOException {
Request request = new Request.Builder()
.url(BongaCams.baseUrl + "/tools/listing_v3.php?livetab=female&online_only=true&is_mobile=true&offset=0")
.url(site.getBaseUrl() + "/tools/listing_v3.php?livetab=female&online_only=true&is_mobile=true&offset=0")
.addHeader(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
.addHeader(ACCEPT, MIMETYPE_APPLICATION_JSON)
.addHeader(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage())
.addHeader(REFERER, BongaCams.baseUrl)
.addHeader(REFERER, site.getBaseUrl())
.addHeader(X_REQUESTED_WITH, XML_HTTP_REQUEST)
.build();
try(Response response = execute(request)) {
try (Response response = execute(request)) {
if (response.isSuccessful()) {
String content = response.body().string();
String content = Objects.requireNonNull(response.body(), HTTP_RESPONSE_BODY_IS_NULL).string();
JSONObject json = new JSONObject(content);
if(json.optString("status").equals("success")) {
if (json.optString("status").equals("success")) {
JSONArray jsonModels = json.getJSONArray("models");
JSONObject m = jsonModels.getJSONObject(0);
String name = m.getString("username");
return name;
} else {
} else {
throw new IOException("Request was not successful: " + content);
}
} else {
@ -145,45 +137,8 @@ public class BongaCamsHttpClient extends HttpClient {
}
}
// @Override
// public boolean login() throws IOException {
// String url = BongaCams.BASE_URL + "/login";
// String dateTime = new SimpleDateFormat("d.MM.yyyy', 'HH:mm:ss").format(new Date());
// RequestBody body = new FormBody.Builder()
// .add("security_log_additional_info","{\"language\":\"en\",\"cookieEnabled\":true,\"javaEnabled\":false,\"flashVersion\":\"31.0.0\",\"dateTime\":\""+dateTime+"\",\"ips\":[\"192.168.0.1\"]}")
// .add("log_in[username]", Config.getInstance().getSettings().bongaUsername)
// .add("log_in[password]", Config.getInstance().getSettings().bongaPassword)
// .add("log_in[remember]", "1")
// .add("log_in[bfpt]", "")
// .add("header_form", "1")
// .build();
// Request request = new Request.Builder()
// .url(url)
// .post(body)
// .addHeader(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
// .addHeader(ACCEPT,"application/json")
// .addHeader(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage())
// .addHeader(REFERER, BongaCams.BASE_URL)
// .addHeader(X_REQUESTED_WITH, XML_HTTP_REQUEST)
// .build();
// try(Response response = execute(request)) {
// if(response.isSuccessful()) {
// JSONObject json = new JSONObject(response.body().string());
// if(json.optString("status").equals("success")) {
// return true;
// } else {
// LOG.debug("Login response: {}", json.toString(2));
// Platform.runLater(() -> new BongaCamsLoginDialog());
// throw new IOException("Login not successful");
// }
// } else {
// throw new HttpException(response.code(), response.message());
// }
// }
// }
public int getUserId() throws IOException {
if(userId == 0) {
if (userId == 0) {
login();
}
return userId;

View File

@ -1,44 +1,34 @@
package ctbrec.sites.bonga;
import static ctbrec.Model.State.*;
import static ctbrec.io.HttpConstants.*;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutionException;
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.io.HtmlParser;
import ctbrec.io.HtmlParserException;
import ctbrec.io.HttpException;
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.ErrorMessages.HTTP_RESPONSE_BODY_IS_NULL;
import static ctbrec.Model.State.*;
import static ctbrec.io.HttpConstants.*;
public class BongaCamsModel extends AbstractModel {
@ -47,61 +37,87 @@ public class BongaCamsModel extends AbstractModel {
private static final String SUCCESS = "success";
private static final String STATUS = "status";
private int userId;
private static final Pattern ONLINE_BADGE_REGEX = Pattern.compile("class=\"badge_online\s*\"");
private boolean online = false;
private transient List<StreamSource> streamSources = new ArrayList<>();
private final transient List<StreamSource> streamSources = new ArrayList<>();
private int[] resolution;
@Override
public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException {
if (ignoreCache) {
String url = "https://en.bongacams.com/" + URLEncoder.encode(getName(), StandardCharsets.UTF_8.name());
Request req = new Request.Builder().url(url)
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
.header(ACCEPT, "*")
.header(ACCEPT_LANGUAGE, "en")
.header(REFERER, getSite().getBaseUrl())
.build();
try (Response resp = site.getHttpClient().execute(req)) {
String body = resp.body().string();
String chatType = parseChatType(body);
onlineState = mapState(chatType);
if (onlineState == ONLINE) {
if (isStreamAvailable()) {
online = true;
} else {
online = false;
onlineState = AWAY;
}
} else {
online = false;
}
boolean modelIsConnected = basicOnlineCheck();
if (!modelIsConnected) {
onlineState = OFFLINE;
online = false;
return false;
}
return completeOnlineCheck();
}
return online;
}
private String parseChatType(String body) {
String chatType = "";
if (body.contains("chatType")) {
try {
chatType = HtmlParser.getText(body, ".chatType");
} catch (HtmlParserException e) {
LOG.warn("Online check didn't work", e);
}
private boolean completeOnlineCheck() throws IOException {
JSONObject roomData = getRoomData();
if (!roomData.has("performerData")) {
onlineState = UNKNOWN;
return false;
}
return chatType;
JSONObject performerData = roomData.getJSONObject("performerData");
setDisplayName(performerData.optString("displayName"));
String chatType = performerData.optString("showType");
boolean isAway = performerData.optBoolean("isAway");
onlineState = mapState(chatType);
if (onlineState == ONLINE) {
if (isStreamAvailable()) {
if (isAway) {
onlineState = AWAY;
online = false;
} else {
online = true;
}
} else {
online = false;
onlineState = AWAY;
}
} else {
online = false;
}
return online;
}
private State mapState(String chatType) {
if (chatType.matches(".*? is in a public chat")) {
return ONLINE;
} else if (chatType.matches(".*? is in a group chat")) {
return GROUP;
} else if (chatType.matches(".*? is in a private chat")) {
return PRIVATE;
} else {
return OFFLINE;
private boolean basicOnlineCheck() {
try {
String url = site.getBaseUrl() + "/profile/" + getName().toLowerCase();
Request req = new Request.Builder().url(url).build();
try (Response resp = site.getHttpClient().execute(req)) {
if (resp.isSuccessful()) {
String body = Objects.requireNonNull(resp.body(), HTTP_RESPONSE_BODY_IS_NULL).string();
Matcher m = ONLINE_BADGE_REGEX.matcher(body);
return m.find();
} else {
return false;
}
}
} catch (Exception e) {
LOG.warn("Couldn't check if model is connected: {}", e.getLocalizedMessage());
return false;
}
}
public State mapState(String roomState) {
switch (roomState) {
case "private", "fullprivate":
return PRIVATE;
case "group":
return GROUP;
case "public":
return ONLINE;
default:
LOG.debug(roomState);
return OFFLINE;
}
}
@ -111,20 +127,20 @@ public class BongaCamsModel extends AbstractModel {
Request req = new Request.Builder().url(url).build();
try (Response resp = site.getHttpClient().execute(req)) {
if (resp.isSuccessful()) {
String body = resp.body().string();
String body = Objects.requireNonNull(resp.body(), HTTP_RESPONSE_BODY_IS_NULL).string();
return body.contains("#EXT-X-STREAM-INF");
} else {
return false;
}
}
} catch(Exception e) {
} catch (Exception e) {
LOG.warn("Couldn't check if stream is available: {}", e.getLocalizedMessage());
return false;
}
}
private JSONObject getRoomData() throws IOException {
String url = BongaCams.baseUrl + "/tools/amf.php";
String url = getSite().getBaseUrl() + "/tools/amf.php";
RequestBody body = new FormBody.Builder()
.add("method", "getRoomData")
.add(ARGS, getName())
@ -135,13 +151,13 @@ public class BongaCamsModel extends AbstractModel {
.addHeader(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
.addHeader(ACCEPT, MIMETYPE_APPLICATION_JSON)
.addHeader(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage())
.addHeader(REFERER, BongaCams.baseUrl)
.addHeader(REFERER, getSite().getBaseUrl())
.addHeader(X_REQUESTED_WITH, XML_HTTP_REQUEST)
.post(body)
.build();
try(Response response = site.getHttpClient().execute(request)) {
if(response.isSuccessful()) {
JSONObject json = new JSONObject(response.body().string());
try (Response response = site.getHttpClient().execute(request)) {
if (response.isSuccessful()) {
JSONObject json = new JSONObject(Objects.requireNonNull(response.body(), HTTP_RESPONSE_BODY_IS_NULL).string());
return json;
} else {
throw new IOException(response.code() + " " + response.message());
@ -155,9 +171,7 @@ public class BongaCamsModel extends AbstractModel {
@Override
public State getOnlineState(boolean failFast) throws IOException, ExecutionException {
if (failFast) {
return onlineState;
} else {
if (!failFast) {
try {
isOnline(true);
} catch (InterruptedException e) {
@ -166,8 +180,8 @@ public class BongaCamsModel extends AbstractModel {
} catch (IOException | ExecutionException e) {
onlineState = OFFLINE;
}
return onlineState;
}
return onlineState;
}
@Override
@ -179,28 +193,13 @@ public class BongaCamsModel extends AbstractModel {
public List<StreamSource> getStreamSources() throws IOException, ExecutionException, ParseException, PlaylistException {
String streamUrl = getStreamUrl();
Request req = new Request.Builder().url(streamUrl).build();
try(Response response = site.getHttpClient().execute(req)) {
if(response.isSuccessful()) {
InputStream inputStream = response.body().byteStream();
try (Response response = site.getHttpClient().execute(req)) {
if (response.isSuccessful()) {
InputStream inputStream = Objects.requireNonNull(response.body(), HTTP_RESPONSE_BODY_IS_NULL).byteStream();
PlaylistParser parser = new PlaylistParser(inputStream, Format.EXT_M3U, Encoding.UTF_8, ParsingMode.LENIENT);
Playlist playlist = parser.parse();
MasterPlaylist master = playlist.getMasterPlaylist();
streamSources.clear();
for (PlaylistData playlistData : master.getPlaylists()) {
StreamSource streamsource = new StreamSource();
streamsource.mediaPlaylistUrl = streamUrl.replace("playlist.m3u8", playlistData.getUri());
if (playlistData.hasStreamInfo()) {
StreamInfo info = playlistData.getStreamInfo();
streamsource.bandwidth = info.getBandwidth();
streamsource.width = info.hasResolution() ? info.getResolution().width : 0;
streamsource.height = info.hasResolution() ? info.getResolution().height : 0;
} else {
streamsource.bandwidth = 0;
streamsource.width = 0;
streamsource.height = 0;
}
streamSources.add(streamsource);
}
extractStreamSources(streamUrl, master);
} else {
throw new HttpException(response.code(), response.message());
}
@ -208,6 +207,25 @@ public class BongaCamsModel extends AbstractModel {
return streamSources;
}
private void extractStreamSources(String streamUrl, MasterPlaylist master) {
streamSources.clear();
for (PlaylistData playlistData : master.getPlaylists()) {
StreamSource streamsource = new StreamSource();
streamsource.mediaPlaylistUrl = streamUrl.replace("playlist.m3u8", playlistData.getUri());
if (playlistData.hasStreamInfo()) {
StreamInfo info = playlistData.getStreamInfo();
streamsource.bandwidth = info.getBandwidth();
streamsource.width = info.hasResolution() ? info.getResolution().width : 0;
streamsource.height = info.hasResolution() ? info.getResolution().height : 0;
} else {
streamsource.bandwidth = 0;
streamsource.width = 0;
streamsource.height = 0;
}
streamSources.add(streamsource);
}
}
private String getStreamUrl() throws IOException {
JSONObject roomData = getRoomData();
if (roomData.optString(STATUS).equals(SUCCESS)) {
@ -226,8 +244,8 @@ public class BongaCamsModel extends AbstractModel {
@Override
public void receiveTip(Double tokens) throws IOException {
String url = BongaCams.baseUrl + "/chat-ajax-amf-service?" + System.currentTimeMillis();
userId = ((BongaCamsHttpClient)site.getHttpClient()).getUserId();
String url = getSite().getBaseUrl() + "/chat-ajax-amf-service?" + System.currentTimeMillis();
int userId = ((BongaCamsHttpClient) site.getHttpClient()).getUserId();
RequestBody body = new FormBody.Builder()
.add("method", "tipModel")
.add(ARGS, getName())
@ -240,14 +258,14 @@ public class BongaCamsModel extends AbstractModel {
.addHeader(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
.addHeader(ACCEPT, MIMETYPE_APPLICATION_JSON)
.addHeader(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage())
.addHeader(REFERER, BongaCams.baseUrl + '/' + getName())
.addHeader(REFERER, getSite().getBaseUrl() + '/' + getName())
.addHeader(X_REQUESTED_WITH, XML_HTTP_REQUEST)
.post(body)
.build();
try(Response response = site.getHttpClient().execute(request)) {
if(response.isSuccessful()) {
JSONObject json = new JSONObject(response.body().string());
if(!json.optString(STATUS).equals(SUCCESS)) {
try (Response response = site.getHttpClient().execute(request)) {
if (response.isSuccessful()) {
JSONObject json = new JSONObject(Objects.requireNonNull(response.body(), HTTP_RESPONSE_BODY_IS_NULL).string());
if (!json.optString(STATUS).equals(SUCCESS)) {
LOG.error("Sending tip failed {}", json.toString(2));
throw new IOException("Sending tip failed");
}
@ -259,18 +277,18 @@ public class BongaCamsModel extends AbstractModel {
@Override
public int[] getStreamResolution(boolean failFast) throws ExecutionException {
if(resolution == null) {
if(failFast) {
if (resolution == null) {
if (failFast) {
return new int[2];
}
try {
if(!isOnline()) {
if (!isOnline()) {
return new int[2];
}
List<StreamSource> sources = getStreamSources();
Collections.sort(sources);
StreamSource best = sources.get(sources.size()-1);
resolution = new int[] {best.width, best.height};
StreamSource best = sources.get(sources.size() - 1);
resolution = new int[]{best.width, best.height};
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LOG.warn("Couldn't determine stream resolution for {} - {}", getName(), e.getMessage());
@ -279,15 +297,13 @@ public class BongaCamsModel extends AbstractModel {
LOG.warn("Couldn't determine stream resolution for {} - {}", getName(), e.getMessage());
resolution = new int[2];
}
return resolution;
} else {
return resolution;
}
return resolution;
}
@Override
public boolean follow() throws IOException {
if(!getSite().login()) {
if (!getSite().login()) {
throw new IOException("Not logged in");
}
@ -306,11 +322,11 @@ public class BongaCamsModel extends AbstractModel {
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
.header(X_REQUESTED_WITH, XML_HTTP_REQUEST)
.build();
try(Response resp = site.getHttpClient().execute(req)) {
if(resp.isSuccessful()) {
String msg = resp.body().string();
try (Response resp = site.getHttpClient().execute(req)) {
if (resp.isSuccessful()) {
String msg = Objects.requireNonNull(resp.body(), HTTP_RESPONSE_BODY_IS_NULL).string();
JSONObject json = new JSONObject(msg);
if(json.optBoolean(SUCCESS)) {
if (json.optBoolean(SUCCESS)) {
LOG.debug("Follow/Unfollow -> {}", msg);
return true;
} else {
@ -328,12 +344,12 @@ public class BongaCamsModel extends AbstractModel {
.url(getUrl())
.header(ACCEPT, "*/*")
.header(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage())
.header(REFERER, BongaCams.baseUrl)
.header(REFERER, getSite().getBaseUrl())
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
.build();
try(Response resp = site.getHttpClient().execute(req)) {
if(resp.isSuccessful()) {
String content = resp.body().string();
try (Response resp = site.getHttpClient().execute(req)) {
if (resp.isSuccessful()) {
String content = Objects.requireNonNull(resp.body(), HTTP_RESPONSE_BODY_IS_NULL).string();
Element html = HtmlParser.getTag(content, "html");
String csrfToken = html.attr("data-csrf_value");
LOG.debug("CSRF-Token {}", csrfToken);
@ -366,7 +382,7 @@ public class BongaCamsModel extends AbstractModel {
.build();
try (Response resp = site.getHttpClient().execute(req)) {
if (resp.isSuccessful()) {
String msg = resp.body().string();
String msg = Objects.requireNonNull(resp.body(), HTTP_RESPONSE_BODY_IS_NULL).string();
JSONObject json = new JSONObject(msg);
if (json.optBoolean(SUCCESS)) {
LOG.debug("Follow/Unfollow -> {}", msg);
@ -381,32 +397,17 @@ public class BongaCamsModel extends AbstractModel {
}
}
public int getUserId() throws IOException {
if (userId == 0) {
JSONObject roomData = getRoomData();
userId = roomData.getJSONObject("performerData").getInt("userId");
}
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public void mapOnlineState(String roomState) {
switch (roomState) {
case "private":
case "fullprivate":
setOnlineState(PRIVATE);
break;
case "group":
case "public":
setOnlineState(ONLINE);
setOnline(true);
break;
default:
LOG.debug(roomState);
setOnlineState(OFFLINE);
case "private", "fullprivate" -> setOnlineState(PRIVATE);
case "group", "public" -> {
setOnlineState(ONLINE);
setOnline(true);
}
default -> {
LOG.debug(roomState);
setOnlineState(OFFLINE);
}
}
}