work on send file
This commit is contained in:
@@ -44,11 +44,17 @@ dependencies {
|
||||
implementation('net.synedra:validatorfx:0.5.0') {
|
||||
exclude group: 'org.openjfx'
|
||||
}
|
||||
//For upload files
|
||||
implementation 'com.sparkjava:spark-core:2.9.4'
|
||||
implementation 'org.jcodec:jcodec:0.2.5'
|
||||
implementation 'org.jcodec:jcodec-javase:0.2.5'
|
||||
implementation 'com.mpatric:mp3agic:0.9.1' //for mp3
|
||||
implementation 'org.json:json:20231013'
|
||||
implementation 'org.kordamp.ikonli:ikonli-javafx:12.3.1'
|
||||
implementation 'org.kordamp.bootstrapfx:bootstrapfx-core:0.4.0'
|
||||
implementation('eu.hansolo:tilesfx:21.0.3') {
|
||||
exclude group: 'org.openjfx'
|
||||
|
||||
}
|
||||
|
||||
test {
|
||||
|
||||
@@ -11,6 +11,12 @@ module org.to.telegramfinalproject {
|
||||
requires eu.hansolo.tilesfx;
|
||||
requires org.json;
|
||||
requires java.sql;
|
||||
requires javax.servlet.api;
|
||||
requires spark.core;
|
||||
requires java.desktop;
|
||||
requires jcodec;
|
||||
requires mp3agic;
|
||||
requires jcodec.javase;
|
||||
opens org.to.telegramfinalproject to javafx.fxml;
|
||||
exports org.to.telegramfinalproject;
|
||||
exports org.to.telegramfinalproject.Client;
|
||||
|
||||
@@ -66,6 +66,87 @@ public class MessageDatabase {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static boolean insertMessageTx(Connection conn, UUID messageId, UUID senderId, UUID receiverId,
|
||||
String receiverType, String content, String messageType) throws SQLException {
|
||||
String sql = "INSERT INTO messages (message_id, sender_id, receiver_type, receiver_id, content, message_type) " +
|
||||
"VALUES (?, ?, ?, ?, ?, ?)";
|
||||
try (PreparedStatement ps = conn.prepareStatement(sql)) {
|
||||
ps.setObject(1, messageId);
|
||||
ps.setObject(2, senderId);
|
||||
ps.setString(3, receiverType);
|
||||
ps.setObject(4, receiverId);
|
||||
if (content == null || content.isBlank()) ps.setNull(5, java.sql.Types.VARCHAR); else ps.setString(5, content);
|
||||
ps.setString(6, messageType);
|
||||
return ps.executeUpdate() > 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean insertAttachmentsTx(Connection conn, UUID messageId, List<FileAttachment> attachments) throws SQLException {
|
||||
if (attachments == null || attachments.isEmpty()) return true;
|
||||
String sql = """
|
||||
INSERT INTO message_attachments
|
||||
(attachment_id, message_id, file_url, file_type, file_name, file_size, mime_type, width, height, duration_seconds, thumbnail_url)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""";
|
||||
try (PreparedStatement ps = conn.prepareStatement(sql)) {
|
||||
for (FileAttachment att : attachments) {
|
||||
ps.setObject(1, UUID.randomUUID());
|
||||
ps.setObject(2, messageId);
|
||||
ps.setString(3, att.getFileUrl());
|
||||
ps.setString(4, att.getFileType()); // IMAGE/VIDEO/AUDIO/FILE/GIF/STICKER
|
||||
ps.setString(5, att.getFileName());
|
||||
if (att.getFileSize() != null) ps.setLong(6, att.getFileSize()); else ps.setNull(6, java.sql.Types.BIGINT);
|
||||
ps.setString(7, att.getMimeType());
|
||||
if (att.getWidth() != null) ps.setInt(8, att.getWidth()); else ps.setNull(8, java.sql.Types.INTEGER);
|
||||
if (att.getHeight() != null) ps.setInt(9, att.getHeight()); else ps.setNull(9, java.sql.Types.INTEGER);
|
||||
if (att.getDurationSeconds() != null) ps.setInt(10, att.getDurationSeconds()); else ps.setNull(10, java.sql.Types.INTEGER);
|
||||
ps.setString(11, att.getThumbnailUrl());
|
||||
ps.addBatch();
|
||||
}
|
||||
ps.executeBatch();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static boolean saveMessageWithOptionalAttachments(UUID messageId, UUID senderId, UUID receiverId,
|
||||
String receiverType, String content, String messageType,
|
||||
List<FileAttachment> attachments) {
|
||||
Connection conn = null;
|
||||
try {
|
||||
conn = ConnectionDb.connect();
|
||||
conn.setAutoCommit(false);
|
||||
|
||||
boolean isText = "TEXT".equalsIgnoreCase(messageType);
|
||||
if (isText) {
|
||||
if (attachments != null && !attachments.isEmpty())
|
||||
throw new IllegalArgumentException("TEXT must not have attachments");
|
||||
if (content == null || content.isBlank())
|
||||
throw new IllegalArgumentException("TEXT must have non-empty content");
|
||||
} else {
|
||||
if (attachments == null || attachments.isEmpty())
|
||||
throw new IllegalArgumentException("Non-TEXT must have at least one attachment");
|
||||
}
|
||||
|
||||
insertMessageTx(conn, messageId, senderId, receiverId, receiverType, content, messageType);
|
||||
if (!isText) insertAttachmentsTx(conn, messageId, attachments);
|
||||
|
||||
conn.commit();
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
if (conn != null) try { conn.rollback(); } catch (SQLException ignored) {}
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
try { conn.setAutoCommit(true); } catch (SQLException ignored) {}
|
||||
try { conn.close(); } catch (SQLException ignored) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void markGloballyDeleted(UUID chatId) {
|
||||
String sql = "UPDATE messages SET is_deleted_globally = true WHERE receiver_id = ? AND receiver_type = 'private'";
|
||||
try (Connection conn = ConnectionDb.connect(); PreparedStatement ps = conn.prepareStatement(sql)) {
|
||||
@@ -393,14 +474,21 @@ public class MessageDatabase {
|
||||
AND d.message_id IS NULL
|
||||
AND m.is_deleted_globally = FALSE
|
||||
AND (
|
||||
(m.receiver_type = 'private' AND m.receiver_id = ?)
|
||||
(m.receiver_type = 'private' AND EXISTS (
|
||||
SELECT 1
|
||||
FROM private_chat pc
|
||||
WHERE pc.chat_id = m.receiver_id
|
||||
AND (pc.user1_id = ? OR pc.user2_id = ?)
|
||||
)) -- فقط دو تا پرانتز
|
||||
OR
|
||||
(m.receiver_type = 'group' AND EXISTS (
|
||||
SELECT 1 FROM group_members gm WHERE gm.group_id = m.receiver_id AND gm.user_id = ?
|
||||
SELECT 1 FROM group_members gm
|
||||
WHERE gm.group_id = m.receiver_id AND gm.user_id = ?
|
||||
))
|
||||
OR
|
||||
(m.receiver_type = 'channel' AND EXISTS (
|
||||
SELECT 1 FROM channel_subscribers cs WHERE cs.channel_id = m.receiver_id AND cs.user_id = ?
|
||||
SELECT 1 FROM channel_subscribers cs
|
||||
WHERE cs.channel_id = m.receiver_id AND cs.user_id = ?
|
||||
))
|
||||
)
|
||||
ORDER BY m.send_at DESC
|
||||
@@ -409,15 +497,17 @@ public class MessageDatabase {
|
||||
try (Connection conn = ConnectionDb.connect();
|
||||
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||
|
||||
stmt.setObject(1, userId); // for message_receipts
|
||||
stmt.setObject(2, userId); // for deleted_messages
|
||||
stmt.setObject(3, userId); // for private messages
|
||||
stmt.setObject(4, userId); // for group members
|
||||
stmt.setObject(5, userId); // for channel subscribers
|
||||
int i = 1;
|
||||
stmt.setObject(i++, userId); // 1) receipts
|
||||
stmt.setObject(i++, userId); // 2) deleted
|
||||
stmt.setObject(i++, userId); // 3) private: pc.user1_id
|
||||
stmt.setObject(i++, userId); // 4) private: pc.user2_id
|
||||
stmt.setObject(i++, userId); // 5) group: gm.user_id
|
||||
stmt.setObject(i++, userId); // 6) channel: cs.user_id
|
||||
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
try (ResultSet rs = stmt.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
Message message = new Message(
|
||||
messages.add(new Message(
|
||||
UUID.fromString(rs.getString("message_id")),
|
||||
rs.getObject("sender_id") != null ? UUID.fromString(rs.getString("sender_id")) : null,
|
||||
rs.getString("receiver_type"),
|
||||
@@ -432,11 +522,9 @@ public class MessageDatabase {
|
||||
rs.getObject("original_message_id") != null ? UUID.fromString(rs.getString("original_message_id")) : null,
|
||||
rs.getObject("forwarded_by") != null ? UUID.fromString(rs.getString("forwarded_by")) : null,
|
||||
rs.getObject("forwarded_from") != null ? UUID.fromString(rs.getString("forwarded_from")) : null
|
||||
);
|
||||
|
||||
messages.add(message);
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -448,30 +536,34 @@ public class MessageDatabase {
|
||||
|
||||
public static List<FileAttachment> getAttachments(UUID messageId) {
|
||||
List<FileAttachment> attachments = new ArrayList<>();
|
||||
String sql = "SELECT file_url, file_type FROM message_attachments WHERE message_id = ?";
|
||||
|
||||
String sql = "SELECT file_url, file_type, file_name, file_size, mime_type, width, height, duration_seconds, thumbnail_url " +
|
||||
"FROM message_attachments WHERE message_id = ? ORDER BY uploaded_at";
|
||||
try (Connection conn = ConnectionDb.connect();
|
||||
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||
|
||||
stmt.setObject(1, messageId);
|
||||
ResultSet rs = stmt.executeQuery();
|
||||
|
||||
while (rs.next()) {
|
||||
attachments.add(new FileAttachment(
|
||||
rs.getString("file_url"),
|
||||
rs.getString("file_type")
|
||||
rs.getString("file_type"),
|
||||
rs.getString("file_name"),
|
||||
(Long) rs.getObject("file_size"),
|
||||
rs.getString("mime_type"),
|
||||
(Integer) rs.getObject("width"),
|
||||
(Integer) rs.getObject("height"),
|
||||
(Integer) rs.getObject("duration_seconds"),
|
||||
rs.getString("thumbnail_url")
|
||||
));
|
||||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return attachments;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static LocalDateTime getLastMessageTimeBetween(UUID user1, UUID user2, String type) {
|
||||
String sql = """
|
||||
SELECT MAX(send_at) FROM messages
|
||||
|
||||
@@ -1,14 +1,44 @@
|
||||
package org.to.telegramfinalproject.Models;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class FileAttachment {
|
||||
private String fileUrl;
|
||||
private String fileType;
|
||||
private String fileType; // IMAGE, VIDEO, AUDIO, FILE, GIF, STICKER
|
||||
private String fileName;
|
||||
private Long fileSize;
|
||||
private String mimeType; // MIME type (example: image/png)
|
||||
private Integer width;
|
||||
private Integer height;
|
||||
private Integer durationSeconds; //time for video and audio
|
||||
private String thumbnailUrl;
|
||||
|
||||
public FileAttachment(String fileUrl,
|
||||
String fileType,
|
||||
String fileName,
|
||||
Long fileSize,
|
||||
String mimeType,
|
||||
Integer width,
|
||||
Integer height,
|
||||
Integer durationSeconds,
|
||||
String thumbnailUrl) {
|
||||
this.fileUrl = fileUrl;
|
||||
this.fileType = fileType;
|
||||
this.fileName = fileName;
|
||||
this.fileSize = fileSize;
|
||||
this.mimeType = mimeType;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.durationSeconds = durationSeconds;
|
||||
this.thumbnailUrl = thumbnailUrl;
|
||||
}
|
||||
|
||||
public FileAttachment(String fileUrl, String fileType) {
|
||||
this.fileUrl = fileUrl;
|
||||
this.fileType = fileType;
|
||||
}
|
||||
|
||||
// Getters
|
||||
public String getFileUrl() {
|
||||
return fileUrl;
|
||||
}
|
||||
@@ -16,4 +46,32 @@ public class FileAttachment {
|
||||
public String getFileType() {
|
||||
return fileType;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public Long getFileSize() {
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
public String getMimeType() {
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
public Integer getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public Integer getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public Integer getDurationSeconds() {
|
||||
return durationSeconds;
|
||||
}
|
||||
|
||||
public String getThumbnailUrl() {
|
||||
return thumbnailUrl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
package org.to.telegramfinalproject.Server;
|
||||
|
||||
import static spark.Spark.*;
|
||||
import javax.servlet.MultipartConfigElement;
|
||||
import javax.servlet.http.Part;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.*;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.nio.file.*;
|
||||
|
||||
|
||||
|
||||
|
||||
import java.nio.file.*;
|
||||
import java.time.LocalDate;
|
||||
|
||||
|
||||
// برای ویدیو (MP4 و …)
|
||||
import org.jcodec.api.FrameGrab;
|
||||
import org.jcodec.common.io.NIOUtils;
|
||||
import org.jcodec.common.model.Picture;
|
||||
import org.jcodec.scale.AWTUtil;
|
||||
//import org.jcodec.containers.mp4.MP4Demuxer;
|
||||
//import org.jcodec.containers.mp4.MP4DemuxerTrack;
|
||||
|
||||
// برای MP3
|
||||
import com.mpatric.mp3agic.Mp3File;
|
||||
|
||||
public class UploadHttp {
|
||||
|
||||
public static void start(int httpPort, String baseDir) throws IOException {
|
||||
port(httpPort);
|
||||
|
||||
Path basePath = Paths.get(baseDir).toAbsolutePath().normalize();
|
||||
Files.createDirectories(basePath);
|
||||
staticFiles.externalLocation(basePath.toString());
|
||||
|
||||
post("/upload", (req, res) -> {
|
||||
res.type("application/json");
|
||||
try {
|
||||
long MAX_FILE = 25L * 1024 * 1024; // 25MB
|
||||
req.attribute("org.eclipse.jetty.multipartConfig",
|
||||
new MultipartConfigElement("/tmp", MAX_FILE, MAX_FILE, 0));
|
||||
|
||||
Part filePart = req.raw().getPart("file");
|
||||
if (filePart == null || filePart.getSize() == 0) {
|
||||
res.status(400);
|
||||
return jsonError("empty file");
|
||||
}
|
||||
if (filePart.getSize() > MAX_FILE) {
|
||||
res.status(413);
|
||||
return jsonError("file too large");
|
||||
}
|
||||
|
||||
String mime = filePart.getContentType();
|
||||
if (mime == null) {
|
||||
res.status(415);
|
||||
return jsonError("unknown mime");
|
||||
}
|
||||
|
||||
String original = filePart.getSubmittedFileName();
|
||||
String ext = guessExt(original, mime);
|
||||
String day = LocalDate.now().toString();
|
||||
String typeDir = subdirFor(mime); // images/videos/audios/files
|
||||
String subdir = typeDir + "/" + day;
|
||||
String name = java.util.UUID.randomUUID() + ext;
|
||||
|
||||
Path dir = basePath.resolve(subdir).normalize();
|
||||
Files.createDirectories(dir);
|
||||
Path target = dir.resolve(name).normalize();
|
||||
|
||||
try (InputStream in = filePart.getInputStream()) {
|
||||
Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING);
|
||||
} finally {
|
||||
filePart.delete();
|
||||
}
|
||||
|
||||
String fileUrl = "/" + subdir.replace('\\', '/') + "/" + name;
|
||||
String fileType = mapToFileType(mime);
|
||||
|
||||
// متادیتا
|
||||
Integer width = null, height = null, durationSeconds = null;
|
||||
String thumbnailUrl = null;
|
||||
|
||||
if ("IMAGE".equals(fileType) || "GIF".equals(fileType)) {
|
||||
int[] wh = imageSize(target);
|
||||
if (wh != null) { width = wh[0]; height = wh[1]; }
|
||||
} else if ("VIDEO".equals(fileType)) {
|
||||
// تلاش برای استخراج width/height/duration با JCodec
|
||||
VideoMeta vm = videoMeta(target);
|
||||
if (vm != null) {
|
||||
width = vm.width;
|
||||
height = vm.height;
|
||||
durationSeconds = vm.durationSeconds;
|
||||
}
|
||||
// ساخت thumbnail (اختیاری)
|
||||
try {
|
||||
String thumbName = name.replace(ext, "") + "_thumb.jpg";
|
||||
Path thumbDir = basePath.resolve("thumbs/" + day).normalize();
|
||||
Files.createDirectories(thumbDir);
|
||||
Path thumbTarget = thumbDir.resolve(thumbName).normalize();
|
||||
if (makeVideoThumbnail(target, thumbTarget)) {
|
||||
thumbnailUrl = "/thumbs/" + day + "/" + thumbName;
|
||||
}
|
||||
} catch (Exception ignore) {}
|
||||
} else if ("AUDIO".equals(fileType)) {
|
||||
// اگر MP3 بود، مدت را با mp3agic بگیر
|
||||
if ("audio/mpeg".equalsIgnoreCase(mime) || ext.equalsIgnoreCase(".mp3")) {
|
||||
try {
|
||||
Mp3File mp3 = new Mp3File(target.toFile());
|
||||
durationSeconds = (int) mp3.getLengthInSeconds();
|
||||
} catch (Exception ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
res.status(200);
|
||||
return new JSONObject()
|
||||
.put("file_url", fileUrl)
|
||||
.put("file_type", fileType)
|
||||
.put("file_name", original == null ? "" : safeName(original))
|
||||
.put("file_size", Files.size(target))
|
||||
.put("mime_type", mime)
|
||||
.put("width", width == null ? JSONObject.NULL : width)
|
||||
.put("height", height == null ? JSONObject.NULL : height)
|
||||
.put("duration_seconds", durationSeconds == null ? JSONObject.NULL : durationSeconds)
|
||||
.put("thumbnail_url", thumbnailUrl == null ? JSONObject.NULL : thumbnailUrl)
|
||||
.toString();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(); // لوکال
|
||||
res.status(500);
|
||||
return jsonError("internal error");
|
||||
}
|
||||
});
|
||||
|
||||
init();
|
||||
awaitInitialization();
|
||||
System.out.println("Upload HTTP server on http://localhost:" + httpPort + " baseDir=" + basePath);
|
||||
}
|
||||
|
||||
// ---------- Helpers ----------
|
||||
|
||||
private static String jsonError(String msg) {
|
||||
return new JSONObject().put("error", msg).toString();
|
||||
}
|
||||
|
||||
private static String subdirFor(String mime) {
|
||||
String m = mime.toLowerCase();
|
||||
if (m.startsWith("image/")) return "images";
|
||||
if (m.startsWith("video/")) return "videos";
|
||||
if (m.startsWith("audio/")) return "audios";
|
||||
return "files";
|
||||
}
|
||||
|
||||
private static String mapToFileType(String mime) {
|
||||
String m = mime.toLowerCase();
|
||||
if (m.startsWith("image/")) {
|
||||
if (m.contains("gif")) return "GIF";
|
||||
return "IMAGE";
|
||||
}
|
||||
if (m.startsWith("video/")) return "VIDEO";
|
||||
if (m.startsWith("audio/")) return "AUDIO";
|
||||
return "FILE";
|
||||
}
|
||||
|
||||
private static String guessExt(String original, String mime) {
|
||||
if (original != null && original.contains(".")) {
|
||||
String ext = original.substring(original.lastIndexOf('.'));
|
||||
if (ext.length() <= 10) return ext;
|
||||
}
|
||||
if ("image/png".equalsIgnoreCase(mime)) return ".png";
|
||||
if ("image/jpeg".equalsIgnoreCase(mime)) return ".jpg";
|
||||
if ("image/gif".equalsIgnoreCase(mime)) return ".gif";
|
||||
if ("video/mp4".equalsIgnoreCase(mime)) return ".mp4";
|
||||
if ("audio/mpeg".equalsIgnoreCase(mime)) return ".mp3";
|
||||
if ("application/pdf".equalsIgnoreCase(mime)) return ".pdf";
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String safeName(String name) {
|
||||
// پاکسازی خیلی ساده برای خروجی
|
||||
return name.replace("\"", "").replace("\n", "").replace("\r", "");
|
||||
}
|
||||
|
||||
private static int[] imageSize(Path file) {
|
||||
try {
|
||||
BufferedImage bi = ImageIO.read(file.toFile());
|
||||
if (bi != null) return new int[]{bi.getWidth(), bi.getHeight()};
|
||||
} catch (Exception ignore) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
// --- Video meta via JCodec ---
|
||||
private static class VideoMeta {
|
||||
final Integer width, height, durationSeconds;
|
||||
VideoMeta(Integer w, Integer h, Integer d) { this.width = w; this.height = h; this.durationSeconds = d; }
|
||||
}
|
||||
|
||||
private static VideoMeta videoMeta(Path file) {
|
||||
try {
|
||||
// Width/Height از طریق اولین فریم
|
||||
BufferedImage first = null;
|
||||
try {
|
||||
FrameGrab grab = FrameGrab.createFrameGrab(NIOUtils.readableChannel(file.toFile()));
|
||||
Picture p = grab.getNativeFrame();
|
||||
if (p != null) first = AWTUtil.toBufferedImage(p);
|
||||
} catch (Exception ignore) {}
|
||||
|
||||
Integer w = null, h = null;
|
||||
if (first != null) { w = first.getWidth(); h = first.getHeight(); }
|
||||
|
||||
// Duration از Demuxer (فقط MP4ها عالی جواب میده)
|
||||
Integer dur = null;
|
||||
// try {
|
||||
// MP4Demuxer demuxer = new MP4Demuxer(NIOUtils.readableChannel(file.toFile()));
|
||||
// MP4DemuxerTrack vt = (MP4DemuxerTrack) demuxer.getVideoTrack();
|
||||
// double seconds = vt.getMeta().getTotalDuration();
|
||||
// dur = (int) Math.round(seconds);
|
||||
// } catch (Exception ignore) {}
|
||||
|
||||
if (w != null || h != null || dur != null) return new VideoMeta(w, h, dur);
|
||||
} catch (Exception ignore) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean makeVideoThumbnail(Path videoFile, Path thumbTarget) {
|
||||
try {
|
||||
FrameGrab grab = FrameGrab.createFrameGrab(NIOUtils.readableChannel(videoFile.toFile()));
|
||||
Picture p = grab.getNativeFrame();
|
||||
if (p == null) return false;
|
||||
BufferedImage bi = AWTUtil.toBufferedImage(p);
|
||||
Files.createDirectories(thumbTarget.getParent());
|
||||
return ImageIO.write(bi, "jpg", thumbTarget.toFile());
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user