Added setting to record all followed models
This commit is contained in:
parent
e00c653c23
commit
94bede6367
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue