bug4476 added i18n, added ability to not upload specific videos, added

error handling if index is invalid url, added refresh to mediapanel
after video linking, fix for leaking temp files in mp4parser
This commit is contained in:
Kai Börnert committed 2018-04-27 12:58:30 +02:00
1 parent 611e22d18c
commit 5d5f296d72
7 files changed
+183 -63

No files matched your search

@@ -116,11 +116,17 @@ public class MediaPanel extends FlowPanel implements MediaTracksRefresher {
});
buttonAndFilterPanel.add(addUrlButton);
Button multiVideo = new Button("18todo multi video");
Button multiVideo = new Button(stringMessages.multiVideoLinking());
multiVideo.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
new MultiVideoDialog(sailingService, mediaService, stringMessages).center();
new MultiVideoDialog(sailingService, mediaService, stringMessages, errorReporter, new Runnable() {
@Override
public void run() {
loadMediaTracks();
}
}).center();
}
});
buttonAndFilterPanel.add(multiVideo);
@@ -50,8 +50,20 @@ import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.common.media.MimeType;
import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.controls.datetime.DateAndTimeInput;
import com.sap.sse.gwt.client.controls.datetime.DateTimeInput.Accuracy;
public class MultiVideoDialog extends DialogBox {
private static final String EMPTY_TEXT = "";
private static final int DELETE_COLUMN = 0;
private static final int URL_COLUMN = 1;
private static final int STATUS_COLUMN = 2;
private static final int DURATION_COLUMN = 3;
private static final int STARTTIME_COLUMN = 4;
private static final int MIMETYPE_COLUMN = 5;
private static final int RACES_COLUMN = 6;
private static final StyleHolder style = GWT.create(StyleHolder.class);
private StringMessages stringMessages;
private List<RemoteFileInfo> remoteFiles = new ArrayList<>();
@@ -62,12 +74,16 @@ public class MultiVideoDialog extends DialogBox {
private SailingServiceAsync sailingService;
private boolean isWorking;
private Button doSaveButton;
private Runnable afterLinking;
private ErrorReporter errorReporter;
public MultiVideoDialog(SailingServiceAsync sailingService, MediaServiceAsync mediaService,
StringMessages stringMessages) {
StringMessages stringMessages, ErrorReporter errorReporter, Runnable afterLinking) {
this.stringMessages = stringMessages;
this.mediaService = mediaService;
this.sailingService = sailingService;
this.errorReporter = errorReporter;
this.afterLinking = afterLinking;
setGlassEnabled(true);
FlowPanel mainContent = new FlowPanel();
@@ -88,7 +104,7 @@ public class MultiVideoDialog extends DialogBox {
}
});
statusLabel = new Label("i18n idle");
statusLabel = new Label(stringMessages.multiVideoIdle());
mainContent.add(statusLabel);
FlowPanel buttonPanel = new FlowPanel();
@@ -113,7 +129,7 @@ public class MultiVideoDialog extends DialogBox {
}
});
doSaveButton = new Button("i18n save");
doSaveButton = new Button(stringMessages.addMediaTrack());
buttonPanel.add(doSaveButton);
doSaveButton.addClickHandler(new ClickHandler() {
@@ -137,22 +153,35 @@ public class MultiVideoDialog extends DialogBox {
protected void updateUI() {
int y = 0;
dataTable.removeAllRows();
dataTable.clear();
dataTable.setWidget(y, 0, new Label("i18n url"));
dataTable.setWidget(y, 1, new Label("i18n status"));
dataTable.setWidget(y, 2, new Label(stringMessages.duration()));
dataTable.setWidget(y, 3, new Label(stringMessages.startTime()));
dataTable.setWidget(y, 4, new Label(stringMessages.mimeType()));
dataTable.setWidget(y, 5, new Label(stringMessages.linkedRaces()));
dataTable.setWidget(y, DELETE_COLUMN, new Label(stringMessages.delete()));
dataTable.setWidget(y, URL_COLUMN, new Label(stringMessages.url()));
dataTable.setWidget(y, STATUS_COLUMN, new Label(stringMessages.status()));
dataTable.setWidget(y, DURATION_COLUMN, new Label(stringMessages.duration()));
dataTable.setWidget(y, STARTTIME_COLUMN, new Label(stringMessages.startTime()));
dataTable.setWidget(y, MIMETYPE_COLUMN, new Label(stringMessages.mimeType()));
dataTable.setWidget(y, RACES_COLUMN, new Label(stringMessages.linkedRaces()));
y++;
for (RemoteFileInfo remoteFile : remoteFiles) {
Anchor link = new Anchor(remoteFile.url);
link.setHref(remoteFile.url);
link.setTarget("_blank");
dataTable.setWidget(y, 0, link);
dataTable.setWidget(y, 1, new Label(asString(remoteFile.status)));
dataTable.setWidget(y, URL_COLUMN, link);
dataTable.setWidget(y, STATUS_COLUMN, new Label(asString(remoteFile.status)));
Button removeVideo = new Button(stringMessages.remove());
removeVideo.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
remoteFiles.remove(remoteFile);
updateUI();
}
});
dataTable.setWidget(y, DELETE_COLUMN, removeVideo);
if (remoteFile.duration == null) {
dataTable.setWidget(y, 2, new Label("-"));
dataTable.setWidget(y, DURATION_COLUMN, new Label(EMPTY_TEXT));
} else {
TextBox durationInput = new TextBox();
durationInput.setText(TimeFormatUtil.durationToHrsMinSec(remoteFile.duration));
@@ -164,19 +193,28 @@ public class MultiVideoDialog extends DialogBox {
updateUI();
}
});
dataTable.setWidget(y, 2, durationInput);
dataTable.setWidget(y, DURATION_COLUMN, durationInput);
}
if (remoteFile.startTime == null) {
dataTable.setWidget(y, 3, new Label("-"));
dataTable.setWidget(y, STARTTIME_COLUMN, new Label(EMPTY_TEXT));
} else {
dataTable.setWidget(y, 3,
new Label(TimeFormatUtil.DATETIME_FORMAT.format(remoteFile.startTime.asDate())));
DateAndTimeInput startTimeInput = new DateAndTimeInput(Accuracy.SECONDS);
startTimeInput.setValue(remoteFile.startTime.asDate());
startTimeInput.addValueChangeHandler(new ValueChangeHandler<Date>() {
@Override
public void onValueChange(ValueChangeEvent<Date> event) {
remoteFile.startTime = new MillisecondsTimePoint(event.getValue());
updateUI();
}
});
dataTable.setWidget(y, STARTTIME_COLUMN, startTimeInput);
}
if (remoteFile.mime == null) {
if (remoteFile.message == null) {
dataTable.setWidget(y, 4, new Label("-"));
dataTable.setWidget(y, MIMETYPE_COLUMN, new Label(EMPTY_TEXT));
} else {
dataTable.setWidget(y, 4, new Label(remoteFile.message));
dataTable.setWidget(y, MIMETYPE_COLUMN, new Label(remoteFile.message));
}
} else {
ListBox mimeTypeBox = new ListBox();
@@ -192,17 +230,17 @@ public class MultiVideoDialog extends DialogBox {
}
});
mimeTypeBox.setSelectedIndex(MimeType.mp4 == remoteFile.mime ? 0 : 1);
dataTable.setWidget(y, 4, mimeTypeBox);
dataTable.setWidget(y, MIMETYPE_COLUMN, mimeTypeBox);
}
if (remoteFile.candidates == null) {
dataTable.setWidget(y, 5, new Label("-"));
dataTable.setWidget(y, RACES_COLUMN, new Label(EMPTY_TEXT));
} else {
if (remoteFile.candidates.isEmpty()) {
dataTable.setWidget(y, 5, new Label(stringMessages.empty()));
dataTable.setWidget(y, RACES_COLUMN, new Label(stringMessages.empty()));
} else {
FlowPanel ft = new FlowPanel();
dataTable.setWidget(y, 5, ft);
dataTable.setWidget(y, RACES_COLUMN, ft);
for (RegattaAndRaceIdentifier candidate : remoteFile.candidates) {
CheckBox cb = new CheckBox(candidate.getRegattaName() + " " + candidate.getRaceName());
cb.setValue(true, false);
@@ -227,13 +265,12 @@ public class MultiVideoDialog extends DialogBox {
doScanButton.setEnabled(!isWorking);
if (!isWorking) {
statusLabel.setText("i18n idle");
statusLabel.setText(stringMessages.multiVideoIdle());
}
center();
}
private void startNextLinkingRemoteTask() {
int done = 0;
for (RemoteFileInfo remoteFile : remoteFiles) {
if (remoteFile.status == EStatus.WAIT_FOR_SAVE) {
MediaTrack mediaTrack = new MediaTrack(remoteFile.url, remoteFile.url, remoteFile.startTime,
@@ -254,14 +291,10 @@ public class MultiVideoDialog extends DialogBox {
startNextLinkingRemoteTask();
}
});
if (remoteFile.status == EStatus.DONE) {
done++;
}
return;
}
}
setWorking(false);
Window.alert("i18n " + " linked " + done);
afterLinking.run();
}
private void startNextInitializingRemoteTask() {
@@ -340,6 +373,7 @@ public class MultiVideoDialog extends DialogBox {
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError(caught.getMessage());
remoteFile.status = EStatus.ERROR_LINKING;
updateUI();
}
@@ -361,8 +395,6 @@ public class MultiVideoDialog extends DialogBox {
if (raceColumn.isTrackedRace(fleet)) {
RaceDTO race = raceColumn.getRace(fleet);
if (race.trackedRace != null) {
GWT.log(race.getRaceIdentifier() + " " + remoteFile.startTime + " "
+ race.endOfRace);
if (race.endOfRace == null || race.endOfRace.after(remoteFile.startTime.asDate())) {
if (race.startOfRace == null || race.startOfRace.before(new Date(
remoteFile.startTime.asMillis() + remoteFile.duration.asMillis()))) {
@@ -419,7 +451,7 @@ public class MultiVideoDialog extends DialogBox {
@Override
public void error(Object msg) {
asyncCallback.onSuccess(
new VideoMetadataDTO(false, null, false, null, msg == null ? "" : msg.toString()));
new VideoMetadataDTO(false, null, false, null, msg == null ? EMPTY_TEXT : msg.toString()));
}
@Override
@@ -444,9 +476,29 @@ public class MultiVideoDialog extends DialogBox {
private String asString(EStatus status) {
switch (status) {
case NOT_ANALYSED:
return "18n not analysied";
return stringMessages.multiVideoNotAnalyzed();
case ALREADY_ADDED:
return stringMessages.multiVideoAlreadyKnown();
case CLIENT_ANALYZE:
return stringMessages.multiVideoClientIsUploading();
case DONE:
return stringMessages.multiVideoFinishedLinking();
case ERROR_ANALYZE:
return stringMessages.multiVideoErrorInAnalyzingFile();
case ERROR_DOWNLOAD:
return stringMessages.couldNotDownload(EMPTY_TEXT);
case ERROR_LINKING:
return stringMessages.error();
case GETTING_MEDIATRACK:
return stringMessages.multiVideoObtainingMediaTrack();
case SERVER_ANALYSE:
return stringMessages.multiVideoServerIsAnalyzing();
case WAITING_FOR_LINK:
return stringMessages.multiVideoWaitingForLinkPhase();
case WAIT_FOR_SAVE:
return stringMessages.multiVideoWaitingForSave();
default:
return status.name();
return stringMessages.unknown();
}
}
@@ -512,11 +564,11 @@ public class MultiVideoDialog extends DialogBox {
ERROR_ANALYZE,
CLIENT_ANALYZE,
ERROR_DOWNLOAD,
ERROR_LINKING,
WAIT_FOR_SAVE,
DONE,
ALREADY_ADDED,
GETTING_MEDIATRACK;
GETTING_MEDIATRACK,
ERROR_LINKING;
}
static class RemoteFileInfo {
@@ -2163,4 +2163,15 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
String delaysMustNotBeNegative();
String multiVideoURLOfIndex();
String multiVideoScan();
String multiVideoLinking();
String multiVideoNotAnalyzed();
String multiVideoAlreadyKnown();
String multiVideoClientIsUploading();
String multiVideoFinishedLinking();
String multiVideoErrorInAnalyzingFile();
String multiVideoObtainingMediaTrack();
String multiVideoServerIsAnalyzing();
String multiVideoWaitingForLinkPhase();
String multiVideoWaitingForSave();
String multiVideoIdle();
}
@@ -2151,4 +2151,15 @@ noDataManeuverTable=There are no maneuvers detected yet
errorTryingToDetermineBoatLinkedToCompetitor=Error trying to determine boat linked to competitor {0} in leaderboard {1}: {2}
delaysMustNotBeNegative=Delays must not be negative
multiVideoURLOfIndex=Please insert the index url of the webserver
multiVideoScan=Scan index
multiVideoScan=Scan index
multiVideoLinking=Multi video linking
multiVideoNotAnalyzed=Video not yet analyzed
multiVideoAlreadyKnown=Video has already existing mediatrack
multiVideoClientIsUploading=Video is analyzed via client proxy
multiVideoFinishedLinking=Video is linked
multiVideoErrorInAnalyzingFile=Error while analysing file
multiVideoObtainingMediaTrack=Searching for matching media track
multiVideoServerIsAnalyzing=Video is analyzed on server
multiVideoWaitingForLinkPhase=Video is waiting for link phase
multiVideoWaitingForSave=Waiting for confirmation
multiVideoIdle=Work queue is idle
@@ -2145,4 +2145,17 @@ speedOut=Endgeschwindigkeit
selectAtLeastOneCompetitorManeuver=Um die Manövertabelle anzuzeigen, muss mindestens ein Teilnehmer ausgewählt werden
noDataManeuverTable=Es wurde noch keine Manöver erkannt
errorTryingToDetermineBoatLinkedToCompetitor=Fehler bei der Ermittlung des Bootes für Teilnehmer {0} in Ergebnisliste {1}: {2}
delaysMustNotBeNegative=Abhängige Zeiten dürfen nicht negativ sein
delaysMustNotBeNegative=Abhängige Zeiten dürfen nicht negativ sein
multiVideoURLOfIndex=Bitte die url zum Index des webservers eintragen
multiVideoScan=Index durchsuchen
multiVideoLinking=Mehrere Videos hinzufügen
multiVideoNotAnalyzed=Video ist noch nicht analysiert
multiVideoAlreadyKnown=Für dieses Video existiert bereits ein Mediatrack
multiVideoClientIsUploading=Das Video wird analysiert via clientseitigen Proxy
multiVideoFinishedLinking=Video fertig verlinkt
multiVideoErrorInAnalyzingFile=Fehler beim Metadaten parsen der Datei
multiVideoObtainingMediaTrack=Suche nach existierenden Medientrack
multiVideoServerIsAnalyzing=Video wird vom Server analysiert
multiVideoWaitingForLinkPhase=Video wartet auf die Linkphase
multiVideoWaitingForSave=Wartet auf Bestätigung
multiVideoIdle=Keine Arbeit offen
@@ -174,30 +174,35 @@ public class JSDownloadUtils {
}
private native static void getFileListNative(String url, JSHrefCallback callback)/*-{
var xmlHttp = null;
var allLinks = []; //set of all internal and external links
xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", url, true );
xmlHttp.send( null );
xmlHttp.onreadystatechange = function () {
if ( xmlHttp.readyState == 4) {
if (xmlHttp.status == 200){
var container = document.createElement("p");
container.innerHTML = xmlHttp.responseText;
var anchors = container.getElementsByTagName("a");
for (var i = 0; i < anchors.length; i++) {
try {
var href = anchors[i].getAttribute("href");
callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSHrefCallback::newHref(Ljava/lang/String;)(href);
} catch (error) {
console.log(error);
try{
var xmlHttp = null;
var allLinks = []; //set of all internal and external links
xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", url, true );
xmlHttp.send( null );
xmlHttp.onreadystatechange = function () {
if ( xmlHttp.readyState == 4) {
if (xmlHttp.status == 200){
var container = document.createElement("p");
container.innerHTML = xmlHttp.responseText;
var anchors = container.getElementsByTagName("a");
for (var i = 0; i < anchors.length; i++) {
try {
var href = anchors[i].getAttribute("href");
callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSHrefCallback::newHref(Ljava/lang/String;)(href);
} catch (error) {
console.log(error);
}
}
callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSHrefCallback::complete()();
} else {
callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSHrefCallback::noResult()();
}
callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSHrefCallback::complete()();
} else {
callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSHrefCallback::noResult()();
}
}
};
}
};
} catch (error) {
callback.@com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSHrefCallback::noResult()();
}
}-*/;
}
@@ -7,6 +7,7 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.URL;
@@ -14,6 +15,7 @@ import java.nio.channels.Channels;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -24,6 +26,7 @@ import javax.xml.parsers.ParserConfigurationException;
import org.apache.shiro.SecurityUtils;
import org.mp4parser.IsoFile;
import org.mp4parser.boxes.UserBox;
import org.mp4parser.boxes.iso14496.part12.MediaDataBox;
import org.mp4parser.boxes.iso14496.part12.MovieBox;
import org.mp4parser.boxes.iso14496.part12.MovieHeaderBox;
import org.mp4parser.tools.Path;
@@ -211,6 +214,7 @@ public class MediaServiceImpl extends RemoteServiceServlet implements MediaServi
Date recordStartedTimer = determineRecordingStart(isof);
Duration duration = determineDuration(isof);
boolean spherical = determine360(isof);
removeTempFiles(isof);
return new VideoMetadataDTO(canDownload, duration, spherical, recordStartedTimer, "");
}
}
@@ -229,6 +233,7 @@ public class MediaServiceImpl extends RemoteServiceServlet implements MediaServi
recordStartedTimer = determineRecordingStart(isof);
spherical = determine360(isof);
duration = determineDuration(isof);
removeTempFiles(isof);
}
} catch (Exception e) {
logger.log(Level.WARNING, "Error in video analysis ", e);
@@ -241,6 +246,23 @@ public class MediaServiceImpl extends RemoteServiceServlet implements MediaServi
return new VideoMetadataDTO(true, duration, spherical, recordStartedTimer, message);
}
/**
* Some boxes (we don't actually need to read) create internal tempfiles, we delete them here, as the VM could run quite long
*/
private void removeTempFiles(IsoFile isof) {
List<MediaDataBox> boxesWithTempFiles = isof.getBoxes(MediaDataBox.class, true);
for(MediaDataBox box:boxesWithTempFiles) {
try {
Field field = box.getClass().getDeclaredField("dataFile");
field.setAccessible(true);
File data = (File) field.get(box);
data.delete();
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
logger.log(Level.WARNING, "Could not delete mp4 temp files", e);
}
}
}
/**
* Creates a dummy mp4 file, only containing the start and the end, the middle is filled with 0 so that all file
* internal pointers from start to end are working