/////////////////////////////////////////////////////////////////////////////////////////////// // archivebox-youtube-helper: 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.archiveboxyoutubehelper; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author Robert Vokac * @since 0.0.0 */ 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; public static String argVideo; public static String argChannel; public static void main(String[] args) throws IOException, InterruptedException { System.out.println("archiveboxyoutubehelper - HTML generator\n"); 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) { throw new ArchiveBoxYoutubeHelperException("Fatal error: missing value for --video"); } argVideo = args[i]; } if(s.equals("--channel")) { i++; if(i >= args.length) { throw new ArchiveBoxYoutubeHelperException("Fatal error: missing value for --channel"); } argChannel = args[i]; } } } File archiveBoxRootDirectory = new File(args[0]); File archiveBoxArchiveDirectory = new File(archiveBoxRootDirectory, "archive"); int i = 0; List 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); if(!Main.argVideo.isBlank() && !youtubeVideo.getId().equals(Main.argVideo)) { continue; } if(!argVideo.isBlank() && !youtubeVideo.getId().equals(argVideo)) { continue; } if(!argChannel.isBlank() && !youtubeVideo.getChannelId().equals(argChannel)) { continue; } i++; System.out.println("\n\nFound video #" + i); 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("comments = " + youtubeVideo.getComments()); youtubeVideos.add(youtubeVideo); } Collections.sort(youtubeVideos); YoutubeVideo previousVideo = null; YoutubeVideo nextVideo = null; YoutubeVideo currentVideo = null; for(int j = 0; j channelUrls = new HashMap<>(); List channels = new ArrayList<>(); youtubeVideos.stream().forEach(c -> { final String channelName_ = c.getChannelName(); if (channelName_ != null && !channelUrls.containsKey(c.getChannelName())) { channelUrls.put(channelName_, c.getChannelUrl()); channels.add(channelName_); } }); StringBuilder sb = new StringBuilder(); File videosHtmlFile = new File(archiveBoxRootDirectory, "videos.html"); File videosDirectory = new File(archiveBoxRootDirectory, "videos"); if (!videosDirectory.exists()) { videosDirectory.mkdir(); } sb.append(""" Youtube videos """); channels.forEach(c -> { sb.append("

").append(c).append("

\n"); sb.append("
").append(channelUrls.get(c)).append("
"); iii = 0; videoNumberPerRow = 0; sb.append("\n"); youtubeVideos.stream().filter(v -> c.equals(v.getChannelName())).forEach(z -> { iii++; if (videoNumberPerRow == 0) { sb.append(""); } videoNumberPerRow++; sb.append("\n"); if (videoNumberPerRow == VIDEOS_PER_ROW) { sb.append(""); videoNumberPerRow = 0; } File videoHtmlFile = new File(videosDirectory, z.getId() + ".html"); // if(videoHtmlFile.exists()) { // // } { StringBuilder sb2 = new StringBuilder(""" """ +z.getTitle() + """ """ ); String finalUrl = "https://www.youtube.com/watch?v=" + z.getId(); sb2.append("

"); sb2.append(""); sb2.append(finalUrl).append("").append("
"); 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()); } sb2.append(""); sb2.append("
"); sb2.append("").append(z.getTitle()).append(""); sb2.append("

"); sb2.append("#").append(z.getNumber()).append("   "); if(z.getPreviousVideoId() != null) sb2.append(""); sb2.append("Back"); if(z.getPreviousVideoId() != null) sb2.append(""); sb2.append("   "); if(z.getNextVideoId()!= null) sb2.append(""); sb2.append("Next"); if(z.getNextVideoId() != null) sb2.append(""); sb2.append(" "); sb2.append("
"); sb2.append("
");
                    sb2.append(z.getDescription().isBlank() ? "No description" : z.getDescription());
                    sb2.append("
"); sb2.append("

Comments

"); z.getComments().forEach(co -> { // private String id, parentId, text, author; // private int timestamp; sb2.append("
"); sb2.append("

").append(co.getAuthor()).append("

"); sb2.append("") .append(Utils.DATE_FORMAT.format(new Date(co.getTimestamp() * 1000))).append("
"); sb2.append("") .append(co.getId() + " " + co.getParentId()).append("
"); sb2.append("
").append(co.getText()).append("
"); sb2.append("
"); }); // 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 comments = new ArrayList<>(); sb2.append(""); Utils.writeTextToFile(sb2.toString(), videoHtmlFile); } }); if (videoNumberPerRow < VIDEOS_PER_ROW) { sb.append(""); } sb.append("
\n\n"); sb.append("\n"); String uploadDate = z.getUploadDate(); uploadDate = uploadDate.substring(0, 4) + "-" + uploadDate.substring(4, 6) + "-" + uploadDate.substring(6, 8); sb.append("\n"); z.setNumber(iii); sb.append("
").append(z.getTitle()).append("
").append(uploadDate).append(" •︎ ").append(z.getVideoDuration()) .append(" •︎ ") .append("#").append(iii) .append("
\n"); sb.append(""); }); sb.append(""" """); Utils.writeTextToFile(sb.toString(), videosHtmlFile); System.out.println("[Warning] Snapshots without videos:"); YoutubeVideo.missingYoutubeVideos.forEach(s -> System.out.println(s)); } }