Add interfaces to abstract from camsite
This step should enable the application to handle different camsites. At the moment only chaturbate is available, but others like MFC can now be added. There might be still some things to do, like the settings and HttpClient etc. But this is the first step to support more sites than only Chatubate.
This commit is contained in:
parent
c7d55c6fe0
commit
54de1339fb
|
@ -27,5 +27,8 @@ public interface Model {
|
||||||
public String getOnlineState(boolean failFast) throws IOException, ExecutionException;
|
public String getOnlineState(boolean failFast) throws IOException, ExecutionException;
|
||||||
public List<StreamSource> getStreamSources() throws IOException, ExecutionException, ParseException, PlaylistException;
|
public List<StreamSource> getStreamSources() throws IOException, ExecutionException, ParseException, PlaylistException;
|
||||||
public String getSegmentPlaylistUrl() throws IOException, ExecutionException, ParseException, PlaylistException;
|
public String getSegmentPlaylistUrl() throws IOException, ExecutionException, ParseException, PlaylistException;
|
||||||
|
public void invalidateCacheEntries();
|
||||||
|
public void receiveTip(int tokens) throws IOException;
|
||||||
|
public int[] getStreamResolution(boolean failFast) throws ExecutionException;
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package ctbrec;
|
||||||
|
|
||||||
|
import ctbrec.recorder.Recorder;
|
||||||
|
import ctbrec.ui.TabProvider;
|
||||||
|
|
||||||
|
public interface Site {
|
||||||
|
public String getName();
|
||||||
|
public String getBaseUrl();
|
||||||
|
public String getAffiliateLink();
|
||||||
|
public void setRecorder(Recorder recorder);
|
||||||
|
public TabProvider getTabProvider();
|
||||||
|
public Model createModel(String name);
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ import org.slf4j.LoggerFactory;
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.Settings.ProxyType;
|
import ctbrec.Settings.ProxyType;
|
||||||
import ctbrec.ui.CookieJarImpl;
|
import ctbrec.ui.CookieJarImpl;
|
||||||
import ctbrec.ui.CtbrecApplication;
|
import ctbrec.ui.CamrecApplication;
|
||||||
import ctbrec.ui.HtmlParser;
|
import ctbrec.ui.HtmlParser;
|
||||||
import okhttp3.ConnectionPool;
|
import okhttp3.ConnectionPool;
|
||||||
import okhttp3.Cookie;
|
import okhttp3.Cookie;
|
||||||
|
@ -122,7 +122,7 @@ public class HttpClient {
|
||||||
public boolean login() throws IOException {
|
public boolean login() throws IOException {
|
||||||
try {
|
try {
|
||||||
Request login = new Request.Builder()
|
Request login = new Request.Builder()
|
||||||
.url(CtbrecApplication.BASE_URI + "/auth/login/")
|
.url(CamrecApplication.BASE_URI + "/auth/login/")
|
||||||
.build();
|
.build();
|
||||||
Response response = client.newCall(login).execute();
|
Response response = client.newCall(login).execute();
|
||||||
String content = response.body().string();
|
String content = response.body().string();
|
||||||
|
@ -136,8 +136,8 @@ public class HttpClient {
|
||||||
.add("csrfmiddlewaretoken", token)
|
.add("csrfmiddlewaretoken", token)
|
||||||
.build();
|
.build();
|
||||||
login = new Request.Builder()
|
login = new Request.Builder()
|
||||||
.url(CtbrecApplication.BASE_URI + "/auth/login/")
|
.url(CamrecApplication.BASE_URI + "/auth/login/")
|
||||||
.header("Referer", CtbrecApplication.BASE_URI + "/auth/login/")
|
.header("Referer", CamrecApplication.BASE_URI + "/auth/login/")
|
||||||
.post(body)
|
.post(body)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,7 @@ import ctbrec.recorder.PlaylistGenerator.InvalidPlaylistException;
|
||||||
import ctbrec.recorder.download.Download;
|
import ctbrec.recorder.download.Download;
|
||||||
import ctbrec.recorder.download.HlsDownload;
|
import ctbrec.recorder.download.HlsDownload;
|
||||||
import ctbrec.recorder.download.MergedHlsDownload;
|
import ctbrec.recorder.download.MergedHlsDownload;
|
||||||
import ctbrec.sites.chaturbate.ChaturbateModel;
|
import ctbrec.sites.chaturbate.ChaturbateModelParser;
|
||||||
import ctbrec.sites.chaturbate.ModelParser;
|
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
@ -270,10 +269,10 @@ public class LocalRecorder implements Recorder {
|
||||||
Request request = new Request.Builder().url(url).build();
|
Request request = new Request.Builder().url(url).build();
|
||||||
Response response = client.execute(request, true);
|
Response response = client.execute(request, true);
|
||||||
if (response.isSuccessful()) {
|
if (response.isSuccessful()) {
|
||||||
List<ChaturbateModel> followed = ModelParser.parseModels(response.body().string());
|
List<Model> followed = ChaturbateModelParser.parseModels(response.body().string());
|
||||||
response.close();
|
response.close();
|
||||||
followedModels.clear();
|
followedModels.clear();
|
||||||
for (ChaturbateModel model : followed) {
|
for (Model model : followed) {
|
||||||
if (!followedModels.contains(model) && !models.contains(model)) {
|
if (!followedModels.contains(model) && !models.contains(model)) {
|
||||||
LOG.info("Model {} added", model);
|
LOG.info("Model {} added", model);
|
||||||
followedModels.add(model);
|
followedModels.add(model);
|
||||||
|
|
|
@ -25,7 +25,6 @@ import ctbrec.Recording;
|
||||||
import ctbrec.io.InstantJsonAdapter;
|
import ctbrec.io.InstantJsonAdapter;
|
||||||
import ctbrec.io.ModelJsonAdapter;
|
import ctbrec.io.ModelJsonAdapter;
|
||||||
import ctbrec.recorder.Recorder;
|
import ctbrec.recorder.Recorder;
|
||||||
import ctbrec.sites.chaturbate.ChaturbateModel;
|
|
||||||
|
|
||||||
public class RecorderServlet extends AbstractCtbrecServlet {
|
public class RecorderServlet extends AbstractCtbrecServlet {
|
||||||
|
|
||||||
|
@ -74,7 +73,7 @@ public class RecorderServlet extends AbstractCtbrecServlet {
|
||||||
break;
|
break;
|
||||||
case "list":
|
case "list":
|
||||||
resp.getWriter().write("{\"status\": \"success\", \"msg\": \"List of models\", \"models\": [");
|
resp.getWriter().write("{\"status\": \"success\", \"msg\": \"List of models\", \"models\": [");
|
||||||
JsonAdapter<Model> modelAdapter = moshi.adapter(Model.class);
|
JsonAdapter<Model> modelAdapter = new ModelJsonAdapter();
|
||||||
List<Model> models = recorder.getModelsRecording();
|
List<Model> models = recorder.getModelsRecording();
|
||||||
for (Iterator<Model> iterator = models.iterator(); iterator.hasNext();) {
|
for (Iterator<Model> iterator = models.iterator(); iterator.hasNext();) {
|
||||||
Model model = iterator.next();
|
Model model = iterator.next();
|
||||||
|
@ -133,7 +132,7 @@ public class RecorderServlet extends AbstractCtbrecServlet {
|
||||||
|
|
||||||
private static class Request {
|
private static class Request {
|
||||||
public String action;
|
public String action;
|
||||||
public ChaturbateModel model;
|
public Model model;
|
||||||
public String recording;
|
public String recording;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package ctbrec.sites.chaturbate;
|
||||||
|
|
||||||
|
import ctbrec.Model;
|
||||||
|
import ctbrec.Site;
|
||||||
|
import ctbrec.recorder.Recorder;
|
||||||
|
import ctbrec.ui.TabProvider;
|
||||||
|
|
||||||
|
public class Chaturbate implements Site {
|
||||||
|
|
||||||
|
private Recorder recorder;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Chaturbate";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getBaseUrl() {
|
||||||
|
return "https://chaturbate.com";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAffiliateLink() {
|
||||||
|
return getBaseUrl() + "/in/?track=default&tour=LQps&campaign=55vTi&room=0xb00bface";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TabProvider getTabProvider() {
|
||||||
|
return new ChaturbateTabProvider(this, recorder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRecorder(Recorder recorder) {
|
||||||
|
this.recorder = recorder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Model createModel(String name) {
|
||||||
|
ChaturbateModel m = new ChaturbateModel();
|
||||||
|
m.setName(name);
|
||||||
|
m.setUrl(getBaseUrl() + '/' + name + '/');
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
}
|
|
@ -55,23 +55,25 @@ public class ChaturbateModel extends AbstractModel {
|
||||||
return Objects.equals("public", info.room_status);
|
return Objects.equals("public", info.room_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int[] getStreamResolution(boolean failFast) throws ExecutionException {
|
public int[] getStreamResolution(boolean failFast) throws ExecutionException {
|
||||||
int[] resolution = Chaturbate.INSTANCE.streamResolutionCache.getIfPresent(getName());
|
int[] resolution = Chaturbate.INSTANCE.streamResolutionCache.getIfPresent(getName());
|
||||||
if(resolution != null) {
|
if(resolution != null) {
|
||||||
return Chaturbate.INSTANCE.getResolution(getName());
|
return Chaturbate.INSTANCE.getResolution(getName());
|
||||||
} else {
|
} else {
|
||||||
return new int[2];
|
if(failFast) {
|
||||||
|
return new int[2];
|
||||||
|
} else {
|
||||||
|
return Chaturbate.INSTANCE.getResolution(getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int[] getStreamResolution() throws ExecutionException {
|
|
||||||
return Chaturbate.INSTANCE.getResolution(getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invalidates the entries in StreamInfo and resolution cache for this model
|
* Invalidates the entries in StreamInfo and resolution cache for this model
|
||||||
* and thus causes causes the LoadingCache to update them
|
* and thus causes causes the LoadingCache to update them
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public void invalidateCacheEntries() {
|
public void invalidateCacheEntries() {
|
||||||
Chaturbate.INSTANCE.streamInfoCache.invalidate(getName());
|
Chaturbate.INSTANCE.streamInfoCache.invalidate(getName());
|
||||||
Chaturbate.INSTANCE.streamResolutionCache.invalidate(getName());
|
Chaturbate.INSTANCE.streamResolutionCache.invalidate(getName());
|
||||||
|
@ -94,6 +96,7 @@ public class ChaturbateModel extends AbstractModel {
|
||||||
return Chaturbate.INSTANCE.getMasterPlaylist(getName());
|
return Chaturbate.INSTANCE.getMasterPlaylist(getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void receiveTip(int tokens) throws IOException {
|
public void receiveTip(int tokens) throws IOException {
|
||||||
Chaturbate.INSTANCE.sendTip(getName(), tokens);
|
Chaturbate.INSTANCE.sendTip(getName(), tokens);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package ctbrec.sites.chaturbate;
|
package ctbrec.sites.chaturbate;
|
||||||
|
|
||||||
import static ctbrec.ui.CtbrecApplication.BASE_URI;
|
import static ctbrec.ui.CamrecApplication.BASE_URI;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -10,18 +10,19 @@ import org.jsoup.select.Elements;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import ctbrec.Model;
|
||||||
import ctbrec.ui.HtmlParser;
|
import ctbrec.ui.HtmlParser;
|
||||||
|
|
||||||
public class ModelParser {
|
public class ChaturbateModelParser {
|
||||||
private static final transient Logger LOG = LoggerFactory.getLogger(ModelParser.class);
|
private static final transient Logger LOG = LoggerFactory.getLogger(ChaturbateModelParser.class);
|
||||||
|
|
||||||
public static List<ChaturbateModel> parseModels(String html) {
|
public static List<Model> parseModels(String html) {
|
||||||
List<ChaturbateModel> models = new ArrayList<>();
|
List<Model> models = new ArrayList<>();
|
||||||
Elements cells = HtmlParser.getTags(html, "ul.list > li");
|
Elements cells = HtmlParser.getTags(html, "ul.list > li");
|
||||||
for (Element cell : cells) {
|
for (Element cell : cells) {
|
||||||
String cellHtml = cell.html();
|
String cellHtml = cell.html();
|
||||||
try {
|
try {
|
||||||
ChaturbateModel model = new ChaturbateModel();
|
Model model = new ChaturbateModel();
|
||||||
model.setName(HtmlParser.getText(cellHtml, "div.title > a").trim());
|
model.setName(HtmlParser.getText(cellHtml, "div.title > a").trim());
|
||||||
model.setPreview(HtmlParser.getTag(cellHtml, "a img").attr("src"));
|
model.setPreview(HtmlParser.getTag(cellHtml, "a img").attr("src"));
|
||||||
model.setUrl(BASE_URI + HtmlParser.getTag(cellHtml, "a").attr("href"));
|
model.setUrl(BASE_URI + HtmlParser.getTag(cellHtml, "a").attr("href"));
|
|
@ -0,0 +1,45 @@
|
||||||
|
package ctbrec.sites.chaturbate;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ctbrec.recorder.Recorder;
|
||||||
|
import ctbrec.ui.FollowedTab;
|
||||||
|
import ctbrec.ui.TabProvider;
|
||||||
|
import ctbrec.ui.ThumbOverviewTab;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.control.Tab;
|
||||||
|
|
||||||
|
public class ChaturbateTabProvider extends TabProvider {
|
||||||
|
|
||||||
|
private Chaturbate chaturbate;
|
||||||
|
private Recorder recorder;
|
||||||
|
|
||||||
|
public ChaturbateTabProvider(Chaturbate chaturbate, Recorder recorder) {
|
||||||
|
this.chaturbate = chaturbate;
|
||||||
|
this.recorder = recorder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Tab> getTabs(Scene scene) {
|
||||||
|
final String BASE_URI = chaturbate.getBaseUrl();
|
||||||
|
List<Tab> tabs = new ArrayList<>();
|
||||||
|
tabs.add(createTab("Featured", BASE_URI + "/"));
|
||||||
|
tabs.add(createTab("Female", BASE_URI + "/female-cams/"));
|
||||||
|
tabs.add(createTab("Male", BASE_URI + "/male-cams/"));
|
||||||
|
tabs.add(createTab("Couples", BASE_URI + "/couple-cams/"));
|
||||||
|
tabs.add(createTab("Trans", BASE_URI + "/trans-cams/"));
|
||||||
|
FollowedTab followedTab = new FollowedTab("Followed", BASE_URI + "/followed-cams/");
|
||||||
|
followedTab.setRecorder(recorder);
|
||||||
|
followedTab.setScene(scene);
|
||||||
|
tabs.add(followedTab);
|
||||||
|
return tabs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Tab createTab(String title, String url) {
|
||||||
|
ChaturbateUpdateService updateService = new ChaturbateUpdateService(url, false);
|
||||||
|
ThumbOverviewTab tab = new ThumbOverviewTab(title, updateService);
|
||||||
|
tab.setRecorder(recorder);
|
||||||
|
return tab;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
package ctbrec.sites.chaturbate;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import ctbrec.Model;
|
||||||
|
import ctbrec.io.HttpClient;
|
||||||
|
import ctbrec.ui.PaginatedScheduledService;
|
||||||
|
import javafx.concurrent.Task;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
public class ChaturbateUpdateService extends PaginatedScheduledService {
|
||||||
|
|
||||||
|
private static final transient Logger LOG = LoggerFactory.getLogger(ChaturbateUpdateService.class);
|
||||||
|
private String url;
|
||||||
|
private boolean loginRequired;
|
||||||
|
|
||||||
|
public ChaturbateUpdateService(String url, boolean loginRequired) {
|
||||||
|
this.url = url;
|
||||||
|
this.loginRequired = loginRequired;
|
||||||
|
|
||||||
|
ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactory() {
|
||||||
|
@Override
|
||||||
|
public Thread newThread(Runnable r) {
|
||||||
|
Thread t = new Thread(r);
|
||||||
|
t.setDaemon(true);
|
||||||
|
t.setName("ThumbOverviewTab UpdateService");
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setExecutor(executor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Task<List<Model>> createTask() {
|
||||||
|
return new Task<List<Model>>() {
|
||||||
|
@Override
|
||||||
|
public List<Model> call() throws IOException {
|
||||||
|
String url = ChaturbateUpdateService.this.url + "?page="+page+"&keywords=&_=" + System.currentTimeMillis();
|
||||||
|
LOG.debug("Fetching page {}", url);
|
||||||
|
Request request = new Request.Builder().url(url).build();
|
||||||
|
Response response = HttpClient.getInstance().execute(request, loginRequired);
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
List<Model> models = ChaturbateModelParser.parseModels(response.body().string());
|
||||||
|
response.close();
|
||||||
|
return models;
|
||||||
|
} else {
|
||||||
|
int code = response.code();
|
||||||
|
response.close();
|
||||||
|
throw new IOException("HTTP status " + code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -20,11 +20,13 @@ import com.squareup.moshi.Moshi;
|
||||||
import com.squareup.moshi.Types;
|
import com.squareup.moshi.Types;
|
||||||
|
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
|
import ctbrec.Site;
|
||||||
import ctbrec.Version;
|
import ctbrec.Version;
|
||||||
import ctbrec.io.HttpClient;
|
import ctbrec.io.HttpClient;
|
||||||
import ctbrec.recorder.LocalRecorder;
|
import ctbrec.recorder.LocalRecorder;
|
||||||
import ctbrec.recorder.Recorder;
|
import ctbrec.recorder.Recorder;
|
||||||
import ctbrec.recorder.RemoteRecorder;
|
import ctbrec.recorder.RemoteRecorder;
|
||||||
|
import ctbrec.sites.chaturbate.Chaturbate;
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.application.HostServices;
|
import javafx.application.HostServices;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
@ -49,9 +51,9 @@ import javafx.stage.Stage;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
|
||||||
public class CtbrecApplication extends Application {
|
public class CamrecApplication extends Application {
|
||||||
|
|
||||||
static final transient Logger LOG = LoggerFactory.getLogger(CtbrecApplication.class);
|
static final transient Logger LOG = LoggerFactory.getLogger(CamrecApplication.class);
|
||||||
public static final String BASE_URI = "https://chaturbate.com";
|
public static final String BASE_URI = "https://chaturbate.com";
|
||||||
public static final String AFFILIATE_LINK = BASE_URI + "/in/?track=default&tour=LQps&campaign=55vTi&room=0xb00bface";
|
public static final String AFFILIATE_LINK = BASE_URI + "/in/?track=default&tour=LQps&campaign=55vTi&room=0xb00bface";
|
||||||
|
|
||||||
|
@ -63,6 +65,7 @@ public class CtbrecApplication extends Application {
|
||||||
private TabPane tabPane = new TabPane();
|
private TabPane tabPane = new TabPane();
|
||||||
static EventBus bus;
|
static EventBus bus;
|
||||||
private HBox tokenPanel;
|
private HBox tokenPanel;
|
||||||
|
private Site site;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage primaryStage) throws Exception {
|
public void start(Stage primaryStage) throws Exception {
|
||||||
|
@ -71,6 +74,8 @@ public class CtbrecApplication extends Application {
|
||||||
hostServices = getHostServices();
|
hostServices = getHostServices();
|
||||||
client = HttpClient.getInstance();
|
client = HttpClient.getInstance();
|
||||||
createRecorder();
|
createRecorder();
|
||||||
|
site = new Chaturbate();
|
||||||
|
site.setRecorder(recorder);
|
||||||
doInitialLogin();
|
doInitialLogin();
|
||||||
createGui(primaryStage);
|
createGui(primaryStage);
|
||||||
checkForUpdates();
|
checkForUpdates();
|
||||||
|
@ -81,8 +86,12 @@ public class CtbrecApplication extends Application {
|
||||||
primaryStage.setTitle("CTB Recorder " + getVersion());
|
primaryStage.setTitle("CTB Recorder " + getVersion());
|
||||||
InputStream icon = getClass().getResourceAsStream("/icon.png");
|
InputStream icon = getClass().getResourceAsStream("/icon.png");
|
||||||
primaryStage.getIcons().add(new Image(icon));
|
primaryStage.getIcons().add(new Image(icon));
|
||||||
|
int windowWidth = Config.getInstance().getSettings().windowWidth;
|
||||||
|
int windowHeight = Config.getInstance().getSettings().windowHeight;
|
||||||
tabPane = new TabPane();
|
tabPane = new TabPane();
|
||||||
|
Scene scene = new Scene(tabPane, windowWidth, windowHeight);
|
||||||
|
primaryStage.setScene(scene);
|
||||||
|
|
||||||
tabPane.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>() {
|
tabPane.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Tab>() {
|
||||||
@Override
|
@Override
|
||||||
public void changed(ObservableValue<? extends Tab> ov, Tab from, Tab to) {
|
public void changed(ObservableValue<? extends Tab> ov, Tab from, Tab to) {
|
||||||
|
@ -95,26 +104,18 @@ public class CtbrecApplication extends Application {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
tabPane.setTabClosingPolicy(TabClosingPolicy.SELECTED_TAB);
|
tabPane.setTabClosingPolicy(TabClosingPolicy.SELECTED_TAB);
|
||||||
tabPane.getTabs().add(createTab("Featured", BASE_URI + "/"));
|
for (Tab tab : site.getTabProvider().getTabs(scene)) {
|
||||||
tabPane.getTabs().add(createTab("Female", BASE_URI + "/female-cams/"));
|
tabPane.getTabs().add(tab);
|
||||||
tabPane.getTabs().add(createTab("Male", BASE_URI + "/male-cams/"));
|
}
|
||||||
tabPane.getTabs().add(createTab("Couples", BASE_URI + "/couple-cams/"));
|
RecordedModelsTab modelsTab = new RecordedModelsTab("Recording", recorder, site);
|
||||||
tabPane.getTabs().add(createTab("Trans", BASE_URI + "/trans-cams/"));
|
|
||||||
FollowedTab followedTab = new FollowedTab("Followed", BASE_URI + "/followed-cams/");
|
|
||||||
followedTab.setRecorder(recorder);
|
|
||||||
tabPane.getTabs().add(followedTab);
|
|
||||||
RecordedModelsTab modelsTab = new RecordedModelsTab("Recording", recorder);
|
|
||||||
tabPane.getTabs().add(modelsTab);
|
tabPane.getTabs().add(modelsTab);
|
||||||
RecordingsTab recordingsTab = new RecordingsTab("Recordings", recorder, config);
|
RecordingsTab recordingsTab = new RecordingsTab("Recordings", recorder, config, site);
|
||||||
tabPane.getTabs().add(recordingsTab);
|
tabPane.getTabs().add(recordingsTab);
|
||||||
settingsTab = new SettingsTab();
|
settingsTab = new SettingsTab();
|
||||||
tabPane.getTabs().add(settingsTab);
|
tabPane.getTabs().add(settingsTab);
|
||||||
tabPane.getTabs().add(new DonateTabFx());
|
tabPane.getTabs().add(new DonateTabFx());
|
||||||
|
|
||||||
int windowWidth = Config.getInstance().getSettings().windowWidth;
|
|
||||||
int windowHeight = Config.getInstance().getSettings().windowHeight;
|
|
||||||
primaryStage.setScene(new Scene(tabPane, windowWidth, windowHeight));
|
|
||||||
followedTab.setScene(primaryStage.getScene());
|
|
||||||
primaryStage.getScene().getStylesheets().add("/ctbrec/ui/ThumbCell.css");
|
primaryStage.getScene().getStylesheets().add("/ctbrec/ui/ThumbCell.css");
|
||||||
primaryStage.getScene().widthProperty().addListener((observable, oldVal, newVal) -> Config.getInstance().getSettings().windowWidth = newVal.intValue());
|
primaryStage.getScene().widthProperty().addListener((observable, oldVal, newVal) -> Config.getInstance().getSettings().windowWidth = newVal.intValue());
|
||||||
primaryStage.getScene().heightProperty().addListener((observable, oldVal, newVal) -> Config.getInstance().getSettings().windowHeight = newVal.intValue());
|
primaryStage.getScene().heightProperty().addListener((observable, oldVal, newVal) -> Config.getInstance().getSettings().windowHeight = newVal.intValue());
|
||||||
|
@ -270,12 +271,6 @@ public class CtbrecApplication extends Application {
|
||||||
config = Config.getInstance();
|
config = Config.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
Tab createTab(String title, String url) {
|
|
||||||
ThumbOverviewTab tab = new ThumbOverviewTab(title, url, false);
|
|
||||||
tab.setRecorder(recorder);
|
|
||||||
return tab;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
launch(args);
|
launch(args);
|
||||||
}
|
}
|
|
@ -19,7 +19,7 @@ public class DesktopIntergation {
|
||||||
|
|
||||||
public static void open(String uri) {
|
public static void open(String uri) {
|
||||||
try {
|
try {
|
||||||
CtbrecApplication.hostServices.showDocument(uri);
|
CamrecApplication.hostServices.showDocument(uri);
|
||||||
return;
|
return;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.debug("Couldn't open URL with host services {}", uri);
|
LOG.debug("Couldn't open URL with host services {}", uri);
|
||||||
|
|
|
@ -44,7 +44,7 @@ public class DonateTabFx extends Tab {
|
||||||
|
|
||||||
ImageView tokenImage = new ImageView(getClass().getResource("/html/token.png").toString());
|
ImageView tokenImage = new ImageView(getClass().getResource("/html/token.png").toString());
|
||||||
Button tokenButton = new Button("Buy tokens");
|
Button tokenButton = new Button("Buy tokens");
|
||||||
tokenButton.setOnAction((e) -> { DesktopIntergation.open(CtbrecApplication.AFFILIATE_LINK); });
|
tokenButton.setOnAction((e) -> { DesktopIntergation.open(CamrecApplication.AFFILIATE_LINK); });
|
||||||
VBox tokenBox = new VBox(5);
|
VBox tokenBox = new VBox(5);
|
||||||
tokenBox.setAlignment(Pos.TOP_CENTER);
|
tokenBox.setAlignment(Pos.TOP_CENTER);
|
||||||
Label tokenDesc = new Label("If you buy tokens by using this button,\n"
|
Label tokenDesc = new Label("If you buy tokens by using this button,\n"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package ctbrec.ui;
|
package ctbrec.ui;
|
||||||
|
|
||||||
|
import ctbrec.sites.chaturbate.ChaturbateUpdateService;
|
||||||
import javafx.concurrent.WorkerStateEvent;
|
import javafx.concurrent.WorkerStateEvent;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
|
@ -16,7 +17,7 @@ public class FollowedTab extends ThumbOverviewTab {
|
||||||
private String offlineUrl;
|
private String offlineUrl;
|
||||||
|
|
||||||
public FollowedTab(String title, String url) {
|
public FollowedTab(String title, String url) {
|
||||||
super(title, url, true);
|
super(title, new ChaturbateUpdateService(url, true));
|
||||||
onlineUrl = url;
|
onlineUrl = url;
|
||||||
offlineUrl = url + "offline/";
|
offlineUrl = url + "offline/";
|
||||||
|
|
||||||
|
@ -43,9 +44,9 @@ public class FollowedTab extends ThumbOverviewTab {
|
||||||
online.setSelected(true);
|
online.setSelected(true);
|
||||||
group.selectedToggleProperty().addListener((e) -> {
|
group.selectedToggleProperty().addListener((e) -> {
|
||||||
if(online.isSelected()) {
|
if(online.isSelected()) {
|
||||||
super.url = onlineUrl;
|
((ChaturbateUpdateService)updateService).setUrl(onlineUrl);
|
||||||
} else {
|
} else {
|
||||||
super.url = offlineUrl;
|
((ChaturbateUpdateService)updateService).setUrl(offlineUrl);
|
||||||
}
|
}
|
||||||
queue.clear();
|
queue.clear();
|
||||||
updateService.restart();
|
updateService.restart();
|
||||||
|
|
|
@ -111,4 +111,19 @@ public class JavaFxModel extends AbstractModel {
|
||||||
public List<StreamSource> getStreamSources() throws IOException, ExecutionException, ParseException, PlaylistException {
|
public List<StreamSource> getStreamSources() throws IOException, ExecutionException, ParseException, PlaylistException {
|
||||||
return delegate.getStreamSources();
|
return delegate.getStreamSources();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invalidateCacheEntries() {
|
||||||
|
delegate.invalidateCacheEntries();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void receiveTip(int tokens) throws IOException {
|
||||||
|
delegate.receiveTip(tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[] getStreamResolution(boolean b) throws ExecutionException {
|
||||||
|
return delegate.getStreamResolution(b);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ public class Launcher {
|
||||||
// check for OpenJFX
|
// check for OpenJFX
|
||||||
try {
|
try {
|
||||||
Class.forName("javafx.application.Application");
|
Class.forName("javafx.application.Application");
|
||||||
CtbrecApplication.main(args);
|
CamrecApplication.main(args);
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
LOG.error("You are running ctbrec with OpenJDK, but OpenJFX can not be found.\n"
|
LOG.error("You are running ctbrec with OpenJDK, but OpenJFX can not be found.\n"
|
||||||
+ "Please either install OpenJFX or use the Oracle JRE, which you can download at\n"
|
+ "Please either install OpenJFX or use the Oracle JRE, which you can download at\n"
|
||||||
|
@ -21,7 +21,7 @@ public class Launcher {
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
CtbrecApplication.main(args);
|
CamrecApplication.main(args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package ctbrec.ui;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ctbrec.Model;
|
||||||
|
import javafx.concurrent.ScheduledService;
|
||||||
|
|
||||||
|
public abstract class PaginatedScheduledService extends ScheduledService<List<Model>> {
|
||||||
|
|
||||||
|
protected int page = 1;
|
||||||
|
|
||||||
|
public int getPage() {
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPage(int page) {
|
||||||
|
this.page = page;
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,9 +19,9 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
|
import ctbrec.Site;
|
||||||
import ctbrec.io.HttpClient;
|
import ctbrec.io.HttpClient;
|
||||||
import ctbrec.recorder.Recorder;
|
import ctbrec.recorder.Recorder;
|
||||||
import ctbrec.sites.chaturbate.ChaturbateModel;
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
|
@ -60,6 +60,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
|
|
||||||
private ScheduledService<List<Model>> updateService;
|
private ScheduledService<List<Model>> updateService;
|
||||||
private Recorder recorder;
|
private Recorder recorder;
|
||||||
|
private Site site;
|
||||||
|
|
||||||
FlowPane grid = new FlowPane();
|
FlowPane grid = new FlowPane();
|
||||||
ScrollPane scrollPane = new ScrollPane();
|
ScrollPane scrollPane = new ScrollPane();
|
||||||
|
@ -71,9 +72,10 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
TextField model = new TextField();
|
TextField model = new TextField();
|
||||||
Button addModelButton = new Button("Record");
|
Button addModelButton = new Button("Record");
|
||||||
|
|
||||||
public RecordedModelsTab(String title, Recorder recorder) {
|
public RecordedModelsTab(String title, Recorder recorder, Site site) {
|
||||||
super(title);
|
super(title);
|
||||||
this.recorder = recorder;
|
this.recorder = recorder;
|
||||||
|
this.site = site;
|
||||||
createGui();
|
createGui();
|
||||||
setClosable(false);
|
setClosable(false);
|
||||||
initializeUpdateService();
|
initializeUpdateService();
|
||||||
|
@ -126,9 +128,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
model.setPrefWidth(300);
|
model.setPrefWidth(300);
|
||||||
BorderPane.setMargin(addModelBox, new Insets(5));
|
BorderPane.setMargin(addModelBox, new Insets(5));
|
||||||
addModelButton.setOnAction((e) -> {
|
addModelButton.setOnAction((e) -> {
|
||||||
ChaturbateModel m = new ChaturbateModel();
|
Model m = site.createModel(model.getText());
|
||||||
m.setName(model.getText());
|
|
||||||
m.setUrl("https://chaturbate.com/" + m.getName() + "/");
|
|
||||||
try {
|
try {
|
||||||
recorder.startRecording(m);
|
recorder.startRecording(m);
|
||||||
} catch (IOException | InvalidKeyException | NoSuchAlgorithmException | IllegalStateException e1) {
|
} catch (IOException | InvalidKeyException | NoSuchAlgorithmException | IllegalStateException e1) {
|
||||||
|
|
|
@ -29,12 +29,13 @@ import com.iheartradio.m3u8.ParseException;
|
||||||
import com.iheartradio.m3u8.PlaylistException;
|
import com.iheartradio.m3u8.PlaylistException;
|
||||||
|
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
|
import ctbrec.Model;
|
||||||
import ctbrec.Recording;
|
import ctbrec.Recording;
|
||||||
import ctbrec.Recording.STATUS;
|
import ctbrec.Recording.STATUS;
|
||||||
|
import ctbrec.Site;
|
||||||
import ctbrec.io.HttpClient;
|
import ctbrec.io.HttpClient;
|
||||||
import ctbrec.recorder.Recorder;
|
import ctbrec.recorder.Recorder;
|
||||||
import ctbrec.recorder.download.MergedHlsDownload;
|
import ctbrec.recorder.download.MergedHlsDownload;
|
||||||
import ctbrec.sites.chaturbate.ChaturbateModel;
|
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
|
@ -67,6 +68,7 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
|
||||||
private ScheduledService<List<JavaFxRecording>> updateService;
|
private ScheduledService<List<JavaFxRecording>> updateService;
|
||||||
private Config config;
|
private Config config;
|
||||||
private Recorder recorder;
|
private Recorder recorder;
|
||||||
|
private Site site;
|
||||||
|
|
||||||
FlowPane grid = new FlowPane();
|
FlowPane grid = new FlowPane();
|
||||||
ScrollPane scrollPane = new ScrollPane();
|
ScrollPane scrollPane = new ScrollPane();
|
||||||
|
@ -74,10 +76,11 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
|
||||||
ObservableList<JavaFxRecording> observableRecordings = FXCollections.observableArrayList();
|
ObservableList<JavaFxRecording> observableRecordings = FXCollections.observableArrayList();
|
||||||
ContextMenu popup;
|
ContextMenu popup;
|
||||||
|
|
||||||
public RecordingsTab(String title, Recorder recorder, Config config) {
|
public RecordingsTab(String title, Recorder recorder, Config config, Site site) {
|
||||||
super(title);
|
super(title);
|
||||||
this.recorder = recorder;
|
this.recorder = recorder;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
this.site = site;
|
||||||
createGui();
|
createGui();
|
||||||
setClosable(false);
|
setClosable(false);
|
||||||
initializeUpdateService();
|
initializeUpdateService();
|
||||||
|
@ -246,9 +249,7 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
|
||||||
|
|
||||||
MenuItem stopRecording = new MenuItem("Stop recording");
|
MenuItem stopRecording = new MenuItem("Stop recording");
|
||||||
stopRecording.setOnAction((e) -> {
|
stopRecording.setOnAction((e) -> {
|
||||||
ChaturbateModel m = new ChaturbateModel();
|
Model m = site.createModel(recording.getModelName());
|
||||||
m.setName(recording.getModelName());
|
|
||||||
m.setUrl(CtbrecApplication.BASE_URI + '/' + recording.getModelName() + '/');
|
|
||||||
try {
|
try {
|
||||||
recorder.stopRecording(m);
|
recorder.stopRecording(m);
|
||||||
} catch (Exception e1) {
|
} catch (Exception e1) {
|
||||||
|
|
|
@ -188,7 +188,7 @@ public class SettingsTab extends Tab implements TabSelectionListener {
|
||||||
layout.add(password, 1, 1);
|
layout.add(password, 1, 1);
|
||||||
|
|
||||||
Button createAccount = new Button("Create new Account");
|
Button createAccount = new Button("Create new Account");
|
||||||
createAccount.setOnAction((e) -> DesktopIntergation.open(CtbrecApplication.AFFILIATE_LINK));
|
createAccount.setOnAction((e) -> DesktopIntergation.open(CamrecApplication.AFFILIATE_LINK));
|
||||||
layout.add(createAccount, 1, 2);
|
layout.add(createAccount, 1, 2);
|
||||||
GridPane.setColumnSpan(createAccount, 2);
|
GridPane.setColumnSpan(createAccount, 2);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package ctbrec.ui;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.control.Tab;
|
||||||
|
|
||||||
|
public class TabProvider {
|
||||||
|
|
||||||
|
public List<Tab> getTabs(Scene scene) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
package ctbrec.ui;
|
package ctbrec.ui;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
@ -8,12 +10,14 @@ import java.util.function.Function;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.iheartradio.m3u8.ParseException;
|
||||||
|
import com.iheartradio.m3u8.PlaylistException;
|
||||||
|
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
import ctbrec.io.HttpClient;
|
import ctbrec.io.HttpClient;
|
||||||
import ctbrec.recorder.Recorder;
|
import ctbrec.recorder.Recorder;
|
||||||
import ctbrec.sites.chaturbate.ChaturbateModel;
|
import ctbrec.recorder.download.StreamSource;
|
||||||
import ctbrec.sites.chaturbate.StreamInfo;
|
|
||||||
import javafx.animation.FadeTransition;
|
import javafx.animation.FadeTransition;
|
||||||
import javafx.animation.FillTransition;
|
import javafx.animation.FillTransition;
|
||||||
import javafx.animation.ParallelTransition;
|
import javafx.animation.ParallelTransition;
|
||||||
|
@ -51,7 +55,7 @@ public class ThumbCell extends StackPane {
|
||||||
public static int width = 180;
|
public static int width = 180;
|
||||||
private static final Duration ANIMATION_DURATION = new Duration(250);
|
private static final Duration ANIMATION_DURATION = new Duration(250);
|
||||||
|
|
||||||
private ChaturbateModel model;
|
private Model model;
|
||||||
private ImageView iv;
|
private ImageView iv;
|
||||||
private Rectangle resolutionBackground;
|
private Rectangle resolutionBackground;
|
||||||
private final Paint resolutionOnlineColor = new Color(0.22, 0.8, 0.29, 1);
|
private final Paint resolutionOnlineColor = new Color(0.22, 0.8, 0.29, 1);
|
||||||
|
@ -77,7 +81,7 @@ public class ThumbCell extends StackPane {
|
||||||
private boolean mouseHovering = false;
|
private boolean mouseHovering = false;
|
||||||
private boolean recording = false;
|
private boolean recording = false;
|
||||||
|
|
||||||
public ThumbCell(ThumbOverviewTab parent, ChaturbateModel model, Recorder recorder, HttpClient client) {
|
public ThumbCell(ThumbOverviewTab parent, Model model, Recorder recorder, HttpClient client) {
|
||||||
this.thumbCellList = parent.grid.getChildren();
|
this.thumbCellList = parent.grid.getChildren();
|
||||||
this.model = model;
|
this.model = model;
|
||||||
this.recorder = recorder;
|
this.recorder = recorder;
|
||||||
|
@ -198,7 +202,7 @@ public class ThumbCell extends StackPane {
|
||||||
ThumbOverviewTab.threadPool.submit(() -> {
|
ThumbOverviewTab.threadPool.submit(() -> {
|
||||||
try {
|
try {
|
||||||
ThumbOverviewTab.resolutionProcessing.add(model);
|
ThumbOverviewTab.resolutionProcessing.add(model);
|
||||||
int[] resolution = model.getStreamResolution();
|
int[] resolution = model.getStreamResolution(false);
|
||||||
updateResolutionTag(resolution);
|
updateResolutionTag(resolution);
|
||||||
|
|
||||||
// the model is online, but the resolution is 0. probably something went wrong
|
// the model is online, but the resolution is 0. probably something went wrong
|
||||||
|
@ -225,14 +229,14 @@ public class ThumbCell extends StackPane {
|
||||||
private void updateResolutionTag(int[] resolution) throws IOException, ExecutionException {
|
private void updateResolutionTag(int[] resolution) throws IOException, ExecutionException {
|
||||||
String _res = "n/a";
|
String _res = "n/a";
|
||||||
Paint resolutionBackgroundColor = resolutionOnlineColor;
|
Paint resolutionBackgroundColor = resolutionOnlineColor;
|
||||||
String state = model.getOnlineState();
|
String state = model.getOnlineState(false);
|
||||||
if ("public".equals(state)) {
|
if ("public".equals(state)) {
|
||||||
LOG.trace("Model resolution {} {}x{}", model.getName(), resolution[0], resolution[1]);
|
LOG.trace("Model resolution {} {}x{}", model.getName(), resolution[0], resolution[1]);
|
||||||
LOG.trace("Resolution queue size: {}", ThumbOverviewTab.queue.size());
|
LOG.trace("Resolution queue size: {}", ThumbOverviewTab.queue.size());
|
||||||
final int w = resolution[1];
|
final int w = resolution[1];
|
||||||
_res = w > 0 ? Integer.toString(w) : state;
|
_res = w > 0 ? Integer.toString(w) : state;
|
||||||
} else {
|
} else {
|
||||||
_res = model.getOnlineState();
|
_res = model.getOnlineState(false);
|
||||||
resolutionBackgroundColor = resolutionOfflineColor;
|
resolutionBackgroundColor = resolutionOfflineColor;
|
||||||
}
|
}
|
||||||
final String resText = _res;
|
final String resText = _res;
|
||||||
|
@ -281,16 +285,18 @@ public class ThumbCell extends StackPane {
|
||||||
void startPlayer() {
|
void startPlayer() {
|
||||||
try {
|
try {
|
||||||
if(model.isOnline(true)) {
|
if(model.isOnline(true)) {
|
||||||
StreamInfo streamInfo = model.getStreamInfo();
|
List<StreamSource> sources = model.getStreamSources();
|
||||||
LOG.debug("Playing {}", streamInfo.url);
|
Collections.sort(sources);
|
||||||
Player.play(streamInfo.url);
|
StreamSource best = sources.get(sources.size()-1);
|
||||||
|
LOG.debug("Playing {}", best.getMediaPlaylistUrl());
|
||||||
|
Player.play(best.getMediaPlaylistUrl());
|
||||||
} else {
|
} else {
|
||||||
Alert alert = new AutosizeAlert(Alert.AlertType.INFORMATION);
|
Alert alert = new AutosizeAlert(Alert.AlertType.INFORMATION);
|
||||||
alert.setTitle("Room not public");
|
alert.setTitle("Room not public");
|
||||||
alert.setHeaderText("Room is currently not public");
|
alert.setHeaderText("Room is currently not public");
|
||||||
alert.showAndWait();
|
alert.showAndWait();
|
||||||
}
|
}
|
||||||
} catch (IOException | ExecutionException | InterruptedException e1) {
|
} catch (IOException | ExecutionException | InterruptedException | ParseException | PlaylistException e1) {
|
||||||
LOG.error("Couldn't get stream information for model {}", model, e1);
|
LOG.error("Couldn't get stream information for model {}", model, e1);
|
||||||
Alert alert = new AutosizeAlert(Alert.AlertType.ERROR);
|
Alert alert = new AutosizeAlert(Alert.AlertType.ERROR);
|
||||||
alert.setTitle("Error");
|
alert.setTitle("Error");
|
||||||
|
@ -374,9 +380,9 @@ public class ThumbCell extends StackPane {
|
||||||
|
|
||||||
String url = null;
|
String url = null;
|
||||||
if(follow) {
|
if(follow) {
|
||||||
url = CtbrecApplication.BASE_URI + "/follow/follow/" + model.getName() + "/";
|
url = CamrecApplication.BASE_URI + "/follow/follow/" + model.getName() + "/";
|
||||||
} else {
|
} else {
|
||||||
url = CtbrecApplication.BASE_URI + "/follow/unfollow/" + model.getName() + "/";
|
url = CamrecApplication.BASE_URI + "/follow/unfollow/" + model.getName() + "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
RequestBody body = RequestBody.create(null, new byte[0]);
|
RequestBody body = RequestBody.create(null, new byte[0]);
|
||||||
|
@ -422,7 +428,7 @@ public class ThumbCell extends StackPane {
|
||||||
}.start();
|
}.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChaturbateModel getModel() {
|
public Model getModel() {
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,7 @@ import java.util.Set;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.ThreadFactory;
|
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
@ -28,13 +26,10 @@ import org.slf4j.LoggerFactory;
|
||||||
import com.sun.javafx.collections.ObservableListWrapper;
|
import com.sun.javafx.collections.ObservableListWrapper;
|
||||||
|
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
|
import ctbrec.Model;
|
||||||
import ctbrec.io.HttpClient;
|
import ctbrec.io.HttpClient;
|
||||||
import ctbrec.recorder.Recorder;
|
import ctbrec.recorder.Recorder;
|
||||||
import ctbrec.sites.chaturbate.ChaturbateModel;
|
|
||||||
import ctbrec.sites.chaturbate.ModelParser;
|
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.concurrent.ScheduledService;
|
|
||||||
import javafx.concurrent.Task;
|
|
||||||
import javafx.concurrent.Worker.State;
|
import javafx.concurrent.Worker.State;
|
||||||
import javafx.concurrent.WorkerStateEvent;
|
import javafx.concurrent.WorkerStateEvent;
|
||||||
import javafx.event.EventHandler;
|
import javafx.event.EventHandler;
|
||||||
|
@ -59,17 +54,15 @@ import javafx.scene.layout.BorderPane;
|
||||||
import javafx.scene.layout.FlowPane;
|
import javafx.scene.layout.FlowPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
import okhttp3.Request;
|
|
||||||
import okhttp3.Response;
|
|
||||||
|
|
||||||
public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
private static final transient Logger LOG = LoggerFactory.getLogger(ThumbOverviewTab.class);
|
private static final transient Logger LOG = LoggerFactory.getLogger(ThumbOverviewTab.class);
|
||||||
|
|
||||||
static Set<ChaturbateModel> resolutionProcessing = Collections.synchronizedSet(new HashSet<>());
|
static Set<Model> resolutionProcessing = Collections.synchronizedSet(new HashSet<>());
|
||||||
static BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
|
static BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
|
||||||
static ExecutorService threadPool = new ThreadPoolExecutor(2, 2, 10, TimeUnit.MINUTES, queue);
|
static ExecutorService threadPool = new ThreadPoolExecutor(2, 2, 10, TimeUnit.MINUTES, queue);
|
||||||
|
|
||||||
ScheduledService<List<ChaturbateModel>> updateService;
|
PaginatedScheduledService updateService;
|
||||||
Recorder recorder;
|
Recorder recorder;
|
||||||
List<ThumbCell> filteredThumbCells = Collections.synchronizedList(new ArrayList<>());
|
List<ThumbCell> filteredThumbCells = Collections.synchronizedList(new ArrayList<>());
|
||||||
List<ThumbCell> selectedThumbCells = Collections.synchronizedList(new ArrayList<>());
|
List<ThumbCell> selectedThumbCells = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
@ -77,12 +70,10 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
FlowPane grid = new FlowPane();
|
FlowPane grid = new FlowPane();
|
||||||
ReentrantLock gridLock = new ReentrantLock();
|
ReentrantLock gridLock = new ReentrantLock();
|
||||||
ScrollPane scrollPane = new ScrollPane();
|
ScrollPane scrollPane = new ScrollPane();
|
||||||
String url;
|
|
||||||
boolean loginRequired;
|
boolean loginRequired;
|
||||||
HttpClient client = HttpClient.getInstance();
|
HttpClient client = HttpClient.getInstance();
|
||||||
HBox pagination;
|
HBox pagination;
|
||||||
int page = 1;
|
TextField pageInput = new TextField(Integer.toString(1));
|
||||||
TextField pageInput = new TextField(Integer.toString(page));
|
|
||||||
Button pagePrev = new Button("◀");
|
Button pagePrev = new Button("◀");
|
||||||
Button pageNext = new Button("▶");
|
Button pageNext = new Button("▶");
|
||||||
private volatile boolean updatesSuspended = false;
|
private volatile boolean updatesSuspended = false;
|
||||||
|
@ -90,10 +81,9 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
|
|
||||||
private ComboBox<Integer> thumbWidth;
|
private ComboBox<Integer> thumbWidth;
|
||||||
|
|
||||||
public ThumbOverviewTab(String title, String url, boolean loginRequired) {
|
public ThumbOverviewTab(String title, PaginatedScheduledService updateService) {
|
||||||
super(title);
|
super(title);
|
||||||
this.url = url;
|
this.updateService = updateService;
|
||||||
this.loginRequired = loginRequired;
|
|
||||||
setClosable(false);
|
setClosable(false);
|
||||||
createGui();
|
createGui();
|
||||||
initializeUpdateService();
|
initializeUpdateService();
|
||||||
|
@ -136,13 +126,17 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
pageInput.setPrefWidth(50);
|
pageInput.setPrefWidth(50);
|
||||||
pageInput.setOnAction((e) -> handlePageNumberInput());
|
pageInput.setOnAction((e) -> handlePageNumberInput());
|
||||||
pagePrev.setOnAction((e) -> {
|
pagePrev.setOnAction((e) -> {
|
||||||
|
int page = updateService.getPage();
|
||||||
page = Math.max(1, --page);
|
page = Math.max(1, --page);
|
||||||
pageInput.setText(Integer.toString(page));
|
pageInput.setText(Integer.toString(page));
|
||||||
|
updateService.setPage(page);
|
||||||
restartUpdateService();
|
restartUpdateService();
|
||||||
});
|
});
|
||||||
pageNext.setOnAction((e) -> {
|
pageNext.setOnAction((e) -> {
|
||||||
|
int page = updateService.getPage();
|
||||||
page++;
|
page++;
|
||||||
pageInput.setText(Integer.toString(page));
|
pageInput.setText(Integer.toString(page));
|
||||||
|
updateService.setPage(page);
|
||||||
restartUpdateService();
|
restartUpdateService();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -189,12 +183,13 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
|
|
||||||
private void handlePageNumberInput() {
|
private void handlePageNumberInput() {
|
||||||
try {
|
try {
|
||||||
page = Integer.parseInt(pageInput.getText());
|
int page = Integer.parseInt(pageInput.getText());
|
||||||
page = Math.max(1, page);
|
page = Math.max(1, page);
|
||||||
|
updateService.setPage(page);
|
||||||
restartUpdateService();
|
restartUpdateService();
|
||||||
} catch(NumberFormatException e) {
|
} catch(NumberFormatException e) {
|
||||||
} finally {
|
} finally {
|
||||||
pageInput.setText(Integer.toString(page));
|
pageInput.setText(Integer.toString(updateService.getPage()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,7 +206,6 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
void initializeUpdateService() {
|
void initializeUpdateService() {
|
||||||
updateService = createUpdateService();
|
|
||||||
updateService.setPeriod(new Duration(TimeUnit.SECONDS.toMillis(10)));
|
updateService.setPeriod(new Duration(TimeUnit.SECONDS.toMillis(10)));
|
||||||
updateService.setOnSucceeded((event) -> onSuccess());
|
updateService.setOnSucceeded((event) -> onSuccess());
|
||||||
updateService.setOnFailed((event) -> onFail(event));
|
updateService.setOnFailed((event) -> onFail(event));
|
||||||
|
@ -223,7 +217,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
}
|
}
|
||||||
gridLock.lock();
|
gridLock.lock();
|
||||||
try {
|
try {
|
||||||
List<ChaturbateModel> models = updateService.getValue();
|
List<Model> models = updateService.getValue();
|
||||||
ObservableList<Node> nodes = grid.getChildren();
|
ObservableList<Node> nodes = grid.getChildren();
|
||||||
|
|
||||||
// first remove models, which are not in the updated list
|
// first remove models, which are not in the updated list
|
||||||
|
@ -238,7 +232,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
|
|
||||||
List<ThumbCell> positionChangedOrNew = new ArrayList<>();
|
List<ThumbCell> positionChangedOrNew = new ArrayList<>();
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (ChaturbateModel model : models) {
|
for (Model model : models) {
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
for (Iterator<Node> iterator = nodes.iterator(); iterator.hasNext();) {
|
for (Iterator<Node> iterator = nodes.iterator(); iterator.hasNext();) {
|
||||||
Node node = iterator.next();
|
Node node = iterator.next();
|
||||||
|
@ -278,7 +272,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ThumbCell createThumbCell(ThumbOverviewTab thumbOverviewTab, ChaturbateModel model, Recorder recorder2, HttpClient client2) {
|
ThumbCell createThumbCell(ThumbOverviewTab thumbOverviewTab, Model model, Recorder recorder2, HttpClient client2) {
|
||||||
ThumbCell newCell = new ThumbCell(this, model, recorder, client);
|
ThumbCell newCell = new ThumbCell(this, model, recorder, client);
|
||||||
newCell.addEventHandler(ContextMenuEvent.CONTEXT_MENU_REQUESTED, event -> {
|
newCell.addEventHandler(ContextMenuEvent.CONTEXT_MENU_REQUESTED, event -> {
|
||||||
suspendUpdates(true);
|
suspendUpdates(true);
|
||||||
|
@ -341,7 +335,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
Map<String, Object> event = new HashMap<>();
|
Map<String, Object> event = new HashMap<>();
|
||||||
event.put("event", "tokens.sent");
|
event.put("event", "tokens.sent");
|
||||||
event.put("amount", tokens);
|
event.put("amount", tokens);
|
||||||
CtbrecApplication.bus.post(event);
|
CamrecApplication.bus.post(event);
|
||||||
} catch (IOException e1) {
|
} catch (IOException e1) {
|
||||||
Alert alert = new AutosizeAlert(Alert.AlertType.ERROR);
|
Alert alert = new AutosizeAlert(Alert.AlertType.ERROR);
|
||||||
alert.setTitle("Error");
|
alert.setTitle("Error");
|
||||||
|
@ -476,7 +470,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
for (Iterator<Node> iterator = grid.getChildren().iterator(); iterator.hasNext();) {
|
for (Iterator<Node> iterator = grid.getChildren().iterator(); iterator.hasNext();) {
|
||||||
Node node = iterator.next();
|
Node node = iterator.next();
|
||||||
ThumbCell cell = (ThumbCell) node;
|
ThumbCell cell = (ThumbCell) node;
|
||||||
ChaturbateModel m = cell.getModel();
|
Model m = cell.getModel();
|
||||||
if(!matches(m, filter)) {
|
if(!matches(m, filter)) {
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
filteredThumbCells.add(cell);
|
filteredThumbCells.add(cell);
|
||||||
|
@ -487,7 +481,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
// add the ones, which might have been filtered before, but now match
|
// add the ones, which might have been filtered before, but now match
|
||||||
for (Iterator<ThumbCell> iterator = filteredThumbCells.iterator(); iterator.hasNext();) {
|
for (Iterator<ThumbCell> iterator = filteredThumbCells.iterator(); iterator.hasNext();) {
|
||||||
ThumbCell thumbCell = iterator.next();
|
ThumbCell thumbCell = iterator.next();
|
||||||
ChaturbateModel m = thumbCell.getModel();
|
Model m = thumbCell.getModel();
|
||||||
if(matches(m, filter)) {
|
if(matches(m, filter)) {
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
insert(thumbCell);
|
insert(thumbCell);
|
||||||
|
@ -520,7 +514,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean matches(ChaturbateModel m, String filter) {
|
private boolean matches(Model m, String filter) {
|
||||||
try {
|
try {
|
||||||
String[] tokens = filter.split(" ");
|
String[] tokens = filter.split(" ");
|
||||||
StringBuilder searchTextBuilder = new StringBuilder(m.getName());
|
StringBuilder searchTextBuilder = new StringBuilder(m.getName());
|
||||||
|
@ -558,43 +552,6 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ScheduledService<List<ChaturbateModel>> createUpdateService() {
|
|
||||||
ScheduledService<List<ChaturbateModel>> updateService = new ScheduledService<List<ChaturbateModel>>() {
|
|
||||||
@Override
|
|
||||||
protected Task<List<ChaturbateModel>> createTask() {
|
|
||||||
return new Task<List<ChaturbateModel>>() {
|
|
||||||
@Override
|
|
||||||
public List<ChaturbateModel> call() throws IOException {
|
|
||||||
String url = ThumbOverviewTab.this.url + "?page="+page+"&keywords=&_=" + System.currentTimeMillis();
|
|
||||||
LOG.debug("Fetching page {}", url);
|
|
||||||
Request request = new Request.Builder().url(url).build();
|
|
||||||
Response response = client.execute(request, loginRequired);
|
|
||||||
if (response.isSuccessful()) {
|
|
||||||
List<ChaturbateModel> models = ModelParser.parseModels(response.body().string());
|
|
||||||
response.close();
|
|
||||||
return models;
|
|
||||||
} else {
|
|
||||||
int code = response.code();
|
|
||||||
response.close();
|
|
||||||
throw new IOException("HTTP status " + code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactory() {
|
|
||||||
@Override
|
|
||||||
public Thread newThread(Runnable r) {
|
|
||||||
Thread t = new Thread(r);
|
|
||||||
t.setDaemon(true);
|
|
||||||
t.setName("ThumbOverviewTab UpdateService");
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
updateService.setExecutor(executor);
|
|
||||||
return updateService;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRecorder(Recorder recorder) {
|
public void setRecorder(Recorder recorder) {
|
||||||
this.recorder = recorder;
|
this.recorder = recorder;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ public class TipDialog extends TextInputDialog {
|
||||||
Map<String, Object> event = new HashMap<>();
|
Map<String, Object> event = new HashMap<>();
|
||||||
event.put("event", "tokens");
|
event.put("event", "tokens");
|
||||||
event.put("amount", tokens);
|
event.put("amount", tokens);
|
||||||
CtbrecApplication.bus.post(event);
|
CamrecApplication.bus.post(event);
|
||||||
return tokens;
|
return tokens;
|
||||||
} else {
|
} else {
|
||||||
throw new IOException("HTTP response: " + resp.code() + " - " + resp.message());
|
throw new IOException("HTTP response: " + resp.code() + " - " + resp.message());
|
||||||
|
@ -78,7 +78,7 @@ public class TipDialog extends TextInputDialog {
|
||||||
buyTokens.showAndWait();
|
buyTokens.showAndWait();
|
||||||
TipDialog.this.close();
|
TipDialog.this.close();
|
||||||
if(buyTokens.getResult() == ButtonType.YES) {
|
if(buyTokens.getResult() == ButtonType.YES) {
|
||||||
DesktopIntergation.open(CtbrecApplication.AFFILIATE_LINK);
|
DesktopIntergation.open(CamrecApplication.AFFILIATE_LINK);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
getEditor().setDisable(false);
|
getEditor().setDisable(false);
|
||||||
|
|
|
@ -14,7 +14,7 @@ public class TokenLabel extends Label {
|
||||||
|
|
||||||
public TokenLabel() {
|
public TokenLabel() {
|
||||||
setText("Tokens: loading…");
|
setText("Tokens: loading…");
|
||||||
CtbrecApplication.bus.register(new Object() {
|
CamrecApplication.bus.register(new Object() {
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void tokensUpdates(Map<String, Object> e) {
|
public void tokensUpdates(Map<String, Object> e) {
|
||||||
if(Objects.equals("tokens", e.get("event"))) {
|
if(Objects.equals("tokens", e.get("event"))) {
|
||||||
|
|
|
@ -3,7 +3,7 @@ package ctbrec.ui;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import ctbrec.ui.CtbrecApplication.Release;
|
import ctbrec.ui.CamrecApplication.Release;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
|
|
Loading…
Reference in New Issue