mirror of
https://github.com/tonikelope/megabasterd.git
synced 2025-04-30 14:44:33 +02:00
7.62
https://github.com/tonikelope/megabasterd/issues/437 (EXPERIMENTAL FOR IMAGES AND VIDEOS)
This commit is contained in:
parent
49ee626665
commit
34f77537bb
21
pom.xml
21
pom.xml
@ -3,8 +3,22 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>com.tonikelope</groupId>
|
<groupId>com.tonikelope</groupId>
|
||||||
<artifactId>MegaBasterd</artifactId>
|
<artifactId>MegaBasterd</artifactId>
|
||||||
<version>7.61</version>
|
<version>7.62</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>olivier-ayache-xuggler</id>
|
||||||
|
<url>https://dl.cloudsmith.io/public/olivier-ayache/xuggler/maven/</url>
|
||||||
|
<releases>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
<updatePolicy>always</updatePolicy>
|
||||||
|
</releases>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
<updatePolicy>always</updatePolicy>
|
||||||
|
</snapshots>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.xerial</groupId>
|
<groupId>org.xerial</groupId>
|
||||||
@ -39,6 +53,11 @@
|
|||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
<version>2.12.6.1</version>
|
<version>2.12.6.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>xuggle</groupId>
|
||||||
|
<artifactId>xuggle-xuggler-server-all</artifactId>
|
||||||
|
<version>5.7.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
@ -285,7 +285,6 @@
|
|||||||
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
|
||||||
<Font name="Dialog" size="14" style="1"/>
|
<Font name="Dialog" size="14" style="1"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="selected" type="boolean" value="true"/>
|
|
||||||
<Property name="text" type="java.lang.String" value="Enable log file"/>
|
<Property name="text" type="java.lang.String" value="Enable log file"/>
|
||||||
<Property name="doubleBuffered" type="boolean" value="true"/>
|
<Property name="doubleBuffered" type="boolean" value="true"/>
|
||||||
<Property name="enabled" type="boolean" value="false"/>
|
<Property name="enabled" type="boolean" value="false"/>
|
||||||
|
@ -330,7 +330,6 @@ public class FileGrabberDialog extends javax.swing.JDialog {
|
|||||||
});
|
});
|
||||||
|
|
||||||
upload_log_checkbox.setFont(new java.awt.Font("Dialog", 1, 14)); // NOI18N
|
upload_log_checkbox.setFont(new java.awt.Font("Dialog", 1, 14)); // NOI18N
|
||||||
upload_log_checkbox.setSelected(true);
|
|
||||||
upload_log_checkbox.setText("Enable log file");
|
upload_log_checkbox.setText("Enable log file");
|
||||||
upload_log_checkbox.setDoubleBuffered(true);
|
upload_log_checkbox.setDoubleBuffered(true);
|
||||||
upload_log_checkbox.setEnabled(false);
|
upload_log_checkbox.setEnabled(false);
|
||||||
|
@ -891,6 +891,7 @@ public class LabelTranslatorSingleton {
|
|||||||
_addTranslation("Execute this command when MEGA download limit is reached:", "Ejecutar este comando cuando se alcance el límite de descarga de MEGA:");
|
_addTranslation("Execute this command when MEGA download limit is reached:", "Ejecutar este comando cuando se alcance el límite de descarga de MEGA:");
|
||||||
_addTranslation("Use this proxy list (instead of the one included in MegaBasterd) Format is [*]IP:PORT[@user_b64:password_b64]", "Usar esta lista de proxys (en vez de la incluida en MegaBasterd) El formato es [*]IP:PUERTO[@usuario_b64:password_b64]");
|
_addTranslation("Use this proxy list (instead of the one included in MegaBasterd) Format is [*]IP:PORT[@user_b64:password_b64]", "Usar esta lista de proxys (en vez de la incluida en MegaBasterd) El formato es [*]IP:PUERTO[@usuario_b64:password_b64]");
|
||||||
_addTranslation("Waiting for completion handler ... ***DO NOT EXIT MEGABASTERD NOW***", "Esperando manejador de finalización ... ***NO CIERRES MEGABASTERD EN ESTE MOMENTO***");
|
_addTranslation("Waiting for completion handler ... ***DO NOT EXIT MEGABASTERD NOW***", "Esperando manejador de finalización ... ***NO CIERRES MEGABASTERD EN ESTE MOMENTO***");
|
||||||
|
_addTranslation("Creating and uploading thumbnails ... ***DO NOT EXIT MEGABASTERD NOW***", "Creando y subiendo thumbnails ... ***NO CIERRES MEGABASTERD EN ESTE MOMENTO***");
|
||||||
_addTranslation("Finishing calculating CBC-MAC code (this could take a while) ... ***DO NOT EXIT MEGABASTERD NOW***", "Terminando de calcular código CBC-MAC (esto podría llevar tiempo) ... ***NO CIERRES MEGABASTERD EN ESTE MOMENTO***");
|
_addTranslation("Finishing calculating CBC-MAC code (this could take a while) ... ***DO NOT EXIT MEGABASTERD NOW***", "Terminando de calcular código CBC-MAC (esto podría llevar tiempo) ... ***NO CIERRES MEGABASTERD EN ESTE MOMENTO***");
|
||||||
_addTranslation("Split content in different uploads", "Separar contenido en diferentes subidas");
|
_addTranslation("Split content in different uploads", "Separar contenido en diferentes subidas");
|
||||||
_addTranslation("Merge content in the same upload", "Juntar todo en la misma subida");
|
_addTranslation("Merge content in the same upload", "Juntar todo en la misma subida");
|
||||||
|
@ -67,7 +67,7 @@ import javax.swing.UIManager;
|
|||||||
*/
|
*/
|
||||||
public final class MainPanel {
|
public final class MainPanel {
|
||||||
|
|
||||||
public static final String VERSION = "7.61";
|
public static final String VERSION = "7.62";
|
||||||
public static final boolean FORCE_SMART_PROXY = false; //TRUE FOR DEBUGING SMART PROXY
|
public static final boolean FORCE_SMART_PROXY = false; //TRUE FOR DEBUGING SMART PROXY
|
||||||
public static final int THROTTLE_SLICE_SIZE = 16 * 1024;
|
public static final int THROTTLE_SLICE_SIZE = 16 * 1024;
|
||||||
public static final int DEFAULT_BYTE_BUFFER_SIZE = 16 * 1024;
|
public static final int DEFAULT_BYTE_BUFFER_SIZE = 16 * 1024;
|
||||||
|
@ -17,12 +17,15 @@ import java.io.ByteArrayOutputStream;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.Proxy;
|
import java.net.Proxy;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -634,6 +637,19 @@ public class MegaAPI implements Serializable {
|
|||||||
return file_data;
|
return file_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private byte[] _encThumbAttr(byte[] attr_byte, byte[] key) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
return aes_cbc_encrypt_pkcs7(attr_byte, key, AES_ZERO_IV);
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
LOG.log(Level.SEVERE, ex.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private byte[] _encAttr(String attr, byte[] key) {
|
private byte[] _encAttr(String attr, byte[] key) {
|
||||||
|
|
||||||
byte[] ret = null;
|
byte[] ret = null;
|
||||||
@ -714,6 +730,115 @@ public class MegaAPI implements Serializable {
|
|||||||
return ul_url;
|
return ul_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String uploadThumbnails(Upload upload, String node_handle, String filename0, String filename1) throws MegaAPIException {
|
||||||
|
|
||||||
|
String[] ul_url = new String[2];
|
||||||
|
|
||||||
|
String[] hash = new String[2];
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
File[] files = new File[2];
|
||||||
|
|
||||||
|
files[0] = new File(filename0);
|
||||||
|
|
||||||
|
byte[][] file_bytes = new byte[2][];
|
||||||
|
|
||||||
|
file_bytes[0] = _encThumbAttr(Files.readAllBytes(files[0].toPath()), upload.getByte_file_key());
|
||||||
|
|
||||||
|
files[1] = new File(filename1);
|
||||||
|
|
||||||
|
file_bytes[1] = _encThumbAttr(Files.readAllBytes(files[1].toPath()), upload.getByte_file_key());
|
||||||
|
|
||||||
|
String request = "[{\"a\":\"ufa\", \"s\":" + String.valueOf(file_bytes[0].length) + ", \"ssl\":1}, {\"a\":\"ufa\", \"s\":" + String.valueOf(file_bytes[1].length) + ", \"ssl\":1}]";
|
||||||
|
|
||||||
|
System.out.println(request);
|
||||||
|
URL url_api = new URL(API_URL + "/cs?id=" + String.valueOf(_seqno) + (_sid != null ? "&sid=" + _sid : "") + (API_KEY != null ? "&ak=" + API_KEY : ""));
|
||||||
|
|
||||||
|
String res = _rawRequest(request, url_api);
|
||||||
|
|
||||||
|
System.out.println(res);
|
||||||
|
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
HashMap[] res_map = objectMapper.readValue(res, HashMap[].class);
|
||||||
|
|
||||||
|
ul_url[0] = (String) res_map[0].get("p");
|
||||||
|
|
||||||
|
ul_url[1] = (String) res_map[1].get("p");
|
||||||
|
|
||||||
|
int h = 0;
|
||||||
|
|
||||||
|
for (String u : ul_url) {
|
||||||
|
|
||||||
|
URL url = new URL(u);
|
||||||
|
|
||||||
|
HttpURLConnection con;
|
||||||
|
|
||||||
|
con = (HttpURLConnection) url.openConnection();
|
||||||
|
|
||||||
|
con.setConnectTimeout(Transference.HTTP_CONNECT_TIMEOUT);
|
||||||
|
|
||||||
|
con.setReadTimeout(Transference.HTTP_READ_TIMEOUT);
|
||||||
|
|
||||||
|
con.setRequestMethod("POST");
|
||||||
|
|
||||||
|
con.setDoOutput(true);
|
||||||
|
|
||||||
|
con.setUseCaches(false);
|
||||||
|
|
||||||
|
con.setRequestProperty("User-Agent", MainPanel.DEFAULT_USER_AGENT);
|
||||||
|
|
||||||
|
byte[] buffer = new byte[8192];
|
||||||
|
|
||||||
|
int reads;
|
||||||
|
|
||||||
|
try ( OutputStream out = new ThrottledOutputStream(con.getOutputStream(), upload.getMain_panel().getStream_supervisor())) {
|
||||||
|
|
||||||
|
out.write(file_bytes[h]);
|
||||||
|
}
|
||||||
|
|
||||||
|
try ( InputStream is = con.getInputStream(); ByteArrayOutputStream byte_res = new ByteArrayOutputStream()) {
|
||||||
|
|
||||||
|
while ((reads = is.read(buffer)) != -1) {
|
||||||
|
byte_res.write(buffer, 0, reads);
|
||||||
|
}
|
||||||
|
|
||||||
|
hash[h] = MiscTools.Bin2UrlBASE64(byte_res.toByteArray());
|
||||||
|
|
||||||
|
System.out.println(hash[h]);
|
||||||
|
}
|
||||||
|
|
||||||
|
h++;
|
||||||
|
}
|
||||||
|
|
||||||
|
request = "[{\"a\":\"pfa\", \"fa\":\"0*" + hash[0] + "/1*" + hash[1] + "\", \"n\":\"" + node_handle + "\"}]";
|
||||||
|
|
||||||
|
url_api = new URL(API_URL + "/cs?id=" + String.valueOf(_seqno) + (_sid != null ? "&sid=" + _sid : "") + (API_KEY != null ? "&ak=" + API_KEY : ""));
|
||||||
|
|
||||||
|
res = _rawRequest(request, url_api);
|
||||||
|
|
||||||
|
System.out.println(request);
|
||||||
|
|
||||||
|
objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
String[] resp = objectMapper.readValue(res, String[].class);
|
||||||
|
|
||||||
|
System.out.println((String) resp[0]);
|
||||||
|
|
||||||
|
return (String) resp[0];
|
||||||
|
|
||||||
|
} catch (MegaAPIException mae) {
|
||||||
|
|
||||||
|
throw mae;
|
||||||
|
|
||||||
|
} catch (Exception ex) {
|
||||||
|
LOG.log(Level.SEVERE, ex.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
public HashMap<String, Object> finishUploadFile(String fbasename, int[] ul_key, int[] fkey, int[] meta_mac, String completion_handle, String mega_parent, byte[] master_key, String root_node, byte[] share_key) throws MegaAPIException {
|
public HashMap<String, Object> finishUploadFile(String fbasename, int[] ul_key, int[] fkey, int[] meta_mac, String completion_handle, String mega_parent, byte[] master_key, String root_node, byte[] share_key) throws MegaAPIException {
|
||||||
|
|
||||||
HashMap[] res_map = null;
|
HashMap[] res_map = null;
|
||||||
|
@ -17,12 +17,15 @@ import java.awt.Dialog;
|
|||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.FontFormatException;
|
import java.awt.FontFormatException;
|
||||||
import java.awt.Frame;
|
import java.awt.Frame;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
import java.awt.GraphicsEnvironment;
|
import java.awt.GraphicsEnvironment;
|
||||||
|
import java.awt.Image;
|
||||||
import java.awt.Toolkit;
|
import java.awt.Toolkit;
|
||||||
import java.awt.datatransfer.Clipboard;
|
import java.awt.datatransfer.Clipboard;
|
||||||
import java.awt.datatransfer.DataFlavor;
|
import java.awt.datatransfer.DataFlavor;
|
||||||
import java.awt.datatransfer.StringSelection;
|
import java.awt.datatransfer.StringSelection;
|
||||||
import java.awt.datatransfer.Transferable;
|
import java.awt.datatransfer.Transferable;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -126,6 +129,28 @@ public class MiscTools {
|
|||||||
return getFechaHoraActual(format);
|
return getFechaHoraActual(format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isVideoFile(Path path) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
return Files.probeContentType(path).startsWith("video/");
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Logger.getLogger(MiscTools.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isImageFile(Path path) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
return Files.probeContentType(path).startsWith("image/");
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Logger.getLogger(MiscTools.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public static String getFechaHoraActual(String format) {
|
public static String getFechaHoraActual(String format) {
|
||||||
|
|
||||||
Date currentDate = new Date(System.currentTimeMillis());
|
Date currentDate = new Date(System.currentTimeMillis());
|
||||||
@ -241,6 +266,23 @@ public class MiscTools {
|
|||||||
return bigi;
|
return bigi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BufferedImage toBufferedImage(Image img) {
|
||||||
|
if (img instanceof BufferedImage) {
|
||||||
|
return (BufferedImage) img;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a buffered image with transparency
|
||||||
|
BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
|
||||||
|
|
||||||
|
// Draw the image on to the buffered image
|
||||||
|
Graphics2D bGr = bimage.createGraphics();
|
||||||
|
bGr.drawImage(img, 0, 0, null);
|
||||||
|
bGr.dispose();
|
||||||
|
|
||||||
|
// Return the buffered image
|
||||||
|
return bimage;
|
||||||
|
}
|
||||||
|
|
||||||
public static String genID(int length) {
|
public static String genID(int length) {
|
||||||
|
|
||||||
String pos = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
String pos = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
|
@ -2049,7 +2049,7 @@ public class SettingsDialog extends javax.swing.JDialog {
|
|||||||
|
|
||||||
boolean error_2FA = false;
|
boolean error_2FA = false;
|
||||||
|
|
||||||
if (ma.check2FA(email)) {
|
if (!_main_panel.getMega_active_accounts().containsKey(email) && ma.check2FA(email)) {
|
||||||
|
|
||||||
Get2FACode dialog = new Get2FACode((Frame) getParent(), true, email, _main_panel);
|
Get2FACode dialog = new Get2FACode((Frame) getParent(), true, email, _main_panel);
|
||||||
|
|
||||||
@ -2065,6 +2065,7 @@ public class SettingsDialog extends javax.swing.JDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!error_2FA) {
|
if (!error_2FA) {
|
||||||
|
if (!_main_panel.getMega_active_accounts().containsKey(email)) {
|
||||||
ma.login(email, pass, pincode);
|
ma.login(email, pass, pincode);
|
||||||
|
|
||||||
ByteArrayOutputStream bs = new ByteArrayOutputStream();
|
ByteArrayOutputStream bs = new ByteArrayOutputStream();
|
||||||
@ -2096,6 +2097,8 @@ public class SettingsDialog extends javax.swing.JDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DBTools.insertMegaAccount(email, password, password_aes, user_hash);
|
DBTools.insertMegaAccount(email, password, password_aes, user_hash);
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
email_error.add(email);
|
email_error.add(email);
|
||||||
}
|
}
|
||||||
@ -2133,7 +2136,7 @@ public class SettingsDialog extends javax.swing.JDialog {
|
|||||||
|
|
||||||
boolean error_2FA = false;
|
boolean error_2FA = false;
|
||||||
|
|
||||||
if (ma.check2FA(email)) {
|
if (!_main_panel.getMega_active_accounts().containsKey(email) && ma.check2FA(email)) {
|
||||||
|
|
||||||
Get2FACode dialog = new Get2FACode((Frame) getParent(), true, email, _main_panel);
|
Get2FACode dialog = new Get2FACode((Frame) getParent(), true, email, _main_panel);
|
||||||
|
|
||||||
@ -2149,7 +2152,7 @@ public class SettingsDialog extends javax.swing.JDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!error_2FA) {
|
if (!error_2FA) {
|
||||||
|
if (!_main_panel.getMega_active_accounts().containsKey(email)) {
|
||||||
ma.login(email, pass, pincode);
|
ma.login(email, pass, pincode);
|
||||||
|
|
||||||
ByteArrayOutputStream bs = new ByteArrayOutputStream();
|
ByteArrayOutputStream bs = new ByteArrayOutputStream();
|
||||||
@ -2183,6 +2186,7 @@ public class SettingsDialog extends javax.swing.JDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DBTools.insertMegaAccount(email, password, password_aes, user_hash);
|
DBTools.insertMegaAccount(email, password, password_aes, user_hash);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
email_error.add(email);
|
email_error.add(email);
|
||||||
}
|
}
|
||||||
|
289
src/main/java/com/tonikelope/megabasterd/Thumbnailer.java
Normal file
289
src/main/java/com/tonikelope/megabasterd/Thumbnailer.java
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
package com.tonikelope.megabasterd;
|
||||||
|
|
||||||
|
import com.xuggle.xuggler.Global;
|
||||||
|
import com.xuggle.xuggler.ICodec;
|
||||||
|
import com.xuggle.xuggler.IContainer;
|
||||||
|
import com.xuggle.xuggler.IPacket;
|
||||||
|
import com.xuggle.xuggler.IPixelFormat;
|
||||||
|
import com.xuggle.xuggler.IStream;
|
||||||
|
import com.xuggle.xuggler.IStreamCoder;
|
||||||
|
import com.xuggle.xuggler.IVideoPicture;
|
||||||
|
import com.xuggle.xuggler.IVideoResampler;
|
||||||
|
import com.xuggle.xuggler.Utils;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.RenderingHints;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
|
public class Thumbnailer {
|
||||||
|
|
||||||
|
public Thumbnailer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final int IMAGE_THUMB_SIZE = 250;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of seconds between frames.
|
||||||
|
*/
|
||||||
|
public static final double SECONDS_BETWEEN_FRAMES = 10;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of nano-seconds between frames.
|
||||||
|
*/
|
||||||
|
public static final long NANO_SECONDS_BETWEEN_FRAMES
|
||||||
|
= (long) (Global.DEFAULT_PTS_PER_SECOND * SECONDS_BETWEEN_FRAMES);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time of last frame write.
|
||||||
|
*/
|
||||||
|
private long mLastPtsWrite = Global.NO_PTS;
|
||||||
|
|
||||||
|
private int conta_frames = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the video frame out to a PNG file every once and a while. The files
|
||||||
|
* are written out to the system's temporary directory.
|
||||||
|
*
|
||||||
|
* @param picture the video frame which contains the time stamp.
|
||||||
|
* @param image the buffered image to write out
|
||||||
|
*/
|
||||||
|
private String processFrame(IVideoPicture picture, BufferedImage image) {
|
||||||
|
try {
|
||||||
|
// if uninitialized, backdate mLastPtsWrite so we get the very
|
||||||
|
// first frame
|
||||||
|
|
||||||
|
if (mLastPtsWrite == Global.NO_PTS) {
|
||||||
|
mLastPtsWrite = picture.getPts() - NANO_SECONDS_BETWEEN_FRAMES;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if it's time to write the next frame
|
||||||
|
if (picture.getPts() - mLastPtsWrite >= NANO_SECONDS_BETWEEN_FRAMES) {
|
||||||
|
// Make a temorary file name
|
||||||
|
|
||||||
|
if (conta_frames == 1) {
|
||||||
|
|
||||||
|
File file = File.createTempFile("megabasterd_thumbnail_" + MiscTools.genID(20), ".jpg");
|
||||||
|
|
||||||
|
// write out JPG
|
||||||
|
ImageIO.write(image, "jpg", file);
|
||||||
|
|
||||||
|
// indicate file written
|
||||||
|
//double seconds = ((double) picture.getPts()) / Global.DEFAULT_PTS_PER_SECOND;
|
||||||
|
//System.out.printf("at elapsed time of %6.3f seconds wrote: %s\n", seconds, file);
|
||||||
|
conta_frames++;
|
||||||
|
|
||||||
|
return file.getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
conta_frames++;
|
||||||
|
|
||||||
|
// update last write time
|
||||||
|
mLastPtsWrite += NANO_SECONDS_BETWEEN_FRAMES;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String createImageThumbnail(String filename) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
BufferedImage imagen_original = ImageIO.read(new File(filename));
|
||||||
|
|
||||||
|
if (imagen_original.getHeight() <= IMAGE_THUMB_SIZE) {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
int h = IMAGE_THUMB_SIZE;
|
||||||
|
|
||||||
|
int w = Math.round((((float) imagen_original.getWidth()) * h) / imagen_original.getHeight());
|
||||||
|
|
||||||
|
BufferedImage newImage = new BufferedImage(w, h, imagen_original.getType());
|
||||||
|
|
||||||
|
Graphics2D g = newImage.createGraphics();
|
||||||
|
|
||||||
|
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
||||||
|
|
||||||
|
g.drawImage(imagen_original, 0, 0, w, h, null);
|
||||||
|
|
||||||
|
g.dispose();
|
||||||
|
|
||||||
|
File file = File.createTempFile("megabasterd_thumbnail_" + MiscTools.genID(20), ".png");
|
||||||
|
|
||||||
|
ImageIO.write(newImage, "png", file);
|
||||||
|
|
||||||
|
return file.getAbsolutePath();
|
||||||
|
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Logger.getLogger(Thumbnailer.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a media container (file) as the first argument, opens it, reads
|
||||||
|
* through the file and captures video frames periodically as specified by
|
||||||
|
* SECONDS_BETWEEN_FRAMES. The frames are written as PNG files into the
|
||||||
|
* system's temporary directory.
|
||||||
|
*
|
||||||
|
* @param args must contain one string which represents a filename
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public String createVideoThumbnail(String filename) {
|
||||||
|
|
||||||
|
// make sure that we can actually convert video pixel formats
|
||||||
|
if (!IVideoResampler.isSupported(
|
||||||
|
IVideoResampler.Feature.FEATURE_COLORSPACECONVERSION)) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"you must install the GPL version of Xuggler (with IVideoResampler"
|
||||||
|
+ " support) for this demo to work");
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a Xuggler container object
|
||||||
|
IContainer container = IContainer.make();
|
||||||
|
|
||||||
|
// open up the container
|
||||||
|
if (container.open(filename, IContainer.Type.READ, null) < 0) {
|
||||||
|
throw new IllegalArgumentException("could not open file: " + filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// query how many streams the call to open found
|
||||||
|
int numStreams = container.getNumStreams();
|
||||||
|
|
||||||
|
// and iterate through the streams to find the first video stream
|
||||||
|
int videoStreamId = -1;
|
||||||
|
IStreamCoder videoCoder = null;
|
||||||
|
for (int i = 0; i < numStreams; i++) {
|
||||||
|
// find the stream object
|
||||||
|
|
||||||
|
IStream stream = container.getStream(i);
|
||||||
|
|
||||||
|
// get the pre-configured decoder that can decode this stream;
|
||||||
|
IStreamCoder coder = stream.getStreamCoder();
|
||||||
|
|
||||||
|
if (coder.getCodecType() == ICodec.Type.CODEC_TYPE_VIDEO) {
|
||||||
|
videoStreamId = i;
|
||||||
|
videoCoder = coder;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (videoStreamId == -1) {
|
||||||
|
throw new RuntimeException("could not find video stream in container: " + filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we have found the video stream in this file. Let's open up
|
||||||
|
// our decoder so it can do work
|
||||||
|
if (videoCoder.open() < 0) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"could not open video decoder for container: " + filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
IVideoResampler resampler = null;
|
||||||
|
if (videoCoder.getPixelType() != IPixelFormat.Type.BGR24) {
|
||||||
|
// if this stream is not in BGR24, we're going to need to
|
||||||
|
// convert it. The VideoResampler does that for us.
|
||||||
|
|
||||||
|
resampler = IVideoResampler.make(
|
||||||
|
videoCoder.getWidth(), videoCoder.getHeight(), IPixelFormat.Type.BGR24,
|
||||||
|
videoCoder.getWidth(), videoCoder.getHeight(), videoCoder.getPixelType());
|
||||||
|
if (resampler == null) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"could not create color space resampler for: " + filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, we start walking through the container looking at each packet.
|
||||||
|
IPacket packet = IPacket.make();
|
||||||
|
|
||||||
|
String frame_file = null;
|
||||||
|
|
||||||
|
while (container.readNextPacket(packet) >= 0 && conta_frames < 2) {
|
||||||
|
|
||||||
|
// Now we have a packet, let's see if it belongs to our video strea
|
||||||
|
if (packet.getStreamIndex() == videoStreamId) {
|
||||||
|
// We allocate a new picture to get the data out of Xuggle
|
||||||
|
|
||||||
|
IVideoPicture picture = IVideoPicture.make(videoCoder.getPixelType(),
|
||||||
|
videoCoder.getWidth(), videoCoder.getHeight());
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
while (offset < packet.getSize()) {
|
||||||
|
// Now, we decode the video, checking for any errors.
|
||||||
|
|
||||||
|
int bytesDecoded = videoCoder.decodeVideo(picture, packet, offset);
|
||||||
|
if (bytesDecoded < 0) {
|
||||||
|
throw new RuntimeException("got error decoding video in: " + filename);
|
||||||
|
}
|
||||||
|
offset += bytesDecoded;
|
||||||
|
|
||||||
|
// Some decoders will consume data in a packet, but will not
|
||||||
|
// be able to construct a full video picture yet. Therefore
|
||||||
|
// you should always check if you got a complete picture from
|
||||||
|
// the decode.
|
||||||
|
if (picture.isComplete()) {
|
||||||
|
IVideoPicture newPic = picture;
|
||||||
|
|
||||||
|
// If the resampler is not null, it means we didn't get the
|
||||||
|
// video in BGR24 format and need to convert it into BGR24
|
||||||
|
// format.
|
||||||
|
if (resampler != null) {
|
||||||
|
// we must resample
|
||||||
|
newPic = IVideoPicture.make(
|
||||||
|
resampler.getOutputPixelFormat(), picture.getWidth(),
|
||||||
|
picture.getHeight());
|
||||||
|
if (resampler.resample(newPic, picture) < 0) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"could not resample video from: " + filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newPic.getPixelType() != IPixelFormat.Type.BGR24) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"could not decode video as BGR 24 bit data in: " + filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert the BGR24 to an Java buffered image
|
||||||
|
BufferedImage javaImage = Utils.videoPictureToImage(newPic);
|
||||||
|
|
||||||
|
// process the video frame
|
||||||
|
frame_file = processFrame(newPic, javaImage);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This packet isn't part of our video stream, so we just
|
||||||
|
// silently drop it.
|
||||||
|
do {
|
||||||
|
} while (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Technically since we're exiting anyway, these will be cleaned up
|
||||||
|
// by the garbage collector... but because we're nice people and
|
||||||
|
// want to be invited places for Christmas, we're going to show how
|
||||||
|
// to clean up.
|
||||||
|
if (videoCoder != null) {
|
||||||
|
videoCoder.close();
|
||||||
|
videoCoder = null;
|
||||||
|
}
|
||||||
|
if (container != null) {
|
||||||
|
container.close();
|
||||||
|
container = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame_file;
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,8 @@ import java.io.File;
|
|||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import static java.lang.Integer.MAX_VALUE;
|
import static java.lang.Integer.MAX_VALUE;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -929,10 +931,43 @@ public class Upload implements Transference, Runnable, SecureSingleThreadNotifia
|
|||||||
} while (upload_res == null && !_exit);
|
} while (upload_res == null && !_exit);
|
||||||
|
|
||||||
if (upload_res != null && !_exit) {
|
if (upload_res != null && !_exit) {
|
||||||
|
try {
|
||||||
List files = (List) upload_res.get("f");
|
List files = (List) upload_res.get("f");
|
||||||
|
|
||||||
_fid = (String) ((Map<String, Object>) files.get(0)).get("h");
|
_fid = (String) ((Map<String, Object>) files.get(0)).get("h");
|
||||||
|
|
||||||
|
if (MiscTools.isVideoFile(Paths.get(_file_name))) {
|
||||||
|
|
||||||
|
getView().printStatusNormal("Creating and uploading thumbnails ... ***DO NOT EXIT MEGABASTERD NOW***");
|
||||||
|
|
||||||
|
Thumbnailer thumbnailer = new Thumbnailer();
|
||||||
|
|
||||||
|
String thumb_file = thumbnailer.createVideoThumbnail(_file_name);
|
||||||
|
|
||||||
|
if (thumb_file != null) {
|
||||||
|
|
||||||
|
_ma.uploadThumbnails(this, _fid, thumb_file, thumb_file);
|
||||||
|
|
||||||
|
Files.deleteIfExists(Paths.get(thumb_file));
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (MiscTools.isImageFile(Paths.get(_file_name))) {
|
||||||
|
|
||||||
|
getView().printStatusNormal("Creating and uploading thumbnails ... ***DO NOT EXIT MEGABASTERD NOW***");
|
||||||
|
|
||||||
|
Thumbnailer thumbnailer = new Thumbnailer();
|
||||||
|
|
||||||
|
String thumb_file = thumbnailer.createImageThumbnail(_file_name);
|
||||||
|
|
||||||
|
if (thumb_file != null) {
|
||||||
|
|
||||||
|
_ma.uploadThumbnails(this, _fid, thumb_file, thumb_file);
|
||||||
|
|
||||||
|
Files.deleteIfExists(Paths.get(thumb_file));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
_file_link = _ma.getPublicFileLink(_fid, i32a2bin(node_key));
|
_file_link = _ma.getPublicFileLink(_fid, i32a2bin(node_key));
|
||||||
@ -965,6 +1000,12 @@ public class Upload implements Transference, Runnable, SecureSingleThreadNotifia
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} catch (MegaAPIException ex) {
|
||||||
|
Logger.getLogger(Upload.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Logger.getLogger(Upload.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
|
}
|
||||||
|
|
||||||
} else if (_status_error != null) {
|
} else if (_status_error != null) {
|
||||||
getView().hideAllExceptStatus();
|
getView().hideAllExceptStatus();
|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 178 KiB After Width: | Height: | Size: 182 KiB |
Loading…
x
Reference in New Issue
Block a user