Use global thread pool instead of creating new threads

This commit is contained in:
0xb00bface 2021-01-10 22:14:20 +01:00
parent ec9c463f80
commit 967b5dec42
34 changed files with 283 additions and 373 deletions

View File

@ -28,11 +28,10 @@ public class ExternalBrowser implements AutoCloseable {
private static final ExternalBrowser INSTANCE = new ExternalBrowser();
private Lock lock = new ReentrantLock();
private Process p;
private Consumer<String> messageListener;
private InputStream in;
private OutputStream out;
private Socket socket;
private Socket socket; // NOSONAR
private Thread reader;
private volatile boolean stopped = true;
private volatile boolean browserReady = false;
@ -53,10 +52,10 @@ public class ExternalBrowser implements AutoCloseable {
File configDir = new File(Config.getInstance().getConfigDir(), "ctbrec-minimal-browser");
String[] cmdline = OS.getBrowserCommand(configDir.getCanonicalPath());
p = new ProcessBuilder(cmdline).start();
Process p = new ProcessBuilder(cmdline).start();
if (LOG.isTraceEnabled()) {
new Thread(new StreamRedirector(p.getInputStream(), System.out)).start();
new Thread(new StreamRedirector(p.getErrorStream(), System.err)).start();
new Thread(new StreamRedirector(p.getInputStream(), System.out)).start(); // NOSONAR
new Thread(new StreamRedirector(p.getErrorStream(), System.err)).start(); // NOSONAR
} else {
new Thread(new StreamRedirector(p.getInputStream(), OutputStream.nullOutputStream())).start();
new Thread(new StreamRedirector(p.getErrorStream(), OutputStream.nullOutputStream())).start();
@ -81,7 +80,6 @@ public class ExternalBrowser implements AutoCloseable {
LOG.debug("Waiting for browser to terminate");
p.waitFor();
int exitValue = p.exitValue();
p = null;
reader = null;
in = null;
out = null;
@ -119,7 +117,6 @@ public class ExternalBrowser implements AutoCloseable {
}
public void executeJavaScript(String javaScript) throws IOException {
//LOG.debug("Executing JS {}", javaScript);
JSONObject script = new JSONObject();
script.put("execute", javaScript);
out.write(script.toString().getBytes(UTF_8));
@ -141,8 +138,7 @@ public class ExternalBrowser implements AutoCloseable {
private void readBrowserOutput() {
LOG.debug("Browser output reader started");
try {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
try (BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
String line;
synchronized (browserReadyLock) {
browserReady = true;
@ -150,11 +146,8 @@ public class ExternalBrowser implements AutoCloseable {
}
while( !Thread.interrupted() && (line = br.readLine()) != null ) {
LOG.debug("Browser output: {}", line);
if(!line.startsWith("{")) {
} else {
if(messageListener != null) {
messageListener.accept(line);
}
if (line.startsWith("{") && messageListener != null) {
messageListener.accept(line);
}
}
} catch (IOException e) {

View File

@ -166,12 +166,10 @@ public class Player {
// create threads, which read stdout and stderr of the player process. these are needed,
// because otherwise the internal buffer for these streams fill up and block the process
Thread std = new Thread(new StreamRedirector(playerProcess.getInputStream(), OutputStream.nullOutputStream()));
//Thread std = new Thread(new StreamRedirectThread(playerProcess.getInputStream(), System.out));
std.setName("Player stdout pipe");
std.setDaemon(true);
std.start();
Thread err = new Thread(new StreamRedirector(playerProcess.getErrorStream(), OutputStream.nullOutputStream()));
//Thread err = new Thread(new StreamRedirectThread(playerProcess.getErrorStream(), System.err));
err.setName("Player stderr pipe");
err.setDaemon(true);
err.start();

View File

@ -22,7 +22,7 @@ import javafx.scene.layout.StackPane;
import javafx.stage.Popup;
public class PreviewPopupHandler implements EventHandler<MouseEvent> {
private static final transient Logger LOG = LoggerFactory.getLogger(PreviewPopupHandler.class);
private static final Logger LOG = LoggerFactory.getLogger(PreviewPopupHandler.class);
private static final int offset = 10;
private long timeForPopupOpen = TimeUnit.SECONDS.toMillis(1);
@ -67,11 +67,11 @@ public class PreviewPopupHandler implements EventHandler<MouseEvent> {
} else if(event.getEventType() == MouseEvent.MOUSE_ENTERED) {
popup.setX(event.getScreenX()+ offset);
popup.setY(event.getScreenY()+ offset);
JavaFxModel model = getModel(event);
if(model != null) {
JavaFxModel newModel = getModel(event);
if(newModel != null) {
closeCountdown = -1;
boolean modelChanged = model != this.model;
this.model = model;
boolean modelChanged = newModel != this.model;
this.model = newModel;
if(popup.isShowing()) {
openCountdown = -1;
if(modelChanged) {
@ -97,15 +97,15 @@ public class PreviewPopupHandler implements EventHandler<MouseEvent> {
@SuppressWarnings("unchecked")
TableRow<JavaFxModel> row = (TableRow<JavaFxModel>) event.getSource();
TableView<JavaFxModel> table = row.getTableView();
double offset = 0;
double columnOffset = 0;
double width = 0;
for (TableColumn<JavaFxModel, ?> col : table.getColumns()) {
offset += width;
columnOffset += width;
width = col.getWidth();
if(Objects.equals(col.getId(), "preview")) {
Point2D screenToLocal = table.screenToLocal(event.getScreenX(), event.getScreenY());
double x = screenToLocal.getX();
return x >= offset && x <= offset + width;
return x >= columnOffset && x <= columnOffset + width;
}
}
return false;
@ -176,6 +176,7 @@ public class PreviewPopupHandler implements EventHandler<MouseEvent> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LOG.error("PreviewPopupTimer interrupted");
break;
}

View File

@ -7,6 +7,7 @@ import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.function.Function;
import ctbrec.GlobalThreadPool;
import ctbrec.Model;
import ctbrec.recorder.download.StreamSource;
import ctbrec.ui.controls.Dialogs;
@ -19,9 +20,10 @@ import javafx.stage.Stage;
public class StreamSourceSelectionDialog {
private static final StreamSource BEST = new BestStreamSource();
private StreamSourceSelectionDialog() {}
private StreamSourceSelectionDialog() {
}
public static void show(Scene parent, Model model, Function<Model,Void> onSuccess, Function<Throwable, Void> onFail) {
public static void show(Scene parent, Model model, Function<Model, Void> onSuccess, Function<Throwable, Void> onFail) {
Task<List<StreamSource>> selectStreamSource = new Task<List<StreamSource>>() {
@Override
protected List<StreamSource> call() throws Exception {
@ -35,7 +37,7 @@ public class StreamSourceSelectionDialog {
List<StreamSource> sources;
try {
sources = selectStreamSource.get();
int selectedIndex = model.getStreamUrlIndex() > -1 ? Math.min(model.getStreamUrlIndex(), sources.size()-1) : sources.size()-1;
int selectedIndex = model.getStreamUrlIndex() > -1 ? Math.min(model.getStreamUrlIndex(), sources.size() - 1) : sources.size() - 1;
ChoiceDialog<StreamSource> choiceDialog = new ChoiceDialog<>(sources.get(selectedIndex), sources);
choiceDialog.setTitle("Stream Quality");
choiceDialog.setHeaderText("Select your preferred stream quality");
@ -45,7 +47,7 @@ public class StreamSourceSelectionDialog {
InputStream icon = Dialogs.class.getResourceAsStream("/icon.png");
stage.getIcons().add(new Image(icon));
Optional<StreamSource> selectedSource = choiceDialog.showAndWait();
if(selectedSource.isPresent()) {
if (selectedSource.isPresent()) {
int index = -1;
if (selectedSource.get() != BEST) {
index = sources.indexOf(selectedSource.get());
@ -61,7 +63,7 @@ public class StreamSourceSelectionDialog {
}
});
selectStreamSource.setOnFailed(e -> onFail.apply(selectStreamSource.getException()));
new Thread(selectStreamSource).start();
GlobalThreadPool.submit(selectStreamSource);
}
private static class BestStreamSource extends StreamSource {

View File

@ -7,7 +7,7 @@ import java.util.concurrent.ExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ctbrec.Model;
import ctbrec.GlobalThreadPool;
import ctbrec.sites.Site;
import javafx.application.Platform;
import javafx.concurrent.Task;
@ -19,11 +19,11 @@ import javafx.stage.Stage;
public class TipDialog extends TextInputDialog {
private static final transient Logger LOG = LoggerFactory.getLogger(TipDialog.class);
private static final Logger LOG = LoggerFactory.getLogger(TipDialog.class);
private Site site;
private Scene parent;
public TipDialog(Scene parent, Site site, Model model) {
public TipDialog(Scene parent, Site site) {
this.parent = parent;
this.site = site;
setTitle("Send Tip");
@ -32,7 +32,7 @@ public class TipDialog extends TextInputDialog {
setContentText("Amount of tokens to tip:");
setResizable(true);
getEditor().setDisable(true);
if(parent != null) {
if (parent != null) {
Stage stage = (Stage) getDialogPane().getScene().getWindow();
stage.getScene().getStylesheets().addAll(parent.getStylesheets());
}
@ -56,14 +56,14 @@ public class TipDialog extends TextInputDialog {
double tokens = get();
Platform.runLater(() -> {
if (tokens <= 0) {
String msg = "Do you want to buy tokens now?\n\nIf you agree, "+site.getName()+" will open in a browser. "
String msg = "Do you want to buy tokens now?\n\nIf you agree, " + site.getName() + " will open in a browser. "
+ "The used address is an affiliate link, which supports me, but doesn't cost you anything more.";
Alert buyTokens = new AutosizeAlert(Alert.AlertType.CONFIRMATION, msg, parent, ButtonType.NO, ButtonType.YES);
buyTokens.setTitle("No tokens");
buyTokens.setHeaderText("You don't have any tokens");
buyTokens.showAndWait();
TipDialog.this.close();
if(buyTokens.getResult() == ButtonType.YES) {
if (buyTokens.getResult() == ButtonType.YES) {
DesktopIntegration.open(site.getAffiliateLink());
}
} else {
@ -72,13 +72,20 @@ public class TipDialog extends TextInputDialog {
setHeaderText("Current token balance: " + df.format(tokens));
}
});
} catch (InterruptedException | ExecutionException e) {
LOG.error("Couldn't retrieve account balance", e);
showErrorDialog(e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
handleExcetion(e);
} catch (ExecutionException e) {
handleExcetion(e);
}
}
};
new Thread(task).start();
GlobalThreadPool.submit(task);
}
private void handleExcetion(Exception e) {
LOG.error("Couldn't retrieve account balance", e);
showErrorDialog(e);
}
private void showErrorDialog(Throwable throwable) {

View File

@ -10,6 +10,7 @@ import org.slf4j.LoggerFactory;
import com.google.common.eventbus.Subscribe;
import ctbrec.GlobalThreadPool;
import ctbrec.event.EventBusHolder;
import ctbrec.sites.Site;
import javafx.application.Platform;
@ -19,7 +20,7 @@ import javafx.scene.control.Tooltip;
public class TokenLabel extends Label {
private static final transient Logger LOG = LoggerFactory.getLogger(TokenLabel.class);
private static final Logger LOG = LoggerFactory.getLogger(TokenLabel.class);
private double tokens = -1;
private Site site;
@ -72,17 +73,24 @@ public class TokenLabel extends Label {
@Override
protected void done() {
try {
double tokens = get();
tokens = get();
update(tokens);
} catch (InterruptedException | ExecutionException e) {
LOG.error("Couldn't retrieve account balance", e);
Platform.runLater(() -> {
setText("Tokens: error");
setTooltip(new Tooltip(e.getMessage()));
});
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
handleException(e);
} catch (ExecutionException e) {
handleException(e);
}
}
private void handleException(Exception e) {
LOG.error("Couldn't retrieve account balance", e);
Platform.runLater(() -> {
setText("Tokens: error");
setTooltip(new Tooltip(e.getMessage()));
});
}
};
new Thread(task).start();
GlobalThreadPool.submit(task);
}
}

View File

@ -9,6 +9,7 @@ import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ctbrec.GlobalThreadPool;
import ctbrec.Model;
import ctbrec.recorder.Recorder;
import ctbrec.ui.controls.Dialogs;
@ -70,6 +71,6 @@ public class CheckModelAccountAction {
});
}
});
new Thread(checker).start();
GlobalThreadPool.submit(checker);
}
}

View File

@ -10,7 +10,6 @@ import ctbrec.Config;
import ctbrec.Model;
import ctbrec.ui.JavaFxModel;
import ctbrec.ui.controls.Dialogs;
import javafx.application.Platform;
import javafx.scene.Cursor;
import javafx.scene.Node;
import javafx.scene.control.TableView;
@ -30,23 +29,21 @@ public class EditNotesAction {
public void execute() {
source.setCursor(Cursor.WAIT);
new Thread(() -> Platform.runLater(() -> {
String notes = Config.getInstance().getSettings().modelNotes.getOrDefault(model.getUrl(), "");
Optional<String> newNotes = Dialogs.showTextInput(source.getScene(), "Model Notes", "Notes for " + model.getName(), notes);
newNotes.ifPresent(n -> {
if (!n.trim().isEmpty()) {
Config.getInstance().getSettings().modelNotes.put(model.getUrl(), n);
} else {
Config.getInstance().getSettings().modelNotes.remove(model.getUrl());
}
try {
Config.getInstance().save();
} catch (IOException e) {
LOG.warn("Couldn't save config", e);
}
});
table.refresh();
source.setCursor(Cursor.DEFAULT);
})).start();
String notes = Config.getInstance().getSettings().modelNotes.getOrDefault(model.getUrl(), "");
Optional<String> newNotes = Dialogs.showTextInput(source.getScene(), "Model Notes", "Notes for " + model.getName(), notes);
newNotes.ifPresent(n -> {
if (!n.trim().isEmpty()) {
Config.getInstance().getSettings().modelNotes.put(model.getUrl(), n);
} else {
Config.getInstance().getSettings().modelNotes.remove(model.getUrl());
}
try {
Config.getInstance().save();
} catch (IOException e) {
LOG.warn("Couldn't save config", e);
}
});
table.refresh();
source.setCursor(Cursor.DEFAULT);
}
}

View File

@ -2,13 +2,9 @@ package ctbrec.ui.action;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import ctbrec.GlobalThreadPool;
import ctbrec.Model;
import javafx.application.Platform;
import javafx.scene.Cursor;
@ -16,9 +12,6 @@ import javafx.scene.Node;
public class ModelMassEditAction {
static BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
static ExecutorService threadPool = new ThreadPoolExecutor(2, 10, 10, TimeUnit.MINUTES, queue);
protected List<? extends Model> models;
protected Consumer<Model> action;
protected Node source;
@ -42,7 +35,7 @@ public class ModelMassEditAction {
Consumer<Model> cb = Objects.requireNonNull(callback, "Callback is null, call execute() instead");
source.setCursor(Cursor.WAIT);
for (Model model : models) {
threadPool.submit(() -> {
GlobalThreadPool.submit(() -> {
action.accept(model);
cb.accept(model);
Platform.runLater(() -> source.setCursor(Cursor.DEFAULT));

View File

@ -4,6 +4,7 @@ import java.io.File;
import java.time.Instant;
import ctbrec.Config;
import ctbrec.GlobalThreadPool;
import ctbrec.Model;
import ctbrec.Settings.DirectoryStructure;
import ctbrec.ui.DesktopIntegration;
@ -26,7 +27,7 @@ public class OpenRecordingsDir {
File fileForRecording = Config.getInstance().getFileForRecording(selectedModel, ".mp4", Instant.now());
final File dir = getModelDirectory(fileForRecording);
if (dir.exists()) {
new Thread(() -> DesktopIntegration.open(dir)).start();
GlobalThreadPool.submit(() -> DesktopIntegration.open(dir));
} else {
Dialogs.showError(source.getScene(), "Directory does not exist", "There are no recordings for this model", null);
}

View File

@ -1,5 +1,6 @@
package ctbrec.ui.action;
import ctbrec.GlobalThreadPool;
import ctbrec.recorder.Recorder;
import ctbrec.ui.controls.Dialogs;
import javafx.application.Platform;
@ -20,7 +21,7 @@ public class ToggleRecordingAction {
public void execute() {
toggleButton.setCursor(Cursor.WAIT);
Thread t = new Thread(() -> {
GlobalThreadPool.submit(() -> {
try {
if (pause) {
recorder.pause();
@ -36,7 +37,5 @@ public class ToggleRecordingAction {
Platform.runLater(() -> toggleButton.setCursor(Cursor.DEFAULT));
}
});
t.setDaemon(true);
t.start();
}
}

View File

@ -38,6 +38,7 @@ import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ctbrec.GlobalThreadPool;
import ctbrec.Model;
import ctbrec.recorder.Recorder;
import ctbrec.ui.action.PlayAction;
@ -167,7 +168,7 @@ public class SearchPopoverTreeList extends PopoverTreeList<Model> implements Pop
follow = new Button("Follow");
follow.setOnAction(evt -> {
setCursor(Cursor.WAIT);
new Thread(new Task<Boolean>() {
GlobalThreadPool.submit(new Task<Boolean>() {
@Override
protected Boolean call() throws Exception {
model.getSite().login();
@ -183,12 +184,12 @@ public class SearchPopoverTreeList extends PopoverTreeList<Model> implements Pop
}
Platform.runLater(() -> setCursor(Cursor.DEFAULT));
}
}).start();
});
});
record = new Button("Record");
record.setOnAction(evt -> {
setCursor(Cursor.WAIT);
new Thread(new Task<Void>() {
GlobalThreadPool.submit(new Task<Void>() {
@Override
protected Void call() throws Exception {
recorder.addModel(model);
@ -199,7 +200,7 @@ public class SearchPopoverTreeList extends PopoverTreeList<Model> implements Pop
protected void done() {
Platform.runLater(() -> setCursor(Cursor.DEFAULT));
}
}).start();
});
});
getChildren().addAll(thumb, title, follow, record);
@ -296,12 +297,12 @@ public class SearchPopoverTreeList extends PopoverTreeList<Model> implements Pop
@Override
protected double computePrefHeight(double width) {
return thumbSize + 20;
return thumbSize + 20.0;
}
@Override
protected double computeMaxHeight(double width) {
return thumbSize + 20;
return thumbSize + 20.0;
}
@Override

View File

@ -12,6 +12,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ctbrec.Config;
import ctbrec.GlobalThreadPool;
import ctbrec.Model;
import ctbrec.io.HttpException;
import ctbrec.recorder.download.StreamSource;
@ -79,7 +80,7 @@ public class StreamPreview extends StackPane {
double w = Config.getInstance().getSettings().thumbWidth;
double h = w / aspect;
resizeTo(w, h);
} catch (Exception e) {}
} catch (Exception e) { /* nothing to do */ }
}
if(future != null && !future.isDone()) {
@ -157,14 +158,14 @@ public class StreamPreview extends StackPane {
running = false;
MediaPlayer old = videoPlayer;
Future<?> oldFuture = future;
new Thread(() -> {
GlobalThreadPool.submit(() -> {
if(oldFuture != null && !oldFuture.isDone()) {
oldFuture.cancel(true);
}
if(old != null) {
old.dispose();
}
}).start();
});
}
private void onError(MediaPlayer videoPlayer) {

View File

@ -1,5 +1,6 @@
package ctbrec.ui.controls;
import ctbrec.GlobalThreadPool;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
@ -13,6 +14,8 @@ import javafx.stage.StageStyle;
import javafx.util.Duration;
public final class Toast {
private Toast() {}
public static void makeText(Scene owner, String toastMsg, int toastDelay, int fadeInDelay, int fadeOutDelay) {
Stage toastStage = new Stage();
toastStage.initOwner(owner.getWindow());
@ -35,20 +38,18 @@ public final class Toast {
Timeline fadeInTimeline = new Timeline();
KeyFrame fadeInKey1 = new KeyFrame(Duration.millis(fadeInDelay), new KeyValue(toastStage.getScene().getRoot().opacityProperty(), 1));
fadeInTimeline.getKeyFrames().add(fadeInKey1);
fadeInTimeline.setOnFinished((ae) -> {
new Thread(() -> {
try {
Thread.sleep(toastDelay);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
Timeline fadeOutTimeline = new Timeline();
KeyFrame fadeOutKey1 = new KeyFrame(Duration.millis(fadeOutDelay), new KeyValue(toastStage.getScene().getRoot().opacityProperty(), 0));
fadeOutTimeline.getKeyFrames().add(fadeOutKey1);
fadeOutTimeline.setOnFinished((aeb) -> toastStage.close());
fadeOutTimeline.play();
}).start();
});
fadeInTimeline.setOnFinished(ae -> GlobalThreadPool.submit(() -> {
try {
Thread.sleep(toastDelay);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
Timeline fadeOutTimeline = new Timeline();
KeyFrame fadeOutKey1 = new KeyFrame(Duration.millis(fadeOutDelay), new KeyValue(toastStage.getScene().getRoot().opacityProperty(), 0));
fadeOutTimeline.getKeyFrames().add(fadeOutKey1);
fadeOutTimeline.setOnFinished(aeb -> toastStage.close());
fadeOutTimeline.play();
}));
fadeInTimeline.play();
}
}

View File

@ -1,7 +1,16 @@
package ctbrec.ui.news;
import static ctbrec.io.HttpConstants.*;
import java.io.IOException;
import java.util.Objects;
import org.json.JSONObject;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import ctbrec.GlobalThreadPool;
import ctbrec.io.HttpException;
import ctbrec.ui.CamrecApplication;
import ctbrec.ui.controls.Dialogs;
@ -14,12 +23,6 @@ import javafx.scene.control.Tab;
import javafx.scene.layout.VBox;
import okhttp3.Request;
import okhttp3.Response;
import org.json.JSONObject;
import java.io.IOException;
import java.util.Objects;
import static ctbrec.io.HttpConstants.USER_AGENT;
public class NewsTab extends Tab implements TabSelectionListener {
private static final String ACCESS_TOKEN = "a2804d73a89951a22e0f8483a6fcec8943afd88b7ba17c459c095aa9e6f94fd0";
@ -36,7 +39,7 @@ public class NewsTab extends Tab implements TabSelectionListener {
@Override
public void selected() {
new Thread(this::loadToots).start();
GlobalThreadPool.submit(this::loadToots);
}
private void loadToots() {

View File

@ -22,7 +22,7 @@ import okhttp3.HttpUrl;
public class BongaCamsElectronLoginDialog {
private static final transient Logger LOG = LoggerFactory.getLogger(BongaCamsElectronLoginDialog.class);
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 CookieJar cookieJar;
@ -40,18 +40,18 @@ public class BongaCamsElectronLoginDialog {
msg.put("config", config);
browser.run(msg, msgHandler);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException("Couldn't wait for login dialog", e);
} finally {
browser.close();
}
}
private Consumer<String> msgHandler = (line) -> {
private Consumer<String> msgHandler = line -> {
if(!line.startsWith("{")) {
System.err.println(line);
LOG.error("Didn't received a JSON object {}", line);
} else {
JSONObject json = new JSONObject(line);
//LOG.debug("Browser: {}", json.toString(2));
if(json.has("url")) {
String url = json.getString("url");
if(url.endsWith("/login")) {
@ -82,16 +82,16 @@ public class BongaCamsElectronLoginDialog {
}
if(json.has("cookies")) {
JSONArray _cookies = json.getJSONArray("cookies");
for (int i = 0; i < _cookies.length(); i++) {
JSONObject cookie = _cookies.getJSONObject(i);
JSONArray cookiesFromBrowser = json.getJSONArray("cookies");
for (int i = 0; i < cookiesFromBrowser.length(); i++) {
JSONObject cookie = cookiesFromBrowser.getJSONObject(i);
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(Double.valueOf(cookie.optDouble("expirationDate")).longValue());
.expiresAt((long) cookie.optDouble("expirationDate"));
if(cookie.optBoolean("hostOnly")) {
b.hostOnlyDomain(DOMAIN);
}
@ -108,8 +108,7 @@ public class BongaCamsElectronLoginDialog {
}
try {
URL _url = new URL(url);
if (Objects.equals(_url.getPath(), "/")) {
if (Objects.equals(new URL(url).getPath(), "/")) {
browser.close();
}
} catch (MalformedURLException e) {

View File

@ -1,17 +1,16 @@
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;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class BongaCamsSiteUi extends AbstractSiteUi {
@ -39,37 +38,20 @@ public class BongaCamsSiteUi extends AbstractSiteUi {
@Override
public synchronized boolean login() throws IOException {
boolean automaticLogin = bongaCams.login();
if(automaticLogin) {
if (automaticLogin) {
return true;
} else {
BlockingQueue<Boolean> queue = new LinkedBlockingQueue<>();
// login with external browser window
try {
new Thread(() -> {
// login with external browser window
try {
new BongaCamsElectronLoginDialog(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);
}
try {
queue.put(true);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LOG.error("Error while signaling termination", e);
}
}).start();
queue.take();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
LOG.error("Error while waiting for login dialog to close", e);
throw new IOException(e);
new BongaCamsElectronLoginDialog(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);
}
BongaCamsHttpClient httpClient = (BongaCamsHttpClient)bongaCams.getHttpClient();
BongaCamsHttpClient httpClient = (BongaCamsHttpClient) bongaCams.getHttpClient();
boolean loggedIn = httpClient.checkLoginSuccess();
if(loggedIn) {
if (loggedIn) {
LOG.info("Logged in. User ID is {}", httpClient.getUserId());
} else {
LOG.info("Login failed");

View File

@ -22,7 +22,7 @@ import okhttp3.HttpUrl;
public class Cam4ElectronLoginDialog {
private static final transient Logger LOG = LoggerFactory.getLogger(Cam4ElectronLoginDialog.class);
private static final Logger LOG = LoggerFactory.getLogger(Cam4ElectronLoginDialog.class);
public static final String DOMAIN = "cam4.com";
public static final String URL = Cam4.BASE_URI + "/login";
private CookieJar cookieJar;
@ -40,15 +40,16 @@ public class Cam4ElectronLoginDialog {
msg.put("config", config);
browser.run(msg, msgHandler);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException("Couldn't wait for login dialog", e);
} finally {
browser.close();
}
}
private Consumer<String> msgHandler = (line) -> {
private Consumer<String> msgHandler = line -> {
if(!line.startsWith("{")) {
System.err.println(line);
LOG.error("Didn't received a JSON object {}", line);
} else {
JSONObject json = new JSONObject(line);
if(json.has("url")) {
@ -75,11 +76,10 @@ public class Cam4ElectronLoginDialog {
}
if(json.has("cookies")) {
JSONArray _cookies = json.getJSONArray("cookies");
JSONArray cookiesFromBrowser = json.getJSONArray("cookies");
try {
URL _url = new URL(url);
for (int i = 0; i < _cookies.length(); i++) {
JSONObject cookie = _cookies.getJSONObject(i);
for (int i = 0; i < cookiesFromBrowser.length(); i++) {
JSONObject cookie = cookiesFromBrowser.getJSONObject(i);
if(cookie.getString("domain").contains("cam4")) {
String domain = cookie.getString("domain");
if(domain.startsWith(".")) {
@ -91,12 +91,8 @@ public class Cam4ElectronLoginDialog {
cookieJar.saveFromResponse(HttpUrl.parse(Cam4.BASE_URI), Collections.singletonList(c));
}
}
if (Objects.equals(_url.getPath(), "/")) {
try {
browser.close();
} catch(IOException e) {
LOG.error("Couldn't send close request to browser", e);
}
if (Objects.equals(new URL(url).getPath(), "/")) {
closeBrowser();
}
} catch (MalformedURLException e) {
LOG.error("Couldn't parse new url {}", url, e);
@ -112,7 +108,7 @@ public class Cam4ElectronLoginDialog {
.domain(domain)
.name(cookie.getString("name"))
.value(cookie.getString("value"))
.expiresAt(Double.valueOf(cookie.optDouble("expirationDate")).longValue());
.expiresAt((long) cookie.optDouble("expirationDate"));
if(cookie.optBoolean("hostOnly")) {
b.hostOnlyDomain(domain);
}
@ -124,4 +120,12 @@ public class Cam4ElectronLoginDialog {
}
return b.build();
}
private void closeBrowser() {
try {
browser.close();
} catch(IOException e) {
LOG.error("Couldn't send close request to browser", e);
}
}
}

View File

@ -1,8 +1,6 @@
package ctbrec.ui.sites.cam4;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -13,10 +11,9 @@ import ctbrec.ui.controls.Dialogs;
import ctbrec.ui.sites.AbstractSiteUi;
import ctbrec.ui.sites.ConfigUI;
import ctbrec.ui.tabs.TabProvider;
import javafx.application.Platform;
public class Cam4SiteUi extends AbstractSiteUi {
private static final transient Logger LOG = LoggerFactory.getLogger(Cam4SiteUi.class);
private static final Logger LOG = LoggerFactory.getLogger(Cam4SiteUi.class);
private Cam4TabProvider tabProvider;
private Cam4ConfigUI configUI;
@ -44,33 +41,13 @@ public class Cam4SiteUi extends AbstractSiteUi {
if (automaticLogin) {
return true;
} else {
BlockingQueue<Boolean> queue = new LinkedBlockingQueue<>();
Runnable showDialog = () -> {
// login with external browser
try {
new Cam4ElectronLoginDialog(cam4.getHttpClient().getCookieJar());
} catch (Exception e1) {
LOG.error("Error logging in with external browser", e1);
Dialogs.showError("Login error", "Couldn't login to " + cam4.getName(), e1);
}
try {
queue.put(true);
} catch (InterruptedException e) {
LOG.error("Error while signaling termination", e);
}
};
Platform.runLater(showDialog);
// login with external browser
try {
queue.take();
} catch (InterruptedException e) {
LOG.error("Error while waiting for login dialog to close", e);
throw new IOException(e);
new Cam4ElectronLoginDialog(cam4.getHttpClient().getCookieJar());
} catch (Exception e1) {
LOG.error("Error logging in with external browser", e1);
Dialogs.showError("Login error", "Couldn't login to " + cam4.getName(), e1);
}
Cam4HttpClient httpClient = (Cam4HttpClient) cam4.getHttpClient();
boolean loggedIn = httpClient.checkLoginSuccess();
return loggedIn;

View File

@ -10,7 +10,6 @@ import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import org.json.JSONObject;
import org.jsoup.nodes.Element;
@ -43,14 +42,11 @@ public class Cam4UpdateService extends PaginatedScheduledService {
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;
}
ExecutorService executor = Executors.newSingleThreadExecutor(r -> {
Thread t = new Thread(r);
t.setDaemon(true);
t.setName("ThumbOverviewTab UpdateService");
return t;
});
setExecutor(executor);
}
@ -60,16 +56,16 @@ public class Cam4UpdateService extends PaginatedScheduledService {
return new Task<List<Model>>() {
@Override
public List<Model> call() throws IOException {
if(loginRequired && StringUtil.isBlank(Config.getInstance().getSettings().cam4Username)) {
if (loginRequired && StringUtil.isBlank(Config.getInstance().getSettings().cam4Username)) {
return Collections.emptyList();
} else {
String url = Cam4UpdateService.this.url + "&page=" + page;
LOG.debug("Fetching page {}", url);
if(loginRequired) {
String pageUrl = Cam4UpdateService.this.url + "&page=" + page;
LOG.debug("Fetching page {}", pageUrl);
if (loginRequired) {
SiteUiFactory.getUi(site).login();
}
Request request = new Request.Builder()
.url(url)
.url(pageUrl)
.header(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage())
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
.build();
@ -91,7 +87,7 @@ public class Cam4UpdateService extends PaginatedScheduledService {
model.setPreview("https://snapshots.xcdnpro.com/thumbnails/" + model.getName() + "?s=" + System.currentTimeMillis());
model.setDescription(parseDesription(boxHtml));
model.setOnlineState(ONLINE);
if(boxHtml.contains("In private show")) {
if (boxHtml.contains("In private show")) {
model.setOnlineState(PRIVATE);
}
models.add(model);

View File

@ -5,7 +5,6 @@ import java.util.Collections;
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;
@ -21,7 +20,7 @@ import okhttp3.Response;
public class ChaturbateUpdateService extends PaginatedScheduledService {
private static final transient Logger LOG = LoggerFactory.getLogger(ChaturbateUpdateService.class);
private static final Logger LOG = LoggerFactory.getLogger(ChaturbateUpdateService.class);
private String url;
private boolean loginRequired;
private Chaturbate chaturbate;
@ -31,14 +30,11 @@ public class ChaturbateUpdateService extends PaginatedScheduledService {
this.loginRequired = loginRequired;
this.chaturbate = chaturbate;
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;
}
ExecutorService executor = Executors.newSingleThreadExecutor(r -> {
Thread t = new Thread(r);
t.setDaemon(true);
t.setName("ThumbOverviewTab UpdateService");
return t;
});
setExecutor(executor);
}
@ -51,12 +47,12 @@ public class ChaturbateUpdateService extends PaginatedScheduledService {
if(loginRequired && !chaturbate.credentialsAvailable()) {
return Collections.emptyList();
} else {
String url = ChaturbateUpdateService.this.url + "?page="+page+"&keywords=&_=" + System.currentTimeMillis();
LOG.debug("Fetching page {}", url);
String pageUrl = ChaturbateUpdateService.this.url + "?page="+page+"&keywords=&_=" + System.currentTimeMillis();
LOG.debug("Fetching page {}", pageUrl);
if(loginRequired) {
SiteUiFactory.getUi(chaturbate).login();
}
Request request = new Request.Builder().url(url).build();
Request request = new Request.Builder().url(pageUrl).build();
Response response = chaturbate.getHttpClient().execute(request);
if (response.isSuccessful()) {
List<Model> models = ChaturbateModelParser.parseModels(chaturbate, response.body().string());

View File

@ -5,6 +5,7 @@ import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ctbrec.GlobalThreadPool;
import ctbrec.Model;
import ctbrec.sites.fc2live.Fc2Live;
import ctbrec.sites.fc2live.Fc2Model;
@ -16,7 +17,7 @@ import ctbrec.ui.sites.ConfigUI;
import ctbrec.ui.tabs.TabProvider;
public class Fc2LiveSiteUi extends AbstractSiteUi {
private static final transient Logger LOG = LoggerFactory.getLogger(Fc2LiveSiteUi.class);
private static final Logger LOG = LoggerFactory.getLogger(Fc2LiveSiteUi.class);
private Fc2Live fc2live;
private Fc2TabProvider tabProvider;
private Fc2LiveConfigUI configUi;
@ -44,10 +45,10 @@ public class Fc2LiveSiteUi extends AbstractSiteUi {
@Override
public boolean play(Model model) {
new Thread(() -> {
GlobalThreadPool.submit(() -> {
Fc2Model m;
if(model instanceof JavaFxModel) {
m = (Fc2Model) ((JavaFxModel)model).getDelegate();
if (model instanceof JavaFxModel) {
m = (Fc2Model) ((JavaFxModel) model).getDelegate();
} else {
m = (Fc2Model) model;
}
@ -55,12 +56,20 @@ public class Fc2LiveSiteUi extends AbstractSiteUi {
m.openWebsocket();
LOG.debug("Starting player for {}", model);
Player.play(model, false);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
handleException(e);
} catch (IOException e) {
handleException(e);
} finally {
m.closeWebsocket();
} catch (InterruptedException | IOException e) {
LOG.error("Error playing the stream", e);
Dialogs.showError("Player", "Error playing the stream", e);
}
}).start();
});
return true;
}
private void handleException(Exception e) {
LOG.error("Error playing the stream", e);
Dialogs.showError("Player", "Error playing the stream", e);
}
}

View File

@ -1,8 +1,6 @@
package ctbrec.ui.sites.jasmin;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
@ -17,7 +15,7 @@ import ctbrec.ui.tabs.TabProvider;
public class LiveJasminSiteUi extends AbstractSiteUi {
private static final transient Logger LOG = LoggerFactory.getLogger(LiveJasminSiteUi.class);
private static final Logger LOG = LoggerFactory.getLogger(LiveJasminSiteUi.class);
private LiveJasmin liveJasmin;
private LiveJasminTabProvider tabProvider;
private LiveJasminConfigUi configUi;
@ -44,43 +42,27 @@ public class LiveJasminSiteUi extends AbstractSiteUi {
// renew login every 30 min
long now = System.currentTimeMillis();
boolean renew = false;
if((now - lastLoginTime) > TimeUnit.MINUTES.toMillis(30)) {
if ((now - lastLoginTime) > TimeUnit.MINUTES.toMillis(30)) {
renew = true;
}
boolean automaticLogin = liveJasmin.login();
if(automaticLogin && !renew) {
if (automaticLogin && !renew) {
return true;
} else {
lastLoginTime = System.currentTimeMillis();
BlockingQueue<Boolean> queue = new LinkedBlockingQueue<>();
new Thread (() -> {
// login with external browser window
try {
new LiveJasminElectronLoginDialog(liveJasmin.getHttpClient().getCookieJar());
} catch (Exception e1) {
LOG.error("Error logging in with external browser", e1);
Dialogs.showError("Login error", "Couldn't login to " + liveJasmin.getName(), e1);
}
try {
queue.put(true);
} catch (InterruptedException e) {
LOG.error("Error while signaling termination", e);
}
}).start();
// login with external browser window
try {
queue.take();
} catch (InterruptedException e) {
LOG.error("Error while waiting for login dialog to close", e);
throw new IOException(e);
new LiveJasminElectronLoginDialog(liveJasmin.getHttpClient().getCookieJar());
} catch (Exception e1) {
LOG.error("Error logging in with external browser", e1);
Dialogs.showError("Login error", "Couldn't login to " + liveJasmin.getName(), e1);
}
LiveJasminHttpClient httpClient = (LiveJasminHttpClient)liveJasmin.getHttpClient();
LiveJasminHttpClient httpClient = (LiveJasminHttpClient) liveJasmin.getHttpClient();
boolean loggedIn = httpClient.checkLoginSuccess();
if(loggedIn) {
if (loggedIn) {
LOG.info("Logged in");
} else {
LOG.info("Login failed");

View File

@ -33,6 +33,7 @@ import com.iheartradio.m3u8.ParseException;
import com.iheartradio.m3u8.PlaylistException;
import ctbrec.Config;
import ctbrec.GlobalThreadPool;
import ctbrec.Model;
import ctbrec.Settings;
import ctbrec.StringUtil;
@ -353,7 +354,7 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
if (Objects.equals(System.getenv("CTBREC_DEV"), "1")) {
MenuItem debug = new MenuItem("debug");
debug.setOnAction(e -> new Thread(() -> {
debug.setOnAction(e -> GlobalThreadPool.submit(() -> {
for (Model m : selectedModels) {
try {
List<StreamSource> sources = m.getStreamSources();
@ -365,7 +366,7 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
LOG.error("Couldn't get stream sources", e1);
}
}
}).start());
}));
menu.getItems().add(debug);
}
@ -464,7 +465,7 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
private String escape(Property<?> prop) {
String value = prop.getValue() != null ? prop.getValue().toString() : "";
return "\"" + value.replaceAll("\"", "\"\"") + "\"";
return "\"" + value.replace("\"", "\"\"") + "\"";
}
private void showColumnSelection(ActionEvent evt) {
@ -566,7 +567,7 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
if(!file.exists()) {
return;
}
String json = new String(Files.readAllBytes(file.toPath()), "utf-8");
String json = new String(Files.readAllBytes(file.toPath()), UTF_8);
JSONArray data = new JSONArray(json);
for (int i = 0; i < data.length(); i++) {
try {
@ -701,7 +702,6 @@ public class MyFreeCamsTableTab extends Tab implements TabSelectionListener {
setProperty(continent, Optional.ofNullable(st.getM()).map(ctbrec.sites.mfc.Model::getContinent));
setProperty(occupation, Optional.ofNullable(st.getU()).map(User::getOccupation));
int flags = Optional.ofNullable(st.getM()).map(ctbrec.sites.mfc.Model::getFlags).orElse(0);
//isHd.set((flags & 1024) == 1024);
isWebrtc.set((flags & 524288) == 524288);
isHd.set(Optional.ofNullable(st.getU()).map(User::getPhase).orElse("z").equalsIgnoreCase("a"));
flagsProperty.setValue(flags);

View File

@ -1,8 +1,6 @@
package ctbrec.ui.sites.showup;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -44,33 +42,17 @@ public class ShowupSiteUi extends AbstractSiteUi {
if (automaticLogin) {
return true;
} else {
BlockingQueue<Boolean> queue = new LinkedBlockingQueue<>();
// login with external browser window
try {
new Thread(() -> {
// login with external browser window
try {
new ShowupElectronLoginDialog(site.getHttpClient().getCookieJar());
} catch (Exception e1) {
LOG.error("Error logging in with external browser", e1);
Dialogs.showError("Login error", "Couldn't login to " + site.getName(), e1);
}
try {
queue.put(true);
} catch (InterruptedException e) {
LOG.error("Error while signaling termination", e);
Thread.currentThread().interrupt();
}
}).start();
queue.take();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException(e);
new ShowupElectronLoginDialog(site.getHttpClient().getCookieJar());
} catch (Exception e1) {
LOG.error("Error logging in with external browser", e1);
Dialogs.showError("Login error", "Couldn't login to " + site.getName(), e1);
}
ShowupHttpClient httpClient = (ShowupHttpClient)site.getHttpClient();
ShowupHttpClient httpClient = (ShowupHttpClient) site.getHttpClient();
boolean loggedIn = httpClient.checkLoginSuccess();
if(loggedIn) {
if (loggedIn) {
LOG.info("Logged in");
} else {
LOG.info("Login failed");
@ -78,5 +60,4 @@ public class ShowupSiteUi extends AbstractSiteUi {
return loggedIn;
}
}
}

View File

@ -1,8 +1,6 @@
package ctbrec.ui.sites.stripchat;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -13,7 +11,6 @@ import ctbrec.ui.controls.Dialogs;
import ctbrec.ui.sites.AbstractSiteUi;
import ctbrec.ui.sites.ConfigUI;
import ctbrec.ui.tabs.TabProvider;
import javafx.application.Platform;
public class StripchatSiteUi extends AbstractSiteUi {
@ -45,31 +42,12 @@ public class StripchatSiteUi extends AbstractSiteUi {
if (automaticLogin) {
return true;
} else {
BlockingQueue<Boolean> queue = new LinkedBlockingQueue<>();
Runnable showDialog = () -> {
// login with external browser
try {
new StripchatElectronLoginDialog(site.getHttpClient().getCookieJar());
} catch (Exception e1) {
LOG.error("Error logging in with external browser", e1);
Dialogs.showError("Login error", "Couldn't login to " + site.getName(), e1);
}
try {
queue.put(true);
} catch (InterruptedException e) {
LOG.error("Error while signaling termination", e);
}
};
Platform.runLater(showDialog);
// login with external browser
try {
queue.take();
} catch (InterruptedException e) {
LOG.error("Error while waiting for login dialog to close", e);
throw new IOException(e);
new StripchatElectronLoginDialog(site.getHttpClient().getCookieJar());
} catch (Exception e1) {
LOG.error("Error logging in with external browser", e1);
Dialogs.showError("Login error", "Couldn't login to " + site.getName(), e1);
}
StripchatHttpClient httpClient = (StripchatHttpClient) site.getHttpClient();

View File

@ -28,6 +28,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ctbrec.Config;
import ctbrec.GlobalThreadPool;
import ctbrec.Model;
import ctbrec.Recording;
import ctbrec.Recording.State;
@ -496,9 +497,9 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
private void openContactSheet(JavaFxRecording recording) {
if (config.getSettings().localRecording) {
recording.getContactSheet().ifPresent(f -> new Thread(() -> DesktopIntegration.open(f)).start());
recording.getContactSheet().ifPresent(f -> GlobalThreadPool.submit(() -> DesktopIntegration.open(f)));
} else {
recording.getContactSheet().ifPresent(f -> new Thread(() -> {
recording.getContactSheet().ifPresent(f -> GlobalThreadPool.submit(() -> {
File target;
try {
target = File.createTempFile("cs_", ".jpg");
@ -516,7 +517,7 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
} catch (IOException | InvalidKeyException | NoSuchAlgorithmException | IllegalStateException e) {
Dialogs.showError(getTabPane().getScene(), "Download Error", "An error occurred while downloading the contact sheet", e);
}
}).start());
}));
}
}
@ -526,7 +527,7 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
Optional<String> newNote = Dialogs.showTextInput(source.getScene(), "Recording Notes", "", notes);
if (newNote.isPresent()) {
table.setCursor(Cursor.WAIT);
Thread backgroundThread = new Thread(() -> {
GlobalThreadPool.submit(() -> {
List<Exception> exceptions = new ArrayList<>();
try {
recording.setNote(newNote.get());
@ -542,13 +543,12 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
});
}
});
backgroundThread.start();
}
}
private void pin(List<JavaFxRecording> recordings) {
table.setCursor(Cursor.WAIT);
Thread backgroundThread = new Thread(() -> {
GlobalThreadPool.submit(() -> {
List<Exception> exceptions = new ArrayList<>();
try {
for (JavaFxRecording javaFxRecording : recordings) {
@ -569,12 +569,11 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
});
}
});
backgroundThread.start();
}
private void unpin(List<JavaFxRecording> recordings) {
table.setCursor(Cursor.WAIT);
Thread backgroundThread = new Thread(() -> {
GlobalThreadPool.submit(() -> {
List<Exception> exceptions = new ArrayList<>();
try {
for (JavaFxRecording javaFxRecording : recordings) {
@ -595,7 +594,6 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
});
}
});
backgroundThread.start();
}
private void jumpToNextModel(KeyCode code) {
@ -646,11 +644,11 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
private void onOpenDirectory(JavaFxRecording first) {
File tsFile = first.getAbsoluteFile();
new Thread(() -> DesktopIntegration.open(tsFile.getParent())).start();
GlobalThreadPool.submit(() -> DesktopIntegration.open(tsFile.getParent()));
}
private void triggerPostProcessing(List<JavaFxRecording> recs) {
new Thread(() -> {
GlobalThreadPool.submit(() -> {
for (JavaFxRecording rec : recs) {
try {
recorder.rerunPostProcessing(rec.getDelegate());
@ -659,7 +657,7 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
LOG.error("Error while starting post-processing", e1);
}
}
}).start();
});
}
private void download(Recording recording) {
@ -761,12 +759,12 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
}
private void play(Recording recording) {
new Thread(() -> {
GlobalThreadPool.submit(() -> {
boolean started = Player.play(recording);
if (started && Config.getInstance().getSettings().showPlayerStarting) {
Platform.runLater(() -> Toast.makeText(getTabPane().getScene(), "Starting Player", 2000, 500, 500));
}
}).start();
});
}
private void play(Model model) {

View File

@ -8,8 +8,6 @@ import java.util.Locale;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
@ -107,7 +105,6 @@ public class ThumbCell extends StackPane {
private ObservableList<Node> thumbCellList;
private boolean mouseHovering = false;
private boolean recording = false;
private static ExecutorService imageLoadingThreadPool = Executors.newFixedThreadPool(30);
static LoadingCache<Model, int[]> resolutionCache = CacheBuilder.newBuilder()
.expireAfterAccess(5, TimeUnit.MINUTES)
.maximumSize(10000)
@ -388,7 +385,7 @@ public class ThumbCell extends StackPane {
if (!Objects.equals(System.getenv("CTBREC_DEV"), "1")) {
boolean updateThumbs = Config.getInstance().getSettings().updateThumbnails;
if (updateThumbs || iv.getImage() == null) {
imageLoadingThreadPool.submit(createThumbDownload(url));
GlobalThreadPool.submit(createThumbDownload(url));
}
}
}
@ -513,7 +510,7 @@ public class ThumbCell extends StackPane {
void pauseResumeAction(boolean pause) {
setCursor(Cursor.WAIT);
new Thread(() -> {
GlobalThreadPool.submit(() -> {
try {
if (pause) {
recorder.suspendRecording(model);
@ -533,11 +530,11 @@ public class ThumbCell extends StackPane {
} finally {
Platform.runLater(() -> setCursor(Cursor.DEFAULT));
}
}).start();
});
}
private void startStopActionAsync(Model model, boolean start) {
new Thread(() -> {
GlobalThreadPool.submit(() -> {
try {
if (start) {
recorder.addModel(model);
@ -553,7 +550,7 @@ public class ThumbCell extends StackPane {
} finally {
Platform.runLater(() -> setCursor(Cursor.DEFAULT));
}
}).start();
});
}
CompletableFuture<Boolean> follow(boolean follow) {

View File

@ -27,6 +27,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ctbrec.Config;
import ctbrec.GlobalThreadPool;
import ctbrec.Model;
import ctbrec.event.EventBusHolder;
import ctbrec.recorder.Recorder;
@ -299,7 +300,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
return;
}
searchTask = new ThumbOverviewTabSearchTask(site, popover, popoverTreeList, newValue);
new Thread(searchTask).start();
GlobalThreadPool.submit(searchTask);
};
}
@ -602,7 +603,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
private MenuItem createTipMenuItem(ThumbCell cell) {
MenuItem sendTip = new MenuItem("Send Tip");
sendTip.setOnAction(e -> {
TipDialog tipDialog = new TipDialog(getTabPane().getScene(), site, cell.getModel());
TipDialog tipDialog = new TipDialog(getTabPane().getScene(), site);
tipDialog.showAndWait();
String tipText = tipDialog.getResult();
if(tipText != null) {

View File

@ -8,7 +8,7 @@ import java.util.concurrent.Future;
public class GlobalThreadPool {
private static ExecutorService threadPool = Executors.newCachedThreadPool(r -> {
private static ExecutorService threadPool = Executors.newFixedThreadPool(30, r -> {
Thread t = new Thread(r);
t.setDaemon(true);
t.setName("GlobalWorker-" + UUID.randomUUID().toString().substring(0, 8));

View File

@ -82,9 +82,6 @@ public class MergedFfmpegHlsDownload extends AbstractHlsDownload {
public void start() throws IOException {
try {
running = true;
Thread.currentThread().setName("Download " + model.getName());
super.startTime = Instant.now();
String segments = getSegmentPlaylistUrl(model);
Files.createDirectories(targetFile.getParentFile().toPath());

View File

@ -11,6 +11,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ctbrec.Config;
import ctbrec.GlobalThreadPool;
import ctbrec.Model;
import ctbrec.io.HttpClient;
import okhttp3.Request;
@ -78,9 +79,9 @@ public class LiveJasminTippingWebSocket {
LOG.trace("relay <-- {} T{}", model.getName(), text);
JSONObject event = new JSONObject(text);
if (event.optString("event").equals("accept")) {
new Thread(() -> {
GlobalThreadPool.submit(() -> {
sendToRelay("{\"event\":\"connectSharedObject\",\"name\":\"data/chat_so\"}");
}).start();
});
} else if(event.optString("event").equals("call")) {
String func = event.optString("funcName");
if (func.equals("setName")) {

View File

@ -1,5 +1,6 @@
package ctbrec.recorder.server;
import static java.nio.charset.StandardCharsets.*;
import static javax.servlet.http.HttpServletResponse.*;
import java.io.BufferedReader;
@ -53,6 +54,7 @@ import org.slf4j.LoggerFactory;
import com.google.common.base.Objects;
import ctbrec.Config;
import ctbrec.NotLoggedInExcetion;
import ctbrec.Version;
import ctbrec.event.EventBusHolder;
import ctbrec.event.EventHandler;
@ -124,7 +126,7 @@ public class HttpServer {
if (success) {
LOG.info("Successfully logged in to {}", site.getName());
} else {
throw new RuntimeException("Login returned false");
throw new NotLoggedInExcetion("Login returned false");
}
} catch (Exception e) {
LOG.info("Login to {} failed", site.getName());
@ -243,7 +245,7 @@ public class HttpServer {
byte[] hmac = Optional.ofNullable(HttpServer.this.config.getSettings().key).orElse(new byte[0]);
try {
JSONObject response = new JSONObject();
response.put("hmac", new String(hmac, "utf-8"));
response.put("hmac", new String(hmac, UTF_8));
resp.getOutputStream().println(response.toString());
} catch (Exception e) {
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);

View File

@ -1,23 +1,7 @@
package ctbrec.recorder.server;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import ctbrec.Config;
import ctbrec.Model;
import ctbrec.Recording;
import ctbrec.io.BandwidthMeter;
import ctbrec.io.FileJsonAdapter;
import ctbrec.io.InstantJsonAdapter;
import ctbrec.io.ModelJsonAdapter;
import ctbrec.recorder.Recorder;
import ctbrec.sites.Site;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static javax.servlet.http.HttpServletResponse.*;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.security.InvalidKeyException;
@ -27,7 +11,27 @@ import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import static javax.servlet.http.HttpServletResponse.*;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import ctbrec.Config;
import ctbrec.GlobalThreadPool;
import ctbrec.Model;
import ctbrec.Recording;
import ctbrec.io.BandwidthMeter;
import ctbrec.io.FileJsonAdapter;
import ctbrec.io.InstantJsonAdapter;
import ctbrec.io.ModelJsonAdapter;
import ctbrec.recorder.Recorder;
import ctbrec.sites.Site;
public class RecorderServlet extends AbstractCtbrecServlet {
@ -87,24 +91,24 @@ public class RecorderServlet extends AbstractCtbrecServlet {
resp.getWriter().write(response);
break;
case "stop":
new Thread(() -> {
GlobalThreadPool.submit(() -> {
try {
recorder.stopRecording(request.model);
} catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException | IOException e) {
LOG.error("Couldn't stop recording for model {}", request.model, e);
}
}).start();
});
response = "{\"status\": \"success\", \"msg\": \"Stopping recording\"}";
resp.getWriter().write(response);
break;
case "stopAt":
new Thread(() -> {
GlobalThreadPool.submit(() -> {
try {
recorder.stopRecordingAt(request.model);
} catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException | IOException e) {
LOG.error("Couldn't stop recording for model {}", request.model, e);
}
}).start();
});
response = "{\"status\": \"success\", \"msg\": \"Stopping recording\"}";
resp.getWriter().write(response);
break;
@ -189,13 +193,13 @@ public class RecorderServlet extends AbstractCtbrecServlet {
break;
case "suspend":
LOG.debug("Suspend recording for model {} - {}", request.model.getName(), request.model.getUrl());
new Thread(() -> {
GlobalThreadPool.submit(() -> {
try {
recorder.suspendRecording(request.model);
} catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException | IOException e) {
LOG.error("Couldn't suspend recording for model {}", request.model, e);
}
}).start();
});
response = "{\"status\": \"success\", \"msg\": \"Suspending recording\"}";
resp.getWriter().write(response);
break;