1
0
mirror of https://github.com/openeggbert/youtubedl-frontend.git synced 2025-03-14 21:23:27 +01:00

Renamed to youtubedl-frontend. Added many improvements

This commit is contained in:
Robert Vokac 2024-07-05 14:17:22 +02:00
parent 7318598d8d
commit c4dc2f650f
No known key found for this signature in database
GPG Key ID: C459E1E4B4A986BB
9 changed files with 317 additions and 107 deletions

View File

@ -1,2 +1,2 @@
# archivebox-youtube-helper
# youtubedl-frontend

30
pom.xml
View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
archivebox-youtube-helper: Tool generating html pages for Archive Box.
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
@ -29,12 +29,12 @@
</parent>
<groupId>org.nanoboot.tools</groupId>
<artifactId>archivebox-youtube-helper</artifactId>
<artifactId>youtubedl-frontend</artifactId>
<version>0.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>archivebox-youtube-helper</name>
<description>archivebox-youtube-helper</description>
<name>youtubedl-frontend</name>
<description>youtubedl-frontend</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@ -82,7 +82,7 @@
<configuration>
<archive>
<manifest>
<mainClass>org.nanoboot.archiveboxyoutubehelper.Main</mainClass>
<mainClass>org.nanoboot.youtubedlfrontend.Main</mainClass>
</manifest>
</archive>
<descriptorRefs>
@ -187,6 +187,21 @@
<artifactId>jackson-databind</artifactId>
<version>2.17.1</version>
</dependency>
<!-- <dependency>
<groupId>com.github.jai-imageio</groupId>
<artifactId>jai-imageio-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>com.github.jai-imageio</groupId>
<artifactId>jai-imageio-jpeg2000</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.sejda.imageio</groupId>
<artifactId>webp-imageio</artifactId>
<version>0.1.6</version>
</dependency>-->
</dependencies>
@ -201,6 +216,11 @@
<name>nanoboot-snapshots-repository</name>
<url>https://maven.nanoboot.org/snapshots</url>
</repository>
<repository>
<id>AsposeJavaAPI</id>
<name>Aspose Java API</name>
<url>https://repository.aspose.com/repo/</url>
</repository>
</repositories>
<pluginRepositories>

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// archiveboxyoutubehelper:
// youtubedlfrontend:
// Copyright (C) 2024 the original author or authors.
//
// This program is free software; you can redistribute it and/or
@ -17,7 +17,7 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
module archiveboxyoutubehelper {
module youtubedlfrontend {
requires lombok;
requires org.apache.logging.log4j;
requires org.json;
@ -25,4 +25,5 @@ module archiveboxyoutubehelper {
requires humble.video.noarch;
requires humble.video.all;
requires com.fasterxml.jackson.databind;
requires java.desktop;
}

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// archivebox-youtube-helper: Tool generating html pages for Archive Box.
// 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
@ -16,7 +16,7 @@
// 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.archiveboxyoutubehelper;
package org.nanoboot.youtubedlfrontend;
import java.io.File;
import java.io.IOException;
@ -37,48 +37,111 @@ import java.util.Map;
public class Main {
private static int iii = 0;
private static int videoNumberPerRow = 0;
public static final boolean ALWAYS_COMPUTE_METADATA = false;
public static final int VIDEOS_PER_ROW = 4;
private static int THUMBNAIL_WIDTH = 250;
private static int internalStaticVariableVideoNumberPerRow = 0;
public static boolean argAlwaysGenerateMetadata = true;
public static boolean argAlwaysGenerateHtmlFiles = true;
public static int argVideosPerRow = 4;
public static int THUMBNAIL_WIDTH = 250;
public static String argVideo;
public static String argChannel;
public static void main(String[] args) throws IOException, InterruptedException {
System.out.println("archiveboxyoutubehelper - HTML generator\n");
System.out.println("youtubedlfrontend - HTML generator\n");
args = "/rv/blupi/archivebox --_video UDpsz1yIwiw --always-generate-metadata 1 --always-generate-html-files 1 --videos-per-row 4".split(" ");
//args = "/rv/databig/youtube --_video UDpsz1yIwiw --always-generate-metadata 1 --always-generate-html-files 1 --videos-per-row 4".split(" ");
if (args.length == 0) {
args = new String[]{"/rv/blupi/archivebox"
//, "--video", "gPU_onaTzXs"
};
}
if (args.length < 1) {
System.err.println("At least one argument is expected, but the count of arguments is: " + args.length + ".");
System.exit(1);
}
argVideo = "";
argChannel = "";
if(args.length > 1) {
for(int i = 1;i<args.length;i++) {
String s = args[i];
if(s.equals("--video")) {
if (args.length > 0) {
for (int i = 0; i < args.length; i++) {
String arg = args[i];
if (i == 0 && !arg.startsWith(TWO_DASHES)) {
continue;
}
if (arg.equals("--video")) {
i++;
if(i >= args.length) {
throw new ArchiveBoxYoutubeHelperException("Fatal error: missing value for --video");
if (i >= args.length) {
throw new YoutubedlFrontendException("Fatal error: missing value for --video");
}
argVideo = args[i];
}
if(s.equals("--channel")) {
if (arg.equals("--channel")) {
i++;
if(i >= args.length) {
throw new ArchiveBoxYoutubeHelperException("Fatal error: missing value for --channel");
if (i >= args.length) {
throw new YoutubedlFrontendException("Fatal error: missing value for --channel");
}
argChannel = args[i];
}
if (arg.equals("--videos-per-row")) {
i++;
if (i >= args.length) {
throw new YoutubedlFrontendException("Fatal error: missing value for --videos-per-row");
}
argVideosPerRow = Integer.parseInt(args[i]);
if (argVideosPerRow < 2) {
argVideosPerRow = 0;
}
}
if (arg.equals("--always-generate-metadata")) {
i++;
if (i >= args.length) {
throw new YoutubedlFrontendException("Fatal error: missing value for --always-generate-metadata");
}
String s = args[i];
switch (s) {
case "1":
argAlwaysGenerateMetadata = true;
break;
case "true":
argAlwaysGenerateMetadata = true;
break;
case "0":
argAlwaysGenerateMetadata = false;
break;
case "false":
argAlwaysGenerateMetadata = false;
break;
default:
throw new YoutubedlFrontendException("Invalid value for --always-generate-metadata");
};
}
if (arg.equals("--always-generate-html-files")) {
i++;
if (i >= args.length) {
throw new YoutubedlFrontendException("Fatal error: missing value for --always-generate-html-files");
}
String s = args[i];
switch (s) {
case "1":
argAlwaysGenerateHtmlFiles = true;
break;
case "true":
argAlwaysGenerateHtmlFiles = true;
break;
case "0":
argAlwaysGenerateHtmlFiles = false;
break;
case "false":
argAlwaysGenerateHtmlFiles = false;
break;
default:
throw new YoutubedlFrontendException("Invalid value for --always-generate-html-files");
};
}
}
}
File archiveBoxRootDirectory = new File(args[0]);
String workingDirectory = args.length > 0 && !args[0].startsWith(TWO_DASHES) ? args[0] : new File(".").getAbsolutePath();
File archiveBoxRootDirectory = new File(workingDirectory);
File archiveBoxArchiveDirectory = new File(archiveBoxRootDirectory, "archive");
int i = 0;
List<YoutubeVideo> youtubeVideos = new ArrayList<>();
@ -90,13 +153,13 @@ public class Main {
continue;
}
YoutubeVideo youtubeVideo = new YoutubeVideo(mediaDirectory);
if(!Main.argVideo.isBlank() && !youtubeVideo.getId().equals(Main.argVideo)) {
continue;
}
if(!argVideo.isBlank() && !youtubeVideo.getId().equals(argVideo)) {
if (!Main.argVideo.isBlank() && !youtubeVideo.getId().equals(Main.argVideo)) {
continue;
}
if(!argChannel.isBlank() && !youtubeVideo.getChannelId().equals(argChannel)) {
if (!argVideo.isBlank() && !youtubeVideo.getId().equals(argVideo)) {
continue;
}
if (!argChannel.isBlank() && !youtubeVideo.getChannelId().equals(argChannel)) {
continue;
}
i++;
@ -121,14 +184,18 @@ public class Main {
YoutubeVideo previousVideo = null;
YoutubeVideo nextVideo = null;
YoutubeVideo currentVideo = null;
for(int j = 0; j<youtubeVideos.size(); j++) {
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 (j < (youtubeVideos.size() - 1)) {
nextVideo = youtubeVideos.get(j + 1);
}
if (previousVideo != null) {
currentVideo.setPreviousVideoId(previousVideo.getId());
}
if (nextVideo != null) {
currentVideo.setNextVideoId(nextVideo.getId());
}
if(previousVideo != null) currentVideo.setPreviousVideoId(previousVideo.getId());
if(nextVideo != null) currentVideo.setNextVideoId(nextVideo.getId());
}
Map<String, String> channelUrls = new HashMap<>();
List<String> channels = new ArrayList<>();
@ -173,21 +240,24 @@ public class Main {
channels.forEach(c -> {
sb.append("<h1>").append(c).append("</h1>\n");
sb.append("<div style=\"max-width:").append((Main.THUMBNAIL_WIDTH + 20) * Main.VIDEOS_PER_ROW).append("px\"><a href =\"").append(channelUrls.get(c)).append("\">").append(channelUrls.get(c)).append("</a><div class=\"videos\">");
sb.append("<div style=\"max-width:").append((Main.THUMBNAIL_WIDTH + 20) * Main.argVideosPerRow).append("px\"><a href =\"").append(channelUrls.get(c)).append("\">").append(channelUrls.get(c)).append("</a><div class=\"videos\">");
iii = 0;
videoNumberPerRow = 0;
internalStaticVariableVideoNumberPerRow = 0;
sb.append("<table>\n");
youtubeVideos.stream().filter(v -> c.equals(v.getChannelName())).forEach(z -> {
iii++;
if (videoNumberPerRow == 0) {
if (internalStaticVariableVideoNumberPerRow == 0) {
sb.append("<tr>");
}
videoNumberPerRow++;
internalStaticVariableVideoNumberPerRow++;
sb.append("<td><div class=\"box\"><table style=\"margin:5px;max-width:")
.append(THUMBNAIL_WIDTH)
.append("px;\">\n<tr><td><a href=\"videos/" + z.getId() + ".html\" target=\"_blank\"><img src=\"archive/");
sb.append(z.getSnapshot());
sb.append("/media/thumbnail.jpg\" width=\"")
sb
.append("/media/mini-thumbnail.")
.append(z.getMiniThumbnailFormat())
.append("\" width=\"")
.append(THUMBNAIL_WIDTH)
.append("\"></a></td></tr>\n");
sb.append("<tr><td><b style=\"font-size:90%;\">").append(z.getTitle()).append("</b></td></tr>\n");
@ -199,14 +269,14 @@ public class Main {
.append("</td></tr>\n");
z.setNumber(iii);
sb.append("</table></div></td>\n");
if (videoNumberPerRow == VIDEOS_PER_ROW) {
if (internalStaticVariableVideoNumberPerRow == argVideosPerRow) {
sb.append("<tr>");
videoNumberPerRow = 0;
internalStaticVariableVideoNumberPerRow = 0;
}
File videoHtmlFile = new File(videosDirectory, z.getId() + ".html");
// if(videoHtmlFile.exists()) {
//
// }
if(!videoHtmlFile.exists() || argAlwaysGenerateHtmlFiles) {
{
StringBuilder sb2 = new StringBuilder("""
<!DOCTYPE html>
@ -214,8 +284,8 @@ public class Main {
<head>
<link rel="icon" type="image/x-icon" href="../favicon.ico" sizes="16x16">
<title>"""
+z.getTitle() +
"""
+ z.getTitle()
+ """
</title>
<style>
body {padding:20px;}
@ -230,54 +300,78 @@ public class Main {
);
String finalUrl = "https://www.youtube.com/watch?v=" + z.getId();
sb2.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><br>");
sb2.append("<a target=\"_blank\" href=\"").append(finalUrl).append("\">");
sb2.append(finalUrl).append("</a>").append("<br>");
sb2.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");
sb2.append("<a target=\"_blank\" href=\"").append(finalUrl).append("\">");
sb2.append(finalUrl).append("</a>").append("<br>\n");
String videoLocalUrl = "";
try {
videoLocalUrl = "file:///" + archiveBoxRootDirectory.getAbsolutePath() + "/archive/" + z.getSnapshot() + "/media/" + URLEncoder.encode(z.getVideoFileName(), StandardCharsets.UTF_8.toString()).replace("+", "%20");
} catch (UnsupportedEncodingException ex) {
throw new ArchiveBoxYoutubeHelperException(ex.getMessage());
throw new YoutubedlFrontendException(ex.getMessage());
}
if(!z.getVideoFileName().endsWith(".mkv")) {
try {
sb2.append("<video src=\"");
sb2.append("../archive/" + z.getSnapshot() + "/media/" + URLEncoder.encode(z.getVideoFileName(), StandardCharsets.UTF_8.toString()).replace("+", "%20"));
sb2.append("""
" controls width=\"800\">
Your browser does not support the video tag.
</video><br>
""");
} catch (UnsupportedEncodingException ex) {
throw new YoutubedlFrontendException(ex.getMessage());
}
} else {
sb2.append("<a target=\"_blank\" href=\"").append(videoLocalUrl).append("\">");
sb2.append("<img style=\"margin:10px;width:600px;\" src=\"../archive/")
.append(z.getSnapshot())
.append("/media/thumbnail.jpg\"></a><br>");
.append("/media/thumbnail.")
.append(z.getThumbnailFormat())
.append("\"></a><br>\n");
}
sb2.append("<span style=\"font-size:160%;font-weight:bold;\">").append(z.getTitle()).append("</span>");
sb2.append("<br><br>");
sb2.append("<br>\n<br>\n");
sb2.append("#").append(z.getNumber()).append("&nbsp;&nbsp;&nbsp;");
if(z.getPreviousVideoId() != null) sb2.append("<a href=\"./").append(z.getPreviousVideoId()).append(".html\">");
if (z.getPreviousVideoId() != null) {
sb2.append("<a href=\"./").append(z.getPreviousVideoId()).append(".html\">");
}
sb2.append("Back");
if(z.getPreviousVideoId() != null) sb2.append("</a>");
if (z.getPreviousVideoId() != null) {
sb2.append("</a>");
}
sb2.append("&nbsp;&nbsp;&nbsp;");
if(z.getNextVideoId()!= null) sb2.append("<a href=\"./").append(z.getNextVideoId()).append(".html\">");
if (z.getNextVideoId() != null) {
sb2.append("<a href=\"./").append(z.getNextVideoId()).append(".html\">");
}
sb2.append("Next");
if(z.getNextVideoId() != null) sb2.append("</a>");
if (z.getNextVideoId() != null) {
sb2.append("</a>");
}
sb2.append(" ");
sb2.append("<br>");
sb2.append("<br>\n");
sb2.append("<pre style=\"white-space: pre-wrap; border:1px solid black;max-width:600px;padding:10px;min-height:50px;\">");
sb2.append(z.getDescription().isBlank() ? "No description" : z.getDescription());
sb2.append("</pre>");
sb2.append("<h2>Comments</h2>");
z.getComments().forEach(co -> {
// private String id, parentId, text, author;
// private int timestamp;
sb2.append("<div style=\"margin-left:")
.append(co.dotCount() * 50)
.append("px;\">");
sb2.append("<div style=\"margin-left:")
.append(co.dotCount() * 50)
.append("px;\">");
sb2.append("<h3>").append(co.getAuthor()).append("</h3>");
sb2.append("<span style=\"color:grey;font-size:80%;\">")
.append(Utils.DATE_FORMAT.format(new Date(co.getTimestamp() * 1000))).append("</span><br>");
.append(Utils.DATE_FORMAT.format(new Date(co.getTimestamp() * 1000))).append("</span><br>\n");
sb2.append("<span style=\"color:grey;font-size:80%;\">")
.append(co.getId() + " " + co.getParentId()).append("</span><br>");
.append(co.getId() + " " + co.getParentId()).append("</span><br>\n");
sb2.append("<pre style=\"white-space: pre-wrap;border:1px solid black;max-width:600px;padding:10px;min-height:50px;\">").append(co.getText()).append("</pre>");
sb2.append("</div>");
});
// private String id;
//
// private String title;
@ -292,18 +386,17 @@ sb2.append("<div style=\"margin-left:")
// private String description;
// private String thumbnail;
// private List<YoutubeComment> comments = new ArrayList<>();
sb2.append("</body></html>");
Utils.writeTextToFile(sb2.toString(), videoHtmlFile);
String singleVideo = sb2.toString();
//singleVideo.replace("<br>\n", "<br>\n\n");
Utils.writeTextToFile(singleVideo, videoHtmlFile);
}
}
});
if (videoNumberPerRow < VIDEOS_PER_ROW) {
if (internalStaticVariableVideoNumberPerRow < argVideosPerRow) {
sb.append("<tr>");
}
sb.append("<table>\n");
sb.append("</table>\n");
sb.append("</div></div>");
});
sb.append("""
@ -317,5 +410,6 @@ sb2.append("<div style=\"margin-left:")
System.out.println("[Warning] Snapshots without videos:");
YoutubeVideo.missingYoutubeVideos.forEach(s -> System.out.println(s));
}
private static final String TWO_DASHES = "--";
}

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// archivebox-youtube-helper: Tool generating html pages for Archive Box.
// 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
@ -16,7 +16,7 @@
// 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.archiveboxyoutubehelper;
package org.nanoboot.youtubedlfrontend;
import dev.mccue.guava.hash.Hashing;
import java.io.BufferedReader;
@ -99,7 +99,7 @@ public class Utils {
return result;//.substring(0, result.length() - 1);
}
public static void copyFile(File originalFile, File copiedFile) throws ArchiveBoxYoutubeHelperException {
public static void copyFile(File originalFile, File copiedFile) throws YoutubedlFrontendException {
Path originalPath = originalFile.toPath();
Path copied = new File(copiedFile, originalFile.getName()).toPath();
@ -107,7 +107,7 @@ public class Utils {
Files.copy(originalPath, copied, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ex) {
ex.printStackTrace();
throw new ArchiveBoxYoutubeHelperException("Copying file failed: " + originalFile.getAbsolutePath());
throw new YoutubedlFrontendException("Copying file failed: " + originalFile.getAbsolutePath());
}
}
@ -117,7 +117,7 @@ public class Utils {
fileWriter = new FileWriter(file);
} catch (IOException ex) {
ex.printStackTrace();
throw new ArchiveBoxYoutubeHelperException("Writing to file failed: " + file.getName(), ex);
throw new YoutubedlFrontendException("Writing to file failed: " + file.getName(), ex);
}
PrintWriter printWriter = new PrintWriter(fileWriter);
printWriter.print(text);
@ -131,7 +131,7 @@ public class Utils {
try {
return new String(Files.readAllBytes(Paths.get(file.getAbsolutePath())));
} catch (IOException ex) {
throw new ArchiveBoxYoutubeHelperException("Reading file failed: " + file.getName(), ex);
throw new YoutubedlFrontendException("Reading file failed: " + file.getName(), ex);
}
}
@ -141,7 +141,7 @@ public class Utils {
InputStream inputStream = clazz.getResourceAsStream(fileName);
return readFromInputStream(inputStream);
} catch (IOException ex) {
throw new ArchiveBoxYoutubeHelperException("Reading file failed: " + fileName, ex);
throw new YoutubedlFrontendException("Reading file failed: " + fileName, ex);
}
}
@ -164,7 +164,7 @@ public class Utils {
return dev.mccue.guava.io.Files.hash(file, Hashing.sha512()).toString();
} catch (IOException ex) {
System.err.println(ex.getMessage());
throw new ArchiveBoxYoutubeHelperException(ex.getMessage());
throw new YoutubedlFrontendException(ex.getMessage());
}
}

View File

@ -2,7 +2,7 @@
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package org.nanoboot.archiveboxyoutubehelper;
package org.nanoboot.youtubedlfrontend;
import java.util.ArrayList;
import java.util.Collections;

View File

@ -2,7 +2,7 @@
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package org.nanoboot.archiveboxyoutubehelper;
package org.nanoboot.youtubedlfrontend;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@ -21,6 +21,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Properties;
import javax.imageio.ImageIO;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@ -50,6 +51,7 @@ public class YoutubeVideo implements Comparable<YoutubeVideo> {
private long timestamp;
private String description;
private String thumbnail;
private String miniThumbnail;
private List<YoutubeComment> comments = new ArrayList<>();
private String previousVideoId = null;
private String nextVideoId = null;
@ -60,7 +62,7 @@ public class YoutubeVideo implements Comparable<YoutubeVideo> {
public YoutubeVideo(File mediaDirectory) throws InterruptedException, IOException {
File metadataFile = new File(mediaDirectory, "metadata");
if (!Main.ALWAYS_COMPUTE_METADATA && metadataFile.exists()) {
if (!Main.argAlwaysGenerateMetadata && metadataFile.exists()) {
YoutubeVideo yv = new YoutubeVideo();
//new ObjectMapper().readValue(Utils.readTextFromFile(metadataFile), YoutubeVideo.class);
@ -86,6 +88,7 @@ public class YoutubeVideo implements Comparable<YoutubeVideo> {
timestamp = Long.parseLong(properties.getProperty("timestamp"));
description = properties.getProperty("description");
thumbnail = properties.getProperty("thumbnail");
miniThumbnail = properties.getProperty("miniThumbnail");
comments = new ArrayList<>();
JSONArray ja = new JSONArray(properties.getProperty("comments"));
ja.forEach(o -> {
@ -96,7 +99,7 @@ public class YoutubeVideo implements Comparable<YoutubeVideo> {
comments.add(new ObjectMapper().readValue(toString, YoutubeComment.class));
} catch (JsonProcessingException ex) {
throw new ArchiveBoxYoutubeHelperException(ex.getMessage());
throw new YoutubedlFrontendException(ex.getMessage());
}
}
);
@ -119,17 +122,82 @@ public class YoutubeVideo implements Comparable<YoutubeVideo> {
if (thumbnail == null) {
thumbnail = "";
}
File thumbnailFile = new File(mediaDirectory, "thumbnail.jpg");
if (!thumbnailFile.exists() && thumbnail != null) {
try (BufferedInputStream in = new BufferedInputStream(new URL(thumbnail).openStream()); FileOutputStream fileOutputStream = new FileOutputStream(thumbnailFile.getAbsolutePath())) {
byte dataBuffer[] = new byte[1024];
int bytesRead;
while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
fileOutputStream.write(dataBuffer, 0, bytesRead);
JSONArray thumbnails = jsonObject.getJSONArray("thumbnails");
for (int i = 0; i < thumbnails.length(); i++) {
JSONObject o = (JSONObject) thumbnails.get(i);
if (!o.has("width")) {
continue;
} else {
int width = o.getInt("width");
if (width < (((double)Main.THUMBNAIL_WIDTH) * 0.8d)) {
continue;
}
} catch (IOException e) {
System.out.println(e.getMessage());
miniThumbnail = o.getString("url");
break;
}
}
File thumbnailFile = new File(mediaDirectory, "thumbnail." + getThumbnailFormat());
File miniThumbnailFile = new File(mediaDirectory, "mini-thumbnail." + getMiniThumbnailFormat());
// new File(mediaDirectory, "thumbnail.jpg").delete();
// new File(mediaDirectory, "mini-thumbnail.jpg").delete();
// new File(mediaDirectory, "thumbnail.webp").delete();
// new File(mediaDirectory, "mini-thumbnail.webp").delete();
if (thumbnail != null) {
if (!thumbnailFile.exists()) {
try (BufferedInputStream in = new BufferedInputStream(new URL(thumbnail).openStream()); FileOutputStream fileOutputStream = new FileOutputStream(thumbnailFile.getAbsolutePath())) {
byte dataBuffer[] = new byte[1024];
int bytesRead;
while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
fileOutputStream.write(dataBuffer, 0, bytesRead);
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
if (!miniThumbnailFile.exists()) {
try (BufferedInputStream in = new BufferedInputStream(new URL(miniThumbnail).openStream()); FileOutputStream fileOutputStream = new FileOutputStream(miniThumbnailFile.getAbsolutePath())) {
byte dataBuffer[] = new byte[1024];
int bytesRead;
while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
fileOutputStream.write(dataBuffer, 0, bytesRead);
}
} catch (IOException e) {
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();
@ -198,6 +266,7 @@ public class YoutubeVideo implements Comparable<YoutubeVideo> {
properties.put("timestamp", String.valueOf(timestamp));
properties.put("description", description);
properties.put("thumbnail", thumbnail);
properties.put("minithumbnail", miniThumbnail);
properties.put("comments", new JSONArray(comments).toString());
if (previousVideoId != null) {
properties.put("previousVideoId", previousVideoId);
@ -225,6 +294,32 @@ public class YoutubeVideo implements Comparable<YoutubeVideo> {
}
public String getThumbnailFormat() {
return getExtensionFromUrl(thumbnail);
}
public String getMiniThumbnailFormat() {
return getExtensionFromUrl(miniThumbnail);
}
private String getExtensionFromUrl(String url) {
String result = url.substring(url
.lastIndexOf(".") + 1);
int questionMarkIndex = 0;
for(int i = 0;i<result.length();i++) {
char ch = result.charAt(i);
if(ch != '?') {
continue;
} else {
questionMarkIndex = i;
}
}
if(questionMarkIndex > 0) {
result = result.substring(0, questionMarkIndex);
}
return result;
}
/**
* Pretty prints a timestamp (in {@link Global.NO_PTS} units) into a string.
*

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////////////////////
// archivebox-youtube-helper: Tool generating html pages for Archive Box.
// 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
@ -17,19 +17,19 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
///////////////////////////////////////////////////////////////////////////////////////////////
package org.nanoboot.archiveboxyoutubehelper;
package org.nanoboot.youtubedlfrontend;
/**
* @author <a href="mailto:robertvokac@nanoboot.org">Robert Vokac</a>
* @since 0.0.0
*/
public class ArchiveBoxYoutubeHelperException extends RuntimeException {
public class YoutubedlFrontendException extends RuntimeException {
public ArchiveBoxYoutubeHelperException(String msg) {
public YoutubedlFrontendException(String msg) {
super(msg);
}
public ArchiveBoxYoutubeHelperException(String msg, Exception e) {
public YoutubedlFrontendException(String msg, Exception e) {
super(msg, e);
}