mirror of
https://github.com/openeggbert/youtubedl-frontend.git
synced 2025-03-25 17:17:46 +01:00
Refactoring II
This commit is contained in:
parent
76291ea038
commit
c45092a52c
2
pom.xml
2
pom.xml
@ -192,7 +192,7 @@
|
|||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
<version>2.17.1</version>
|
<version>2.17.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- <dependency>
|
<!-- <dependency>
|
||||||
<groupId>com.github.jai-imageio</groupId>
|
<groupId>com.github.jai-imageio</groupId>
|
||||||
<artifactId>jai-imageio-core</artifactId>
|
<artifactId>jai-imageio-core</artifactId>
|
||||||
<version>1.4.0</version>
|
<version>1.4.0</version>
|
||||||
|
@ -25,10 +25,10 @@ import lombok.Data;
|
|||||||
*
|
*
|
||||||
* @author robertvokac
|
* @author robertvokac
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class Arg {
|
public class Arg {
|
||||||
|
|
||||||
private ArgType argType;
|
private ArgType argType;
|
||||||
private String value;
|
private String value;
|
||||||
}
|
}
|
||||||
|
@ -36,9 +36,10 @@ public enum ArgType {
|
|||||||
private String name;
|
private String name;
|
||||||
@Getter
|
@Getter
|
||||||
private String defaultValue;
|
private String defaultValue;
|
||||||
|
|
||||||
ArgType(String name, String defaultValue) {
|
ArgType(String name, String defaultValue) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.defaultValue = defaultValue;
|
this.defaultValue = defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -46,13 +46,12 @@ public class Main {
|
|||||||
|
|
||||||
public static int THUMBNAIL_WIDTH = 250;
|
public static int THUMBNAIL_WIDTH = 250;
|
||||||
|
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException, InterruptedException {
|
public static void main(String[] args) throws IOException, InterruptedException {
|
||||||
System.out.println("youtubedlfrontend - HTML generator\n");
|
System.out.println("youtubedlfrontend - HTML generator\n");
|
||||||
|
|
||||||
if (args.length < 1) {
|
if (args.length < 1) {
|
||||||
//System.err.println("At least one argument is expected, but the count of arguments is: " + args.length + ".");
|
//System.err.println("At least one argument is expected, but the count of arguments is: " + args.length + ".");
|
||||||
String argsS = "/rv/blupi/archivebox --_video UDpsz1yIwiw --always-generate-metadata 0 "
|
String argsS = "/rv/blupi/archivebox --_video UDpsz1yIwiw --always-generate-metadata 0"
|
||||||
+ " --always-generate-html-files 0 --videos-per-row 4 --thumbnail-links-to-youtube 1"
|
+ " --always-generate-html-files 0 --videos-per-row 4 --thumbnail-links-to-youtube 1"
|
||||||
+ " --thumbnail-as-base64 1";
|
+ " --thumbnail-as-base64 1";
|
||||||
args = argsS.split(" ");
|
args = argsS.split(" ");
|
||||||
@ -64,67 +63,8 @@ public class Main {
|
|||||||
|
|
||||||
File archiveBoxRootDirectory = new File(workingDirectory);
|
File archiveBoxRootDirectory = new File(workingDirectory);
|
||||||
File archiveBoxArchiveDirectory = new File(archiveBoxRootDirectory, "archive");
|
File archiveBoxArchiveDirectory = new File(archiveBoxRootDirectory, "archive");
|
||||||
int i = 0;
|
|
||||||
List<YoutubeVideo> youtubeVideos = new ArrayList<>();
|
|
||||||
for (File snapshotDirectory : archiveBoxArchiveDirectory.listFiles()) {
|
|
||||||
//if(i> 10)break;
|
|
||||||
File mediaDirectory = new File(snapshotDirectory, "media");
|
|
||||||
if (!mediaDirectory.exists()) {
|
|
||||||
//nothing to do
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
YoutubeVideo youtubeVideo = new YoutubeVideo(mediaDirectory, argsInstance.getBoolean(ArgType.ALWAYS_GENERATE_METADATA).get(), argsInstance.getString(ArgType.VIDEO).orElse(""));
|
|
||||||
if (argsInstance.getString(ArgType.VIDEO).isPresent() && !argsInstance.getString(ArgType.VIDEO).equals(youtubeVideo.getId())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (argsInstance.getString(ArgType.CHANNEL).isPresent() && !argsInstance.getString(ArgType.CHANNEL).equals(youtubeVideo.getChannelId())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
List<YoutubeVideo> youtubeVideos = YoutubeVideo.loadYoutubeVideos(archiveBoxArchiveDirectory, argsInstance);
|
||||||
System.out.println("\n\nFound video #" + i);
|
|
||||||
|
|
||||||
for (File f : new File(archiveBoxArchiveDirectory + "/" + youtubeVideo.getSnapshot() + "/media/" + youtubeVideo.getVideoFileName()).getParentFile().listFiles()) {
|
|
||||||
if (f.getName().endsWith(".webm")) {
|
|
||||||
//mkv file was manually converted to webm
|
|
||||||
youtubeVideo.setVideoFileName(f.getName());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
System.out.println("id = " + youtubeVideo.getId());
|
|
||||||
System.out.println("snapshot = " + youtubeVideo.getSnapshot());
|
|
||||||
System.out.println("title = " + youtubeVideo.getTitle());
|
|
||||||
System.out.println("videoFileName = " + youtubeVideo.getVideoFileName());
|
|
||||||
System.out.println("videoFileSizeInBytes = " + youtubeVideo.getVideoFileSizeInBytes());
|
|
||||||
System.out.println("videoFileSha512HashSum = " + youtubeVideo.getVideoFileSha512HashSum());
|
|
||||||
System.out.println("videoDuration = " + youtubeVideo.getVideoDuration());
|
|
||||||
System.out.println("channelName = " + youtubeVideo.getChannelName());
|
|
||||||
System.out.println("channelUrl = " + youtubeVideo.getChannelUrl());
|
|
||||||
System.out.println("uploadDate = " + youtubeVideo.getUploadDate());
|
|
||||||
System.out.println("description = " + youtubeVideo.getDescription());
|
|
||||||
System.out.println("thumbnail = " + youtubeVideo.getThumbnail());
|
|
||||||
System.out.println("miniThumbnail = " + youtubeVideo.getMiniThumbnail());
|
|
||||||
System.out.println("comments = " + youtubeVideo.getComments());
|
|
||||||
youtubeVideos.add(youtubeVideo);
|
|
||||||
}
|
|
||||||
Collections.sort(youtubeVideos);
|
|
||||||
YoutubeVideo previousVideo = null;
|
|
||||||
YoutubeVideo nextVideo = null;
|
|
||||||
YoutubeVideo currentVideo = null;
|
|
||||||
for (int j = 0; j < youtubeVideos.size(); j++) {
|
|
||||||
previousVideo = currentVideo;
|
|
||||||
currentVideo = youtubeVideos.get(j);
|
|
||||||
if (j < (youtubeVideos.size() - 1)) {
|
|
||||||
nextVideo = youtubeVideos.get(j + 1);
|
|
||||||
}
|
|
||||||
if (previousVideo != null) {
|
|
||||||
currentVideo.setPreviousVideoId(previousVideo.getId());
|
|
||||||
}
|
|
||||||
if (nextVideo != null) {
|
|
||||||
currentVideo.setNextVideoId(nextVideo.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Map<String, String> channelUrls = new HashMap<>();
|
Map<String, String> channelUrls = new HashMap<>();
|
||||||
List<String> channels = new ArrayList<>();
|
List<String> channels = new ArrayList<>();
|
||||||
youtubeVideos.stream().forEach(c -> {
|
youtubeVideos.stream().forEach(c -> {
|
||||||
@ -136,65 +76,85 @@ public class Main {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
File videosHtmlFile = new File(archiveBoxRootDirectory, "videos.html");
|
File videosHtmlFile = new File(archiveBoxRootDirectory, "videos.html");
|
||||||
File videosDirectory = new File(archiveBoxRootDirectory, "videos");
|
File videosDirectory = new File(archiveBoxRootDirectory, "videos");
|
||||||
|
File channelsDirectory = new File(archiveBoxRootDirectory, "channels");
|
||||||
if (!videosDirectory.exists()) {
|
if (!videosDirectory.exists()) {
|
||||||
videosDirectory.mkdir();
|
videosDirectory.mkdir();
|
||||||
}
|
}
|
||||||
sb.append("""
|
if (!channelsDirectory.exists()) {
|
||||||
<!DOCTYPE html>
|
channelsDirectory.mkdir();
|
||||||
<html>
|
}
|
||||||
<head>
|
channels.stream().forEach(c -> {
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.ico" sizes="16x16">
|
StringBuilder oneChannelStringBuilder = createChannelHtml(c, channels, argsInstance, channelUrls, youtubeVideos, archiveBoxRootDirectory, videosDirectory, archiveBoxArchiveDirectory);
|
||||||
<title>Youtube videos</title>
|
Utils.writeTextToFile(oneChannelStringBuilder.toString(), new File(channelsDirectory, channelUrls.get(c).split("/channel/")[1] + ".html"));
|
||||||
|
});
|
||||||
<!-- Generated by: https://code.nanoboot.org/nanoboot/youtubedl-frontend -->
|
StringBuilder oneChannelStringBuilder = createChannelHtml(null, channels, argsInstance, channelUrls, youtubeVideos, archiveBoxRootDirectory, videosDirectory, archiveBoxArchiveDirectory);
|
||||||
|
Utils.writeTextToFile(oneChannelStringBuilder.toString(), videosHtmlFile);
|
||||||
<style>
|
|
||||||
body {padding:20px;}
|
|
||||||
* {
|
System.out.println("[Warning] Snapshots without videos:");
|
||||||
font-family:Arial;
|
YoutubeVideo.missingYoutubeVideos.forEach(s -> System.out.println(s));
|
||||||
}
|
}
|
||||||
.videos {
|
|
||||||
/*box-sizing: border-box;*/
|
private static StringBuilder createChannelHtml(String wantedChannelName, List<String> channels, Args argsInstance, Map<String, String> channelUrls, List<YoutubeVideo> youtubeVideos, File archiveBoxRootDirectory, File videosDirectory, File archiveBoxArchiveDirectory) {
|
||||||
}
|
StringBuilder oneChannelStringBuilder = new StringBuilder();
|
||||||
.box {
|
oneChannelStringBuilder.append("""
|
||||||
/*float: left;
|
<!DOCTYPE html>
|
||||||
width: 20.0%;*/
|
<html>
|
||||||
padding: 10px;
|
<head>
|
||||||
}
|
<link rel="icon" type="image/x-icon" href="favicon.ico" sizes="16x16">
|
||||||
</style>
|
<title>Youtube videos</title>
|
||||||
</head>
|
<!-- Generated by: https://code.nanoboot.org/nanoboot/youtubedl-frontend -->
|
||||||
<body>
|
<style>
|
||||||
""");
|
body {padding:20px;}
|
||||||
NumberFormat formatter = new DecimalFormat("#0.00");
|
* {
|
||||||
channels.forEach(c -> {
|
font-family:Arial;
|
||||||
sb.append("<h1>").append(c).append("</h1>\n");
|
}
|
||||||
sb.append("<div style=\"max-width:").append((Main.THUMBNAIL_WIDTH + 20) * argsInstance.getInteger(ArgType.VIDEOS_PER_ROW).get()).append("px\"><a href =\"").append(channelUrls.get(c)).append("\">").append(channelUrls.get(c)).append("</a><div class=\"videos\">");
|
.videos {
|
||||||
|
/*box-sizing: border-box;*/
|
||||||
|
}
|
||||||
|
.box {
|
||||||
|
/*float: left;
|
||||||
|
width: 20.0%;*/
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
""");
|
||||||
|
channels.stream().filter(c -> wantedChannelName == null ? true : c.equals(wantedChannelName)).forEach(channel -> {
|
||||||
|
oneChannelStringBuilder.append("<h1>").append(channel).append("</h1>\n");
|
||||||
|
oneChannelStringBuilder.append("<div style=\"max-width:").append((Main.THUMBNAIL_WIDTH + 20) * argsInstance.getInteger(ArgType.VIDEOS_PER_ROW).get()).append("px\">");
|
||||||
|
|
||||||
|
oneChannelStringBuilder.append("<a target=\"_blank\" href =\"channels/").append(channelUrls.get(channel).split("/channel/")[1]).append(".html").append("\">").append("Videos").append("</a>");
|
||||||
|
oneChannelStringBuilder.append(" ( <a href =\"").append(channelUrls.get(channel)).append("\">").append(channelUrls.get(channel)).append("</a> )");
|
||||||
|
|
||||||
|
if(wantedChannelName != null) {
|
||||||
|
oneChannelStringBuilder.append("<div class=\"videos\">");
|
||||||
iii = 0;
|
iii = 0;
|
||||||
internalStaticVariableVideoNumberPerRow = 0;
|
internalStaticVariableVideoNumberPerRow = 0;
|
||||||
sb.append("<table>\n");
|
oneChannelStringBuilder.append("<table>\n");
|
||||||
youtubeVideos.stream().filter(v -> c.equals(v.getChannelName())).forEach(youtubeVideo -> {
|
youtubeVideos.stream().filter(v -> channel.equals(v.getChannelName())).forEach(youtubeVideo -> {
|
||||||
iii++;
|
iii++;
|
||||||
if (internalStaticVariableVideoNumberPerRow == 0) {
|
if (internalStaticVariableVideoNumberPerRow == 0) {
|
||||||
sb.append("<tr>");
|
oneChannelStringBuilder.append("<tr>");
|
||||||
}
|
}
|
||||||
internalStaticVariableVideoNumberPerRow++;
|
internalStaticVariableVideoNumberPerRow++;
|
||||||
sb.append("<td><div class=\"box\"><table style=\"margin:5px;max-width:")
|
oneChannelStringBuilder.append("<td><div class=\"box\"><table style=\"margin:5px;max-width:")
|
||||||
.append(THUMBNAIL_WIDTH)
|
.append(THUMBNAIL_WIDTH)
|
||||||
.append("px;\">\n<tr><td><a href=\"");
|
.append("px;\">\n<tr><td><a href=\"");
|
||||||
if (argsInstance.getBoolean(ArgType.THUMBNAIL_LINKS_TO_YOUTUBE).get()) {
|
if (argsInstance.getBoolean(ArgType.THUMBNAIL_LINKS_TO_YOUTUBE).get()) {
|
||||||
sb.append("https://www.youtube.com/watch?v=").append(youtubeVideo.getId());
|
oneChannelStringBuilder.append("https://www.youtube.com/watch?v=").append(youtubeVideo.getId());
|
||||||
} else {
|
} else {
|
||||||
sb.append("videos/" + youtubeVideo.getId() + ".html");
|
oneChannelStringBuilder.append("videos/" + youtubeVideo.getId() + ".html");
|
||||||
}
|
}
|
||||||
sb.append("\" target=\"_blank\"><img src=\"");
|
oneChannelStringBuilder.append("\" target=\"_blank\"><img src=\"");
|
||||||
String thumbnailPath = new StringBuilder()
|
String thumbnailPath = new StringBuilder()
|
||||||
.append("archive/")
|
.append("archive/")
|
||||||
.append(youtubeVideo.getSnapshot())
|
.append(youtubeVideo.getSnapshot())
|
||||||
.append("/media/mini-thumbnail.")
|
.append("/media/mini-thumbnail.")
|
||||||
.append(youtubeVideo.getMiniThumbnailFormat()).toString();
|
.append(youtubeVideo.getMiniThumbnailFormat()).toString();
|
||||||
if (argsInstance.getBoolean(ArgType.THUMBNAIL_AS_BASE64).get()) {
|
if (argsInstance.getBoolean(ArgType.THUMBNAIL_AS_BASE64).get()) {
|
||||||
try {
|
try {
|
||||||
byte[] bytes = Files.readAllBytes(new File(archiveBoxRootDirectory + "/" + thumbnailPath).toPath());
|
byte[] bytes = Files.readAllBytes(new File(archiveBoxRootDirectory + "/" + thumbnailPath).toPath());
|
||||||
@ -205,208 +165,55 @@ public class Main {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
//bytes = Utils.resizeImage(bais, 125, (int) (9d / 16d * 125d), "webp");
|
//bytes = Utils.resizeImage(bais, 125, (int) (9d / 16d * 125d), "webp");
|
||||||
}
|
}
|
||||||
|
|
||||||
String bytesS = "data:image/jpg;base64, " + org.nanoboot.powerframework.io.bit.base64.Base64Coder.encode(bytes);
|
String bytesS = "data:image/jpg;base64, " + org.nanoboot.powerframework.io.bit.base64.Base64Coder.encode(bytes);
|
||||||
sb.append(bytesS);
|
oneChannelStringBuilder.append(bytesS);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
throw new YoutubedlFrontendException(ex.getMessage());
|
throw new YoutubedlFrontendException(ex.getMessage());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sb.append(thumbnailPath);
|
oneChannelStringBuilder.append(thumbnailPath);
|
||||||
}
|
}
|
||||||
sb.append("\" width=\"")
|
oneChannelStringBuilder.append("\" width=\"")
|
||||||
.append(THUMBNAIL_WIDTH)
|
.append(THUMBNAIL_WIDTH)
|
||||||
.append("\"></a></td></tr>\n");
|
.append("\"></a></td></tr>\n");
|
||||||
sb.append("<tr><td><b style=\"font-size:90%;\">").append(youtubeVideo.getTitle()).append("</b></td></tr>\n");
|
oneChannelStringBuilder.append("<tr><td><b style=\"font-size:90%;\">").append(youtubeVideo.getTitle()).append("</b></td></tr>\n");
|
||||||
String uploadDate = youtubeVideo.getUploadDate();
|
String uploadDate = youtubeVideo.getUploadDate();
|
||||||
uploadDate = uploadDate.substring(0, 4) + "-" + uploadDate.substring(4, 6) + "-" + uploadDate.substring(6, 8);
|
uploadDate = uploadDate.substring(0, 4) + "-" + uploadDate.substring(4, 6) + "-" + uploadDate.substring(6, 8);
|
||||||
sb.append("<tr><td style=\"font-size:80%;color:grey;\">").append(uploadDate).append(" •︎ ").append(youtubeVideo.getVideoDuration())
|
oneChannelStringBuilder.append("<tr><td style=\"font-size:80%;color:grey;\">").append(uploadDate).append(" •︎ ").append(youtubeVideo.getVideoDuration())
|
||||||
.append(" •︎ ")
|
.append(" •︎ ")
|
||||||
.append("#").append(iii)
|
.append("#").append(iii)
|
||||||
.append("</td></tr>\n");
|
.append("</td></tr>\n");
|
||||||
youtubeVideo.setNumber(iii);
|
youtubeVideo.setNumber(iii);
|
||||||
sb.append("</table></div></td>\n");
|
oneChannelStringBuilder.append("</table></div></td>\n");
|
||||||
if (internalStaticVariableVideoNumberPerRow == argsInstance.getInteger(ArgType.VIDEOS_PER_ROW).get()) {
|
if (internalStaticVariableVideoNumberPerRow == argsInstance.getInteger(ArgType.VIDEOS_PER_ROW).get()) {
|
||||||
sb.append("<tr>");
|
oneChannelStringBuilder.append("<tr>");
|
||||||
internalStaticVariableVideoNumberPerRow = 0;
|
internalStaticVariableVideoNumberPerRow = 0;
|
||||||
}
|
}
|
||||||
File videoHtmlFile = new File(videosDirectory, youtubeVideo.getId() + ".html");
|
File videoHtmlFile = new File(videosDirectory, youtubeVideo.getId() + ".html");
|
||||||
if (!videoHtmlFile.exists() || argsInstance.getBoolean(ArgType.ALWAYS_GENERATE_HTML_FILES).get()) {
|
if (!videoHtmlFile.exists() || argsInstance.getBoolean(ArgType.ALWAYS_GENERATE_HTML_FILES).get()) {
|
||||||
|
|
||||||
{
|
{
|
||||||
StringBuilder videoHtml = new StringBuilder("""
|
String singleVideo = new YoutubeVideoHtml(youtubeVideo, archiveBoxRootDirectory, archiveBoxArchiveDirectory).toString();
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<link rel="icon" type="image/x-icon" href="../favicon.ico" sizes="16x16">
|
|
||||||
<title>"""
|
|
||||||
+ youtubeVideo.getTitle()
|
|
||||||
+ """
|
|
||||||
</title>
|
|
||||||
<style>
|
|
||||||
body {padding:20px;}
|
|
||||||
* {
|
|
||||||
font-family:Arial;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
"""
|
|
||||||
);
|
|
||||||
String finalUrl = "https://www.youtube.com/watch?v=" + youtubeVideo.getId();
|
|
||||||
|
|
||||||
videoHtml.append("<input type=\"text\" id=\"youtube_url\" name=\"youtube_url\" size=\"60\" width=\"60\" style=\"margint-bottom:20px;margin-right:10px;font-size:110%;padding:5px;\" value=\"" + finalUrl + "\"><br>\n<br>\n");
|
|
||||||
videoHtml.append("<a target=\"_blank\" href=\"").append(finalUrl).append("\">");
|
|
||||||
videoHtml.append(finalUrl).append("</a>").append("<br>\n");
|
|
||||||
String videoLocalUrl = "";
|
|
||||||
try {
|
|
||||||
videoLocalUrl = "file:///" + archiveBoxRootDirectory.getAbsolutePath() + "/archive/" + youtubeVideo.getSnapshot() + "/media/" + URLEncoder.encode(youtubeVideo.getVideoFileName(), StandardCharsets.UTF_8.toString()).replace("+", "%20");
|
|
||||||
} catch (UnsupportedEncodingException ex) {
|
|
||||||
throw new YoutubedlFrontendException(ex.getMessage());
|
|
||||||
}
|
|
||||||
if (!youtubeVideo.getVideoFileName().endsWith(".mkv")) {
|
|
||||||
//try {
|
|
||||||
videoHtml.append("<video src=\"");
|
|
||||||
|
|
||||||
videoHtml.append("../archive/").append(youtubeVideo.getSnapshot()).append("/media/").append(// URLEncoder.encode(
|
|
||||||
youtubeVideo.getVideoFileName());
|
|
||||||
videoHtml.append("""
|
|
||||||
|
|
||||||
" controls height=\"500px\">
|
|
||||||
Your browser does not support the video tag.
|
|
||||||
</video><br>
|
|
||||||
""");
|
|
||||||
// } catch (UnsupportedEncodingException ex) {
|
|
||||||
// throw new YoutubedlFrontendException(ex.getMessage());
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
videoHtml.append("<a target=\"_blank\" href=\"").append(videoLocalUrl).append("\">");
|
|
||||||
|
|
||||||
videoHtml.append("<img style=\"margin:10px;height:500px;\" src=\"../archive/")
|
|
||||||
.append(youtubeVideo.getSnapshot())
|
|
||||||
.append("/media/thumbnail.")
|
|
||||||
.append(youtubeVideo.getThumbnailFormat())
|
|
||||||
.append("\"></a><br>\n");
|
|
||||||
}
|
|
||||||
videoHtml.append("<span style=\"font-size:160%;font-weight:bold;\">").append(youtubeVideo.getTitle()).append("</span>");
|
|
||||||
videoHtml.append("<br>\n<br>\n");
|
|
||||||
videoHtml.append("#").append(youtubeVideo.getNumber()).append(" ");
|
|
||||||
if (youtubeVideo.getPreviousVideoId() != null) {
|
|
||||||
// videoHtml.append("<a href=\"./").append(youtubeVideo.getPreviousVideoId()).append(".html\">");
|
|
||||||
videoHtml.append("<button style=\"font-size:150%;\" onclick=\"window.location ='").append("./").append(youtubeVideo.getPreviousVideoId()).append(".html'\">");
|
|
||||||
//<button class="link" onclick="alert(1)">Click</button>
|
|
||||||
}
|
|
||||||
videoHtml.append("Back");
|
|
||||||
if (youtubeVideo.getPreviousVideoId() != null) {
|
|
||||||
//videoHtml.append("</a>");
|
|
||||||
videoHtml.append("</button>");
|
|
||||||
}
|
|
||||||
videoHtml.append(" ");
|
|
||||||
if (youtubeVideo.getNextVideoId() != null) {
|
|
||||||
//videoHtml.append("<a href=\"./").append(youtubeVideo.getNextVideoId()).append(".html\">");
|
|
||||||
videoHtml.append("<button style=\"font-size:150%;\" onclick=\"window.location ='").append("./").append(youtubeVideo.getNextVideoId()).append(".html'\">");
|
|
||||||
}
|
|
||||||
videoHtml.append("Next");
|
|
||||||
if (youtubeVideo.getNextVideoId() != null) {
|
|
||||||
//videoHtml.append("</a>");
|
|
||||||
videoHtml.append("</button>");
|
|
||||||
|
|
||||||
}
|
|
||||||
videoHtml.append(" ");
|
|
||||||
videoHtml
|
|
||||||
.append("<br><br><a href=\"../archive/")
|
|
||||||
.append(youtubeVideo.getSnapshot())
|
|
||||||
.append("/media/")
|
|
||||||
.append(youtubeVideo.getVideoFileName())
|
|
||||||
.append("\">Download</a> ");
|
|
||||||
|
|
||||||
videoHtml.append(formatter.format(((double) youtubeVideo.getVideoFileSizeInBytes()) / 1024d / 1024d)).append(" MB ");
|
|
||||||
if (youtubeVideo.getVideoFileName().endsWith(".mkv")) {
|
|
||||||
|
|
||||||
String v = youtubeVideo.getVideoFileName().replaceAll(" ", "\\\\ ");
|
|
||||||
v = v.replace("(", "\\(");
|
|
||||||
v = v.replace(")", "\\)");
|
|
||||||
var vWebm = v.substring(0, v.length() - 3) + "webm";
|
|
||||||
|
|
||||||
videoHtml.append("<input type=\"text\" id=\"archiveBoxArchiveDirectory\" name=\"archiveBoxArchiveDirectory\" size=\"100\" width=\"100\" style=\"margin-bottom:20px;margin-right:10px;font-size:110%;padding:5px;\" value=\"");
|
|
||||||
videoHtml.append("cd ").append(archiveBoxArchiveDirectory).append("/").append(youtubeVideo.getSnapshot()).append("/media/");
|
|
||||||
videoHtml.append(" && ffmpeg -i ").append(v).append(" -preset slow -crf 18 ").append(vWebm) ;
|
|
||||||
videoHtml.append("\"><br>");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
|
|
||||||
videoHtml.append("<input type=\"text\" id=\"archiveBoxArchiveDirectory\" name=\"archiveBoxArchiveDirectory\" size=\"100\" width=\"100\" style=\"margin-bottom:20px;margin-right:10px;font-size:110%;padding:5px;\" value=\"");
|
|
||||||
videoHtml.append(archiveBoxArchiveDirectory).append("/").append(youtubeVideo.getSnapshot()).append("/media/");
|
|
||||||
|
|
||||||
videoHtml.append("\"><br>");
|
|
||||||
}
|
|
||||||
videoHtml.append("<a target=\"_blank\" href=\"file://").append(archiveBoxArchiveDirectory).append("/").append(youtubeVideo.getSnapshot()).append("/media\">Directory</a>").append("<br>");
|
|
||||||
videoHtml.append("<br>\n<br>\n");
|
|
||||||
|
|
||||||
videoHtml.append("<br>\n");
|
|
||||||
videoHtml.append("<pre style=\"white-space: pre-wrap; border:1px solid black;max-width:600px;padding:10px;min-height:50px;\">");
|
|
||||||
videoHtml.append(youtubeVideo.getDescription().isBlank() ? "No description" : youtubeVideo.getDescription());
|
|
||||||
videoHtml.append("</pre>");
|
|
||||||
videoHtml.append("<h2>Comments</h2>");
|
|
||||||
youtubeVideo.getComments().forEach(co -> {
|
|
||||||
|
|
||||||
// private String id, parentId, text, author;
|
|
||||||
// private int timestamp;
|
|
||||||
videoHtml.append("<div style=\"margin-left:")
|
|
||||||
.append(co.dotCount() * 50)
|
|
||||||
.append("px;\">");
|
|
||||||
videoHtml.append("<h3>").append(co.getAuthor()).append("</h3>");
|
|
||||||
|
|
||||||
videoHtml.append("<span style=\"color:grey;font-size:80%;\">")
|
|
||||||
.append(Utils.DATE_FORMAT.format(new Date(co.getTimestamp() * 1000))).append("</span><br>\n");
|
|
||||||
videoHtml.append("<span style=\"color:grey;font-size:80%;\">").append(co.getId()).append(" ")
|
|
||||||
.append(co.getParentId()).append("</span><br>\n");
|
|
||||||
videoHtml.append("<pre style=\"white-space: pre-wrap;border:1px solid black;max-width:600px;padding:10px;min-height:50px;\">").append(co.getText()).append("</pre>");
|
|
||||||
videoHtml.append("</div>");
|
|
||||||
});
|
|
||||||
|
|
||||||
// private String id;
|
|
||||||
//
|
|
||||||
// private String title;
|
|
||||||
// private String videoFileName = "";
|
|
||||||
// private long videoFileSizeInBytes = 0;
|
|
||||||
// private String videoFileSha512HashSum = "";
|
|
||||||
// private String videoDuration = "";
|
|
||||||
// private String channelName;
|
|
||||||
// private String channelUrl;
|
|
||||||
// private String channelId;
|
|
||||||
// private String uploadDate;
|
|
||||||
// private String description;
|
|
||||||
// private String thumbnail;
|
|
||||||
// private List<YoutubeComment> comments = new ArrayList<>();
|
|
||||||
videoHtml.append("</body></html>");
|
|
||||||
String singleVideo = videoHtml.toString();
|
|
||||||
//singleVideo.replace("<br>\n", "<br>\n\n");
|
|
||||||
Utils.writeTextToFile(singleVideo, videoHtmlFile);
|
Utils.writeTextToFile(singleVideo, videoHtmlFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (internalStaticVariableVideoNumberPerRow < argsInstance.getInteger(ArgType.VIDEOS_PER_ROW).get()) {
|
if (internalStaticVariableVideoNumberPerRow < argsInstance.getInteger(ArgType.VIDEOS_PER_ROW).get()) {
|
||||||
sb.append("<tr>");
|
oneChannelStringBuilder.append("<tr>");
|
||||||
}
|
}
|
||||||
sb.append("</table>\n");
|
oneChannelStringBuilder.append("</table>\n");
|
||||||
sb.append("</div></div>");
|
oneChannelStringBuilder.append("</div>");
|
||||||
|
}
|
||||||
|
oneChannelStringBuilder.append("</div>");
|
||||||
});
|
});
|
||||||
sb.append("""
|
oneChannelStringBuilder.append("""
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
</body>
|
""");
|
||||||
</html>
|
return oneChannelStringBuilder;
|
||||||
""");
|
|
||||||
Utils.writeTextToFile(sb.toString(), videosHtmlFile);
|
|
||||||
|
|
||||||
System.out.println("[Warning] Snapshots without videos:");
|
|
||||||
YoutubeVideo.missingYoutubeVideos.forEach(s -> System.out.println(s));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@ import java.awt.image.BufferedImage;
|
|||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -35,6 +34,8 @@ import java.nio.file.Path;
|
|||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
import java.text.NumberFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
@ -48,6 +49,7 @@ public class Utils {
|
|||||||
private static final String UNDERSCORE = "_";
|
private static final String UNDERSCORE = "_";
|
||||||
|
|
||||||
public static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
|
public static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
|
||||||
|
public static final NumberFormat TWO_DECIMAL_POINTS_FORMATTER = new DecimalFormat("#0.00");
|
||||||
private Utils() {
|
private Utils() {
|
||||||
//Not meant to be instantiated.
|
//Not meant to be instantiated.
|
||||||
}
|
}
|
||||||
@ -187,6 +189,7 @@ public class Utils {
|
|||||||
throw new YoutubedlFrontendException("Could not create boolean from String: " + s);
|
throw new YoutubedlFrontendException("Could not create boolean from String: " + s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] resizeImage(InputStream inputStream, int width, int height, String formatName) throws IOException {
|
public static byte[] resizeImage(InputStream inputStream, int width, int height, String formatName) throws IOException {
|
||||||
BufferedImage sourceImage = ImageIO.read(inputStream);
|
BufferedImage sourceImage = ImageIO.read(inputStream);
|
||||||
Image thumbnail = sourceImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
|
Image thumbnail = sourceImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
|
||||||
|
@ -43,13 +43,15 @@ public class YoutubeComment implements Comparable<YoutubeComment> {
|
|||||||
author = jsonObject.getString("author");
|
author = jsonObject.getString("author");
|
||||||
timestamp = jsonObject.getInt("timestamp");
|
timestamp = jsonObject.getInt("timestamp");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<YoutubeComment> sort(List<YoutubeComment> list) {
|
public static List<YoutubeComment> sort(List<YoutubeComment> list) {
|
||||||
|
|
||||||
List<YoutubeComment> root = getChildren(list, "root");
|
List<YoutubeComment> root = getChildren(list, "root");
|
||||||
Collections.sort(root);
|
Collections.sort(root);
|
||||||
return list;
|
return list;
|
||||||
//return sort(list, new ArrayList<>(), "root");
|
//return sort(list, new ArrayList<>(), "root");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<YoutubeComment> getChildren(List<YoutubeComment> all, String parentId) {
|
private static List<YoutubeComment> getChildren(List<YoutubeComment> all, String parentId) {
|
||||||
final List<YoutubeComment> children = all.stream().filter(c -> c.getParentId().equals(parentId)).sorted().toList();
|
final List<YoutubeComment> children = all.stream().filter(c -> c.getParentId().equals(parentId)).sorted().toList();
|
||||||
List<YoutubeComment> result = new ArrayList<>();
|
List<YoutubeComment> result = new ArrayList<>();
|
||||||
@ -59,7 +61,7 @@ public class YoutubeComment implements Comparable<YoutubeComment> {
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(YoutubeComment o) {
|
public int compareTo(YoutubeComment o) {
|
||||||
//if(this.timestamp != o.timestamp) {
|
//if(this.timestamp != o.timestamp) {
|
||||||
|
@ -20,6 +20,7 @@ import java.net.URL;
|
|||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
@ -63,7 +64,7 @@ public class YoutubeVideo implements Comparable<YoutubeVideo> {
|
|||||||
|
|
||||||
public YoutubeVideo(File mediaDirectory, boolean argAlwaysGenerateMetadata, String argVideo) throws InterruptedException, IOException {
|
public YoutubeVideo(File mediaDirectory, boolean argAlwaysGenerateMetadata, String argVideo) throws InterruptedException, IOException {
|
||||||
File metadataFile = new File(mediaDirectory, "metadata");
|
File metadataFile = new File(mediaDirectory, "metadata");
|
||||||
if (argAlwaysGenerateMetadata && metadataFile.exists()) {
|
if (!argAlwaysGenerateMetadata && metadataFile.exists()) {
|
||||||
|
|
||||||
YoutubeVideo yv = new YoutubeVideo();
|
YoutubeVideo yv = new YoutubeVideo();
|
||||||
//new ObjectMapper().readValue(Utils.readTextFromFile(metadataFile), YoutubeVideo.class);
|
//new ObjectMapper().readValue(Utils.readTextFromFile(metadataFile), YoutubeVideo.class);
|
||||||
@ -131,7 +132,7 @@ public class YoutubeVideo implements Comparable<YoutubeVideo> {
|
|||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
int width = o.getInt("width");
|
int width = o.getInt("width");
|
||||||
if (width < (((double)Main.THUMBNAIL_WIDTH) * 0.8d)) {
|
if (width < (((double) Main.THUMBNAIL_WIDTH) * 0.8d)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
miniThumbnail = o.getString("url");
|
miniThumbnail = o.getString("url");
|
||||||
@ -147,7 +148,6 @@ public class YoutubeVideo implements Comparable<YoutubeVideo> {
|
|||||||
// new File(mediaDirectory, "mini-thumbnail.jpg").delete();
|
// new File(mediaDirectory, "mini-thumbnail.jpg").delete();
|
||||||
// new File(mediaDirectory, "thumbnail.webp").delete();
|
// new File(mediaDirectory, "thumbnail.webp").delete();
|
||||||
// new File(mediaDirectory, "mini-thumbnail.webp").delete();
|
// new File(mediaDirectory, "mini-thumbnail.webp").delete();
|
||||||
|
|
||||||
if (thumbnail != null) {
|
if (thumbnail != null) {
|
||||||
if (!thumbnailFile.exists()) {
|
if (!thumbnailFile.exists()) {
|
||||||
try (BufferedInputStream in = new BufferedInputStream(new URL(thumbnail).openStream()); FileOutputStream fileOutputStream = new FileOutputStream(thumbnailFile.getAbsolutePath())) {
|
try (BufferedInputStream in = new BufferedInputStream(new URL(thumbnail).openStream()); FileOutputStream fileOutputStream = new FileOutputStream(thumbnailFile.getAbsolutePath())) {
|
||||||
@ -171,35 +171,7 @@ public class YoutubeVideo implements Comparable<YoutubeVideo> {
|
|||||||
System.out.println(e.getMessage());
|
System.out.println(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// for (String s : ImageIO.getReaderFormatNames()) {
|
|
||||||
// System.out.println(s);
|
|
||||||
// }
|
|
||||||
//if(!miniThumbnailFile.exists()) {
|
|
||||||
|
|
||||||
//String miniThumbnailFileAbsolutePath = miniThumbnailFile.getAbsolutePath();
|
|
||||||
// String formatName = miniThumbnailFileAbsolutePath.substring(miniThumbnailFileAbsolutePath
|
|
||||||
// .lastIndexOf(".") + 1);
|
|
||||||
// BufferedImage inputImage = ImageIO.read(thumbnailFile);
|
|
||||||
// if(inputImage == null) {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
// int thumbnailWidth = inputImage.getWidth();
|
|
||||||
// int thumbnailHeight = inputImage.getHeight();
|
|
||||||
// double heightWidthRatio = ((double) thumbnailHeight) / ((double) thumbnailWidth);
|
|
||||||
// int miniThumbnailWidth = Main.THUMBNAIL_WIDTH;
|
|
||||||
// int miniThumbnailHeight = (int) (heightWidthRatio * ((double) Main.THUMBNAIL_WIDTH));
|
|
||||||
//
|
|
||||||
// BufferedImage outputImage = new BufferedImage(miniThumbnailWidth,
|
|
||||||
// miniThumbnailHeight, inputImage.getType());
|
|
||||||
//
|
|
||||||
// Graphics2D g2d = outputImage.createGraphics();
|
|
||||||
// g2d.drawImage(inputImage, 0, 0, miniThumbnailWidth, miniThumbnailHeight, null);
|
|
||||||
// g2d.dispose();
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// ImageIO.write(outputImage, formatName, new File(miniThumbnailFileAbsolutePath));
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
Optional<File> descriptionFile = files.stream().filter(f -> f.getName().endsWith(".description")).findFirst();
|
Optional<File> descriptionFile = files.stream().filter(f -> f.getName().endsWith(".description")).findFirst();
|
||||||
@ -211,14 +183,9 @@ public class YoutubeVideo implements Comparable<YoutubeVideo> {
|
|||||||
.filter(f
|
.filter(f
|
||||||
-> (f.getName().endsWith("." + ext))
|
-> (f.getName().endsWith("." + ext))
|
||||||
|| (f.getName().endsWith(".mp4"))
|
|| (f.getName().endsWith(".mp4"))
|
||||||
|| (f.getName().endsWith(".mkv"))|| (f.getName().endsWith(".webm"))
|
|| (f.getName().endsWith(".mkv")) || (f.getName().endsWith(".webm"))
|
||||||
)
|
)
|
||||||
// .filter(
|
|
||||||
// f -> !f.getName().endsWith(".description")
|
|
||||||
// && !f.getName().endsWith(".json")
|
|
||||||
// && !f.getName().equals("metadata")
|
|
||||||
// && !f.getName().endsWith(thumbnail)
|
|
||||||
// )
|
|
||||||
.findFirst();
|
.findFirst();
|
||||||
|
|
||||||
snapshot = mediaDirectory.getParentFile().getName();
|
snapshot = mediaDirectory.getParentFile().getName();
|
||||||
@ -303,23 +270,24 @@ public class YoutubeVideo implements Comparable<YoutubeVideo> {
|
|||||||
public String getMiniThumbnailFormat() {
|
public String getMiniThumbnailFormat() {
|
||||||
return getExtensionFromUrl(miniThumbnail);
|
return getExtensionFromUrl(miniThumbnail);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getExtensionFromUrl(String url) {
|
private String getExtensionFromUrl(String url) {
|
||||||
String result = url.substring(url
|
String result = url.substring(url
|
||||||
.lastIndexOf(".") + 1);
|
.lastIndexOf(".") + 1);
|
||||||
int questionMarkIndex = 0;
|
int questionMarkIndex = 0;
|
||||||
for(int i = 0;i<result.length();i++) {
|
for (int i = 0; i < result.length(); i++) {
|
||||||
char ch = result.charAt(i);
|
char ch = result.charAt(i);
|
||||||
if(ch != '?') {
|
if (ch != '?') {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
questionMarkIndex = i;
|
questionMarkIndex = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(questionMarkIndex > 0) {
|
if (questionMarkIndex > 0) {
|
||||||
result = result.substring(0, questionMarkIndex);
|
result = result.substring(0, questionMarkIndex);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -359,4 +327,69 @@ public class YoutubeVideo implements Comparable<YoutubeVideo> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<YoutubeVideo> loadYoutubeVideos(File archiveBoxArchiveDirectory, Args argsInstance) throws IOException, InterruptedException {
|
||||||
|
int i = 0;
|
||||||
|
List<YoutubeVideo> youtubeVideos = new ArrayList<>();
|
||||||
|
for (File snapshotDirectory : archiveBoxArchiveDirectory.listFiles()) {
|
||||||
|
//if(i> 40)break;//only for tests
|
||||||
|
File mediaDirectory = new File(snapshotDirectory, "media");
|
||||||
|
if (!mediaDirectory.exists()) {
|
||||||
|
//nothing to do
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
YoutubeVideo youtubeVideo = new YoutubeVideo(mediaDirectory, argsInstance.getBoolean(ArgType.ALWAYS_GENERATE_METADATA).get(), argsInstance.getString(ArgType.VIDEO).orElse(""));
|
||||||
|
if (argsInstance.getString(ArgType.VIDEO).isPresent() && !argsInstance.getString(ArgType.VIDEO).equals(youtubeVideo.getId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (argsInstance.getString(ArgType.CHANNEL).isPresent() && !argsInstance.getString(ArgType.CHANNEL).equals(youtubeVideo.getChannelId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
System.out.println("\n\nFound video #" + i);
|
||||||
|
|
||||||
|
for (File f : new File(archiveBoxArchiveDirectory + "/" + youtubeVideo.getSnapshot() + "/media/" + youtubeVideo.getVideoFileName()).getParentFile().listFiles()) {
|
||||||
|
if (f.getName().endsWith(".webm")) {
|
||||||
|
//mkv file was manually converted to webm
|
||||||
|
youtubeVideo.setVideoFileName(f.getName());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
System.out.println("id = " + youtubeVideo.getId());
|
||||||
|
System.out.println("snapshot = " + youtubeVideo.getSnapshot());
|
||||||
|
System.out.println("title = " + youtubeVideo.getTitle());
|
||||||
|
System.out.println("videoFileName = " + youtubeVideo.getVideoFileName());
|
||||||
|
System.out.println("videoFileSizeInBytes = " + youtubeVideo.getVideoFileSizeInBytes());
|
||||||
|
System.out.println("videoFileSha512HashSum = " + youtubeVideo.getVideoFileSha512HashSum());
|
||||||
|
System.out.println("videoDuration = " + youtubeVideo.getVideoDuration());
|
||||||
|
System.out.println("channelName = " + youtubeVideo.getChannelName());
|
||||||
|
System.out.println("channelUrl = " + youtubeVideo.getChannelUrl());
|
||||||
|
System.out.println("uploadDate = " + youtubeVideo.getUploadDate());
|
||||||
|
System.out.println("description = " + youtubeVideo.getDescription());
|
||||||
|
System.out.println("thumbnail = " + youtubeVideo.getThumbnail());
|
||||||
|
System.out.println("miniThumbnail = " + youtubeVideo.getMiniThumbnail());
|
||||||
|
System.out.println("comments = " + youtubeVideo.getComments());
|
||||||
|
youtubeVideos.add(youtubeVideo);
|
||||||
|
}
|
||||||
|
Collections.sort(youtubeVideos);
|
||||||
|
YoutubeVideo previousVideo = null;
|
||||||
|
YoutubeVideo nextVideo = null;
|
||||||
|
YoutubeVideo currentVideo = null;
|
||||||
|
for (int j = 0; j < youtubeVideos.size(); j++) {
|
||||||
|
previousVideo = currentVideo;
|
||||||
|
currentVideo = youtubeVideos.get(j);
|
||||||
|
if (j < (youtubeVideos.size() - 1)) {
|
||||||
|
nextVideo = youtubeVideos.get(j + 1);
|
||||||
|
}
|
||||||
|
if (previousVideo != null) {
|
||||||
|
currentVideo.setPreviousVideoId(previousVideo.getId());
|
||||||
|
}
|
||||||
|
if (nextVideo != null) {
|
||||||
|
currentVideo.setNextVideoId(nextVideo.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return youtubeVideos;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,178 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// youtubedl-frontend: Tool generating html pages for Archive Box.
|
||||||
|
// Copyright (C) 2024 the original author or authors.
|
||||||
|
//
|
||||||
|
// This program is free software; you can redistribute it and/or
|
||||||
|
// modify it under the terms of the GNU General Public License
|
||||||
|
// as published by the Free Software Foundation; version 2
|
||||||
|
// of the License only.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
package org.nanoboot.youtubedlfrontend;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.text.NumberFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author robertvokac
|
||||||
|
*/
|
||||||
|
public class YoutubeVideoHtml {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private String singleVideo;
|
||||||
|
|
||||||
|
public YoutubeVideoHtml(YoutubeVideo youtubeVideo, File archiveBoxRootDirectory, File archiveBoxArchiveDirectory) {
|
||||||
|
|
||||||
|
StringBuilder videoHtml = new StringBuilder("""
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<link rel="icon" type="image/x-icon" href="../favicon.ico" sizes="16x16">
|
||||||
|
<title>"""
|
||||||
|
+ youtubeVideo.getTitle()
|
||||||
|
+ """
|
||||||
|
</title>
|
||||||
|
<style>
|
||||||
|
body {padding:20px;}
|
||||||
|
* {
|
||||||
|
font-family:Arial;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
String finalUrl = "https://www.youtube.com/watch?v=" + youtubeVideo.getId();
|
||||||
|
videoHtml.append("<input type=\"text\" id=\"youtube_url\" name=\"youtube_url\" size=\"60\" width=\"60\" style=\"margint-bottom:20px;margin-right:10px;font-size:110%;padding:5px;\" value=\"" + finalUrl + "\"><br>\n<br>\n");
|
||||||
|
videoHtml.append("<a target=\"_blank\" href=\"").append(finalUrl).append("\">");
|
||||||
|
videoHtml.append(finalUrl).append("</a>").append("<br>\n");
|
||||||
|
String videoLocalUrl = "";
|
||||||
|
try {
|
||||||
|
videoLocalUrl = "file:///" + archiveBoxRootDirectory.getAbsolutePath() + "/archive/" + youtubeVideo.getSnapshot() + "/media/" + URLEncoder.encode(youtubeVideo.getVideoFileName(), StandardCharsets.UTF_8.toString()).replace("+", "%20");
|
||||||
|
} catch (UnsupportedEncodingException ex) {
|
||||||
|
throw new YoutubedlFrontendException(ex.getMessage());
|
||||||
|
}
|
||||||
|
if (!youtubeVideo.getVideoFileName().endsWith(".mkv")) {
|
||||||
|
//try {
|
||||||
|
videoHtml.append("<video src=\"");
|
||||||
|
|
||||||
|
videoHtml.append("../archive/").append(youtubeVideo.getSnapshot()).append("/media/").append(// URLEncoder.encode(
|
||||||
|
youtubeVideo.getVideoFileName());
|
||||||
|
videoHtml.append("""
|
||||||
|
|
||||||
|
" controls height=\"500px\">
|
||||||
|
Your browser does not support the video tag.
|
||||||
|
</video><br>
|
||||||
|
""");
|
||||||
|
// } catch (UnsupportedEncodingException ex) {
|
||||||
|
// throw new YoutubedlFrontendException(ex.getMessage());
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
videoHtml.append("<a target=\"_blank\" href=\"").append(videoLocalUrl).append("\">");
|
||||||
|
|
||||||
|
videoHtml.append("<img style=\"margin:10px;height:500px;\" src=\"../archive/")
|
||||||
|
.append(youtubeVideo.getSnapshot())
|
||||||
|
.append("/media/thumbnail.")
|
||||||
|
.append(youtubeVideo.getThumbnailFormat())
|
||||||
|
.append("\"></a><br>\n");
|
||||||
|
}
|
||||||
|
videoHtml.append("<span style=\"font-size:160%;font-weight:bold;\">").append(youtubeVideo.getTitle()).append("</span>");
|
||||||
|
videoHtml.append("<br>\n<br>\n");
|
||||||
|
videoHtml.append("#").append(youtubeVideo.getNumber()).append(" ");
|
||||||
|
if (youtubeVideo.getPreviousVideoId() != null) {
|
||||||
|
// videoHtml.append("<a href=\"./").append(youtubeVideo.getPreviousVideoId()).append(".html\">");
|
||||||
|
videoHtml.append("<button style=\"font-size:150%;\" onclick=\"window.location ='").append("./").append(youtubeVideo.getPreviousVideoId()).append(".html'\">");
|
||||||
|
//<button class="link" onclick="alert(1)">Click</button>
|
||||||
|
}
|
||||||
|
videoHtml.append("Back");
|
||||||
|
if (youtubeVideo.getPreviousVideoId() != null) {
|
||||||
|
//videoHtml.append("</a>");
|
||||||
|
videoHtml.append("</button>");
|
||||||
|
}
|
||||||
|
videoHtml.append(" ");
|
||||||
|
if (youtubeVideo.getNextVideoId() != null) {
|
||||||
|
//videoHtml.append("<a href=\"./").append(youtubeVideo.getNextVideoId()).append(".html\">");
|
||||||
|
videoHtml.append("<button style=\"font-size:150%;\" onclick=\"window.location ='").append("./").append(youtubeVideo.getNextVideoId()).append(".html'\">");
|
||||||
|
}
|
||||||
|
videoHtml.append("Next");
|
||||||
|
if (youtubeVideo.getNextVideoId() != null) {
|
||||||
|
//videoHtml.append("</a>");
|
||||||
|
videoHtml.append("</button>");
|
||||||
|
|
||||||
|
}
|
||||||
|
videoHtml.append(" ");
|
||||||
|
videoHtml
|
||||||
|
.append("<br><br><a href=\"../archive/")
|
||||||
|
.append(youtubeVideo.getSnapshot())
|
||||||
|
.append("/media/")
|
||||||
|
.append(youtubeVideo.getVideoFileName())
|
||||||
|
.append("\">Download</a> ");
|
||||||
|
videoHtml.append(Utils.TWO_DECIMAL_POINTS_FORMATTER.format(((double) youtubeVideo.getVideoFileSizeInBytes()) / 1024d / 1024d)).append(" MB ");
|
||||||
|
if (youtubeVideo.getVideoFileName().endsWith(".mkv")) {
|
||||||
|
|
||||||
|
String v = youtubeVideo.getVideoFileName().replaceAll(" ", "\\\\ ");
|
||||||
|
v = v.replace("(", "\\(");
|
||||||
|
v = v.replace(")", "\\)");
|
||||||
|
var vWebm = v.substring(0, v.length() - 3) + "webm";
|
||||||
|
|
||||||
|
videoHtml.append("<input type=\"text\" id=\"archiveBoxArchiveDirectory\" name=\"archiveBoxArchiveDirectory\" size=\"100\" width=\"100\" style=\"margin-bottom:20px;margin-right:10px;font-size:110%;padding:5px;\" value=\"");
|
||||||
|
videoHtml.append("cd ").append(archiveBoxArchiveDirectory).append("/").append(youtubeVideo.getSnapshot()).append("/media/");
|
||||||
|
videoHtml.append(" && ffmpeg -i ").append(v).append(" -preset slow -crf 18 ").append(vWebm);
|
||||||
|
videoHtml.append("\"><br>");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
videoHtml.append("<input type=\"text\" id=\"archiveBoxArchiveDirectory\" name=\"archiveBoxArchiveDirectory\" size=\"100\" width=\"100\" style=\"margin-bottom:20px;margin-right:10px;font-size:110%;padding:5px;\" value=\"");
|
||||||
|
videoHtml.append(archiveBoxArchiveDirectory).append("/").append(youtubeVideo.getSnapshot()).append("/media/");
|
||||||
|
|
||||||
|
videoHtml.append("\"><br>");
|
||||||
|
}
|
||||||
|
videoHtml.append("<a target=\"_blank\" href=\"file://").append(archiveBoxArchiveDirectory).append("/").append(youtubeVideo.getSnapshot()).append("/media\">Directory</a>").append("<br>");
|
||||||
|
videoHtml.append("<br>\n<br>\n");
|
||||||
|
videoHtml.append("<br>\n");
|
||||||
|
videoHtml.append("<pre style=\"white-space: pre-wrap; border:1px solid black;max-width:600px;padding:10px;min-height:50px;\">");
|
||||||
|
videoHtml.append(youtubeVideo.getDescription().isBlank() ? "No description" : youtubeVideo.getDescription());
|
||||||
|
videoHtml.append("</pre>");
|
||||||
|
videoHtml.append("<h2>Comments</h2>");
|
||||||
|
youtubeVideo.getComments().forEach(co -> {
|
||||||
|
|
||||||
|
// private String id, parentId, text, author;
|
||||||
|
// private int timestamp;
|
||||||
|
videoHtml.append("<div style=\"margin-left:")
|
||||||
|
.append(co.dotCount() * 50)
|
||||||
|
.append("px;\">");
|
||||||
|
videoHtml.append("<h3>").append(co.getAuthor()).append("</h3>");
|
||||||
|
|
||||||
|
videoHtml.append("<span style=\"color:grey;font-size:80%;\">")
|
||||||
|
.append(Utils.DATE_FORMAT.format(new Date(co.getTimestamp() * 1000))).append("</span><br>\n");
|
||||||
|
videoHtml.append("<span style=\"color:grey;font-size:80%;\">").append(co.getId()).append(" ")
|
||||||
|
.append(co.getParentId()).append("</span><br>\n");
|
||||||
|
videoHtml.append("<pre style=\"white-space: pre-wrap;border:1px solid black;max-width:600px;padding:10px;min-height:50px;\">").append(co.getText()).append("</pre>");
|
||||||
|
videoHtml.append("</div>");
|
||||||
|
});
|
||||||
|
videoHtml.append("</body></html>");
|
||||||
|
singleVideo = videoHtml.toString();
|
||||||
|
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.singleVideo;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -16,7 +16,6 @@
|
|||||||
// along with this program; if not, write to the Free Software
|
// along with this program; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
package org.nanoboot.youtubedlfrontend;
|
package org.nanoboot.youtubedlfrontend;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,5 +31,5 @@ public class YoutubedlFrontendException extends RuntimeException {
|
|||||||
public YoutubedlFrontendException(String msg, Exception e) {
|
public YoutubedlFrontendException(String msg, Exception e) {
|
||||||
super(msg, e);
|
super(msg, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user