Add resolution to recordings table
This commit is contained in:
parent
e7b688906c
commit
9c2a8242de
|
@ -4,6 +4,7 @@
|
||||||
* Add buttons to settings to delete cookies per site
|
* Add buttons to settings to delete cookies per site
|
||||||
* Fix bug in minimal browser
|
* Fix bug in minimal browser
|
||||||
* Added model notes to the recordings table
|
* Added model notes to the recordings table
|
||||||
|
* Added resolution to the recordings table
|
||||||
* Model placeholders can now be used for player params
|
* Model placeholders can now be used for player params
|
||||||
${modelName}
|
${modelName}
|
||||||
${modelDisplayName}
|
${modelDisplayName}
|
||||||
|
|
|
@ -306,4 +306,8 @@ public class JavaFxRecording extends Recording {
|
||||||
return delegate.getContactSheet();
|
return delegate.getContactSheet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSelectedResolution() {
|
||||||
|
return delegate.getSelectedResolution();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,7 @@ import ctbrec.ui.controls.Toast;
|
||||||
import ctbrec.ui.menu.ModelMenuContributor;
|
import ctbrec.ui.menu.ModelMenuContributor;
|
||||||
import ctbrec.ui.tabs.recorded.ModelName;
|
import ctbrec.ui.tabs.recorded.ModelName;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
|
@ -171,6 +172,11 @@ public class RecordingsTab extends Tab implements TabSelectionListener, Shutdown
|
||||||
size.setPrefWidth(100);
|
size.setPrefWidth(100);
|
||||||
size.setCellValueFactory(cdf -> cdf.getValue().getSizeProperty());
|
size.setCellValueFactory(cdf -> cdf.getValue().getSizeProperty());
|
||||||
size.setCellFactory(param -> createSizeCell());
|
size.setCellFactory(param -> createSizeCell());
|
||||||
|
TableColumn<JavaFxRecording, Number> resolution = new TableColumn<>("Resolution");
|
||||||
|
resolution.setId("resolution");
|
||||||
|
resolution.setStyle("-fx-alignment: CENTER-RIGHT;");
|
||||||
|
resolution.setPrefWidth(100);
|
||||||
|
resolution.setCellValueFactory(cdf -> new SimpleIntegerProperty(cdf.getValue().getSelectedResolution()));
|
||||||
TableColumn<JavaFxRecording, String> notes = new TableColumn<>("Notes");
|
TableColumn<JavaFxRecording, String> notes = new TableColumn<>("Notes");
|
||||||
notes.setId("notes");
|
notes.setId("notes");
|
||||||
notes.setPrefWidth(400);
|
notes.setPrefWidth(400);
|
||||||
|
@ -180,7 +186,7 @@ public class RecordingsTab extends Tab implements TabSelectionListener, Shutdown
|
||||||
modelNotes.setPrefWidth(400);
|
modelNotes.setPrefWidth(400);
|
||||||
modelNotes.setCellValueFactory(cdf -> new SimpleStringProperty(config.getModelNotes(cdf.getValue().getModel())));
|
modelNotes.setCellValueFactory(cdf -> new SimpleStringProperty(config.getModelNotes(cdf.getValue().getModel())));
|
||||||
|
|
||||||
table.getColumns().addAll(name, date, status, progress, size, notes, modelNotes);
|
table.getColumns().addAll(name, date, status, progress, size, resolution, notes, modelNotes);
|
||||||
table.setItems(observableRecordings);
|
table.setItems(observableRecordings);
|
||||||
table.addEventHandler(ContextMenuEvent.CONTEXT_MENU_REQUESTED, this::onContextMenuRequested);
|
table.addEventHandler(ContextMenuEvent.CONTEXT_MENU_REQUESTED, this::onContextMenuRequested);
|
||||||
table.addEventHandler(MouseEvent.MOUSE_PRESSED, this::onMousePressed);
|
table.addEventHandler(MouseEvent.MOUSE_PRESSED, this::onMousePressed);
|
||||||
|
|
|
@ -42,6 +42,7 @@ public class Recording implements Serializable, Callable<Recording> {
|
||||||
private Set<String> associatedFiles = new HashSet<>();
|
private Set<String> associatedFiles = new HashSet<>();
|
||||||
private File absoluteFile = null;
|
private File absoluteFile = null;
|
||||||
private File postProcessedFile = null;
|
private File postProcessedFile = null;
|
||||||
|
private int selectedResolution = -1;
|
||||||
|
|
||||||
public enum State {
|
public enum State {
|
||||||
RECORDING("recording"),
|
RECORDING("recording"),
|
||||||
|
@ -70,6 +71,9 @@ public class Recording implements Serializable, Callable<Recording> {
|
||||||
@Override
|
@Override
|
||||||
public Recording call() throws Exception {
|
public Recording call() throws Exception {
|
||||||
download.call();
|
download.call();
|
||||||
|
if (selectedResolution == -1) {
|
||||||
|
selectedResolution = download.getSelectedResolution();
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,6 +209,10 @@ public class Recording implements Serializable, Callable<Recording> {
|
||||||
this.note = note;
|
this.note = note;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getSelectedResolution() {
|
||||||
|
return selectedResolution;
|
||||||
|
}
|
||||||
|
|
||||||
public Duration getLength() {
|
public Duration getLength() {
|
||||||
File ppFile = getPostProcessedFile();
|
File ppFile = getPostProcessedFile();
|
||||||
if (ppFile.isDirectory()) {
|
if (ppFile.isDirectory()) {
|
||||||
|
|
|
@ -69,4 +69,9 @@ public abstract class AbstractDownload implements Download {
|
||||||
public Model getModel() {
|
public Model getModel() {
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSelectedResolution() {
|
||||||
|
return StreamSource.UNKNOWN;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package ctbrec.recorder.download;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Serializable;
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
@ -11,7 +10,7 @@ import ctbrec.Config;
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
import ctbrec.Recording;
|
import ctbrec.Recording;
|
||||||
|
|
||||||
public interface Download extends Serializable, Callable<Download> {
|
public interface Download extends Callable<Download> {
|
||||||
void init(Config config, Model model, Instant startTime, ExecutorService executorService) throws IOException;
|
void init(Config config, Model model, Instant startTime, ExecutorService executorService) throws IOException;
|
||||||
void stop();
|
void stop();
|
||||||
void finalizeDownload();
|
void finalizeDownload();
|
||||||
|
@ -20,6 +19,7 @@ public interface Download extends Serializable, Callable<Download> {
|
||||||
Instant getStartTime();
|
Instant getStartTime();
|
||||||
Instant getRescheduleTime();
|
Instant getRescheduleTime();
|
||||||
void postprocess(Recording recording);
|
void postprocess(Recording recording);
|
||||||
|
int getSelectedResolution();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the path to the recording in the filesystem as file object
|
* Returns the path to the recording in the filesystem as file object
|
||||||
|
|
|
@ -70,27 +70,28 @@ import okhttp3.Response;
|
||||||
|
|
||||||
public abstract class AbstractHlsDownload extends AbstractDownload {
|
public abstract class AbstractHlsDownload extends AbstractDownload {
|
||||||
|
|
||||||
private static final transient Logger LOG = LoggerFactory.getLogger(AbstractHlsDownload.class);
|
private static final Logger LOG = LoggerFactory.getLogger(AbstractHlsDownload.class);
|
||||||
private static final int A_FEW_SECONDS = 10_000;
|
private static final int A_FEW_SECONDS = 10_000;
|
||||||
private static final int MAX_SECONDS_WITHOUT_TRANSFER = 30;
|
private static final int MAX_SECONDS_WITHOUT_TRANSFER = 30;
|
||||||
|
|
||||||
private transient NumberFormat nf = new DecimalFormat("000000");
|
private NumberFormat nf = new DecimalFormat("000000");
|
||||||
private transient int playlistEmptyCount = 0;
|
private int playlistEmptyCount = 0;
|
||||||
private transient int segmentCounter = 1;
|
private int segmentCounter = 1;
|
||||||
|
|
||||||
protected transient HttpClient client;
|
protected HttpClient client;
|
||||||
protected transient volatile boolean running = true;
|
protected volatile boolean running = true;
|
||||||
|
|
||||||
protected transient int lastSegmentNumber = 0;
|
protected int lastSegmentNumber = 0;
|
||||||
protected transient int nextSegmentNumber = 0;
|
protected int nextSegmentNumber = 0;
|
||||||
protected transient String segmentPlaylistUrl;
|
protected String segmentPlaylistUrl;
|
||||||
|
|
||||||
private transient Instant beforeLastPlaylistRequest= Instant.EPOCH;
|
private Instant beforeLastPlaylistRequest= Instant.EPOCH;
|
||||||
private transient int consecutivePlaylistTimeouts = 0;
|
private int consecutivePlaylistTimeouts = 0;
|
||||||
private transient int consecutivePlaylistErrors = 0;
|
private int consecutivePlaylistErrors = 0;
|
||||||
private transient Instant lastSegmentDownload = Instant.MAX;
|
private Instant lastSegmentDownload = Instant.MAX;
|
||||||
|
private int selectedResolution = UNKNOWN;
|
||||||
|
|
||||||
private transient List<RecordingEvent> recordingEvents = new LinkedList<>();
|
private List<RecordingEvent> recordingEvents = new LinkedList<>();
|
||||||
|
|
||||||
protected AbstractHlsDownload(HttpClient client) {
|
protected AbstractHlsDownload(HttpClient client) {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
|
@ -221,8 +222,10 @@ public abstract class AbstractHlsDownload extends AbstractDownload {
|
||||||
String url = null;
|
String url = null;
|
||||||
if (model.getStreamUrlIndex() >= 0 && model.getStreamUrlIndex() < streamSources.size()) {
|
if (model.getStreamUrlIndex() >= 0 && model.getStreamUrlIndex() < streamSources.size()) {
|
||||||
// TODO don't use the index, but the bandwidth. if the bandwidth does not match, take the closest one
|
// TODO don't use the index, but the bandwidth. if the bandwidth does not match, take the closest one
|
||||||
LOG.debug("{} selected {}", model.getName(), streamSources.get(model.getStreamUrlIndex()));
|
StreamSource source = streamSources.get(model.getStreamUrlIndex());
|
||||||
url = streamSources.get(model.getStreamUrlIndex()).getMediaPlaylistUrl();
|
LOG.debug("{} selected {}", model.getName(), source);
|
||||||
|
url = source.getMediaPlaylistUrl();
|
||||||
|
selectedResolution = source.height;
|
||||||
} else {
|
} else {
|
||||||
// filter out stream resolutions, which are out of range of the configured min and max
|
// filter out stream resolutions, which are out of range of the configured min and max
|
||||||
int minRes = Config.getInstance().getSettings().minimumResolution;
|
int minRes = Config.getInstance().getSettings().minimumResolution;
|
||||||
|
@ -235,8 +238,10 @@ public abstract class AbstractHlsDownload extends AbstractDownload {
|
||||||
if (filteredStreamSources.isEmpty()) {
|
if (filteredStreamSources.isEmpty()) {
|
||||||
throw new ExecutionException(new RuntimeException("No stream left in playlist"));
|
throw new ExecutionException(new RuntimeException("No stream left in playlist"));
|
||||||
} else {
|
} else {
|
||||||
LOG.debug("{} selected {}", model.getName(), filteredStreamSources.get(filteredStreamSources.size() - 1));
|
StreamSource source = filteredStreamSources.get(filteredStreamSources.size() - 1);
|
||||||
url = filteredStreamSources.get(filteredStreamSources.size() - 1).getMediaPlaylistUrl();
|
LOG.debug("{} selected {}", model.getName(), source);
|
||||||
|
url = source.getMediaPlaylistUrl();
|
||||||
|
selectedResolution = source.height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG.debug("Segment playlist url {}", url);
|
LOG.debug("Segment playlist url {}", url);
|
||||||
|
@ -420,6 +425,11 @@ public abstract class AbstractHlsDownload extends AbstractDownload {
|
||||||
return running;
|
return running;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSelectedResolution() {
|
||||||
|
return selectedResolution;
|
||||||
|
}
|
||||||
|
|
||||||
private static class RecordingEvent {
|
private static class RecordingEvent {
|
||||||
Instant timestamp;
|
Instant timestamp;
|
||||||
String message;
|
String message;
|
||||||
|
|
Loading…
Reference in New Issue