diff --git a/client/src/main/java/ctbrec/ui/CamrecApplication.java b/client/src/main/java/ctbrec/ui/CamrecApplication.java index 9628b12c..03c539a9 100644 --- a/client/src/main/java/ctbrec/ui/CamrecApplication.java +++ b/client/src/main/java/ctbrec/ui/CamrecApplication.java @@ -14,6 +14,9 @@ import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -101,14 +104,38 @@ public class CamrecApplication extends Application { private Stage primaryStage; private RecordedModelsTab modelsTab; private RecordingsTab recordingsTab; - + private ScheduledExecutorService scheduler; private int activeRecordings = 0; private double bytesPerSecond = 0; + @Override public void start(Stage primaryStage) throws Exception { this.primaryStage = primaryStage; + scheduler = Executors.newScheduledThreadPool(1, r -> { + Thread t = new Thread(r); + t.setDaemon(true); + t.setName("Scheduler"); + return t; + }); + logEnvironment(); + initSites(); + loadConfig(); + registerAlertSystem(); + registerActiveRecordingsCounter(); + registerBandwidthMeterListener(); + createHttpClient(); + hostServices = getHostServices(); + createRecorder(); + startOnlineMonitor(); + createGui(primaryStage); + checkForUpdates(); + startHelpServer(); + registerClipboardListener(); + } + + private void initSites() { sites.add(new BongaCams()); sites.add(new Cam4()); sites.add(new Camsoda()); @@ -121,17 +148,13 @@ public class CamrecApplication extends Application { sites.add(new Showup()); sites.add(new Streamate()); sites.add(new Stripchat()); - loadConfig(); - registerAlertSystem(); - registerActiveRecordingsCounter(); - registerBandwidthMeterListener(); - createHttpClient(); - hostServices = getHostServices(); - createRecorder(); - startOnlineMonitor(); - createGui(primaryStage); - checkForUpdates(); - startHelpServer(); + } + + private void registerClipboardListener() { + if(config.getSettings().monitorClipboard) { + ClipboardListener clipboardListener = new ClipboardListener(recorder, sites); + scheduler.scheduleAtFixedRate(clipboardListener, 0, 1, TimeUnit.SECONDS); + } } private void startHelpServer() { @@ -307,6 +330,7 @@ public class CamrecApplication extends Application { } catch (IOException e12) { // noop } + scheduler.shutdownNow(); }).start(); }; } diff --git a/client/src/main/java/ctbrec/ui/ClipboardListener.java b/client/src/main/java/ctbrec/ui/ClipboardListener.java new file mode 100644 index 00000000..dc83cb96 --- /dev/null +++ b/client/src/main/java/ctbrec/ui/ClipboardListener.java @@ -0,0 +1,66 @@ +package ctbrec.ui; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.List; +import java.util.Objects; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ctbrec.Model; +import ctbrec.recorder.Recorder; +import ctbrec.sites.Site; +import javafx.application.Platform; +import javafx.scene.input.Clipboard; + +public class ClipboardListener implements Runnable { + + private static final Logger LOG = LoggerFactory.getLogger(ClipboardListener.class); + private Recorder recorder; + private List sites; + private Clipboard systemClipboard; + private String lastUrl = null; + + public ClipboardListener(Recorder recorder, List sites) { + this.recorder = recorder; + this.sites = sites; + systemClipboard = Clipboard.getSystemClipboard(); + } + + @Override + public void run() { + Platform.runLater(() -> { + try { + String url = null; + if (systemClipboard.hasUrl()) { + url = systemClipboard.getUrl(); + } else if (systemClipboard.hasString()) { + url = systemClipboard.getString(); + } + if (!Objects.equals(url, lastUrl)) { + lastUrl = url; + addModelIfUrlMatches(url); + } + } catch (Exception e) { + LOG.error("Error in clipboard polling loop", e); + } + }); + } + + private void addModelIfUrlMatches(String url) { + for (Site site : sites) { + Model m = site.createModelFromUrl(url); + if (m != null) { + try { + recorder.startRecording(m); + DesktopIntegration.notification("Add from clipboard", "Model added", "Model " + m.getDisplayName() + " added"); + } catch (InvalidKeyException | NoSuchAlgorithmException | IOException e) { + DesktopIntegration.notification("Add from clipboard", "Error", "Couldn't add URL from clipboard: " + e.getLocalizedMessage()); + } + break; + } + } + } +} diff --git a/client/src/main/java/ctbrec/ui/settings/SettingsTab.java b/client/src/main/java/ctbrec/ui/settings/SettingsTab.java index c01ed574..39e30bce 100644 --- a/client/src/main/java/ctbrec/ui/settings/SettingsTab.java +++ b/client/src/main/java/ctbrec/ui/settings/SettingsTab.java @@ -74,6 +74,7 @@ public class SettingsTab extends Tab implements TabSelectionListener { private SimpleBooleanProperty determineResolution; private SimpleBooleanProperty chooseStreamQuality; private SimpleBooleanProperty livePreviews; + private SimpleBooleanProperty monitorClipboard; private SimpleListProperty startTab; private SimpleFileProperty mediaPlayer; private SimpleStringProperty mediaPlayerParams; @@ -126,6 +127,7 @@ public class SettingsTab extends Tab implements TabSelectionListener { determineResolution = new SimpleBooleanProperty(null, "determineResolution", settings.determineResolution); chooseStreamQuality = new SimpleBooleanProperty(null, "chooseStreamQuality", settings.chooseStreamQuality); livePreviews = new SimpleBooleanProperty(null, "livePreviews", settings.livePreviews); + monitorClipboard = new SimpleBooleanProperty(null, "monitorClipboard", settings.monitorClipboard); startTab = new SimpleListProperty<>(null, "startTab", FXCollections.observableList(getTabNames())); mediaPlayer = new SimpleFileProperty(null, "mediaPlayer", settings.mediaPlayer); mediaPlayerParams = new SimpleStringProperty(null, "mediaPlayerParams", settings.mediaPlayerParams); @@ -179,6 +181,7 @@ public class SettingsTab extends Tab implements TabSelectionListener { Setting.of("Display stream resolution in overview", determineResolution), Setting.of("Manually select stream quality", chooseStreamQuality, "Opens a dialog to select the video resolution before recording"), Setting.of("Enable live previews (experimental)", livePreviews), + Setting.of("Add models from clipboard", monitorClipboard, "Monitor clipboard for model URLs and automatically add them to the recorder").needsRestart(), Setting.of("Start Tab", startTab), Setting.of("Colors (Base / Accent)", new ColorSettingsPane(Config.getInstance())) ), diff --git a/common/src/main/java/ctbrec/Settings.java b/common/src/main/java/ctbrec/Settings.java index ed233308..49cfa237 100644 --- a/common/src/main/java/ctbrec/Settings.java +++ b/common/src/main/java/ctbrec/Settings.java @@ -99,6 +99,7 @@ public class Settings { public Map modelNotes = new HashMap<>(); public List models = new ArrayList<>(); public List modelsIgnored = new ArrayList<>(); + public boolean monitorClipboard = false; public int onlineCheckIntervalInSecs = 60; public boolean onlineCheckSkipsPausedModels = false; public int overviewUpdateIntervalInSecs = 10;