HtmlUtils.java
package io.github.giulong.spectrum.utils;
import io.github.giulong.spectrum.interfaces.SessionHook;
import io.github.giulong.spectrum.types.TestData;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static java.util.regex.Pattern.DOTALL;
import static lombok.AccessLevel.PRIVATE;
@Slf4j
@NoArgsConstructor(access = PRIVATE)
public class HtmlUtils implements SessionHook {
private static final HtmlUtils INSTANCE = new HtmlUtils();
private static final Pattern VIDEO_SRC = Pattern.compile("<video.*?src=\"(?<src>[^\"]*)\"");
private static final Pattern IMAGE_TAG = Pattern.compile("<div class=\"row mb-3\">\\s*<div class=\"col-md-3\">\\s*<img.*?src=\"(?<src>[^\"]*)\".*?</div>\\s*</div>", DOTALL);
private static final Base64.Encoder ENCODER = Base64.getEncoder();
private static final String SRC = "src";
private final FreeMarkerWrapper freeMarkerWrapper = FreeMarkerWrapper.getInstance();
private final FileUtils fileUtils = FileUtils.getInstance();
private String videoTemplate;
private String divTemplate;
private String frameTemplate;
private String inlineImageTemplate;
@Override
public void sessionOpened() {
this.videoTemplate = fileUtils.readTemplate("video.html");
this.divTemplate = fileUtils.readTemplate("div-template.html");
this.inlineImageTemplate = fileUtils.readTemplate("div-image-template.html");
this.frameTemplate = fileUtils.readTemplate("div-frame-template.html");
}
public static HtmlUtils getInstance() {
return INSTANCE;
}
public String inline(final String html) {
return inlineVideosOf(inlineImagesOf(html));
}
public String buildFrameTagFor(final int number, final String content, final TestData testData) {
return buildFrameTagFor(number, content, testData, "");
}
public String buildFrameTagFor(final int number, final String content, final TestData testData, final String classes) {
return freeMarkerWrapper.interpolate(this.frameTemplate, Map.of("classes", classes, "id", testData.getTestId(), "number", number, "content", content));
}
@SneakyThrows
public String inlineImagesOf(final String html) {
final Matcher matcher = IMAGE_TAG.matcher(html);
String inlineHtml = html;
while (matcher.find()) {
final String src = matcher.group(SRC);
final byte[] bytes = Files.readAllBytes(Path.of(src));
final String encoded = ENCODER.encodeToString(bytes);
final String replacement = freeMarkerWrapper.interpolate(this.inlineImageTemplate, Map.of("encoded", encoded));
log.debug("Found img with src {}", src);
inlineHtml = inlineHtml.replace(matcher.group(0), replacement);
}
return inlineHtml;
}
@SneakyThrows
public String inlineVideosOf(final String html) {
final Matcher matcher = VIDEO_SRC.matcher(html);
String inlineHtml = html;
while (matcher.find()) {
final String src = matcher.group(SRC);
final byte[] bytes = Files.readAllBytes(Path.of(src));
final String encoded = ENCODER.encodeToString(bytes);
final String replacement = String.format("data:video/mp4;base64,%s", encoded);
log.debug("Found video with src {}", src);
inlineHtml = inlineHtml.replace(src, replacement);
}
return inlineHtml;
}
public String generateVideoTag(final String videoId, final String width, final String height, final Path src) {
return freeMarkerWrapper.interpolate(this.videoTemplate, Map.of("videoId", videoId, "width", width, "height", height, SRC, src.toString()));
}
public String generateTestInfoDivs(final String id, final String classDisplayName, final String testDisplayName) {
return freeMarkerWrapper.interpolate(this.divTemplate, Map.of("id", id, "classDisplayName", classDisplayName, "testDisplayName", testDisplayName));
}
}