Fix loading of EventHandlerConfiguration
This commit is contained in:
parent
33b054bc68
commit
b268549ef6
|
@ -7,6 +7,7 @@ import ctbrec.StringUtil;
|
|||
import ctbrec.event.*;
|
||||
import ctbrec.event.EventHandlerConfiguration.ActionConfiguration;
|
||||
import ctbrec.event.EventHandlerConfiguration.PredicateConfiguration;
|
||||
import ctbrec.io.json.mapper.ModelMapper;
|
||||
import ctbrec.recorder.Recorder;
|
||||
import ctbrec.ui.CamrecApplication;
|
||||
import ctbrec.ui.DesktopIntegration;
|
||||
|
@ -33,6 +34,7 @@ import javafx.scene.layout.Priority;
|
|||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -48,6 +50,7 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ActionSettingsPanel extends GridPane {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ActionSettingsPanel.class);
|
||||
|
@ -168,7 +171,7 @@ public class ActionSettingsPanel extends GridPane {
|
|||
if (!modelSelectionPane.isAllSelected()) {
|
||||
var pc = new PredicateConfiguration();
|
||||
pc.setType(ModelPredicate.class.getName());
|
||||
pc.setModels(modelSelectionPane.getSelectedItems());
|
||||
pc.setModels(modelSelectionPane.getSelectedItems().stream().map(Mappers.getMapper(ModelMapper.class)::toDto).collect(Collectors.toList())); // NOSONAR
|
||||
pc.setName("model is one of:" + modelSelectionPane.getSelectedItems());
|
||||
config.getPredicates().add(pc);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
package ctbrec.event;
|
||||
|
||||
import ctbrec.Model;
|
||||
import ctbrec.io.json.dto.ModelDto;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(of = "id")
|
||||
public class EventHandlerConfiguration {
|
||||
|
||||
private String id;
|
||||
|
@ -16,111 +20,25 @@ public class EventHandlerConfiguration {
|
|||
id = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Event.Type getEvent() {
|
||||
return event;
|
||||
}
|
||||
|
||||
public void setEvent(Event.Type event) {
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<PredicateConfiguration> getPredicates() {
|
||||
return predicates;
|
||||
}
|
||||
|
||||
public void setPredicates(List<PredicateConfiguration> predicates) {
|
||||
this.predicates = predicates;
|
||||
}
|
||||
|
||||
public List<ActionConfiguration> getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
public void setActions(List<ActionConfiguration> actions) {
|
||||
this.actions = actions;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class PredicateConfiguration {
|
||||
private String name;
|
||||
private String type;
|
||||
private List<Model> models;
|
||||
private List<ModelDto> models;
|
||||
private Map<String, Object> configuration = new HashMap<>();
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Map<String, Object> getConfiguration() {
|
||||
return configuration;
|
||||
}
|
||||
|
||||
public void setConfiguration(Map<String, Object> configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
public List<Model> getModels() {
|
||||
return models;
|
||||
}
|
||||
|
||||
public void setModels(List<Model> models) {
|
||||
this.models = models;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class ActionConfiguration {
|
||||
private String name;
|
||||
private String type;
|
||||
private Map<String, Object> configuration = new HashMap<>();
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Map<String, Object> getConfiguration() {
|
||||
return configuration;
|
||||
}
|
||||
|
||||
public void setConfiguration(Map<String, Object> configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
|
@ -131,26 +49,4 @@ public class EventHandlerConfiguration {
|
|||
public String toString() {
|
||||
return name + ", when:" + predicates + " do:" + actions + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((id == null) ? 0 : id.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
EventHandlerConfiguration other = (EventHandlerConfiguration) obj;
|
||||
if (id == null) {
|
||||
return other.id == null;
|
||||
} else return id.equals(other.id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
package ctbrec.event;
|
||||
|
||||
import ctbrec.Model;
|
||||
import ctbrec.event.EventHandlerConfiguration.PredicateConfiguration;
|
||||
import ctbrec.io.json.mapper.ModelMapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import ctbrec.Model;
|
||||
import ctbrec.event.EventHandlerConfiguration.PredicateConfiguration;
|
||||
|
||||
public class ModelPredicate extends EventPredicate {
|
||||
|
||||
private Predicate<Event> internal;
|
||||
|
||||
public ModelPredicate() {}
|
||||
public ModelPredicate() {
|
||||
}
|
||||
|
||||
public ModelPredicate(Model model) {
|
||||
internal = createFor(model);
|
||||
|
@ -22,7 +25,7 @@ public class ModelPredicate extends EventPredicate {
|
|||
}
|
||||
|
||||
private void configure(List<Model> models) {
|
||||
if(models.isEmpty()) {
|
||||
if (models.isEmpty()) {
|
||||
throw new IllegalArgumentException("List has to contain at least one model");
|
||||
}
|
||||
|
||||
|
@ -40,8 +43,7 @@ public class ModelPredicate extends EventPredicate {
|
|||
|
||||
private Predicate<Event> createFor(Model model) {
|
||||
return evt -> {
|
||||
if(evt instanceof AbstractModelEvent) {
|
||||
AbstractModelEvent modelEvent = (AbstractModelEvent) evt;
|
||||
if (evt instanceof AbstractModelEvent modelEvent) {
|
||||
Model other = modelEvent.getModel();
|
||||
return Objects.equals(model, other);
|
||||
} else {
|
||||
|
@ -52,6 +54,6 @@ public class ModelPredicate extends EventPredicate {
|
|||
|
||||
@Override
|
||||
public void configure(PredicateConfiguration pc) {
|
||||
configure(pc.getModels());
|
||||
configure(pc.getModels().stream().map(Mappers.getMapper(ModelMapper.class)::toModel).toList());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,174 +0,0 @@
|
|||
package ctbrec.recorder.download.hls;
|
||||
|
||||
import com.iheartradio.m3u8.ParseException;
|
||||
import com.iheartradio.m3u8.PlaylistException;
|
||||
import ctbrec.Config;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.OS;
|
||||
import ctbrec.Recording;
|
||||
import ctbrec.io.HttpClient;
|
||||
import ctbrec.io.StreamRedirector;
|
||||
import ctbrec.recorder.download.ProcessExitedUncleanException;
|
||||
import ctbrec.recorder.download.hls.SegmentPlaylist.Segment;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Does the whole HLS download with FFmpeg. Not used at the moment, because FFMpeg can't
|
||||
* handle the HLS encryption of Flirt4Free correctly
|
||||
*/
|
||||
public class FFmpegDownload extends AbstractHlsDownload {
|
||||
private static final transient Logger LOG = LoggerFactory.getLogger(FFmpegDownload.class);
|
||||
|
||||
private transient Process ffmpeg;
|
||||
private File targetFile;
|
||||
|
||||
public FFmpegDownload(HttpClient client) {
|
||||
super(client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config config, Model model, Instant startTime, ExecutorService executorService) throws IOException {
|
||||
super.init(config, model, startTime, executorService);
|
||||
String suffix = config.getSettings().ffmpegFileSuffix;
|
||||
targetFile = config.getFileForRecording(model, suffix, startTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FFmpegDownload call() throws IOException {
|
||||
try {
|
||||
Files.createDirectories(targetFile.getParentFile().toPath());
|
||||
String chunkPlaylist = getSegmentPlaylistUrl(model);
|
||||
|
||||
String[] args = config.getSettings().ffmpegMergedDownloadArgs.split(" ");
|
||||
String[] argsPlusFile = new String[args.length + 5];
|
||||
int i = 0;
|
||||
argsPlusFile[i++] = "-headers";
|
||||
argsPlusFile[i++] = "User-Agent: " + config.getSettings().httpUserAgent;
|
||||
argsPlusFile[i++] = "-i";
|
||||
argsPlusFile[i++] = chunkPlaylist;
|
||||
System.arraycopy(args, 0, argsPlusFile, i, args.length);
|
||||
argsPlusFile[argsPlusFile.length - 1] = targetFile.getAbsolutePath();
|
||||
String[] cmdline = OS.getFFmpegCommand(argsPlusFile);
|
||||
LOG.debug("Command line: {}", Arrays.toString(cmdline));
|
||||
ffmpeg = Runtime.getRuntime().exec(cmdline, new String[0], targetFile.getParentFile());
|
||||
int exitCode = 1;
|
||||
File ffmpegLog = File.createTempFile(targetFile.getName(), ".log");
|
||||
ffmpegLog.deleteOnExit();
|
||||
try (FileOutputStream mergeLogStream = new FileOutputStream(ffmpegLog)) {
|
||||
Thread stdout = new Thread(new StreamRedirector(ffmpeg.getInputStream(), mergeLogStream));
|
||||
Thread stderr = new Thread(new StreamRedirector(ffmpeg.getErrorStream(), mergeLogStream));
|
||||
stdout.start();
|
||||
stderr.start();
|
||||
exitCode = ffmpeg.waitFor();
|
||||
stdout.join();
|
||||
stderr.join();
|
||||
mergeLogStream.flush();
|
||||
}
|
||||
if (exitCode == 0) {
|
||||
if (ffmpegLog.exists()) {
|
||||
Files.delete(ffmpegLog.toPath());
|
||||
}
|
||||
} else {
|
||||
LOG.info("FFmpeg exit code was {}. Logfile: {}", exitCode, ffmpegLog.getAbsolutePath());
|
||||
throw new ProcessExitedUncleanException("FFmpeg exit code was " + exitCode);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
LOG.error("Thread interrupted while waiting for FFmpeg to terminate");
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (ExecutionException | ParseException | PlaylistException | JAXBException e) {
|
||||
LOG.error("Couldn't start FFmpeg process for stream download", e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
if (ffmpeg != null && ffmpeg.isAlive()) {
|
||||
OutputStream ffmpegStdIn = ffmpeg.getOutputStream();
|
||||
try {
|
||||
ffmpegStdIn.write("q".getBytes(StandardCharsets.UTF_8));
|
||||
ffmpegStdIn.flush();
|
||||
ffmpegStdIn.close();
|
||||
} catch (IOException e) {
|
||||
LOG.error("Couldn't terminate FFmpeg by sending 'q'", e);
|
||||
ffmpeg.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Model getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcess(Recording recording) {
|
||||
// nothing to here for now
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getTarget() {
|
||||
return targetFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath(Model model) {
|
||||
String absolutePath = getTarget().getAbsolutePath();
|
||||
String recordingsDir = Config.getInstance().getSettings().recordingsDir;
|
||||
String relativePath = absolutePath.replaceFirst(Pattern.quote(recordingsDir), "");
|
||||
return relativePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void internalStop() {
|
||||
stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleFile() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSizeInByte() {
|
||||
return getTarget().length();
|
||||
}
|
||||
|
||||
protected void createTargetDirectory() throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(SegmentDownload segmentDownload) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OutputStream getSegmentOutputStream(Segment segment) throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finalizeDownload() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue