Added setting to record all followed models

This commit is contained in:
0xboobface 2018-08-13 18:29:44 +02:00
parent e00c653c23
commit 94bede6367
2 changed files with 190 additions and 126 deletions

View File

@ -1,4 +1,5 @@
package ctbrec.recorder; package ctbrec.recorder;
import static ctbrec.Recording.STATUS.FINISHED; import static ctbrec.Recording.STATUS.FINISHED;
import static ctbrec.Recording.STATUS.GENERATING_PLAYLIST; import static ctbrec.Recording.STATUS.GENERATING_PLAYLIST;
import static ctbrec.Recording.STATUS.RECORDING; import static ctbrec.Recording.STATUS.RECORDING;
@ -18,8 +19,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -30,24 +29,28 @@ import com.iheartradio.m3u8.PlaylistException;
import ctbrec.Config; import ctbrec.Config;
import ctbrec.HttpClient; import ctbrec.HttpClient;
import ctbrec.Model; import ctbrec.Model;
import ctbrec.ModelParser;
import ctbrec.Recording; import ctbrec.Recording;
import ctbrec.Recording.STATUS; import ctbrec.Recording.STATUS;
import ctbrec.recorder.PlaylistGenerator.InvalidPlaylistException; 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 okhttp3.Request;
import okhttp3.Response;
public class LocalRecorder implements Recorder { public class LocalRecorder implements Recorder {
private static final transient Logger LOG = LoggerFactory.getLogger(LocalRecorder.class); private static final transient Logger LOG = LoggerFactory.getLogger(LocalRecorder.class);
private List<Model> followedModels = Collections.synchronizedList(new ArrayList<>());
private List<Model> models = Collections.synchronizedList(new ArrayList<>()); private List<Model> models = Collections.synchronizedList(new ArrayList<>());
private Lock lock = new ReentrantLock();
private Map<Model, Download> recordingProcesses = Collections.synchronizedMap(new HashMap<>()); private Map<Model, Download> recordingProcesses = Collections.synchronizedMap(new HashMap<>());
private Map<File, PlaylistGenerator> playlistGenerators = new HashMap<>(); private Map<File, PlaylistGenerator> playlistGenerators = new HashMap<>();
private Map<File, SegmentMerger> segmentMergers = new HashMap<>(); private Map<File, SegmentMerger> segmentMergers = new HashMap<>();
private Config config; private Config config;
private ProcessMonitor processMonitor; private ProcessMonitor processMonitor;
private OnlineMonitor onlineMonitor; private OnlineMonitor onlineMonitor;
private FollowedMonitor followedMonitor;
private PlaylistGeneratorTrigger playlistGenTrigger; private PlaylistGeneratorTrigger playlistGenTrigger;
private HttpClient client = HttpClient.getInstance(); private HttpClient client = HttpClient.getInstance();
private volatile boolean recording = true; private volatile boolean recording = true;
@ -68,6 +71,11 @@ public class LocalRecorder implements Recorder {
playlistGenTrigger = new PlaylistGeneratorTrigger(); playlistGenTrigger = new PlaylistGeneratorTrigger();
playlistGenTrigger.start(); playlistGenTrigger.start();
if (config.getSettings().recordFollowed) {
followedMonitor = new FollowedMonitor();
followedMonitor.start();
}
LOG.debug("Recorder initialized"); LOG.debug("Recorder initialized");
LOG.info("Models to record: {}", models); LOG.info("Models to record: {}", models);
LOG.info("Saving recordings in {}", config.getSettings().recordingsDir); LOG.info("Saving recordings in {}", config.getSettings().recordingsDir);
@ -75,30 +83,27 @@ public class LocalRecorder implements Recorder {
@Override @Override
public void startRecording(Model model) { public void startRecording(Model model) {
lock.lock(); if (!models.contains(model)) {
if(!models.contains(model)) {
LOG.info("Model {} added", model); LOG.info("Model {} added", model);
if (followedModels.contains(model)) {
followedModels.remove(model);
}
models.add(model); models.add(model);
config.getSettings().models.add(model); config.getSettings().models.add(model);
onlineMonitor.interrupt(); onlineMonitor.interrupt();
} }
lock.unlock();
} }
@Override @Override
public void stopRecording(Model model) throws IOException { public void stopRecording(Model model) throws IOException {
lock.lock(); if (models.contains(model) || followedModels.contains(model)) {
try { models.remove(model);
if (models.contains(model)) { followedModels.remove(model);
models.remove(model); config.getSettings().models.remove(model);
config.getSettings().models.remove(model); if (recordingProcesses.containsKey(model)) {
if(recordingProcesses.containsKey(model)) { stopRecordingProcess(model);
stopRecordingProcess(model);
}
LOG.info("Model {} removed", model);
} }
} finally { LOG.info("Model {} removed", model);
lock.unlock();
} }
} }
@ -109,7 +114,7 @@ public class LocalRecorder implements Recorder {
return; return;
} }
if (!models.contains(model)) { if (!models.contains(model) && !followedModels.contains(model)) {
LOG.info("Model {} has been removed. Restarting of recording cancelled.", model); LOG.info("Model {} has been removed. Restarting of recording cancelled.", model);
return; return;
} }
@ -129,29 +134,22 @@ public class LocalRecorder implements Recorder {
} }
private void stopRecordingProcess(Model model) throws IOException { private void stopRecordingProcess(Model model) throws IOException {
lock.lock(); Download download = recordingProcesses.get(model);
try { download.stop();
Download download = recordingProcesses.get(model); recordingProcesses.remove(model);
download.stop();
recordingProcesses.remove(model);
} finally {
lock.unlock();
}
} }
@Override @Override
public boolean isRecording(Model model) { public boolean isRecording(Model model) {
lock.lock(); return models.contains(model) || followedModels.contains(model);
try {
return models.contains(model);
} finally {
lock.unlock();
}
} }
@Override @Override
public List<Model> getModelsRecording() { public List<Model> getModelsRecording() {
return Collections.unmodifiableList(models); List<Model> union = new ArrayList<>();
union.addAll(models);
union.addAll(followedModels);
return Collections.unmodifiableList(union);
} }
@Override @Override
@ -162,26 +160,24 @@ public class LocalRecorder implements Recorder {
onlineMonitor.running = false; onlineMonitor.running = false;
processMonitor.running = false; processMonitor.running = false;
playlistGenTrigger.running = false; playlistGenTrigger.running = false;
if (followedMonitor != null) {
followedMonitor.running = false;
}
LOG.debug("Stopping all recording processes"); LOG.debug("Stopping all recording processes");
stopRecordingProcesses(); stopRecordingProcesses();
} }
private void stopRecordingProcesses() { private void stopRecordingProcesses() {
lock.lock(); for (Model model : models) {
try { Download recordingProcess = recordingProcesses.get(model);
for (Model model : models) { if (recordingProcess != null) {
Download recordingProcess = recordingProcesses.get(model); try {
if(recordingProcess != null) { recordingProcess.stop();
try { LOG.debug("Stopped recording for {}", model);
recordingProcess.stop(); } catch (Exception e) {
LOG.debug("Stopped recording for {}", model); LOG.error("Couldn't stop recording for model {}", model, e);
} catch (Exception e) {
LOG.error("Couldn't stop recording for model {}", model, e);
}
} }
} }
} finally {
lock.unlock();
} }
} }
@ -193,15 +189,15 @@ public class LocalRecorder implements Recorder {
} }
private void tryRestartRecording(Model model) { private void tryRestartRecording(Model model) {
if(!recording) { if (!recording) {
// recorder is not in recording state // recorder is not in recording state
return; return;
} }
try { try {
boolean modelInRecordingList = models.contains(model); boolean modelInRecordingList = isRecording(model);
boolean online = checkIfOnline(model); boolean online = checkIfOnline(model);
if(modelInRecordingList && online) { if (modelInRecordingList && online) {
LOG.info("Restarting recording for model {}", model); LOG.info("Restarting recording for model {}", model);
recordingProcesses.remove(model); recordingProcesses.remove(model);
startRecordingProcess(model); startRecordingProcess(model);
@ -222,31 +218,74 @@ public class LocalRecorder implements Recorder {
@Override @Override
public void run() { public void run() {
running = true; running = true;
while(running) { while (running) {
lock.lock(); List<Model> restart = new ArrayList<Model>();
try { for (Iterator<Entry<Model, Download>> iterator = recordingProcesses.entrySet().iterator(); iterator.hasNext();) {
List<Model> restart = new ArrayList<Model>(); Entry<Model, Download> entry = iterator.next();
for (Iterator<Entry<Model,Download>> iterator = recordingProcesses.entrySet().iterator(); iterator.hasNext();) { Model m = entry.getKey();
Entry<Model, Download> entry = iterator.next(); Download d = entry.getValue();
Model m = entry.getKey(); if (!d.isAlive()) {
Download d = entry.getValue(); LOG.debug("Recording terminated for model {}", m.getName());
if(!d.isAlive()) { iterator.remove();
LOG.debug("Recording terminated for model {}", m.getName()); restart.add(m);
iterator.remove(); finishRecording(d.getDirectory());
restart.add(m);
finishRecording(d.getDirectory());
}
}
for (Model m : restart) {
tryRestartRecording(m);
} }
} }
finally { for (Model m : restart) {
lock.unlock(); tryRestartRecording(m);
} }
try { try {
if(running) Thread.sleep(1000); if (running)
Thread.sleep(1000);
} catch (InterruptedException e) {
LOG.error("Couldn't sleep", e);
}
}
LOG.debug(getName() + " terminated");
}
}
private class FollowedMonitor extends Thread {
private volatile boolean running = false;
public FollowedMonitor() {
setName("FollowedMonitor");
setDaemon(true);
}
@Override
public void run() {
running = true;
while (running) {
try {
String url = "https://chaturbate.com/followed-cams/?page=1&keywords=&_=" + System.currentTimeMillis();
LOG.debug("Fetching page {}", url);
Request request = new Request.Builder().url(url).build();
Response response = client.execute(request, true);
if (response.isSuccessful()) {
List<Model> followed = ModelParser.parseModels(response.body().string());
response.close();
followedModels.clear();
for (Model model : followed) {
if (!followedModels.contains(model) && !models.contains(model)) {
LOG.info("Model {} added", model);
followedModels.add(model);
}
}
onlineMonitor.interrupt();
} else {
int code = response.code();
response.close();
LOG.error("Couldn't retrieve followed models. HTTP status {}", code);
}
} catch (IOException e) {
LOG.error("Couldn't retrieve followed models.", e);
}
try {
if (running)
Thread.sleep(10000);
} catch (InterruptedException e) { } catch (InterruptedException e) {
LOG.error("Couldn't sleep", e); LOG.error("Couldn't sleep", e);
} }
@ -262,7 +301,7 @@ public class LocalRecorder implements Recorder {
boolean local = Config.getInstance().getSettings().localRecording; boolean local = Config.getInstance().getSettings().localRecording;
boolean automerge = Config.getInstance().getSettings().automerge; boolean automerge = Config.getInstance().getSettings().automerge;
generatePlaylist(directory); generatePlaylist(directory);
if(local && automerge) { if (local && automerge) {
merge(directory); merge(directory);
} }
} }
@ -272,7 +311,6 @@ public class LocalRecorder implements Recorder {
t.start(); t.start();
} }
private File merge(File recDir) { private File merge(File recDir) {
SegmentMerger segmentMerger = new SegmentMerger(); SegmentMerger segmentMerger = new SegmentMerger();
segmentMergers.put(recDir, segmentMerger); segmentMergers.put(recDir, segmentMerger);
@ -280,13 +318,13 @@ public class LocalRecorder implements Recorder {
File mergedFile = Recording.mergedFileFromDirectory(recDir); File mergedFile = Recording.mergedFileFromDirectory(recDir);
segmentMerger.merge(recDir, mergedFile); segmentMerger.merge(recDir, mergedFile);
if(mergedFile != null && mergedFile.exists() && mergedFile.length() > 0) { if (mergedFile != null && mergedFile.exists() && mergedFile.length() > 0) {
LOG.debug("Merged file {}", mergedFile.getAbsolutePath()); LOG.debug("Merged file {}", mergedFile.getAbsolutePath());
if (Config.getInstance().getSettings().mergeDir.length() > 0) { if (Config.getInstance().getSettings().mergeDir.length() > 0) {
File mergeDir = new File(Config.getInstance().getSettings().mergeDir); File mergeDir = new File(Config.getInstance().getSettings().mergeDir);
if(!mergeDir.exists()) { if (!mergeDir.exists()) {
boolean created = mergeDir.mkdirs(); boolean created = mergeDir.mkdirs();
if(!created) { if (!created) {
LOG.error("Couldn't create directory for merged files {}", mergeDir); LOG.error("Couldn't create directory for merged files {}", mergeDir);
} }
} }
@ -350,30 +388,26 @@ public class LocalRecorder implements Recorder {
@Override @Override
public void run() { public void run() {
running = true; running = true;
while(running) { while (running) {
lock.lock(); for (Model model : getModelsRecording()) {
try { try {
for (Model model : models) { if (!recordingProcesses.containsKey(model)) {
if(!recordingProcesses.containsKey(model)) { boolean isOnline = checkIfOnline(model);
try { LOG.trace("Checking online state for {}: {}", model, (isOnline ? "online" : "offline"));
boolean isOnline = checkIfOnline(model); if (isOnline) {
LOG.trace("Checking online state for {}: {}", model, (isOnline ? "online" : "offline")); LOG.info("Model {}'s room back to public. Starting recording", model);
if(isOnline) { startRecordingProcess(model);
LOG.info("Model {}'s room back to public. Starting recording", model);
startRecordingProcess(model);
}
} catch (Exception e) {
LOG.error("Couldn't check if model {} is online", model.getName(), e);
model.setOnline(false);
} }
} }
} catch (Exception e) {
LOG.error("Couldn't check if model {} is online", model.getName(), e);
model.setOnline(false);
} }
} finally {
lock.unlock();
} }
try { try {
if(running) Thread.sleep(10000); if (running)
Thread.sleep(10000);
} catch (InterruptedException e) { } catch (InterruptedException e) {
LOG.trace("Sleep interrupted"); LOG.trace("Sleep interrupted");
} }
@ -393,21 +427,21 @@ public class LocalRecorder implements Recorder {
@Override @Override
public void run() { public void run() {
running = true; running = true;
while(running) { while (running) {
try { try {
List<Recording> recs = getRecordings(); List<Recording> recs = getRecordings();
for (Recording rec : recs) { for (Recording rec : recs) {
if(rec.getStatus() == RECORDING) { if (rec.getStatus() == RECORDING) {
boolean recordingProcessFound = false; boolean recordingProcessFound = false;
File recordingsDir = new File(config.getSettings().recordingsDir); File recordingsDir = new File(config.getSettings().recordingsDir);
File recDir = new File(recordingsDir, rec.getPath()); File recDir = new File(recordingsDir, rec.getPath());
for(Entry<Model, Download> download : recordingProcesses.entrySet()) { for (Entry<Model, Download> download : recordingProcesses.entrySet()) {
if(download.getValue().getDirectory().equals(recDir)) { if (download.getValue().getDirectory().equals(recDir)) {
recordingProcessFound = true; recordingProcessFound = true;
} }
} }
if(!recordingProcessFound) { if (!recordingProcessFound) {
if(deleteInProgress.contains(recDir)) { if (deleteInProgress.contains(recDir)) {
LOG.debug("{} is being deleted. Not going to generate a playlist", recDir); LOG.debug("{} is being deleted. Not going to generate a playlist", recDir);
} else { } else {
finishRecording(recDir); finishRecording(recDir);
@ -416,7 +450,8 @@ public class LocalRecorder implements Recorder {
} }
} }
if(running) Thread.sleep(10000); if (running)
Thread.sleep(10000);
} catch (InterruptedException e) { } catch (InterruptedException e) {
LOG.error("Couldn't sleep", e); LOG.error("Couldn't sleep", e);
} catch (Exception e) { } catch (Exception e) {
@ -432,12 +467,12 @@ public class LocalRecorder implements Recorder {
List<Recording> recordings = new ArrayList<>(); List<Recording> recordings = new ArrayList<>();
File recordingsDir = new File(config.getSettings().recordingsDir); File recordingsDir = new File(config.getSettings().recordingsDir);
File[] subdirs = recordingsDir.listFiles(); File[] subdirs = recordingsDir.listFiles();
if(subdirs == null ) { if (subdirs == null) {
return Collections.emptyList(); return Collections.emptyList();
} }
for (File subdir : subdirs) { for (File subdir : subdirs) {
if(!subdir.isDirectory()) { if (!subdir.isDirectory()) {
continue; continue;
} }
@ -445,9 +480,9 @@ public class LocalRecorder implements Recorder {
for (File rec : recordingsDirs) { for (File rec : recordingsDirs) {
String pattern = "yyyy-MM-dd_HH-mm"; String pattern = "yyyy-MM-dd_HH-mm";
SimpleDateFormat sdf = new SimpleDateFormat(pattern); SimpleDateFormat sdf = new SimpleDateFormat(pattern);
if(rec.isDirectory()) { if (rec.isDirectory()) {
try { try {
if(rec.getName().length() != pattern.length()) { if (rec.getName().length() != pattern.length()) {
continue; continue;
} }
@ -459,20 +494,20 @@ public class LocalRecorder implements Recorder {
recording.setSizeInByte(getSize(rec)); recording.setSizeInByte(getSize(rec));
File playlist = new File(rec, "playlist.m3u8"); File playlist = new File(rec, "playlist.m3u8");
recording.setHasPlaylist(playlist.exists()); recording.setHasPlaylist(playlist.exists());
if(recording.hasPlaylist()) { if (recording.hasPlaylist()) {
recording.setStatus(FINISHED); recording.setStatus(FINISHED);
} else { } else {
// this might be a merged recording // this might be a merged recording
if(Recording.isMergedRecording(rec)) { if (Recording.isMergedRecording(rec)) {
recording.setStatus(FINISHED); recording.setStatus(FINISHED);
} else { } else {
PlaylistGenerator playlistGenerator = playlistGenerators.get(rec); PlaylistGenerator playlistGenerator = playlistGenerators.get(rec);
if(playlistGenerator != null) { if (playlistGenerator != null) {
recording.setStatus(GENERATING_PLAYLIST); recording.setStatus(GENERATING_PLAYLIST);
recording.setProgress(playlistGenerator.getProgress()); recording.setProgress(playlistGenerator.getProgress());
} else { } else {
SegmentMerger merger = segmentMergers.get(rec); SegmentMerger merger = segmentMergers.get(rec);
if(merger != null) { if (merger != null) {
recording.setStatus(STATUS.MERGING); recording.setStatus(STATUS.MERGING);
recording.setProgress(merger.getProgress()); recording.setProgress(merger.getProgress());
} else { } else {
@ -482,7 +517,7 @@ public class LocalRecorder implements Recorder {
} }
} }
recordings.add(recording); recordings.add(recording);
} catch(Exception e) { } catch (Exception e) {
LOG.debug("Ignoring {}", rec.getAbsolutePath()); LOG.debug("Ignoring {}", rec.getAbsolutePath());
} }
} }
@ -507,8 +542,8 @@ public class LocalRecorder implements Recorder {
delete(directory, new File[] {}); delete(directory, new File[] {});
} }
private void delete(File directory, File...excludes) throws IOException { private void delete(File directory, File... excludes) throws IOException {
if(!directory.exists()) { if (!directory.exists()) {
throw new IOException("Recording does not exist"); throw new IOException("Recording does not exist");
} }
@ -519,12 +554,12 @@ public class LocalRecorder implements Recorder {
for (File file : files) { for (File file : files) {
boolean skip = false; boolean skip = false;
for (File exclude : excludes) { for (File exclude : excludes) {
if(file.equals(exclude)) { if (file.equals(exclude)) {
skip = true; skip = true;
break; break;
} }
} }
if(skip) { if (skip) {
continue; continue;
} }
@ -536,11 +571,11 @@ public class LocalRecorder implements Recorder {
} }
} }
if(deletedAllFiles) { if (deletedAllFiles) {
if(directory.list().length == 0) { if (directory.list().length == 0) {
boolean deleted = directory.delete(); boolean deleted = directory.delete();
if(deleted) { if (deleted) {
if(directory.getParentFile().list().length == 0) { if (directory.getParentFile().list().length == 0) {
directory.getParentFile().delete(); directory.getParentFile().delete();
} }
} else { } else {
@ -560,7 +595,7 @@ public class LocalRecorder implements Recorder {
File recordingsDir = new File(config.getSettings().recordingsDir); File recordingsDir = new File(config.getSettings().recordingsDir);
File directory = new File(recordingsDir, rec.getPath()); File directory = new File(recordingsDir, rec.getPath());
File mergedFile = merge(directory); File mergedFile = merge(directory);
if(!keepSegments) { if (!keepSegments) {
delete(directory, mergedFile); delete(directory, mergedFile);
} }
return mergedFile; return mergedFile;

View File

@ -42,6 +42,7 @@ public class SettingsTab extends Tab {
private static final transient Logger LOG = LoggerFactory.getLogger(SettingsTab.class); private static final transient Logger LOG = LoggerFactory.getLogger(SettingsTab.class);
private TextField recordingsDirectory; private TextField recordingsDirectory;
private Button recordingsDirectoryButton;
private TextField mergeDirectory; private TextField mergeDirectory;
private TextField mediaPlayer; private TextField mediaPlayer;
private TextField username; private TextField username;
@ -53,10 +54,13 @@ public class SettingsTab extends Tab {
private CheckBox automerge = new CheckBox(); private CheckBox automerge = new CheckBox();
private CheckBox automergeKeepSegments = new CheckBox(); private CheckBox automergeKeepSegments = new CheckBox();
private CheckBox chooseStreamQuality = new CheckBox(); private CheckBox chooseStreamQuality = new CheckBox();
private CheckBox autoRecordFollowed = new CheckBox();
private PasswordField password; private PasswordField password;
private RadioButton recordLocal; private RadioButton recordLocal;
private RadioButton recordRemote; private RadioButton recordRemote;
private ToggleGroup recordLocation; private ToggleGroup recordLocation;
private TitledPane ctb;
private TitledPane mergePane; private TitledPane mergePane;
public SettingsTab() { public SettingsTab() {
@ -81,7 +85,8 @@ public class SettingsTab extends Tab {
GridPane.setHgrow(recordingsDirectory, Priority.ALWAYS); GridPane.setHgrow(recordingsDirectory, Priority.ALWAYS);
GridPane.setColumnSpan(recordingsDirectory, 2); GridPane.setColumnSpan(recordingsDirectory, 2);
layout.add(recordingsDirectory, 1, 0); layout.add(recordingsDirectory, 1, 0);
layout.add(createRecordingsBrowseButton(), 3, 0); recordingsDirectoryButton = createRecordingsBrowseButton();
layout.add(recordingsDirectoryButton, 3, 0);
layout.add(new Label("Player"), 0, 1); layout.add(new Label("Player"), 0, 1);
mediaPlayer = new TextField(Config.getInstance().getSettings().mediaPlayer); mediaPlayer = new TextField(Config.getInstance().getSettings().mediaPlayer);
@ -116,12 +121,29 @@ public class SettingsTab extends Tab {
GridPane.setHgrow(password, Priority.ALWAYS); GridPane.setHgrow(password, Priority.ALWAYS);
GridPane.setColumnSpan(password, 2); GridPane.setColumnSpan(password, 2);
layout.add(password, 1, 1); layout.add(password, 1, 1);
TitledPane ctb = new TitledPane("Chaturbate", layout);
Label l = new Label("Record all followed models");
layout.add(l, 0, 2);
autoRecordFollowed = new CheckBox();
autoRecordFollowed.setSelected(Config.getInstance().getSettings().recordFollowed);
autoRecordFollowed.setOnAction((e) -> {
Config.getInstance().getSettings().recordFollowed = autoRecordFollowed.isSelected();
showRestartRequired();
});
GridPane.setMargin(autoRecordFollowed, new Insets(0, 0, 0, CHECKBOX_MARGIN));
GridPane.setMargin(username, new Insets(0, 0, 0, CHECKBOX_MARGIN));
GridPane.setMargin(password, new Insets(0, 0, 0, CHECKBOX_MARGIN));
layout.add(autoRecordFollowed, 1, 2);
Label warning = new Label("Don't do this, if you follow many models. You have been warned ;) !");
warning.setTextFill(Color.RED);
layout.add(warning, 2, 2);
ctb = new TitledPane("Chaturbate", layout);
ctb.setCollapsible(false); ctb.setCollapsible(false);
mainLayout.add(ctb, 0, 1); mainLayout.add(ctb, 0, 1);
layout = createGridLayout(); layout = createGridLayout();
Label l = new Label("Display stream resolution in overview"); l = new Label("Display stream resolution in overview");
layout.add(l, 0, 0); layout.add(l, 0, 0);
loadResolution = new CheckBox(); loadResolution = new CheckBox();
loadResolution.setSelected(Config.getInstance().getSettings().determineResolution); loadResolution.setSelected(Config.getInstance().getSettings().determineResolution);
@ -192,11 +214,7 @@ public class SettingsTab extends Tab {
recordLocation.selectedToggleProperty().addListener((e) -> { recordLocation.selectedToggleProperty().addListener((e) -> {
Config.getInstance().getSettings().localRecording = recordLocal.isSelected(); Config.getInstance().getSettings().localRecording = recordLocal.isSelected();
setRecordingMode(recordLocal.isSelected()); setRecordingMode(recordLocal.isSelected());
Alert restart = new AutosizeAlert(AlertType.INFORMATION); showRestartRequired();
restart.setTitle("Restart required");
restart.setHeaderText("Restart required");
restart.setContentText("Changes get applied after a restart of the application");
restart.show();
}); });
GridPane.setMargin(l, new Insets(0, 0, CHECKBOX_MARGIN, 0)); GridPane.setMargin(l, new Insets(0, 0, CHECKBOX_MARGIN, 0));
GridPane.setMargin(recordLocal, new Insets(0, 0, CHECKBOX_MARGIN, 0)); GridPane.setMargin(recordLocal, new Insets(0, 0, CHECKBOX_MARGIN, 0));
@ -267,6 +285,14 @@ public class SettingsTab extends Tab {
setRecordingMode(recordLocal.isSelected()); setRecordingMode(recordLocal.isSelected());
} }
private void showRestartRequired() {
Alert restart = new AutosizeAlert(AlertType.INFORMATION);
restart.setTitle("Restart required");
restart.setHeaderText("Restart required");
restart.setContentText("Changes get applied after a restart of the application");
restart.show();
}
private GridPane createGridLayout() { private GridPane createGridLayout() {
GridPane layout = new GridPane(); GridPane layout = new GridPane();
layout.setPadding(new Insets(10)); layout.setPadding(new Insets(10));
@ -282,6 +308,9 @@ public class SettingsTab extends Tab {
automerge.setDisable(!local); automerge.setDisable(!local);
automergeKeepSegments.setDisable(!local); automergeKeepSegments.setDisable(!local);
mergePane.setDisable(!local); mergePane.setDisable(!local);
ctb.setDisable(!local);
recordingsDirectory.setDisable(!local);
recordingsDirectoryButton.setDisable(!local);
} }
private ChangeListener<? super Boolean> createRecordingsDirectoryFocusListener() { private ChangeListener<? super Boolean> createRecordingsDirectoryFocusListener() {
@ -355,7 +384,7 @@ public class SettingsTab extends Tab {
return null; return null;
} }
private Node createRecordingsBrowseButton() { private Button createRecordingsBrowseButton() {
Button button = new Button("Select"); Button button = new Button("Select");
button.setOnAction((e) -> { button.setOnAction((e) -> {
DirectoryChooser chooser = new DirectoryChooser(); DirectoryChooser chooser = new DirectoryChooser();