forked from j62/ctbrec
Add Event and EventReaction classes
This commit is contained in:
parent
b50df194a0
commit
2dc5fd4581
|
@ -1,8 +1,8 @@
|
||||||
package ctbrec.ui;
|
package ctbrec.ui;
|
||||||
|
|
||||||
import static ctbrec.EventBusHolder.*;
|
|
||||||
import static ctbrec.EventBusHolder.EVENT_TYPE.*;
|
import static ctbrec.Model.State.*;
|
||||||
import static ctbrec.Model.STATUS.*;
|
import static ctbrec.event.Event.Type.*;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -14,7 +14,6 @@ import java.lang.reflect.Type;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -26,11 +25,14 @@ import com.squareup.moshi.Moshi;
|
||||||
import com.squareup.moshi.Types;
|
import com.squareup.moshi.Types;
|
||||||
|
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.EventBusHolder;
|
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
import ctbrec.OS;
|
import ctbrec.OS;
|
||||||
import ctbrec.StringUtil;
|
import ctbrec.StringUtil;
|
||||||
import ctbrec.Version;
|
import ctbrec.Version;
|
||||||
|
import ctbrec.event.Event;
|
||||||
|
import ctbrec.event.EventBusHolder;
|
||||||
|
import ctbrec.event.LogReaction;
|
||||||
|
import ctbrec.event.ModelStateChangedEvent;
|
||||||
import ctbrec.io.HttpClient;
|
import ctbrec.io.HttpClient;
|
||||||
import ctbrec.recorder.LocalRecorder;
|
import ctbrec.recorder.LocalRecorder;
|
||||||
import ctbrec.recorder.OnlineMonitor;
|
import ctbrec.recorder.OnlineMonitor;
|
||||||
|
@ -42,6 +44,7 @@ import ctbrec.sites.cam4.Cam4;
|
||||||
import ctbrec.sites.camsoda.Camsoda;
|
import ctbrec.sites.camsoda.Camsoda;
|
||||||
import ctbrec.sites.chaturbate.Chaturbate;
|
import ctbrec.sites.chaturbate.Chaturbate;
|
||||||
import ctbrec.sites.mfc.MyFreeCams;
|
import ctbrec.sites.mfc.MyFreeCams;
|
||||||
|
import ctbrec.ui.settings.SettingsTab;
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.application.HostServices;
|
import javafx.application.HostServices;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
@ -143,7 +146,7 @@ public class CamrecApplication extends Application {
|
||||||
loadStyleSheet(primaryStage, "color.css");
|
loadStyleSheet(primaryStage, "color.css");
|
||||||
}
|
}
|
||||||
loadStyleSheet(primaryStage, "style.css");
|
loadStyleSheet(primaryStage, "style.css");
|
||||||
primaryStage.getScene().getStylesheets().add("/ctbrec/ui/ColorSettingsPane.css");
|
primaryStage.getScene().getStylesheets().add("/ctbrec/ui/settings/ColorSettingsPane.css");
|
||||||
primaryStage.getScene().getStylesheets().add("/ctbrec/ui/ThumbCell.css");
|
primaryStage.getScene().getStylesheets().add("/ctbrec/ui/ThumbCell.css");
|
||||||
primaryStage.getScene().getStylesheets().add("/ctbrec/ui/controls/SearchBox.css");
|
primaryStage.getScene().getStylesheets().add("/ctbrec/ui/controls/SearchBox.css");
|
||||||
primaryStage.getScene().getStylesheets().add("/ctbrec/ui/controls/Popover.css");
|
primaryStage.getScene().getStylesheets().add("/ctbrec/ui/controls/Popover.css");
|
||||||
|
@ -212,40 +215,43 @@ public class CamrecApplication extends Application {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerAlertSystem() {
|
private void registerAlertSystem() {
|
||||||
new Thread(() -> {
|
// try {
|
||||||
// try {
|
// // don't register before 1 minute has passed, because directly after
|
||||||
// // don't register before 1 minute has passed, because directly after
|
// // the start of ctbrec, an event for every online model would be fired,
|
||||||
// // the start of ctbrec, an event for every online model would be fired,
|
// // which is annoying as f
|
||||||
// // which is annoying as f
|
// Thread.sleep(TimeUnit.MINUTES.toMillis(1));
|
||||||
// Thread.sleep(TimeUnit.MINUTES.toMillis(1));
|
// } catch (InterruptedException e) {
|
||||||
// } catch (InterruptedException e) {
|
// e.printStackTrace();
|
||||||
// e.printStackTrace();
|
// }
|
||||||
// }
|
EventBusHolder.BUS.register(new Object() {
|
||||||
LOG.debug("Alert System registered");
|
@Subscribe
|
||||||
Platform.runLater(() -> {
|
public void modelEvent(Event e) {
|
||||||
EventBusHolder.BUS.register(new Object() {
|
try {
|
||||||
@Subscribe
|
if (e.getType() == MODEL_STATUS_CHANGED) {
|
||||||
public void modelEvent(Map<String, Object> e) {
|
ModelStateChangedEvent evt = (ModelStateChangedEvent) e;
|
||||||
try {
|
Model model = evt.getModel();
|
||||||
if (Objects.equals(e.get(EVENT), MODEL_STATUS_CHANGED)) {
|
if (evt.getNewState() == ONLINE) {
|
||||||
LOG.debug("Alert: {}", e);
|
String header = "Model Online";
|
||||||
Model.STATUS status = (Model.STATUS) e.get(STATUS);
|
String msg = model.getDisplayName() + " is now online";
|
||||||
Model model = (Model) e.get(MODEL);
|
OS.notification(primaryStage.getTitle(), header, msg);
|
||||||
if (status == ONLINE) {
|
|
||||||
Platform.runLater(() -> {
|
|
||||||
String header = "Model Online";
|
|
||||||
String msg = model.getDisplayName() + " is now online";
|
|
||||||
OS.notification(primaryStage.getTitle(), header, msg);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e1) {
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
} catch (Exception e1) {
|
||||||
});
|
LOG.error("Couldn't show notification", e1);
|
||||||
}).start();
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
EventBusHolder.BUS.register(new Object() {
|
||||||
|
LogReaction reaction = new LogReaction();
|
||||||
|
@Subscribe
|
||||||
|
public void modelEvent(Event e) {
|
||||||
|
reaction.reactToEvent(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
LOG.debug("Alert System registered");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeColorSchemeStyleSheet(Stage primaryStage) {
|
private void writeColorSchemeStyleSheet(Stage primaryStage) {
|
||||||
|
|
|
@ -110,7 +110,7 @@ public class JavaFxModel implements Model {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public STATUS getOnlineState(boolean failFast) throws IOException, ExecutionException {
|
public State getOnlineState(boolean failFast) throws IOException, ExecutionException {
|
||||||
return delegate.getOnlineState(failFast);
|
return delegate.getOnlineState(failFast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ public class JavaFxRecording extends Recording {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public STATUS getStatus() {
|
public State getStatus() {
|
||||||
return delegate.getStatus();
|
return delegate.getStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ public class JavaFxRecording extends Recording {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setStatus(STATUS status) {
|
public void setStatus(State status) {
|
||||||
delegate.setStatus(status);
|
delegate.setStatus(status);
|
||||||
switch(status) {
|
switch(status) {
|
||||||
case RECORDING:
|
case RECORDING:
|
||||||
|
@ -121,7 +121,7 @@ public class JavaFxRecording extends Recording {
|
||||||
|
|
||||||
public void update(Recording updated) {
|
public void update(Recording updated) {
|
||||||
if(!Config.getInstance().getSettings().localRecording) {
|
if(!Config.getInstance().getSettings().localRecording) {
|
||||||
if(getStatus() == STATUS.DOWNLOADING && updated.getStatus() != STATUS.DOWNLOADING) {
|
if(getStatus() == State.DOWNLOADING && updated.getStatus() != State.DOWNLOADING) {
|
||||||
// ignore, because the the status coming from the server is FINISHED and we are
|
// ignore, because the the status coming from the server is FINISHED and we are
|
||||||
// overriding it with DOWNLOADING
|
// overriding it with DOWNLOADING
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -369,7 +369,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
.map(m -> new JavaFxModel(m))
|
.map(m -> new JavaFxModel(m))
|
||||||
.peek(fxm -> {
|
.peek(fxm -> {
|
||||||
for (Recording recording : recordings) {
|
for (Recording recording : recordings) {
|
||||||
if(recording.getStatus() == Recording.STATUS.RECORDING &&
|
if(recording.getStatus() == Recording.State.RECORDING &&
|
||||||
recording.getModelName().equals(fxm.getName()))
|
recording.getModelName().equals(fxm.getName()))
|
||||||
{
|
{
|
||||||
fxm.getRecordingProperty().set(true);
|
fxm.getRecordingProperty().set(true);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package ctbrec.ui;
|
package ctbrec.ui;
|
||||||
|
|
||||||
|
import static ctbrec.Recording.State.*;
|
||||||
import static javafx.scene.control.ButtonType.*;
|
import static javafx.scene.control.ButtonType.*;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -34,7 +35,7 @@ import com.iheartradio.m3u8.PlaylistException;
|
||||||
|
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.Recording;
|
import ctbrec.Recording;
|
||||||
import ctbrec.Recording.STATUS;
|
import ctbrec.Recording.State;
|
||||||
import ctbrec.StringUtil;
|
import ctbrec.StringUtil;
|
||||||
import ctbrec.recorder.Recorder;
|
import ctbrec.recorder.Recorder;
|
||||||
import ctbrec.recorder.download.MergedHlsDownload;
|
import ctbrec.recorder.download.MergedHlsDownload;
|
||||||
|
@ -172,7 +173,7 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
|
||||||
if(Objects.equals(System.getenv("CTBREC_DEV"), "1")) {
|
if(Objects.equals(System.getenv("CTBREC_DEV"), "1")) {
|
||||||
int row = this.getTableRow().getIndex();
|
int row = this.getTableRow().getIndex();
|
||||||
JavaFxRecording rec = tableViewProperty().get().getItems().get(row);
|
JavaFxRecording rec = tableViewProperty().get().getItems().get(row);
|
||||||
if(!rec.valueChanged() && rec.getStatus() == STATUS.RECORDING) {
|
if(!rec.valueChanged() && rec.getStatus() == State.RECORDING) {
|
||||||
setStyle("-fx-alignment: CENTER-RIGHT; -fx-background-color: red");
|
setStyle("-fx-alignment: CENTER-RIGHT; -fx-background-color: red");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,11 +213,11 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
|
||||||
List<JavaFxRecording> recordings = table.getSelectionModel().getSelectedItems();
|
List<JavaFxRecording> recordings = table.getSelectionModel().getSelectedItems();
|
||||||
if (recordings != null && !recordings.isEmpty()) {
|
if (recordings != null && !recordings.isEmpty()) {
|
||||||
if (event.getCode() == KeyCode.DELETE) {
|
if (event.getCode() == KeyCode.DELETE) {
|
||||||
if(recordings.size() > 1 || recordings.get(0).getStatus() == STATUS.FINISHED) {
|
if(recordings.size() > 1 || recordings.get(0).getStatus() == State.FINISHED) {
|
||||||
delete(recordings);
|
delete(recordings);
|
||||||
}
|
}
|
||||||
} else if (event.getCode() == KeyCode.ENTER) {
|
} else if (event.getCode() == KeyCode.ENTER) {
|
||||||
if(recordings.get(0).getStatus() == STATUS.FINISHED) {
|
if(recordings.get(0).getStatus() == State.FINISHED) {
|
||||||
play(recordings.get(0));
|
play(recordings.get(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -376,7 +377,7 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
|
||||||
openInPlayer.setOnAction((e) -> {
|
openInPlayer.setOnAction((e) -> {
|
||||||
play(recordings.get(0));
|
play(recordings.get(0));
|
||||||
});
|
});
|
||||||
if(recordings.get(0).getStatus() == STATUS.FINISHED || Config.getInstance().getSettings().localRecording) {
|
if(recordings.get(0).getStatus() == State.FINISHED || Config.getInstance().getSettings().localRecording) {
|
||||||
contextMenu.getItems().add(openInPlayer);
|
contextMenu.getItems().add(openInPlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,7 +399,7 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
|
||||||
deleteRecording.setOnAction((e) -> {
|
deleteRecording.setOnAction((e) -> {
|
||||||
delete(recordings);
|
delete(recordings);
|
||||||
});
|
});
|
||||||
if(recordings.get(0).getStatus() == STATUS.FINISHED || recordings.size() > 1) {
|
if(recordings.get(0).getStatus() == State.FINISHED || recordings.size() > 1) {
|
||||||
contextMenu.getItems().add(deleteRecording);
|
contextMenu.getItems().add(deleteRecording);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,7 +425,7 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
|
||||||
LOG.error("Error while downloading recording", e1);
|
LOG.error("Error while downloading recording", e1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (!Config.getInstance().getSettings().localRecording && recordings.get(0).getStatus() == STATUS.FINISHED) {
|
if (!Config.getInstance().getSettings().localRecording && recordings.get(0).getStatus() == State.FINISHED) {
|
||||||
contextMenu.getItems().add(downloadRecording);
|
contextMenu.getItems().add(downloadRecording);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,11 +464,11 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
|
||||||
download.start(url.toString(), target, (progress) -> {
|
download.start(url.toString(), target, (progress) -> {
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
if (progress == 100) {
|
if (progress == 100) {
|
||||||
recording.setStatus(STATUS.FINISHED);
|
recording.setStatus(FINISHED);
|
||||||
recording.setProgress(-1);
|
recording.setProgress(-1);
|
||||||
LOG.debug("Download finished for recording {}", recording.getPath());
|
LOG.debug("Download finished for recording {}", recording.getPath());
|
||||||
} else {
|
} else {
|
||||||
recording.setStatus(STATUS.DOWNLOADING);
|
recording.setStatus(DOWNLOADING);
|
||||||
recording.setProgress(progress);
|
recording.setProgress(progress);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -482,7 +483,7 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
|
||||||
Platform.runLater(new Runnable() {
|
Platform.runLater(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
recording.setStatus(STATUS.FINISHED);
|
recording.setStatus(FINISHED);
|
||||||
recording.setProgress(-1);
|
recording.setProgress(-1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -493,7 +494,7 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
|
||||||
t.setName("Download Thread " + recording.getPath());
|
t.setName("Download Thread " + recording.getPath());
|
||||||
t.start();
|
t.start();
|
||||||
|
|
||||||
recording.setStatus(STATUS.DOWNLOADING);
|
recording.setStatus(State.DOWNLOADING);
|
||||||
recording.setProgress(0);
|
recording.setProgress(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -563,7 +564,7 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
|
||||||
List<Recording> deleted = new ArrayList<>();
|
List<Recording> deleted = new ArrayList<>();
|
||||||
for (Iterator<JavaFxRecording> iterator = recordings.iterator(); iterator.hasNext();) {
|
for (Iterator<JavaFxRecording> iterator = recordings.iterator(); iterator.hasNext();) {
|
||||||
JavaFxRecording r = iterator.next();
|
JavaFxRecording r = iterator.next();
|
||||||
if(r.getStatus() != STATUS.FINISHED) {
|
if(r.getStatus() != FINISHED) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -25,8 +25,8 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.EventBusHolder;
|
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
|
import ctbrec.event.EventBusHolder;
|
||||||
import ctbrec.recorder.Recorder;
|
import ctbrec.recorder.Recorder;
|
||||||
import ctbrec.sites.Site;
|
import ctbrec.sites.Site;
|
||||||
import ctbrec.sites.mfc.MyFreeCamsClient;
|
import ctbrec.sites.mfc.MyFreeCamsClient;
|
||||||
|
|
|
@ -9,7 +9,7 @@ import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.google.common.eventbus.Subscribe;
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
|
||||||
import ctbrec.EventBusHolder;
|
import ctbrec.event.EventBusHolder;
|
||||||
import ctbrec.sites.Site;
|
import ctbrec.sites.Site;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.concurrent.Task;
|
import javafx.concurrent.Task;
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
package ctbrec.ui.settings;
|
||||||
|
|
||||||
|
import ctbrec.event.Event.Type;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.TitledPane;
|
||||||
|
import javafx.scene.layout.GridPane;
|
||||||
|
|
||||||
|
public class ActionSettingsPanel extends TitledPane {
|
||||||
|
|
||||||
|
public ActionSettingsPanel(SettingsTab settingsTab) {
|
||||||
|
setText("Actions");
|
||||||
|
setExpanded(true);
|
||||||
|
setCollapsible(false);
|
||||||
|
createGui();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createGui() {
|
||||||
|
GridPane mainLayout = SettingsTab.createGridLayout();
|
||||||
|
setContent(mainLayout);
|
||||||
|
|
||||||
|
int row = 0;
|
||||||
|
for (Type type : Type.values()) {
|
||||||
|
Label l = new Label(type.name());
|
||||||
|
mainLayout.add(l, 0, row);
|
||||||
|
Button b = new Button("Configure");
|
||||||
|
mainLayout.add(b, 1, row++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
package ctbrec.ui.sites.bonga;
|
package ctbrec.ui.sites.bonga;
|
||||||
|
|
||||||
import static ctbrec.Model.STATUS.*;
|
import static ctbrec.Model.State.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package ctbrec.ui.sites.camsoda;
|
package ctbrec.ui.sites.camsoda;
|
||||||
|
|
||||||
import static ctbrec.Model.STATUS.*;
|
import static ctbrec.Model.State.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
|
@ -21,7 +21,7 @@ public abstract class AbstractModel implements Model {
|
||||||
private int streamUrlIndex = -1;
|
private int streamUrlIndex = -1;
|
||||||
private boolean suspended = false;
|
private boolean suspended = false;
|
||||||
protected Site site;
|
protected Site site;
|
||||||
protected STATUS onlineState = STATUS.UNKNOWN;
|
protected State onlineState = State.UNKNOWN;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isOnline() throws IOException, ExecutionException, InterruptedException {
|
public boolean isOnline() throws IOException, ExecutionException, InterruptedException {
|
||||||
|
@ -123,11 +123,11 @@ public abstract class AbstractModel implements Model {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public STATUS getOnlineState(boolean failFast) throws IOException, ExecutionException {
|
public State getOnlineState(boolean failFast) throws IOException, ExecutionException {
|
||||||
return onlineState;
|
return onlineState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOnlineState(STATUS status) {
|
public void setOnlineState(State status) {
|
||||||
this.onlineState = status;
|
this.onlineState = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ import ctbrec.sites.Site;
|
||||||
|
|
||||||
public interface Model {
|
public interface Model {
|
||||||
|
|
||||||
public static enum STATUS {
|
public static enum State {
|
||||||
ONLINE("online"),
|
ONLINE("online"),
|
||||||
OFFLINE("offline"),
|
OFFLINE("offline"),
|
||||||
AWAY("away"),
|
AWAY("away"),
|
||||||
|
@ -23,7 +23,7 @@ public interface Model {
|
||||||
UNKNOWN("unknown");
|
UNKNOWN("unknown");
|
||||||
|
|
||||||
String display;
|
String display;
|
||||||
STATUS(String display) {
|
State(String display) {
|
||||||
this.display = display;
|
this.display = display;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ public interface Model {
|
||||||
|
|
||||||
public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException;
|
public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException;
|
||||||
|
|
||||||
public STATUS getOnlineState(boolean failFast) throws IOException, ExecutionException;
|
public State getOnlineState(boolean failFast) throws IOException, ExecutionException;
|
||||||
|
|
||||||
public List<StreamSource> getStreamSources() throws IOException, ExecutionException, ParseException, PlaylistException;
|
public List<StreamSource> getStreamSources() throws IOException, ExecutionException, ParseException, PlaylistException;
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,11 @@ public class Recording {
|
||||||
private Instant startDate;
|
private Instant startDate;
|
||||||
private String path;
|
private String path;
|
||||||
private boolean hasPlaylist;
|
private boolean hasPlaylist;
|
||||||
private STATUS status = STATUS.UNKNOWN;
|
private State status = State.UNKNOWN;
|
||||||
private int progress = -1;
|
private int progress = -1;
|
||||||
private long sizeInByte;
|
private long sizeInByte;
|
||||||
|
|
||||||
public static enum STATUS {
|
public static enum State {
|
||||||
RECORDING,
|
RECORDING,
|
||||||
GENERATING_PLAYLIST,
|
GENERATING_PLAYLIST,
|
||||||
STOPPED,
|
STOPPED,
|
||||||
|
@ -50,11 +50,11 @@ public class Recording {
|
||||||
this.startDate = startDate;
|
this.startDate = startDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public STATUS getStatus() {
|
public State getStatus() {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStatus(STATUS status) {
|
public void setStatus(State status) {
|
||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package ctbrec.event;
|
||||||
|
|
||||||
|
import ctbrec.Model;
|
||||||
|
|
||||||
|
public abstract class AbstractModelEvent extends Event {
|
||||||
|
|
||||||
|
protected Model model;
|
||||||
|
|
||||||
|
public Model getModel() {
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModel(Model model) {
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package ctbrec.event;
|
||||||
|
|
||||||
|
public abstract class Event {
|
||||||
|
|
||||||
|
public static enum Type {
|
||||||
|
/**
|
||||||
|
* This event is fired every time the OnlineMonitor sees a model online
|
||||||
|
* It is also fired, if the model was online before. You can see it as a "still online ping".
|
||||||
|
*/
|
||||||
|
MODEL_ONLINE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This event is fired whenever the model's online state (Model.STATUS) changes.
|
||||||
|
*/
|
||||||
|
MODEL_STATUS_CHANGED,
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This event is fired whenever the state of a recording changes.
|
||||||
|
*/
|
||||||
|
RECORDING_STATUS_CHANGED
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Type getType();
|
||||||
|
public abstract String getName();
|
||||||
|
public abstract String getDescription();
|
||||||
|
public abstract String[] getExecutionParams();
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package ctbrec;
|
package ctbrec.event;
|
||||||
|
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
@ -12,24 +12,5 @@ public class EventBusHolder {
|
||||||
public static final String STATUS = "status";
|
public static final String STATUS = "status";
|
||||||
public static final String MODEL = "model";
|
public static final String MODEL = "model";
|
||||||
|
|
||||||
public static enum EVENT_TYPE {
|
|
||||||
/**
|
|
||||||
* This event is fired every time the OnlineMonitor sees a model online
|
|
||||||
* It is also fired, if the model was online before. You can see it as a "still online ping".
|
|
||||||
*/
|
|
||||||
MODEL_ONLINE,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This event is fired whenever the model's online state (Model.STATUS) changes.
|
|
||||||
*/
|
|
||||||
MODEL_STATUS_CHANGED,
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This event is fired whenever the state of a recording changes.
|
|
||||||
*/
|
|
||||||
RECORDING_STATUS_CHANGED
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final EventBus BUS = new AsyncEventBus(Executors.newSingleThreadExecutor());
|
public static final EventBus BUS = new AsyncEventBus(Executors.newSingleThreadExecutor());
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package ctbrec.event;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
public class EventReaction {
|
||||||
|
|
||||||
|
private List<Predicate<Event>> predicates = new ArrayList<>();
|
||||||
|
private Consumer<Event> action;
|
||||||
|
|
||||||
|
@SafeVarargs
|
||||||
|
public EventReaction(Consumer<Event> action, Predicate<Event>... predicates) {
|
||||||
|
this.action = action;
|
||||||
|
for (Predicate<Event> predicate : predicates) {
|
||||||
|
this.predicates.add(predicate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reactToEvent(Event evt) {
|
||||||
|
boolean matches = true;
|
||||||
|
for (Predicate<Event> predicate : predicates) {
|
||||||
|
if(!predicate.test(evt)) {
|
||||||
|
matches = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(matches) {
|
||||||
|
action.accept(evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package ctbrec.event;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class LogReaction extends EventReaction {
|
||||||
|
|
||||||
|
private static final transient Logger LOG = LoggerFactory.getLogger(LogReaction.class);
|
||||||
|
|
||||||
|
public LogReaction() {
|
||||||
|
super(evt -> {
|
||||||
|
LOG.debug("LogReaction: {}", evt);
|
||||||
|
}, TypePredicate.of(Event.Type.RECORDING_STATUS_CHANGED));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package ctbrec.event;
|
||||||
|
|
||||||
|
import ctbrec.Model;
|
||||||
|
|
||||||
|
public class ModelIsOnlineEvent extends AbstractModelEvent {
|
||||||
|
|
||||||
|
public ModelIsOnlineEvent(Model model) {
|
||||||
|
super.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getType() {
|
||||||
|
return Event.Type.MODEL_ONLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Model is online";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Repeatedly fired when a model is online";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getExecutionParams() {
|
||||||
|
return new String[] {
|
||||||
|
getType().toString(),
|
||||||
|
model.getDisplayName(),
|
||||||
|
model.getUrl(),
|
||||||
|
model.getSite().getName()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package ctbrec.event;
|
||||||
|
|
||||||
|
import ctbrec.Model;
|
||||||
|
import ctbrec.Model.State;
|
||||||
|
|
||||||
|
public class ModelStateChangedEvent extends AbstractModelEvent {
|
||||||
|
|
||||||
|
private State oldState;
|
||||||
|
private State newState;
|
||||||
|
|
||||||
|
public ModelStateChangedEvent(Model model, Model.State oldState, Model.State newState) {
|
||||||
|
super.model = model;
|
||||||
|
this.oldState = oldState;
|
||||||
|
this.newState = newState;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getType() {
|
||||||
|
return Event.Type.MODEL_STATUS_CHANGED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Model state changed";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Fired when a model state changed. E.g. from OFFLINE to ONLINE";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getExecutionParams() {
|
||||||
|
return new String[] {
|
||||||
|
getType().toString(),
|
||||||
|
model.getDisplayName(),
|
||||||
|
model.getUrl(),
|
||||||
|
model.getSite().getName(),
|
||||||
|
oldState.toString(),
|
||||||
|
newState.toString()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public State getOldState() {
|
||||||
|
return oldState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOldState(State oldState) {
|
||||||
|
this.oldState = oldState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public State getNewState() {
|
||||||
|
return newState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNewState(State newState) {
|
||||||
|
this.newState = newState;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package ctbrec.event;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
import ctbrec.Model;
|
||||||
|
import ctbrec.Recording.State;
|
||||||
|
|
||||||
|
public class RecordingStateChangedEvent extends AbstractModelEvent {
|
||||||
|
|
||||||
|
private File path;
|
||||||
|
private State newState;
|
||||||
|
private Instant startTime;
|
||||||
|
|
||||||
|
public RecordingStateChangedEvent(File recording, State newState, Model model, Instant startTime) {
|
||||||
|
super.model = model;
|
||||||
|
this.path = recording;
|
||||||
|
this.newState = newState;
|
||||||
|
this.startTime = startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type getType() {
|
||||||
|
return Event.Type.RECORDING_STATUS_CHANGED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Recording state changed";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Fired when a recording state changed. E.g. from RECORDING to STOPPED";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getExecutionParams() {
|
||||||
|
return new String[] {
|
||||||
|
getType().toString(),
|
||||||
|
path.getAbsolutePath(),
|
||||||
|
newState.toString(),
|
||||||
|
model.getDisplayName(),
|
||||||
|
model.getSite().getName(),
|
||||||
|
model.getUrl(),
|
||||||
|
Long.toString(startTime.getEpochSecond())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "RecordingStateChanged[" + newState + "," + model.getDisplayName() + "," + path + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package ctbrec.event;
|
||||||
|
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import ctbrec.event.Event.Type;
|
||||||
|
|
||||||
|
public class TypePredicate implements Predicate<Event> {
|
||||||
|
|
||||||
|
private Type type;
|
||||||
|
|
||||||
|
private TypePredicate(Type type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(Event evt) {
|
||||||
|
return evt.getType() == type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TypePredicate of(Type type) {
|
||||||
|
return new TypePredicate(type);
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,7 +26,7 @@ public class StreamRedirectThread implements Runnable {
|
||||||
while(in != null && (length = in.read(buffer)) >= 0) {
|
while(in != null && (length = in.read(buffer)) >= 0) {
|
||||||
out.write(buffer, 0, length);
|
out.write(buffer, 0, length);
|
||||||
}
|
}
|
||||||
LOG.debug("Stream redirect thread ended");
|
LOG.trace("Stream redirect thread ended");
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
LOG.error("Couldn't redirect stream: {}", e.getLocalizedMessage());
|
LOG.error("Couldn't redirect stream: {}", e.getLocalizedMessage());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
package ctbrec.recorder;
|
package ctbrec.recorder;
|
||||||
|
|
||||||
import static ctbrec.EventBusHolder.*;
|
import static ctbrec.Recording.State.*;
|
||||||
import static ctbrec.EventBusHolder.EVENT_TYPE.*;
|
import static ctbrec.event.Event.Type.*;
|
||||||
import static ctbrec.Recording.STATUS.*;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FilenameFilter;
|
import java.io.FilenameFilter;
|
||||||
|
@ -24,7 +23,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.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
@ -38,11 +36,14 @@ import com.iheartradio.m3u8.ParseException;
|
||||||
import com.iheartradio.m3u8.PlaylistException;
|
import com.iheartradio.m3u8.PlaylistException;
|
||||||
|
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.EventBusHolder;
|
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
import ctbrec.OS;
|
import ctbrec.OS;
|
||||||
import ctbrec.Recording;
|
import ctbrec.Recording;
|
||||||
import ctbrec.Recording.STATUS;
|
import ctbrec.Recording.State;
|
||||||
|
import ctbrec.event.Event;
|
||||||
|
import ctbrec.event.EventBusHolder;
|
||||||
|
import ctbrec.event.ModelIsOnlineEvent;
|
||||||
|
import ctbrec.event.RecordingStateChangedEvent;
|
||||||
import ctbrec.io.HttpClient;
|
import ctbrec.io.HttpClient;
|
||||||
import ctbrec.io.StreamRedirectThread;
|
import ctbrec.io.StreamRedirectThread;
|
||||||
import ctbrec.recorder.PlaylistGenerator.InvalidPlaylistException;
|
import ctbrec.recorder.PlaylistGenerator.InvalidPlaylistException;
|
||||||
|
@ -97,10 +98,11 @@ public class LocalRecorder implements Recorder {
|
||||||
private void registerEventBusListener() {
|
private void registerEventBusListener() {
|
||||||
EventBusHolder.BUS.register(new Object() {
|
EventBusHolder.BUS.register(new Object() {
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void modelEvent(Map<String, Object> e) {
|
public void modelEvent(Event e) {
|
||||||
try {
|
try {
|
||||||
if (Objects.equals(e.get(EVENT), MODEL_ONLINE)) {
|
if (e.getType() == MODEL_ONLINE) {
|
||||||
Model model = (Model) e.get(MODEL);
|
ModelIsOnlineEvent evt = (ModelIsOnlineEvent) e;
|
||||||
|
Model model = evt.getModel();
|
||||||
if(!isSuspended(model) && !recordingProcesses.containsKey(model)) {
|
if(!isSuspended(model) && !recordingProcesses.containsKey(model)) {
|
||||||
startRecordingProcess(model);
|
startRecordingProcess(model);
|
||||||
}
|
}
|
||||||
|
@ -198,7 +200,6 @@ public class LocalRecorder implements Recorder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.start();
|
}.start();
|
||||||
fireRecordingStateChanged(model, RECORDING);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopRecordingProcess(Model model) {
|
private void stopRecordingProcess(Model model) {
|
||||||
|
@ -208,7 +209,7 @@ public class LocalRecorder implements Recorder {
|
||||||
if(!Config.isServerMode()) {
|
if(!Config.isServerMode()) {
|
||||||
postprocess(download);
|
postprocess(download);
|
||||||
}
|
}
|
||||||
fireRecordingStateChanged(model, FINISHED);
|
fireRecordingStateChanged(download.getTarget(), FINISHED, model, download.getStartTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void postprocess(Download download) {
|
private void postprocess(Download download) {
|
||||||
|
@ -388,7 +389,7 @@ public class LocalRecorder implements Recorder {
|
||||||
} else {
|
} else {
|
||||||
postprocess(d);
|
postprocess(d);
|
||||||
}
|
}
|
||||||
fireRecordingStateChanged(m, FINISHED); // TODO fire all the events
|
fireRecordingStateChanged(d.getTarget(), FINISHED, m, d.getStartTime()); // TODO fire all the events
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (Model m : restart) {
|
for (Model m : restart) {
|
||||||
|
@ -439,13 +440,9 @@ public class LocalRecorder implements Recorder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fireRecordingStateChanged(Model model, Recording.STATUS status) {
|
private void fireRecordingStateChanged(File path, Recording.State newState, Model model, Instant startTime) {
|
||||||
Map<String, Object> evt = new HashMap<>();
|
RecordingStateChangedEvent evt = new RecordingStateChangedEvent(path, newState, model, startTime);
|
||||||
evt.put(EVENT, RECORDING_STATUS_CHANGED);
|
|
||||||
evt.put(STATUS, status);
|
|
||||||
evt.put(MODEL, model);
|
|
||||||
EventBusHolder.BUS.post(evt);
|
EventBusHolder.BUS.post(evt);
|
||||||
LOG.debug("Event fired {}", evt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PostProcessingTrigger extends Thread {
|
private class PostProcessingTrigger extends Thread {
|
||||||
|
@ -532,7 +529,7 @@ public class LocalRecorder implements Recorder {
|
||||||
return recordings;
|
return recordings;
|
||||||
}
|
}
|
||||||
|
|
||||||
private STATUS getStatus(Recording recording) {
|
private State getStatus(Recording recording) {
|
||||||
File absolutePath = new File(Config.getInstance().getSettings().recordingsDir, recording.getPath());
|
File absolutePath = new File(Config.getInstance().getSettings().recordingsDir, recording.getPath());
|
||||||
|
|
||||||
PlaylistGenerator playlistGenerator = playlistGenerators.get(absolutePath);
|
PlaylistGenerator playlistGenerator = playlistGenerators.get(absolutePath);
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package ctbrec.recorder;
|
package ctbrec.recorder;
|
||||||
|
|
||||||
import static ctbrec.EventBusHolder.*;
|
import static ctbrec.Model.State.*;
|
||||||
import static ctbrec.EventBusHolder.EVENT_TYPE.*;
|
|
||||||
import static ctbrec.Model.STATUS.*;
|
|
||||||
|
|
||||||
import java.io.InterruptedIOException;
|
import java.io.InterruptedIOException;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
|
@ -18,9 +16,10 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.EventBusHolder;
|
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
import ctbrec.Model.STATUS;
|
import ctbrec.event.EventBusHolder;
|
||||||
|
import ctbrec.event.ModelIsOnlineEvent;
|
||||||
|
import ctbrec.event.ModelStateChangedEvent;
|
||||||
import ctbrec.io.HttpException;
|
import ctbrec.io.HttpException;
|
||||||
|
|
||||||
public class OnlineMonitor extends Thread {
|
public class OnlineMonitor extends Thread {
|
||||||
|
@ -30,7 +29,7 @@ public class OnlineMonitor extends Thread {
|
||||||
private volatile boolean running = false;
|
private volatile boolean running = false;
|
||||||
private Recorder recorder;
|
private Recorder recorder;
|
||||||
|
|
||||||
private Map<Model, STATUS> states = new HashMap<>();
|
private Map<Model, Model.State> states = new HashMap<>();
|
||||||
|
|
||||||
public OnlineMonitor(Recorder recorder) {
|
public OnlineMonitor(Recorder recorder) {
|
||||||
this.recorder = recorder;
|
this.recorder = recorder;
|
||||||
|
@ -57,13 +56,13 @@ public class OnlineMonitor extends Thread {
|
||||||
for (Model model : models) {
|
for (Model model : models) {
|
||||||
try {
|
try {
|
||||||
if(model.isOnline(IGNORE_CACHE)) {
|
if(model.isOnline(IGNORE_CACHE)) {
|
||||||
fireModelOnline(model);
|
EventBusHolder.BUS.post(new ModelIsOnlineEvent(model));
|
||||||
}
|
}
|
||||||
STATUS state = model.getOnlineState(false);
|
Model.State state = model.getOnlineState(false);
|
||||||
STATUS oldState = states.getOrDefault(model, UNKNOWN);
|
Model.State oldState = states.getOrDefault(model, UNKNOWN);
|
||||||
states.put(model, state);
|
states.put(model, state);
|
||||||
if(state != oldState) {
|
if(state != oldState) {
|
||||||
fireModelOnlineStateChanged(model, oldState, state);
|
EventBusHolder.BUS.post(new ModelStateChangedEvent(model, oldState, state));
|
||||||
}
|
}
|
||||||
} catch (HttpException e) {
|
} catch (HttpException e) {
|
||||||
LOG.error("Couldn't check if model {} is online. HTTP Response: {} - {}",
|
LOG.error("Couldn't check if model {} is online. HTTP Response: {} - {}",
|
||||||
|
@ -98,22 +97,6 @@ public class OnlineMonitor extends Thread {
|
||||||
LOG.debug(getName() + " terminated");
|
LOG.debug(getName() + " terminated");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fireModelOnline(Model model) {
|
|
||||||
Map<String, Object> evt = new HashMap<>();
|
|
||||||
evt.put(EVENT, MODEL_ONLINE);
|
|
||||||
evt.put(MODEL, model);
|
|
||||||
EventBusHolder.BUS.post(evt);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void fireModelOnlineStateChanged(Model model, STATUS oldStatus, STATUS newStatus) {
|
|
||||||
Map<String, Object> evt = new HashMap<>();
|
|
||||||
evt.put(EVENT, MODEL_STATUS_CHANGED);
|
|
||||||
evt.put(STATUS, newStatus);
|
|
||||||
evt.put(OLD, oldStatus);
|
|
||||||
evt.put(MODEL, model);
|
|
||||||
EventBusHolder.BUS.post(evt);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void shutdown() {
|
public void shutdown() {
|
||||||
running = false;
|
running = false;
|
||||||
interrupt();
|
interrupt();
|
||||||
|
|
|
@ -18,10 +18,10 @@ import com.squareup.moshi.JsonAdapter;
|
||||||
import com.squareup.moshi.Moshi;
|
import com.squareup.moshi.Moshi;
|
||||||
|
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.EventBusHolder;
|
|
||||||
import ctbrec.Hmac;
|
import ctbrec.Hmac;
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
import ctbrec.Recording;
|
import ctbrec.Recording;
|
||||||
|
import ctbrec.event.EventBusHolder;
|
||||||
import ctbrec.io.HttpClient;
|
import ctbrec.io.HttpClient;
|
||||||
import ctbrec.io.HttpException;
|
import ctbrec.io.HttpException;
|
||||||
import ctbrec.io.InstantJsonAdapter;
|
import ctbrec.io.InstantJsonAdapter;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package ctbrec.recorder.download;
|
package ctbrec.recorder.download;
|
||||||
|
|
||||||
|
import static ctbrec.Recording.State.*;
|
||||||
|
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
@ -24,6 +26,8 @@ import com.iheartradio.m3u8.PlaylistException;
|
||||||
|
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
|
import ctbrec.event.EventBusHolder;
|
||||||
|
import ctbrec.event.RecordingStateChangedEvent;
|
||||||
import ctbrec.io.HttpClient;
|
import ctbrec.io.HttpClient;
|
||||||
import ctbrec.io.HttpException;
|
import ctbrec.io.HttpException;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
|
@ -54,6 +58,10 @@ public class HlsDownload extends AbstractHlsDownload {
|
||||||
throw new IOException(model.getName() +"'s room is not public");
|
throw new IOException(model.getName() +"'s room is not public");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// let the world know, that we are recording now
|
||||||
|
RecordingStateChangedEvent evt = new RecordingStateChangedEvent(getTarget(), RECORDING, model, getStartTime());
|
||||||
|
EventBusHolder.BUS.post(evt);
|
||||||
|
|
||||||
String segments = getSegmentPlaylistUrl(model);
|
String segments = getSegmentPlaylistUrl(model);
|
||||||
if(segments != null) {
|
if(segments != null) {
|
||||||
if (!Files.exists(downloadDir, LinkOption.NOFOLLOW_LINKS)) {
|
if (!Files.exists(downloadDir, LinkOption.NOFOLLOW_LINKS)) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package ctbrec.recorder.download;
|
package ctbrec.recorder.download;
|
||||||
|
|
||||||
|
import static ctbrec.Recording.State.*;
|
||||||
import static java.nio.file.StandardOpenOption.*;
|
import static java.nio.file.StandardOpenOption.*;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
@ -44,6 +45,8 @@ import com.iheartradio.m3u8.PlaylistException;
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.Hmac;
|
import ctbrec.Hmac;
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
|
import ctbrec.event.EventBusHolder;
|
||||||
|
import ctbrec.event.RecordingStateChangedEvent;
|
||||||
import ctbrec.io.HttpClient;
|
import ctbrec.io.HttpClient;
|
||||||
import ctbrec.io.HttpException;
|
import ctbrec.io.HttpException;
|
||||||
import ctbrec.recorder.ProgressListener;
|
import ctbrec.recorder.ProgressListener;
|
||||||
|
@ -126,6 +129,11 @@ public class MergedHlsDownload extends AbstractHlsDownload {
|
||||||
splitRecStartTime = ZonedDateTime.now();
|
splitRecStartTime = ZonedDateTime.now();
|
||||||
super.model = model;
|
super.model = model;
|
||||||
targetFile = Config.getInstance().getFileForRecording(model);
|
targetFile = Config.getInstance().getFileForRecording(model);
|
||||||
|
|
||||||
|
// let the world know, that we are recording now
|
||||||
|
RecordingStateChangedEvent evt = new RecordingStateChangedEvent(getTarget(), RECORDING, model, getStartTime());
|
||||||
|
EventBusHolder.BUS.post(evt);
|
||||||
|
|
||||||
String segments = getSegmentPlaylistUrl(model);
|
String segments = getSegmentPlaylistUrl(model);
|
||||||
mergeThread = createMergeThread(targetFile, null, true);
|
mergeThread = createMergeThread(targetFile, null, true);
|
||||||
mergeThread.start();
|
mergeThread.start();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package ctbrec.sites.bonga;
|
package ctbrec.sites.bonga;
|
||||||
|
|
||||||
import static ctbrec.Model.STATUS.*;
|
import static ctbrec.Model.State.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -85,7 +85,7 @@ public class BongaCamsModel extends AbstractModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public STATUS getOnlineState(boolean failFast) throws IOException, ExecutionException {
|
public State getOnlineState(boolean failFast) throws IOException, ExecutionException {
|
||||||
if(failFast) {
|
if(failFast) {
|
||||||
return onlineState;
|
return onlineState;
|
||||||
} else {
|
} else {
|
||||||
|
@ -97,7 +97,7 @@ public class BongaCamsModel extends AbstractModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setOnlineState(STATUS onlineState) {
|
public void setOnlineState(State onlineState) {
|
||||||
this.onlineState = onlineState;
|
this.onlineState = onlineState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package ctbrec.sites.cam4;
|
package ctbrec.sites.cam4;
|
||||||
|
|
||||||
import static ctbrec.Model.STATUS.*;
|
import static ctbrec.Model.State.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -109,7 +109,7 @@ public class Cam4Model extends AbstractModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public STATUS getOnlineState(boolean failFast) throws IOException, ExecutionException {
|
public State getOnlineState(boolean failFast) throws IOException, ExecutionException {
|
||||||
if(failFast) {
|
if(failFast) {
|
||||||
return onlineState;
|
return onlineState;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package ctbrec.sites.camsoda;
|
package ctbrec.sites.camsoda;
|
||||||
|
|
||||||
import static ctbrec.Model.STATUS.*;
|
import static ctbrec.Model.State.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -102,7 +102,7 @@ public class CamsodaModel extends AbstractModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public STATUS getOnlineState(boolean failFast) throws IOException, ExecutionException {
|
public State getOnlineState(boolean failFast) throws IOException, ExecutionException {
|
||||||
if(failFast) {
|
if(failFast) {
|
||||||
return onlineState;
|
return onlineState;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package ctbrec.sites.chaturbate;
|
package ctbrec.sites.chaturbate;
|
||||||
|
|
||||||
import static ctbrec.Model.STATUS.*;
|
import static ctbrec.Model.State.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -76,12 +76,12 @@ public class ChaturbateModel extends AbstractModel {
|
||||||
getChaturbate().streamInfoCache.invalidate(getName());
|
getChaturbate().streamInfoCache.invalidate(getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public STATUS getOnlineState() throws IOException, ExecutionException {
|
public State getOnlineState() throws IOException, ExecutionException {
|
||||||
return getOnlineState(false);
|
return getOnlineState(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public STATUS getOnlineState(boolean failFast) throws IOException, ExecutionException {
|
public State getOnlineState(boolean failFast) throws IOException, ExecutionException {
|
||||||
if(failFast) {
|
if(failFast) {
|
||||||
StreamInfo info = getChaturbate().streamInfoCache.getIfPresent(getName());
|
StreamInfo info = getChaturbate().streamInfoCache.getIfPresent(getName());
|
||||||
setOnlineStateByRoomStatus(info.room_status);
|
setOnlineStateByRoomStatus(info.room_status);
|
||||||
|
@ -109,11 +109,11 @@ public class ChaturbateModel extends AbstractModel {
|
||||||
onlineState = AWAY;
|
onlineState = AWAY;
|
||||||
break;
|
break;
|
||||||
case "group":
|
case "group":
|
||||||
onlineState = STATUS.GROUP;
|
onlineState = State.GROUP;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG.debug("Unknown show type {}", room_status);
|
LOG.debug("Unknown show type {}", room_status);
|
||||||
onlineState = STATUS.UNKNOWN;
|
onlineState = State.UNKNOWN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -601,7 +601,7 @@ public class MyFreeCamsClient {
|
||||||
String name = json.getString("nm");
|
String name = json.getString("nm");
|
||||||
MyFreeCamsModel model = mfc.createModel(name);
|
MyFreeCamsModel model = mfc.createModel(name);
|
||||||
model.setUid(json.getInt("uid"));
|
model.setUid(json.getInt("uid"));
|
||||||
model.setState(State.of(json.getInt("vs")));
|
model.setMfcState(State.of(json.getInt("vs")));
|
||||||
String uid = Integer.toString(model.getUid());
|
String uid = Integer.toString(model.getUid());
|
||||||
String uidStart = uid.substring(0, 3);
|
String uidStart = uid.substring(0, 3);
|
||||||
String previewUrl = "https://img.mfcimg.com/photos2/"+uidStart+'/'+uid+"/avatar.90x90.jpg";
|
String previewUrl = "https://img.mfcimg.com/photos2/"+uidStart+'/'+uid+"/avatar.90x90.jpg";
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class MyFreeCamsModel extends AbstractModel {
|
||||||
private String hlsUrl;
|
private String hlsUrl;
|
||||||
private double camScore;
|
private double camScore;
|
||||||
private int viewerCount;
|
private int viewerCount;
|
||||||
private State state;
|
private ctbrec.sites.mfc.State state;
|
||||||
private int resolution[] = new int[2];
|
private int resolution[] = new int[2];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,7 +61,7 @@ public class MyFreeCamsModel extends AbstractModel {
|
||||||
@Override
|
@Override
|
||||||
public boolean isOnline() throws IOException, ExecutionException, InterruptedException {
|
public boolean isOnline() throws IOException, ExecutionException, InterruptedException {
|
||||||
MyFreeCamsClient.getInstance().update(this);
|
MyFreeCamsClient.getInstance().update(this);
|
||||||
return state == State.ONLINE;
|
return state == ctbrec.sites.mfc.State.ONLINE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -70,27 +70,27 @@ public class MyFreeCamsModel extends AbstractModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public STATUS getOnlineState(boolean failFast) throws IOException, ExecutionException {
|
public State getOnlineState(boolean failFast) throws IOException, ExecutionException {
|
||||||
if(state == null) {
|
if(state == null) {
|
||||||
return STATUS.UNKNOWN;
|
return State.UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(state) {
|
switch(state) {
|
||||||
case ONLINE:
|
case ONLINE:
|
||||||
case RECORDING:
|
case RECORDING:
|
||||||
return ctbrec.Model.STATUS.ONLINE;
|
return ctbrec.Model.State.ONLINE;
|
||||||
case AWAY:
|
case AWAY:
|
||||||
return ctbrec.Model.STATUS.AWAY;
|
return ctbrec.Model.State.AWAY;
|
||||||
case PRIVATE:
|
case PRIVATE:
|
||||||
return ctbrec.Model.STATUS.PRIVATE;
|
return ctbrec.Model.State.PRIVATE;
|
||||||
case GROUP_SHOW:
|
case GROUP_SHOW:
|
||||||
return ctbrec.Model.STATUS.GROUP;
|
return ctbrec.Model.State.GROUP;
|
||||||
case OFFLINE:
|
case OFFLINE:
|
||||||
case CAMOFF:
|
case CAMOFF:
|
||||||
return ctbrec.Model.STATUS.OFFLINE;
|
return ctbrec.Model.State.OFFLINE;
|
||||||
default:
|
default:
|
||||||
LOG.debug("State {} is not mapped", this.state);
|
LOG.debug("State {} is not mapped", this.state);
|
||||||
return ctbrec.Model.STATUS.UNKNOWN;
|
return ctbrec.Model.State.UNKNOWN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,7 +233,7 @@ public class MyFreeCamsModel extends AbstractModel {
|
||||||
this.camScore = camScore;
|
this.camScore = camScore;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setState(State state) {
|
public void setMfcState(ctbrec.sites.mfc.State state) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,7 +249,7 @@ public class MyFreeCamsModel extends AbstractModel {
|
||||||
public void update(SessionState state, String streamUrl) {
|
public void update(SessionState state, String streamUrl) {
|
||||||
uid = Integer.parseInt(state.getUid().toString());
|
uid = Integer.parseInt(state.getUid().toString());
|
||||||
setName(state.getNm());
|
setName(state.getNm());
|
||||||
setState(State.of(state.getVs()));
|
setMfcState(ctbrec.sites.mfc.State.of(state.getVs()));
|
||||||
setStreamUrl(streamUrl);
|
setStreamUrl(streamUrl);
|
||||||
Optional<Double> camScore = Optional.ofNullable(state.getM()).map(m -> m.getCamscore());
|
Optional<Double> camScore = Optional.ofNullable(state.getM()).map(m -> m.getCamscore());
|
||||||
setCamScore(camScore.orElse(0.0));
|
setCamScore(camScore.orElse(0.0));
|
||||||
|
@ -258,7 +258,7 @@ public class MyFreeCamsModel extends AbstractModel {
|
||||||
String uid = state.getUid().toString();
|
String uid = state.getUid().toString();
|
||||||
String uidStart = uid.substring(0, 3);
|
String uidStart = uid.substring(0, 3);
|
||||||
String previewUrl = "https://img.mfcimg.com/photos2/"+uidStart+'/'+uid+"/avatar.300x300.jpg";
|
String previewUrl = "https://img.mfcimg.com/photos2/"+uidStart+'/'+uid+"/avatar.300x300.jpg";
|
||||||
if(MyFreeCamsModel.this.state == State.ONLINE) {
|
if(MyFreeCamsModel.this.state == ctbrec.sites.mfc.State.ONLINE) {
|
||||||
try {
|
try {
|
||||||
previewUrl = getLivePreviewUrl(state);
|
previewUrl = getLivePreviewUrl(state);
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
|
|
Loading…
Reference in New Issue