work on send file
This commit is contained in:
@@ -46,8 +46,6 @@ dependencies {
|
||||
}
|
||||
//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'
|
||||
|
||||
@@ -11,12 +11,10 @@ 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 spark.core;
|
||||
requires javax.servlet.api;
|
||||
requires mp3agic;
|
||||
requires jcodec.javase;
|
||||
opens org.to.telegramfinalproject to javafx.fxml;
|
||||
exports org.to.telegramfinalproject;
|
||||
exports org.to.telegramfinalproject.Client;
|
||||
|
||||
@@ -555,6 +555,7 @@ public class ActionHandler {
|
||||
ContactEntry entry = new ContactEntry(
|
||||
UUID.fromString(c.getString("contact_id")),
|
||||
c.getString("user_id"),
|
||||
c.getString("contact_displayId"),
|
||||
c.getString("profile_name"),
|
||||
c.optString("image_url", ""),
|
||||
c.optBoolean("is_blocked", false)
|
||||
@@ -564,7 +565,6 @@ public class ActionHandler {
|
||||
|
||||
|
||||
|
||||
|
||||
Session.activeChats = activeChats;
|
||||
Session.archivedChats = archivedChats;
|
||||
Session.chatList = chatList;
|
||||
@@ -899,6 +899,134 @@ public class ActionHandler {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// public void showContactList() {
|
||||
// System.out.println("1. View All Contacts");
|
||||
// System.out.println("2. Search Contacts");
|
||||
// System.out.println("Choose an option: (0 to go back)");
|
||||
// int option = scanner.nextInt();
|
||||
// scanner.nextLine();
|
||||
//
|
||||
// // Handle invalid input
|
||||
// while (option < 0 || option > 2) {
|
||||
// System.out.println("Invalid choice. Try again: ");
|
||||
// option = scanner.nextInt();
|
||||
// scanner.nextLine();
|
||||
// }
|
||||
//
|
||||
// List<ContactEntry> contacts;
|
||||
//
|
||||
// if (option == 0) {
|
||||
// return;
|
||||
// }
|
||||
// else if (option == 1) {
|
||||
// contacts = Session.contactEntries;
|
||||
//
|
||||
// } else if (option == 2) {
|
||||
// contacts = new ArrayList<>();
|
||||
//
|
||||
// System.out.print("Enter name or user ID to search: ");
|
||||
// String searchTerm = scanner.nextLine();
|
||||
//
|
||||
// // Handle invalid input
|
||||
// while (searchTerm.isEmpty()) {
|
||||
// System.out.print("Search key can not be empty. Try again: ");
|
||||
// searchTerm = scanner.nextLine();
|
||||
// }
|
||||
//
|
||||
// // Send a request to server
|
||||
// JSONObject request = new JSONObject();
|
||||
// request.put("action", "search_contacts");
|
||||
// request.put("user_id", Session.getUserUUID());
|
||||
// request.put("search_term", searchTerm);
|
||||
//
|
||||
// JSONObject response = ActionHandler.sendWithResponse(request);
|
||||
//
|
||||
// if (!response.optString("status", "fail").equals("success")) {
|
||||
// System.out.println("Failed to search contacts: " + response.optString("message", "Unknown error"));
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// JSONObject data = response.getJSONObject("data");
|
||||
// JSONArray contactsJson = data.getJSONArray("contacts");
|
||||
//
|
||||
// for (int i = 0; i < contactsJson.length(); i++) {
|
||||
// JSONObject contact = contactsJson.getJSONObject(i);
|
||||
//
|
||||
// UUID contactId = UUID.fromString(contact.getString("contact_id"));
|
||||
// String userId = contact.getString("user_id");
|
||||
// String profileName = contact.getString("profile_name");
|
||||
// String imageUrl = contact.optString("image_url", "");
|
||||
// boolean isBlocked = contact.getBoolean("is_blocked");
|
||||
// String lastSeenString = contact.getString("last_seen");
|
||||
// LocalDateTime lastSeen = null;
|
||||
// if (lastSeenString != null) {
|
||||
// lastSeen = LocalDateTime.parse(lastSeenString);
|
||||
// }
|
||||
//
|
||||
// contacts.add(new ContactEntry(contactId, userId, profileName, imageUrl, isBlocked));
|
||||
// }
|
||||
//
|
||||
// } else {
|
||||
// System.out.println("❌ Invalid choice.");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if (contacts.isEmpty()) {
|
||||
// System.out.println("📭 No contacts found.");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// System.out.println("👥 Your Contacts:");
|
||||
// for (int i = 0; i < contacts.size(); i++) {
|
||||
// System.out.println((i + 1) + ". " + contacts.get(i));
|
||||
// }
|
||||
//
|
||||
// System.out.print("Select a contact (0 to go back): ");
|
||||
// int choice = scanner.nextInt();
|
||||
// scanner.nextLine();
|
||||
//
|
||||
// if (choice == 0) return;
|
||||
// if (choice < 1 || choice > contacts.size()) {
|
||||
// System.out.println("❌ Invalid choice.");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// ContactEntry selected = contacts.get(choice - 1);
|
||||
// System.out.println("\n📇 What do you want to do with " + selected.getProfileName() + "?");
|
||||
// System.out.println("1. View Profile");
|
||||
// System.out.println("2. Send Message");
|
||||
// System.out.println("3. Remove Contact");
|
||||
// System.out.print("Enter your choice: ");
|
||||
// int action = scanner.nextInt();
|
||||
// scanner.nextLine();
|
||||
// switch (action) {
|
||||
// case 1 -> viewProfile(selected.getContactId());
|
||||
// case 2 -> startPrivateChat(selected);
|
||||
// case 3 -> {
|
||||
// // Send a request to server
|
||||
// JSONObject request = new JSONObject();
|
||||
// request.put("action", "remove_contact");
|
||||
// request.put("user_id", Session.getUserUUID()); // Current user
|
||||
// request.put("contact_id", selected.getContactId().toString()); // Contact to remove
|
||||
//
|
||||
// JSONObject response = ActionHandler.sendWithResponse(request);
|
||||
//
|
||||
// if ("success".equals(response.optString("status"))) {
|
||||
// System.out.println("✅ Contact removed successfully.");
|
||||
// Session.contactEntries.remove(selected); // Remove from local session list
|
||||
// } else {
|
||||
// System.out.println("❌ Failed to remove contact: " +
|
||||
// response.optString("message", "Unknown error"));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// default -> System.out.println("❌ Invalid option.");
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
private void viewProfile(UUID targetId) {
|
||||
JSONObject req = new JSONObject();
|
||||
req.put("action", "view_profile");
|
||||
@@ -3232,32 +3360,110 @@ public class ActionHandler {
|
||||
|
||||
|
||||
|
||||
// public void sendMessage(UUID chatId, String receiverType) {
|
||||
// Scanner scanner = new Scanner(System.in);
|
||||
//
|
||||
// System.out.print("Enter your message: ");
|
||||
// String content = scanner.nextLine();
|
||||
//
|
||||
// System.out.print("Enter message type (TEXT / IMAGE / VIDEO / FILE): ");
|
||||
// String messageType = scanner.nextLine().toUpperCase();
|
||||
// Set<String> allowedTypes = Set.of("TEXT", "IMAGE", "VIDEO", "FILE");
|
||||
// while (!allowedTypes.contains(messageType)) {
|
||||
// System.out.print("❌ Invalid type. Try again (TEXT / IMAGE / VIDEO / FILE): ");
|
||||
// messageType = scanner.nextLine().toUpperCase();
|
||||
// }
|
||||
//
|
||||
// JSONArray attachmentsArray = new JSONArray();
|
||||
// System.out.print("Do you want to attach files? (yes/no): ");
|
||||
// if (scanner.nextLine().equalsIgnoreCase("yes")) {
|
||||
// while (true) {
|
||||
// System.out.print("File URL: ");
|
||||
// String fileUrl = scanner.nextLine();
|
||||
// System.out.print("File Type (IMAGE / VIDEO / FILE): ");
|
||||
// String fileType = scanner.nextLine().toUpperCase();
|
||||
//
|
||||
// JSONObject fileJson = new JSONObject();
|
||||
// fileJson.put("file_url", fileUrl);
|
||||
// fileJson.put("file_type", fileType);
|
||||
// attachmentsArray.put(fileJson);
|
||||
//
|
||||
// System.out.print("Add another file? (yes/no): ");
|
||||
// if (!scanner.nextLine().equalsIgnoreCase("yes")) break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 🔹 فقط ارسال پیام با chat_id و receiver_type
|
||||
// JSONObject messageJson = new JSONObject();
|
||||
// messageJson.put("action", "send_message");
|
||||
// messageJson.put("receiver_type", receiverType);
|
||||
// messageJson.put("receiver_id", chatId.toString());
|
||||
// messageJson.put("content", content);
|
||||
// messageJson.put("message_type", messageType);
|
||||
//
|
||||
// if (!attachmentsArray.isEmpty()) {
|
||||
// messageJson.put("attachments", attachmentsArray);
|
||||
// }
|
||||
//
|
||||
// JSONObject response = sendWithResponse(messageJson);
|
||||
// if (response != null && response.getString("status").equals("success")) {
|
||||
// System.out.println("✅ Message sent! ID: " + response.getJSONObject("data").getString("message_id"));
|
||||
// } else {
|
||||
// System.out.println("❌ Failed to send message: " + (response != null ? response.getString("message") : "No response"));
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
public void sendMessage(UUID chatId, String receiverType) {
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
|
||||
System.out.print("Enter your message: ");
|
||||
System.out.print("Enter your message (leave empty if file only): ");
|
||||
String content = scanner.nextLine();
|
||||
|
||||
System.out.print("Enter message type (TEXT / IMAGE / VIDEO / FILE): ");
|
||||
System.out.print("Enter message type (TEXT / IMAGE / AUDIO / FILE / GIF): ");
|
||||
String messageType = scanner.nextLine().toUpperCase();
|
||||
Set<String> allowedTypes = Set.of("TEXT", "IMAGE", "VIDEO", "FILE");
|
||||
Set<String> allowedTypes = Set.of("TEXT", "IMAGE", "AUDIO", "FILE", "GIF");
|
||||
while (!allowedTypes.contains(messageType)) {
|
||||
System.out.print("❌ Invalid type. Try again (TEXT / IMAGE / VIDEO / FILE): ");
|
||||
System.out.print("❌ Invalid type. Try again (TEXT / IMAGE / AUDIO / FILE / GIF): ");
|
||||
messageType = scanner.nextLine().toUpperCase();
|
||||
}
|
||||
|
||||
JSONArray attachmentsArray = new JSONArray();
|
||||
System.out.print("Do you want to attach files? (yes/no): ");
|
||||
System.out.print("Attach files? (yes/no): ");
|
||||
if (scanner.nextLine().equalsIgnoreCase("yes")) {
|
||||
while (true) {
|
||||
System.out.print("File URL: ");
|
||||
String fileUrl = scanner.nextLine();
|
||||
System.out.print("File Type (IMAGE / VIDEO / FILE): ");
|
||||
String fileType = scanner.nextLine().toUpperCase();
|
||||
System.out.println("Paste the JSON you got from /upload (or leave empty to enter minimal fields):");
|
||||
String jsonLine = scanner.nextLine().trim();
|
||||
|
||||
JSONObject fileJson;
|
||||
if (!jsonLine.isEmpty()) {
|
||||
// انتظار خروجی کامل /upload
|
||||
fileJson = new JSONObject(jsonLine);
|
||||
// اگه خروجی /upload تو ریشهست، تبدیلش کن به ساختار attachment
|
||||
fileJson = new JSONObject()
|
||||
.put("file_url", fileJson.optString("file_url", ""))
|
||||
.put("file_type", fileJson.optString("file_type", "FILE"))
|
||||
.put("file_name", fileJson.optString("file_name", ""))
|
||||
.put("file_size", fileJson.optLong("file_size", 0))
|
||||
.put("mime_type", fileJson.optString("mime_type", ""))
|
||||
.put("width", fileJson.isNull("width") ? JSONObject.NULL : fileJson.optInt("width"))
|
||||
.put("height", fileJson.isNull("height") ? JSONObject.NULL : fileJson.optInt("height"))
|
||||
.put("duration_seconds", fileJson.isNull("duration_seconds") ? JSONObject.NULL : fileJson.optInt("duration_seconds"))
|
||||
.put("thumbnail_url", fileJson.isNull("thumbnail_url") ? JSONObject.NULL : fileJson.optString("thumbnail_url", null));
|
||||
} else {
|
||||
// ورودی حداقلی
|
||||
System.out.print("File URL: ");
|
||||
String fileUrl = scanner.nextLine();
|
||||
System.out.print("File Type (IMAGE / AUDIO / FILE / GIF): ");
|
||||
String fileType = scanner.nextLine().toUpperCase();
|
||||
|
||||
fileJson = new JSONObject();
|
||||
fileJson.put("file_url", fileUrl);
|
||||
fileJson.put("file_type", fileType);
|
||||
}
|
||||
|
||||
JSONObject fileJson = new JSONObject();
|
||||
fileJson.put("file_url", fileUrl);
|
||||
fileJson.put("file_type", fileType);
|
||||
attachmentsArray.put(fileJson);
|
||||
|
||||
System.out.print("Add another file? (yes/no): ");
|
||||
@@ -3265,15 +3471,13 @@ public class ActionHandler {
|
||||
}
|
||||
}
|
||||
|
||||
// 🔹 فقط ارسال پیام با chat_id و receiver_type
|
||||
JSONObject messageJson = new JSONObject();
|
||||
messageJson.put("action", "send_message");
|
||||
messageJson.put("receiver_type", receiverType);
|
||||
messageJson.put("receiver_id", chatId.toString());
|
||||
messageJson.put("receiver_type", receiverType); // "private"/"group"/"channel"
|
||||
messageJson.put("receiver_id", chatId.toString()); // در private = chat_id
|
||||
messageJson.put("content", content);
|
||||
messageJson.put("message_type", messageType);
|
||||
|
||||
if (!attachmentsArray.isEmpty()) {
|
||||
if (attachmentsArray.length() > 0) {
|
||||
messageJson.put("attachments", attachmentsArray);
|
||||
}
|
||||
|
||||
@@ -3281,7 +3485,7 @@ public class ActionHandler {
|
||||
if (response != null && response.getString("status").equals("success")) {
|
||||
System.out.println("✅ Message sent! ID: " + response.getJSONObject("data").getString("message_id"));
|
||||
} else {
|
||||
System.out.println("❌ Failed to send message: " + (response != null ? response.getString("message") : "No response"));
|
||||
System.out.println("❌ Failed to send message: " + (response != null ? response.optString("message","No message") : "No response"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -626,11 +626,13 @@ public class MessageDatabase {
|
||||
rs.getString("status"),
|
||||
(UUID) rs.getObject("reply_to_id"),
|
||||
rs.getBoolean("is_edited"),
|
||||
rs.getBoolean("is_deleted_globally"),
|
||||
// rs.getBoolean("is_deleted_globally"),
|
||||
(UUID) rs.getObject("original_message_id"),
|
||||
(UUID) rs.getObject("forwarded_by"),
|
||||
(UUID) rs.getObject("forwarded_from")
|
||||
);
|
||||
(UUID) rs.getObject("forwarded_from"),
|
||||
rs.getBoolean("is_deleted_globally"),
|
||||
(rs.getTimestamp("edited_at") != null) ? rs.getTimestamp("edited_at").toLocalDateTime() : null
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ public class Contact {
|
||||
this.added_at = LocalDateTime.now();
|
||||
}
|
||||
|
||||
|
||||
public void setUser_id(UUID user_id){this.user_id = user_id;}
|
||||
public void setContact_id(UUID contact_id){this.contact_id = contact_id;}
|
||||
public void setAdd_at(LocalDateTime add_at){this.added_at =add_at;}
|
||||
|
||||
@@ -10,6 +10,7 @@ public class ContactEntry {
|
||||
private String profileName;
|
||||
private String imageUrl;
|
||||
private boolean isBlocked;
|
||||
private String contact_displayId;
|
||||
|
||||
public ContactEntry(UUID contactId, String userId, String profileName, String imageUrl, boolean isBlocked) {
|
||||
this.contactId = contactId;
|
||||
@@ -19,6 +20,15 @@ public class ContactEntry {
|
||||
this.isBlocked = isBlocked;
|
||||
}
|
||||
|
||||
public ContactEntry(UUID contactId, String userId,String contact_displayId , String profileName, String imageUrl, boolean isBlocked){
|
||||
this.contactId = contactId;
|
||||
this.userId = userId;
|
||||
this.contact_displayId = contact_displayId;
|
||||
this.profileName = profileName;
|
||||
this.imageUrl = imageUrl;
|
||||
this.isBlocked = isBlocked;
|
||||
}
|
||||
|
||||
public UUID getContactId() {
|
||||
return contactId;
|
||||
}
|
||||
@@ -41,7 +51,7 @@ public class ContactEntry {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return profileName + " (" + userId + ")" + (isBlocked ? " [Blocked]" : "");
|
||||
return profileName + " ( @" + contact_displayId + ")" + (isBlocked ? " [Blocked]" : "");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
package org.to.telegramfinalproject.Models;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import java.util.Objects;
|
||||
|
||||
public class FileAttachment {
|
||||
private String fileUrl;
|
||||
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;
|
||||
|
||||
private final String fileUrl;
|
||||
private final String fileType; // IMAGE, VIDEO, AUDIO, FILE, GIF, STICKER
|
||||
private final String fileName;
|
||||
private final Long fileSize;
|
||||
private final String mimeType; // e.g., image/png
|
||||
private final Integer width;
|
||||
private final Integer height;
|
||||
private final Integer durationSeconds; // for audio/video
|
||||
private final String thumbnailUrl;
|
||||
|
||||
public FileAttachment(String fileUrl,
|
||||
String fileType,
|
||||
@@ -34,44 +36,91 @@ public class FileAttachment {
|
||||
}
|
||||
|
||||
public FileAttachment(String fileUrl, String fileType) {
|
||||
this.fileUrl = fileUrl;
|
||||
this.fileType = fileType;
|
||||
this(fileUrl, fileType, null, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
// ساخت از JSON /upload
|
||||
public static FileAttachment fromUploadJson(JSONObject j) {
|
||||
return new FileAttachment(
|
||||
j.optString("file_url", ""),
|
||||
j.optString("file_type", "FILE"),
|
||||
emptyToNull(j.optString("file_name", null)),
|
||||
j.has("file_size") && !j.isNull("file_size") ? j.getLong("file_size") : null,
|
||||
emptyToNull(j.optString("mime_type", null)),
|
||||
j.has("width") && !j.isNull("width") ? j.getInt("width") : null,
|
||||
j.has("height") && !j.isNull("height") ? j.getInt("height") : null,
|
||||
j.has("duration_seconds") && !j.isNull("duration_seconds") ? j.getInt("duration_seconds") : null,
|
||||
j.isNull("thumbnail_url") ? null : emptyToNull(j.optString("thumbnail_url", null))
|
||||
);
|
||||
}
|
||||
|
||||
// خروجی JSON برای RT/کلاینت
|
||||
public JSONObject toJson() {
|
||||
JSONObject out = new JSONObject()
|
||||
.put("file_url", fileUrl)
|
||||
.put("file_type", fileType);
|
||||
|
||||
out.put("file_name", fileName == null ? JSONObject.NULL : fileName);
|
||||
out.put("file_size", fileSize == null ? JSONObject.NULL : fileSize);
|
||||
out.put("mime_type", mimeType == null ? JSONObject.NULL : mimeType);
|
||||
out.put("width", width == null ? JSONObject.NULL : width);
|
||||
out.put("height", height == null ? JSONObject.NULL : height);
|
||||
out.put("duration_seconds", durationSeconds == null ? JSONObject.NULL : durationSeconds);
|
||||
out.put("thumbnail_url", thumbnailUrl == null ? JSONObject.NULL : thumbnailUrl);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Helpers
|
||||
public boolean isImage() { return "IMAGE".equalsIgnoreCase(fileType) || "GIF".equalsIgnoreCase(fileType); }
|
||||
public boolean isAudio() { return "AUDIO".equalsIgnoreCase(fileType); }
|
||||
public boolean hasDimensions() { return width != null && height != null; }
|
||||
|
||||
private static String emptyToNull(String s) {
|
||||
return (s == null || s.isBlank()) ? null : s;
|
||||
}
|
||||
|
||||
// Getters
|
||||
public String getFileUrl() {
|
||||
return fileUrl;
|
||||
public String getFileUrl() { return fileUrl; }
|
||||
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; }
|
||||
|
||||
// equals/hashCode/toString
|
||||
@Override public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof FileAttachment)) return false;
|
||||
FileAttachment that = (FileAttachment) o;
|
||||
return Objects.equals(fileUrl, that.fileUrl) &&
|
||||
Objects.equals(fileType, that.fileType) &&
|
||||
Objects.equals(fileName, that.fileName) &&
|
||||
Objects.equals(fileSize, that.fileSize) &&
|
||||
Objects.equals(mimeType, that.mimeType) &&
|
||||
Objects.equals(width, that.width) &&
|
||||
Objects.equals(height, that.height) &&
|
||||
Objects.equals(durationSeconds, that.durationSeconds) &&
|
||||
Objects.equals(thumbnailUrl, that.thumbnailUrl);
|
||||
}
|
||||
|
||||
public String getFileType() {
|
||||
return fileType;
|
||||
@Override public int hashCode() {
|
||||
return Objects.hash(fileUrl, fileType, fileName, fileSize, mimeType, width, height, durationSeconds, thumbnailUrl);
|
||||
}
|
||||
|
||||
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;
|
||||
@Override public String toString() {
|
||||
return "FileAttachment{" +
|
||||
"fileUrl='" + fileUrl + '\'' +
|
||||
", fileType='" + fileType + '\'' +
|
||||
", fileName='" + fileName + '\'' +
|
||||
", fileSize=" + fileSize +
|
||||
", mimeType='" + mimeType + '\'' +
|
||||
", width=" + width +
|
||||
", height=" + height +
|
||||
", durationSeconds=" + durationSeconds +
|
||||
", thumbnailUrl='" + thumbnailUrl + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,26 @@ public class Message {
|
||||
this.forwarded_from = forwarded_from;
|
||||
}
|
||||
|
||||
public Message(UUID message_id, UUID sender_id, String receiver_type, UUID receiver_id, String content,
|
||||
String message_type, LocalDateTime send_at, String status,
|
||||
UUID reply_to_id, boolean is_edited, UUID original_message_id,
|
||||
UUID forwarded_by, UUID forwarded_from,boolean is_deleted_globally, LocalDateTime edited_at) {
|
||||
this.message_id = message_id;
|
||||
this.sender_id = sender_id;
|
||||
this.receiver_type = receiver_type;
|
||||
this.receiver_id = receiver_id;
|
||||
this.content = content;
|
||||
this.message_type = message_type;
|
||||
this.send_at = send_at;
|
||||
this.status = status;
|
||||
this.reply_to_id = reply_to_id;
|
||||
this.is_edited = is_edited;
|
||||
this.original_message_id = original_message_id;
|
||||
this.forwarded_by = forwarded_by;
|
||||
this.forwarded_from = forwarded_from;
|
||||
this.is_deleted_globally = is_deleted_globally;
|
||||
this.edited_at = edited_at;
|
||||
}
|
||||
|
||||
// ✅ Short Constructors
|
||||
//for normal messages
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.to.telegramfinalproject.Utils.GroupPermissionUtil;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.Socket;
|
||||
import java.sql.Connection;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
|
||||
@@ -111,6 +112,8 @@ public class ClientHandler implements Runnable {
|
||||
JSONObject c = new JSONObject();
|
||||
c.put("user_id", contact.getUser_id().toString());
|
||||
c.put("contact_id", contact.getContact_id().toString());
|
||||
User Contact = userDatabase.findByInternalUUID(contact.getContact_id());
|
||||
c.put("contact_displayId", Contact.getUser_id());
|
||||
c.put("is_blocked", contact.getIs_blocked());
|
||||
|
||||
c.put("profile_name", target.getProfile_name());
|
||||
@@ -2469,8 +2472,87 @@ public class ClientHandler implements Runnable {
|
||||
}
|
||||
|
||||
|
||||
private ResponseModel handleSendMessage(JSONObject json) {
|
||||
// private ResponseModel handleSendMessage(JSONObject json) {
|
||||
//
|
||||
// try {
|
||||
// if (currentUser == null)
|
||||
// return new ResponseModel("error", "Unauthorized. Please login first.");
|
||||
//
|
||||
// UUID messageId = UUID.randomUUID();
|
||||
// UUID senderId = currentUser.getInternal_uuid();
|
||||
// String receiverType = json.getString("receiver_type");
|
||||
// UUID receiverId;
|
||||
// receiverId = UUID.fromString(json.getString("receiver_id"));
|
||||
//
|
||||
// if(Objects.equals(receiverType, "private")){
|
||||
// PrivateChatDatabase.clearDeletedFlag(senderId, receiverId);
|
||||
// UUID other = PrivateChatDatabase.getOtherParticipant(receiverId, senderId);
|
||||
// if (other == null) {
|
||||
// return new ResponseModel("error", "Invalid private chat.");
|
||||
// }
|
||||
// if (ContactDatabase.isBlocked(senderId, other) || ContactDatabase.isBlocked(other, senderId)) {
|
||||
// return new ResponseModel("error", "You can't message this user (blocked).");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// String content = json.optString("content", "");
|
||||
// String messageType = json.optString("message_type", "TEXT");
|
||||
//
|
||||
// boolean inserted = MessageDatabase.insertMessage(messageId, senderId, receiverId, receiverType, content, messageType);
|
||||
// if (!inserted)
|
||||
// return new ResponseModel("error", "Failed to insert message.");
|
||||
//
|
||||
// if (json.has("attachments")) {
|
||||
// JSONArray attachmentsArray = json.getJSONArray("attachments");
|
||||
// List<FileAttachment> attachments = new ArrayList<>();
|
||||
//
|
||||
// for (int i = 0; i < attachmentsArray.length(); i++) {
|
||||
// JSONObject attJson = attachmentsArray.getJSONObject(i);
|
||||
// attachments.add(new FileAttachment(
|
||||
// attJson.getString("file_url"),
|
||||
// attJson.getString("file_type")
|
||||
// ));
|
||||
// }
|
||||
//
|
||||
// boolean attInserted = MessageDatabase.insertAttachments(messageId, attachments);
|
||||
// if (!attInserted)
|
||||
// return new ResponseModel("error", "Message inserted but failed to attach files.");
|
||||
// }
|
||||
//
|
||||
// // Send real-time message
|
||||
// Message msg = new Message(messageId, senderId, receiverId, receiverType, content, messageType, LocalDateTime.now());
|
||||
// List<UUID> receivers = getReceiversForChat(receiverId, receiverType);
|
||||
// receivers.remove(senderId);
|
||||
// RealTimeEventDispatcher.sendNewMessage(msg, receivers);
|
||||
//
|
||||
// // Update chat list (last_message_time)
|
||||
// JSONObject chatUpdate = new JSONObject();
|
||||
// chatUpdate.put("chat_id", receiverId.toString());
|
||||
// chatUpdate.put("chat_type", receiverType);
|
||||
// chatUpdate.put("last_message_time", LocalDateTime.now().toString());
|
||||
//
|
||||
// JSONObject chatPayload = new JSONObject();
|
||||
// chatPayload.put("action", "chat_updated");
|
||||
// chatPayload.put("data", chatUpdate);
|
||||
//
|
||||
// for (UUID receiver : receivers) {
|
||||
// RealTimeEventDispatcher.sendToUser(receiver, chatPayload);
|
||||
// }
|
||||
//
|
||||
// JSONObject data = new JSONObject();
|
||||
// data.put("message_id", messageId.toString());
|
||||
// return new ResponseModel("success", "Message sent successfully.", data);
|
||||
//
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// return new ResponseModel("error", "Exception occurred while sending message.");
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
private ResponseModel handleSendMessage(JSONObject json) {
|
||||
try {
|
||||
if (currentUser == null)
|
||||
return new ResponseModel("error", "Unauthorized. Please login first.");
|
||||
@@ -2478,68 +2560,124 @@ public class ClientHandler implements Runnable {
|
||||
UUID messageId = UUID.randomUUID();
|
||||
UUID senderId = currentUser.getInternal_uuid();
|
||||
String receiverType = json.getString("receiver_type");
|
||||
UUID receiverId;
|
||||
receiverId = UUID.fromString(json.getString("receiver_id"));
|
||||
|
||||
if(Objects.equals(receiverType, "private")){
|
||||
PrivateChatDatabase.clearDeletedFlag(senderId, receiverId);
|
||||
UUID other = PrivateChatDatabase.getOtherParticipant(receiverId, senderId);
|
||||
if (other == null) {
|
||||
return new ResponseModel("error", "Invalid private chat.");
|
||||
}
|
||||
if (ContactDatabase.isBlocked(senderId, other) || ContactDatabase.isBlocked(other, senderId)) {
|
||||
return new ResponseModel("error", "You can't message this user (blocked).");
|
||||
}
|
||||
}
|
||||
UUID receiverId = UUID.fromString(json.getString("receiver_id"));
|
||||
|
||||
// private validations...
|
||||
// ...
|
||||
|
||||
String content = json.optString("content", "");
|
||||
String messageType = json.optString("message_type", "TEXT");
|
||||
|
||||
boolean inserted = MessageDatabase.insertMessage(messageId, senderId, receiverId, receiverType, content, messageType);
|
||||
if (!inserted)
|
||||
return new ResponseModel("error", "Failed to insert message.");
|
||||
|
||||
// Parse attachments
|
||||
List<FileAttachment> attachments = new ArrayList<>();
|
||||
if (json.has("attachments")) {
|
||||
JSONArray attachmentsArray = json.getJSONArray("attachments");
|
||||
List<FileAttachment> attachments = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < attachmentsArray.length(); i++) {
|
||||
JSONObject attJson = attachmentsArray.getJSONObject(i);
|
||||
JSONArray arr = json.getJSONArray("attachments");
|
||||
for (int i = 0; i < arr.length(); i++) {
|
||||
JSONObject a = arr.getJSONObject(i);
|
||||
attachments.add(new FileAttachment(
|
||||
attJson.getString("file_url"),
|
||||
attJson.getString("file_type")
|
||||
a.optString("file_url",""),
|
||||
a.optString("file_type","FILE"),
|
||||
a.optString("file_name",""),
|
||||
a.has("file_size") && !a.isNull("file_size") ? a.getLong("file_size") : null,
|
||||
a.optString("mime_type", null),
|
||||
a.has("width") && !a.isNull("width") ? a.getInt("width") : null,
|
||||
a.has("height") && !a.isNull("height") ? a.getInt("height") : null,
|
||||
a.has("duration_seconds") && !a.isNull("duration_seconds") ? a.getInt("duration_seconds") : null,
|
||||
a.isNull("thumbnail_url") ? null : a.optString("thumbnail_url", null)
|
||||
));
|
||||
}
|
||||
|
||||
boolean attInserted = MessageDatabase.insertAttachments(messageId, attachments);
|
||||
if (!attInserted)
|
||||
return new ResponseModel("error", "Message inserted but failed to attach files.");
|
||||
}
|
||||
|
||||
// Send real-time message
|
||||
if ((content == null || content.isBlank()) && attachments.isEmpty()) {
|
||||
return new ResponseModel("error", "Empty message: no content or attachment.");
|
||||
}
|
||||
|
||||
// Harmonize message_type
|
||||
if (!attachments.isEmpty()) {
|
||||
String firstType = attachments.get(0).getFileType();
|
||||
if ("TEXT".equalsIgnoreCase(messageType)) {
|
||||
messageType = firstType;
|
||||
} else if (!messageType.equalsIgnoreCase(firstType) && !messageType.equalsIgnoreCase("FILE")) {
|
||||
return new ResponseModel("error", "message_type and attachment.file_type mismatch.");
|
||||
}
|
||||
}
|
||||
|
||||
// DB transaction
|
||||
try (Connection conn = ConnectionDb.connect()) {
|
||||
conn.setAutoCommit(false);
|
||||
|
||||
boolean inserted = MessageDatabase.insertMessageTx(conn, messageId, senderId, receiverId, receiverType, content, messageType);
|
||||
if (!inserted) {
|
||||
conn.rollback();
|
||||
return new ResponseModel("error", "Failed to insert message.");
|
||||
}
|
||||
|
||||
if (!attachments.isEmpty()) {
|
||||
boolean attInserted = MessageDatabase.insertAttachmentsTx(conn, messageId, attachments);
|
||||
if (!attInserted) {
|
||||
conn.rollback();
|
||||
return new ResponseModel("error", "Message inserted but failed to attach files.");
|
||||
}
|
||||
}
|
||||
|
||||
conn.commit();
|
||||
}
|
||||
|
||||
// Real-Time
|
||||
Message msg = new Message(messageId, senderId, receiverId, receiverType, content, messageType, LocalDateTime.now());
|
||||
|
||||
// رویداد با پیوستها
|
||||
JSONObject payload = new JSONObject();
|
||||
payload.put("action", "new_message");
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("id", messageId.toString());
|
||||
data.put("sender_id", senderId.toString());
|
||||
data.put("receiver_id", receiverId.toString());
|
||||
data.put("receiver_type", receiverType);
|
||||
data.put("content", content);
|
||||
data.put("message_type", messageType);
|
||||
data.put("send_at", msg.getSend_at().toString());
|
||||
|
||||
if (!attachments.isEmpty()) {
|
||||
JSONArray out = new JSONArray();
|
||||
for (FileAttachment a : attachments) {
|
||||
JSONObject ao = new JSONObject()
|
||||
.put("file_url", a.getFileUrl())
|
||||
.put("file_type", a.getFileType())
|
||||
.put("file_name", a.getFileName() == null ? JSONObject.NULL : a.getFileName())
|
||||
.put("file_size", a.getFileSize() == null ? JSONObject.NULL : a.getFileSize())
|
||||
.put("mime_type", a.getMimeType() == null ? JSONObject.NULL : a.getMimeType())
|
||||
.put("width", a.getWidth() == null ? JSONObject.NULL : a.getWidth())
|
||||
.put("height", a.getHeight() == null ? JSONObject.NULL : a.getHeight())
|
||||
.put("duration_seconds", a.getDurationSeconds() == null ? JSONObject.NULL : a.getDurationSeconds())
|
||||
.put("thumbnail_url", a.getThumbnailUrl() == null ? JSONObject.NULL : a.getThumbnailUrl());
|
||||
out.put(ao);
|
||||
}
|
||||
data.put("attachments", out);
|
||||
}
|
||||
|
||||
User sender = userDatabase.findByInternalUUID(senderId);
|
||||
if (sender != null) data.put("sender_name", sender.getProfile_name());
|
||||
payload.put("data", data);
|
||||
|
||||
List<UUID> receivers = getReceiversForChat(receiverId, receiverType);
|
||||
receivers.remove(senderId);
|
||||
RealTimeEventDispatcher.sendNewMessage(msg, receivers);
|
||||
RealTimeEventDispatcher.broadcastToUsers(receivers, payload);
|
||||
|
||||
// Update chat list (last_message_time)
|
||||
JSONObject chatUpdate = new JSONObject();
|
||||
chatUpdate.put("chat_id", receiverId.toString());
|
||||
chatUpdate.put("chat_type", receiverType);
|
||||
chatUpdate.put("last_message_time", LocalDateTime.now().toString());
|
||||
// chat_updated
|
||||
JSONObject chatUpdate = new JSONObject()
|
||||
.put("chat_id", receiverId.toString())
|
||||
.put("chat_type", receiverType)
|
||||
.put("last_message_time", LocalDateTime.now().toString());
|
||||
|
||||
JSONObject chatPayload = new JSONObject();
|
||||
chatPayload.put("action", "chat_updated");
|
||||
chatPayload.put("data", chatUpdate);
|
||||
JSONObject chatPayload = new JSONObject()
|
||||
.put("action", "chat_updated")
|
||||
.put("data", chatUpdate);
|
||||
|
||||
for (UUID receiver : receivers) {
|
||||
RealTimeEventDispatcher.sendToUser(receiver, chatPayload);
|
||||
}
|
||||
for (UUID r : receivers) RealTimeEventDispatcher.sendToUser(r, chatPayload);
|
||||
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("message_id", messageId.toString());
|
||||
return new ResponseModel("success", "Message sent successfully.", data);
|
||||
JSONObject respData = new JSONObject().put("message_id", messageId.toString());
|
||||
return new ResponseModel("success", "Message sent successfully.", respData);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -2548,6 +2686,7 @@ public class ClientHandler implements Runnable {
|
||||
}
|
||||
|
||||
|
||||
|
||||
private List<UUID> getReceiversForChat(UUID receiverId, String receiverType) {
|
||||
switch (receiverType) {
|
||||
case "private":
|
||||
|
||||
@@ -9,6 +9,7 @@ import java.net.Socket;
|
||||
public class MainServer {
|
||||
private static final int PORT = 8000;
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
try (ServerSocket serverSocket = new ServerSocket(PORT)) {
|
||||
System.out.println("Server started on port " + PORT);
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.to.telegramfinalproject.Server;
|
||||
|
||||
import org.to.telegramfinalproject.Database.userDatabase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class TestServer {
|
||||
private static final int SOCKET_PORT = 8000; // سرور سوکت
|
||||
private static final int HTTP_PORT = 8080; // سرور آپلود
|
||||
private static final String UPLOAD_BASE_DIR = "uploads"; // پوشهی ذخیره فایلها
|
||||
|
||||
public static void main(String[] args) {
|
||||
// 1) استارت HTTP Upload در ترد جدا
|
||||
Thread httpThread = new Thread(() -> {
|
||||
try {
|
||||
UploadHttp.start(HTTP_PORT, UPLOAD_BASE_DIR);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Upload HTTP failed to start: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}, "upload-http");
|
||||
httpThread.setDaemon(true);
|
||||
httpThread.start();
|
||||
|
||||
// 2) سرور سوکت با Thread Pool
|
||||
ExecutorService pool = Executors.newCachedThreadPool();
|
||||
try (ServerSocket serverSocket = new ServerSocket(SOCKET_PORT)) {
|
||||
System.out.println("Socket server started on port " + SOCKET_PORT);
|
||||
userDatabase.setAllUsersOffline();
|
||||
|
||||
// 3) Shutdown Hook برای خاموشی تمیز
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||
System.out.println("\nShutting down...");
|
||||
try { serverSocket.close(); } catch (IOException ignore) {}
|
||||
pool.shutdownNow();
|
||||
userDatabase.setAllUsersOffline();
|
||||
System.out.println("Goodbye.");
|
||||
}));
|
||||
|
||||
// 4) حلقه پذیرش اتصالها
|
||||
while (!serverSocket.isClosed()) {
|
||||
Socket clientSocket = serverSocket.accept();
|
||||
clientSocket.setTcpNoDelay(true);
|
||||
System.out.println("New client connected: " + clientSocket.getInetAddress());
|
||||
pool.submit(new ClientHandler(clientSocket));
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
System.err.println("Socket server error: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,20 @@
|
||||
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 javax.servlet.MultipartConfigElement;
|
||||
import javax.servlet.http.Part;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.nio.file.*;
|
||||
|
||||
|
||||
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.*;
|
||||
import java.time.LocalDate;
|
||||
|
||||
import javax.sound.sampled.*; // برای WAV
|
||||
|
||||
// برای ویدیو (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 org.json.JSONObject;
|
||||
import com.mpatric.mp3agic.Mp3File;
|
||||
|
||||
public class UploadHttp {
|
||||
@@ -67,7 +52,7 @@ public class UploadHttp {
|
||||
String original = filePart.getSubmittedFileName();
|
||||
String ext = guessExt(original, mime);
|
||||
String day = LocalDate.now().toString();
|
||||
String typeDir = subdirFor(mime); // images/videos/audios/files
|
||||
String typeDir = subdirFor(mime); // images/audios/files
|
||||
String subdir = typeDir + "/" + day;
|
||||
String name = java.util.UUID.randomUUID() + ext;
|
||||
|
||||
@@ -84,39 +69,15 @@ public class UploadHttp {
|
||||
String fileUrl = "/" + subdir.replace('\\', '/') + "/" + name;
|
||||
String fileType = mapToFileType(mime);
|
||||
|
||||
// متادیتا
|
||||
//Meta deta only for audio and image
|
||||
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) {}
|
||||
}
|
||||
durationSeconds = audioDurationSeconds(target, mime, ext);
|
||||
}
|
||||
|
||||
res.status(200);
|
||||
@@ -129,11 +90,11 @@ public class UploadHttp {
|
||||
.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)
|
||||
.put("thumbnail_url", JSONObject.NULL)
|
||||
.toString();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(); // لوکال
|
||||
e.printStackTrace();
|
||||
res.status(500);
|
||||
return jsonError("internal error");
|
||||
}
|
||||
@@ -153,7 +114,6 @@ public class UploadHttp {
|
||||
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";
|
||||
}
|
||||
@@ -164,7 +124,6 @@ public class UploadHttp {
|
||||
if (m.contains("gif")) return "GIF";
|
||||
return "IMAGE";
|
||||
}
|
||||
if (m.startsWith("video/")) return "VIDEO";
|
||||
if (m.startsWith("audio/")) return "AUDIO";
|
||||
return "FILE";
|
||||
}
|
||||
@@ -177,14 +136,13 @@ public class UploadHttp {
|
||||
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 ("audio/wav".equalsIgnoreCase(mime) || "audio/x-wav".equalsIgnoreCase(mime)) return ".wav";
|
||||
if ("application/pdf".equalsIgnoreCase(mime)) return ".pdf";
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String safeName(String name) {
|
||||
// پاکسازی خیلی ساده برای خروجی
|
||||
return name.replace("\"", "").replace("\n", "").replace("\r", "");
|
||||
}
|
||||
|
||||
@@ -196,49 +154,30 @@ public class UploadHttp {
|
||||
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) {
|
||||
//only audio
|
||||
private static Integer audioDurationSeconds(Path file, String mime, String ext) {
|
||||
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) {}
|
||||
if ("audio/mpeg".equalsIgnoreCase(mime) || ".mp3".equalsIgnoreCase(ext)) {
|
||||
Mp3File mp3 = new Mp3File(file.toFile());
|
||||
return (int) mp3.getLengthInSeconds();
|
||||
}
|
||||
|
||||
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) {}
|
||||
// WAV با javax.sound.sampled
|
||||
if ("audio/wav".equalsIgnoreCase(mime) || "audio/x-wav".equalsIgnoreCase(mime) || ".wav".equalsIgnoreCase(ext)) {
|
||||
try (AudioInputStream ais = AudioSystem.getAudioInputStream(file.toFile())) {
|
||||
AudioFormat format = ais.getFormat();
|
||||
long frames = ais.getFrameLength();
|
||||
if (frames > 0 && format.getFrameRate() > 0) {
|
||||
double seconds = frames / format.getFrameRate();
|
||||
return (int)Math.round(seconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (UnsupportedAudioFileException | IOException ignore) {
|
||||
// فرمت صوتی پشتیبانی نشده برای AudioSystem
|
||||
} catch (Exception ignore) {
|
||||
// mp3agic یا سایر استثناها
|
||||
}
|
||||
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