Improve support for server-side single files

This commit is contained in:
0xboobface 2020-02-22 17:40:22 +01:00
parent 208aa16c80
commit 71be9b3665
15 changed files with 65 additions and 23 deletions

View File

@ -179,6 +179,11 @@ public class JavaFxRecording extends Recording {
return delegate.getMetaDataFile();
}
@Override
public boolean isSingleFile() {
return delegate.isSingleFile();
}
public boolean valueChanged() {
boolean changed = getSizeInByte() != lastValue;
lastValue = getSizeInByte();

View File

@ -162,7 +162,7 @@ public class Player {
private String getRemoteRecordingUrl(Recording rec, Config cfg)
throws MalformedURLException, InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException {
String hlsBase = Config.getInstance().getServerUrl() + "/hls";
String recUrl = hlsBase + rec.getPath() + (rec.isSegmented() ? "/playlist.m3u8" : "");
String recUrl = hlsBase + rec.getPath() + (rec.isSingleFile() ? "" : "/playlist.m3u8");
if (cfg.getSettings().requireAuthentication) {
URL u = new URL(recUrl);
String path = u.getPath();

View File

@ -404,7 +404,7 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
MenuItem rerunPostProcessing = new MenuItem("Rerun Post-Processing");
rerunPostProcessing.setOnAction(e -> triggerPostProcessing(first));
if (first.getStatus() == FAILED || first.getStatus() == WAITING || first.getStatus() == FINISHED) {
if (first.isSegmented() || !first.isSegmented() && first.getPath().endsWith(".part")) {
if (!first.isSingleFile() || first.isSingleFile() && first.getPath().endsWith(".part")) {
contextMenu.getItems().add(rerunPostProcessing);
}
}
@ -488,12 +488,12 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
private String proposeTargetFilename(Recording recording) {
String path = recording.getPath().substring(1);
if(recording.isSegmented()) {
if(recording.isSingleFile()) {
return new File(path).getName();
} else {
String fileSuffix = config.getSettings().ffmpegFileSuffix;
String filename = path.replace("/", "-").replace(".mp4", "") + '.' + fileSuffix;
return filename;
} else {
return new File(path).getName();
}
}
@ -501,16 +501,16 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
Thread t = new Thread(() -> {
try {
String hlsBase = config.getServerUrl() + "/hls";
if (recording.isSegmented()) {
if (recording.isSingleFile()) {
URL url = new URL(hlsBase + recording.getPath());
FileDownload download = new FileDownload(CamrecApplication.httpClient, createDownloadListener(recording));
download.start(url, target);
} else {
URL url = new URL(hlsBase + recording.getPath() + "/playlist.m3u8");
MergedFfmpegHlsDownload download = new MergedFfmpegHlsDownload(CamrecApplication.httpClient);
download.init(config, recording.getModel(), Instant.now());
LOG.info("Downloading {}", url);
download.downloadFinishedRecording(url.toString(), target, createDownloadListener(recording));
} else {
URL url = new URL(hlsBase + recording.getPath());
FileDownload download = new FileDownload(CamrecApplication.httpClient, createDownloadListener(recording));
download.start(url, target);
}
} catch (FileNotFoundException e) {
showErrorDialog(ERROR_WHILE_DOWNLOADING_RECORDING, "The target file couldn't be created", e);

View File

@ -230,7 +230,7 @@ public abstract class AbstractModel implements Model {
@Override
public Download createDownload() {
if (Config.isServerMode()) {
if (Config.isServerMode() && !Config.getInstance().getSettings().recordSingleFile) {
return new HlsDownload(getSite().getHttpClient());
} else {
return new MergedFfmpegHlsDownload(getSite().getHttpClient());

View File

@ -7,7 +7,6 @@ import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Optional;
import ctbrec.event.EventBusHolder;
import ctbrec.event.RecordingStateChangedEvent;
@ -22,6 +21,7 @@ public class Recording implements Serializable {
private int progress = -1;
private long sizeInByte = -1;
private String metaDataFile;
private boolean singleFile = false;
public enum State {
RECORDING("recording"),
@ -123,6 +123,14 @@ public class Recording implements Serializable {
this.download = download;
}
public boolean isSingleFile() {
return singleFile;
}
public void setSingleFile(boolean singleFile) {
this.singleFile = singleFile;
}
public String getMetaDataFile() {
return metaDataFile;
}
@ -224,8 +232,4 @@ public class Recording implements Serializable {
public void refresh() {
sizeInByte = getSize();
}
public boolean isSegmented() {
return !Optional.ofNullable(getPath()).orElse("").endsWith(".mp4");
}
}

View File

@ -103,6 +103,7 @@ public class Settings {
public DirectoryStructure recordingsDirStructure = DirectoryStructure.FLAT;
public String recordingsSortColumn = "";
public String recordingsSortType = "";
public boolean recordSingleFile = false;
public boolean requireAuthentication = false;
public String servletContext = "";
public boolean showPlayerStarting = false;

View File

@ -268,6 +268,7 @@ public class NextGenLocalRecorder implements Recorder {
rec.setPath(download.getPath(model).replaceAll("\\\\", "/"));
rec.setModel(model);
rec.setStartDate(download.getStartTime());
rec.setSingleFile(download.isSingleFile());
recordingProcesses.put(model, rec);
recordingManager.add(rec);
completionService.submit(() -> {

View File

@ -34,4 +34,10 @@ public interface Download extends Serializable {
* @see #getTarget()
*/
public String getPath(Model model);
/**
* Specifies, if the final result of this recording is a single file or consists of segments + playlist
* @return true, if the recording is only a single file
*/
public boolean isSingleFile();
}

View File

@ -425,4 +425,9 @@ public class DashDownload extends AbstractDownload {
}
}
@Override
public boolean isSingleFile() {
return false;
}
}

View File

@ -151,4 +151,9 @@ public class FFmpegDownload extends AbstractHlsDownload {
stop();
}
@Override
public boolean isSingleFile() {
return true;
}
}

View File

@ -366,4 +366,9 @@ public class HlsDownload extends AbstractHlsDownload {
throw new FileNotFoundException(playlist.getAbsolutePath() + " does not exist");
}
}
@Override
public boolean isSingleFile() {
return false;
}
}

View File

@ -489,4 +489,9 @@ public class MergedFfmpegHlsDownload extends AbstractHlsDownload {
public Duration getLength() {
return Duration.between(getStartTime(), Instant.now());
}
@Override
public boolean isSingleFile() {
return true;
}
}

View File

@ -381,7 +381,7 @@ public class Fc2Model extends AbstractModel {
@Override
public Download createDownload() {
if(Config.isServerMode()) {
if(Config.isServerMode() && !Config.getInstance().getSettings().recordSingleFile) {
return new Fc2HlsDownload(getSite().getHttpClient());
} else {
return new Fc2MergedHlsDownload(getSite().getHttpClient());

View File

@ -297,7 +297,7 @@ public class LiveJasminModel extends AbstractModel {
@Override
public Download createDownload() {
if(Config.isServerMode()) {
if(Config.isServerMode() && !Config.getInstance().getSettings().recordSingleFile) {
return new LiveJasminHlsDownload(getSite().getHttpClient());
} else {
return new LiveJasminMergedHlsDownload(getSite().getHttpClient());

View File

@ -158,7 +158,7 @@
<button class="btn btn-secondary fa fa-play" title="Play recording" data-bind="enable: ko_status() == 'FINISHED', click: play"></button>
</td>
<td>
<button class="btn btn-secondary fa fa-download" title="Download recording" data-bind="enable: ko_status() == 'FINISHED', click: function() { $.notify('Not implemented, yet', 'info'); }"></button>
<button class="btn btn-secondary fa fa-download" title="Download recording" data-bind="enable: ko_status() == 'FINISHED' && singleFile, click: function() { $.notify('Not implemented, yet', 'info'); }"></button>
</td>
<td>
<button class="btn btn-secondary fa fa-trash" title="Delete recording" data-bind="enable: ko_status() == 'FINISHED', click: ctbrec.deleteRecording"></button>
@ -389,7 +389,8 @@
};
function play(recording) {
let src = recording.playlist;
let src = recording.singleFile ? '/hls' + recording.path : recording.playlist;
console.log("####################", src);
let hmacOfPath = CryptoJS.HmacSHA256(src, hmac);
src = '..' + src;
if(console) console.log("Path", src, "HMAC", hmacOfPath);
@ -399,15 +400,19 @@
if(console) console.log('Playing video from', src);
if(src.indexOf('.mp4') > 0) {
if(recording.singleFile) {
var video = document.getElementById('player');
video.src = src;
video.load();
console.log(video);
video.oncanplay = function() {
video.height = window.innerHeight * 0.85;
$('#player-window').css('display', 'block');
video.play();
}
};
video.onerror = function() {
$.notify(video.error.message, 'error');
};
} else {
if (Hls.isSupported()) {
var video = document.getElementById('player');