Add BongaCams
This is the first working version. Follow / unfollow and tipping are not implemented.
This commit is contained in:
parent
29ed8648e4
commit
1fec124bbc
|
@ -20,6 +20,7 @@ import ctbrec.Config;
|
|||
import ctbrec.recorder.LocalRecorder;
|
||||
import ctbrec.recorder.Recorder;
|
||||
import ctbrec.sites.Site;
|
||||
import ctbrec.sites.bonga.BongaCams;
|
||||
import ctbrec.sites.cam4.Cam4;
|
||||
import ctbrec.sites.camsoda.Camsoda;
|
||||
import ctbrec.sites.chaturbate.Chaturbate;
|
||||
|
@ -66,6 +67,7 @@ public class HttpServer {
|
|||
sites.add(new MyFreeCams());
|
||||
sites.add(new Camsoda());
|
||||
sites.add(new Cam4());
|
||||
sites.add(new BongaCams());
|
||||
}
|
||||
|
||||
private void addShutdownHook() {
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
package ctbrec.sites.bonga;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ctbrec.Model;
|
||||
import ctbrec.io.HttpClient;
|
||||
import ctbrec.recorder.Recorder;
|
||||
import ctbrec.sites.AbstractSite;
|
||||
import ctbrec.ui.TabProvider;
|
||||
import javafx.scene.Node;
|
||||
|
||||
public class BongaCams extends AbstractSite {
|
||||
|
||||
public static final String BASE_URL = "https://bongacams.com";
|
||||
|
||||
private BongaCamsHttpClient httpClient;
|
||||
|
||||
private Recorder recorder;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "BongaCams";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBaseUrl() {
|
||||
return BASE_URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAffiliateLink() {
|
||||
return BASE_URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRecorder(Recorder recorder) {
|
||||
this.recorder = recorder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TabProvider getTabProvider() {
|
||||
return new BongaCamsTabProvider(recorder, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Model createModel(String name) {
|
||||
BongaCamsModel model = new BongaCamsModel();
|
||||
model.setName(name);
|
||||
model.setUrl(BASE_URL + '/' + name);
|
||||
model.setDescription("");
|
||||
model.setSite(this);
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getTokenBalance() throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBuyTokensLink() {
|
||||
// TODO Auto-generated method stub
|
||||
return getBaseUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void login() throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpClient getHttpClient() {
|
||||
if(httpClient == null) {
|
||||
httpClient = new BongaCamsHttpClient();
|
||||
}
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTips() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFollow() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSiteForModel(Model m) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getConfigurationGui() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean credentialsAvailable() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package ctbrec.sites.bonga;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ctbrec.io.HttpClient;
|
||||
|
||||
public class BongaCamsHttpClient extends HttpClient {
|
||||
|
||||
@Override
|
||||
public boolean login() throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,193 @@
|
|||
package ctbrec.sites.bonga;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.json.JSONObject;
|
||||
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.PlaylistException;
|
||||
import com.iheartradio.m3u8.PlaylistParser;
|
||||
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.recorder.download.StreamSource;
|
||||
import ctbrec.sites.Site;
|
||||
import okhttp3.FormBody;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class BongaCamsModel extends AbstractModel {
|
||||
|
||||
private static final transient Logger LOG = LoggerFactory.getLogger(BongaCamsModel.class);
|
||||
|
||||
private BongaCams site;
|
||||
private int userId;
|
||||
private String onlineState = "n/a";
|
||||
private boolean online = false;
|
||||
private List<StreamSource> streamSources = new ArrayList<>();
|
||||
private int[] resolution;
|
||||
|
||||
@Override
|
||||
public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException {
|
||||
return online;
|
||||
}
|
||||
|
||||
public void setOnline(boolean online) {
|
||||
this.online = online;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOnlineState(boolean failFast) throws IOException, ExecutionException {
|
||||
return onlineState;
|
||||
}
|
||||
|
||||
public void setOnlineState(String onlineState) {
|
||||
this.onlineState = onlineState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StreamSource> getStreamSources() throws IOException, ExecutionException, ParseException, PlaylistException {
|
||||
String streamUrl = getStreamUrl();
|
||||
if (streamUrl == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Request req = new Request.Builder().url(streamUrl).build();
|
||||
Response response = site.getHttpClient().execute(req);
|
||||
try {
|
||||
InputStream inputStream = response.body().byteStream();
|
||||
PlaylistParser parser = new PlaylistParser(inputStream, Format.EXT_M3U, Encoding.UTF_8);
|
||||
Playlist playlist = parser.parse();
|
||||
MasterPlaylist master = playlist.getMasterPlaylist();
|
||||
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);
|
||||
}
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
return streamSources;
|
||||
}
|
||||
|
||||
private String getStreamUrl() throws IOException {
|
||||
String url = BongaCams.BASE_URL + "/tools/amf.php";
|
||||
RequestBody body = new FormBody.Builder()
|
||||
.add("method", "getRoomData")
|
||||
.add("args[]", getName())
|
||||
.add("args[]", "false")
|
||||
.build();
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.addHeader("User-Agent", "Mozilla/5.0 (Android 9.0; Mobile; rv:61.0) Gecko/61.0 Firefox/61.0")
|
||||
.addHeader("Accept", "application/json, text/javascript, */*")
|
||||
.addHeader("Accept-Language", "en")
|
||||
.addHeader("Referer", BongaCams.BASE_URL)
|
||||
.addHeader("X-Requested-With", "XMLHttpRequest")
|
||||
.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")) {
|
||||
JSONObject localData = json.getJSONObject("localData");
|
||||
String server = localData.getString("videoServerUrl");
|
||||
return "https:" + server + "/hls/stream_" + getName() + "/playlist.m3u8";
|
||||
} else {
|
||||
throw new IOException("Request was not successful: " + json.toString(2));
|
||||
}
|
||||
} else {
|
||||
throw new IOException(response.code() + " " + response.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCacheEntries() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveTip(int tokens) throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getStreamResolution(boolean failFast) throws ExecutionException {
|
||||
if(resolution == null) {
|
||||
if(failFast) {
|
||||
return new int[2];
|
||||
}
|
||||
try {
|
||||
List<StreamSource> streamSources = getStreamSources();
|
||||
Collections.sort(streamSources);
|
||||
StreamSource best = streamSources.get(streamSources.size()-1);
|
||||
resolution = new int[] {best.width, best.height};
|
||||
} catch (ExecutionException | IOException | ParseException | PlaylistException e) {
|
||||
LOG.error("Couldn't determine stream resolution", e);
|
||||
}
|
||||
return resolution;
|
||||
} else {
|
||||
return resolution;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean follow() throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unfollow() throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSite(Site site) {
|
||||
if(site instanceof BongaCams) {
|
||||
this.site = (BongaCams) site;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Site has to be an instance of BongaCams");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Site getSite() {
|
||||
return site;
|
||||
}
|
||||
|
||||
public int getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(int userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package ctbrec.sites.bonga;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ctbrec.recorder.Recorder;
|
||||
import ctbrec.ui.PaginatedScheduledService;
|
||||
import ctbrec.ui.TabProvider;
|
||||
import ctbrec.ui.ThumbOverviewTab;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Tab;
|
||||
|
||||
public class BongaCamsTabProvider extends TabProvider {
|
||||
|
||||
private BongaCams bongaCams;
|
||||
private Recorder recorder;
|
||||
|
||||
public BongaCamsTabProvider(Recorder recorder, BongaCams bongaCams) {
|
||||
this.recorder = recorder;
|
||||
this.bongaCams = bongaCams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Tab> getTabs(Scene scene) {
|
||||
List<Tab> tabs = new ArrayList<>();
|
||||
|
||||
BongaCamsUpdateService updateService = new BongaCamsUpdateService(bongaCams);
|
||||
tabs.add(createTab("Online", updateService));
|
||||
|
||||
return tabs;
|
||||
}
|
||||
|
||||
private Tab createTab(String title, PaginatedScheduledService updateService) {
|
||||
ThumbOverviewTab tab = new ThumbOverviewTab(title, updateService, bongaCams);
|
||||
tab.setRecorder(recorder);
|
||||
return tab;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package ctbrec.sites.bonga;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ctbrec.Model;
|
||||
import ctbrec.ui.PaginatedScheduledService;
|
||||
import javafx.concurrent.Task;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class BongaCamsUpdateService extends PaginatedScheduledService {
|
||||
|
||||
private static final transient Logger LOG = LoggerFactory.getLogger(BongaCamsUpdateService.class);
|
||||
|
||||
private BongaCams bongaCams;
|
||||
|
||||
public BongaCamsUpdateService(BongaCams bongaCams) {
|
||||
this.bongaCams = bongaCams;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Task<List<Model>> createTask() {
|
||||
return new Task<List<Model>>() {
|
||||
@Override
|
||||
public List<Model> call() throws IOException {
|
||||
String url = BongaCams.BASE_URL + "/tools/listing_v3.php?livetab=female&online_only=true&is_mobile=true&offset=" + ((page-1) * 50);
|
||||
LOG.debug("Fetching page {}", url);
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.addHeader("User-Agent", "Mozilla/5.0 (Android 9.0; Mobile; rv:61.0) Gecko/61.0 Firefox/61.0")
|
||||
.addHeader("Accept", "application/json, text/javascript, */*")
|
||||
.addHeader("Accept-Language", "en")
|
||||
.addHeader("Referer", bongaCams.getBaseUrl())
|
||||
.addHeader("X-Requested-With", "XMLHttpRequest")
|
||||
.build();
|
||||
Response response = bongaCams.getHttpClient().execute(request);
|
||||
if (response.isSuccessful()) {
|
||||
String content = response.body().string();
|
||||
response.close();
|
||||
List<Model> models = new ArrayList<>();
|
||||
JSONObject json = new JSONObject(content);
|
||||
if(json.optString("status").equals("success")) {
|
||||
JSONArray _models = json.getJSONArray("models");
|
||||
for (int i = 0; i < _models.length(); i++) {
|
||||
JSONObject m = _models.getJSONObject(i);
|
||||
String name = m.getString("username");
|
||||
BongaCamsModel model = (BongaCamsModel) bongaCams.createModel(name);
|
||||
model.setUserId(m.getInt("user_id"));
|
||||
model.setOnlineState(m.getString("room"));
|
||||
model.setOnline(m.optBoolean("online") && !m.optBoolean("is_away"));
|
||||
model.setPreview("https:" + m.getString("thumb_image"));
|
||||
models.add(model);
|
||||
}
|
||||
}
|
||||
return models;
|
||||
} else {
|
||||
int code = response.code();
|
||||
response.close();
|
||||
throw new IOException("HTTP status " + code);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ import ctbrec.recorder.LocalRecorder;
|
|||
import ctbrec.recorder.Recorder;
|
||||
import ctbrec.recorder.RemoteRecorder;
|
||||
import ctbrec.sites.Site;
|
||||
import ctbrec.sites.bonga.BongaCams;
|
||||
import ctbrec.sites.cam4.Cam4;
|
||||
import ctbrec.sites.camsoda.Camsoda;
|
||||
import ctbrec.sites.chaturbate.Chaturbate;
|
||||
|
@ -64,6 +65,7 @@ public class CamrecApplication extends Application {
|
|||
sites.add(new MyFreeCams());
|
||||
sites.add(new Camsoda());
|
||||
sites.add(new Cam4());
|
||||
sites.add(new BongaCams());
|
||||
loadConfig();
|
||||
createHttpClient();
|
||||
bus = new AsyncEventBus(Executors.newSingleThreadExecutor());
|
||||
|
|
Loading…
Reference in New Issue