1000eb.com: fixes #6828

1000eb.com: speed up folder decrypter refs #6828
RAFDownload: added workaround for server responses != 206 example in 1000eb.com hoster plugin
rtmp:
	* upgrade rtmpdump to version 2.4 with redirect patch and other improvements closes #4813
	* new flvfixer class, fixed broken flv streams after resuming
	* add new Config entry in advanced settings tab
rtl2.de: refs #6847
videopremium.net: removed old redirect handling

git-svn-id: svn://svn.jdownloader.org/jdownloader/trunk@18818 ebf7c1c2-ba36-0410-9fe8-c592906822b4
This commit is contained in:
bismarck 2012-10-31 19:33:48 +00:00
parent 6b7e98ffff
commit c36160338f
13 changed files with 609 additions and 201 deletions

View File

@ -0,0 +1,337 @@
// jDownloader - Downloadmanager
// Copyright (C) 2012 JD-Team support@jdownloader.org
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// source@GPLv3: https://github.com/K-S-V/Scripts/blob/master/FlvFixer.php
package jd.network.rtmp;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import jd.utils.JDHexUtils;
import org.appwork.utils.logging2.LogSource;
import org.jdownloader.logging.LogController;
public class FlvFixer {
public static enum Tag {
AUDIO((byte) 0x08),
VIDEO((byte) 0x09),
SCRIPT_DATA((byte) 0x12),
FRAME_TYPE_INFO((byte) 0x05),
CODEC_ID_AVC((byte) 0x07),
CODEC_ID_AAC((byte) 0x0A),
AVC_SEQUENCE_HEADER((byte) 0x00),
AAC_SEQUENCE_HEADER((byte) 0x00),
AVC_SEQUENCE_END((byte) 0x02);
private byte hex;
Tag(byte b) {
hex = b;
}
}
File corruptFile;
File fixedFile;
FileInputStream fis = null;
FileOutputStream fos = null;
final static int FRAMEGAP_DURATION = 8;
final static int INVALID_TIMESTAMP = -1;
boolean DEBUG = false;
private final LogSource logger;
public FlvFixer() {
logger = LogController.CL();
}
public boolean setDebug(boolean b) {
return DEBUG = b;
}
public void setInputFile(File f) {
this.corruptFile = f;
}
public File getoutputFile() {
return fixedFile;
}
public boolean scan() throws Exception {
if (!(corruptFile.exists() && corruptFile.length() > 0)) {
logger.severe("File " + corruptFile.getAbsolutePath() + " not found!");
return false;
}
boolean audio = false;
boolean video = false;
boolean metadata = true;
final String formatDebug = "%14s%14s%14s%14s";
final String format = "%14s%14s%14s";
int baseTS = -1;
int prevTagSize = 4;
int tagHeaderLen = 11;
int filePos = 13;
int prevAudioTS = INVALID_TIMESTAMP;
int prevVideoTS = INVALID_TIMESTAMP;
long pAudioTagPos = 0l;
long pVideoTagPos = 0l;
long pMetaTagPos = 0l;
boolean prevAVCHeader = false;
boolean prevAACHeader = false;
boolean AVCHeaderWritten = false;
boolean AACHeaderWritten = false;
int fileSize = (int) corruptFile.length();
int pFilePos = 0, packetSize = 0, packetTS = 0, tagPos = 0;
byte[] flvHeader = JDHexUtils.getByteArray("464c5601050000000900000000");
byte[] flvTag = new byte[tagHeaderLen];
final List<Byte> extEnum = new ArrayList<Byte>();
extEnum.add((byte) 0x08);
extEnum.add((byte) 0x09);
extEnum.add((byte) 0x12);
fixedFile = new File(corruptFile.getAbsolutePath().replace(".part", ".fixed"));
try {
fis = new FileInputStream(corruptFile);
fos = new FileOutputStream(fixedFile);
/* FLV? */
byte[] flvTagH = new byte[flvHeader.length];
fis.read(flvTagH);
if (!"FLV".equals(new String(flvTagH).substring(0, 3))) {
logger.severe("Input file is not a valid FLV file");
return false;
} else {
fos.write(flvTagH);
}
logger.info("#### FlvFixer: starting scan process... ####");
logger.info("processing file: " + corruptFile.getAbsolutePath());
if (DEBUG) logOutput("Type :", formatDebug, "CurrentTS", "PreviousTS", "Size", "Position", Level.FINEST);
try {
while (filePos < fileSize) {
/* 11 byte header */
fis.read(flvTag);
/* size and type of data */
byte packetType = flvTag[0];
packetSize = getInt(flvTag, 1);
packetTS = getInt(flvTag, 4) | (flvTag[7] & 0xff) << 24;
if (baseTS < 0 && (packetType == Tag.AUDIO.hex || packetType == Tag.VIDEO.hex)) baseTS = packetTS;
if (baseTS > 1000) {
packetTS -= baseTS;
writeFlvTimestamp(packetTS, flvTag);
}
/* header + data */
int totalTagLen = tagHeaderLen + packetSize + prevTagSize;
byte[] newflvTag = new byte[totalTagLen];
System.arraycopy(flvTag, 0, newflvTag, 0, flvTag.length);
int leftBytes = fis.available();
fis.read(newflvTag, tagHeaderLen, packetSize + prevTagSize);
if (newflvTag.length != totalTagLen || leftBytes < packetSize + prevTagSize) {
logger.warning("Broken FLV tag encountered! Aborting further processing.");
break;
}
byte AAC_PacketType = 0;
byte AVC_PacketType = 0;
switch (Tag.values()[extEnum.indexOf(packetType)]) {
case AUDIO:
if (packetTS > prevAudioTS - FRAMEGAP_DURATION * 5) {
byte FrameInfo = newflvTag[tagPos + tagHeaderLen];
byte CodecID = (byte) ((FrameInfo & 0xF0) >> 4);
if (CodecID == Tag.CODEC_ID_AAC.hex) {
AAC_PacketType = newflvTag[tagPos + tagHeaderLen + 1];
if (AAC_PacketType == Tag.AAC_SEQUENCE_HEADER.hex) {
if (AACHeaderWritten) {
logOutput("Skipping AAC sequence header AUDIO:", format, packetTS, prevAudioTS, packetSize, Level.INFO);
break;
} else {
logger.info("Writing AAC sequence header");
AACHeaderWritten = true;
}
}
if (!AACHeaderWritten) {
logOutput("Discarding audio packet received before AAC sequence header AUDIO:", format, packetTS, prevAudioTS, packetSize, Level.WARNING);
break;
}
}
if (packetSize > 0) {
/* Check for packets with non-monotonic audio timestamps and fix them */
if (!(CodecID == Tag.CODEC_ID_AAC.hex && (AAC_PacketType == Tag.AAC_SEQUENCE_HEADER.hex || prevAACHeader))) {
if (prevAudioTS != INVALID_TIMESTAMP && packetTS <= prevAudioTS) {
logOutput("Fixing audio timestamp AUDIO:", format, packetTS, prevAudioTS, packetSize, Level.INFO);
packetTS += FRAMEGAP_DURATION + (prevAudioTS - packetTS);
writeFlvTimestamp(packetTS, flvTag);
}
}
pAudioTagPos = fos.getChannel().position();
fos.write(newflvTag);
if (DEBUG) logOutput("AUDIO:", formatDebug, packetTS, prevAudioTS, packetSize, pAudioTagPos, Level.FINEST);
if (!(CodecID == Tag.CODEC_ID_AAC.hex && AAC_PacketType == Tag.AAC_SEQUENCE_HEADER.hex)) {
prevAACHeader = false;
prevAudioTS = packetTS;
} else {
prevAACHeader = true;
}
} else {
logOutput("Skipping small sized audio packet AUDIO:", format, packetTS, prevAudioTS, packetSize, Level.INFO);
}
} else {
logOutput("Skipping audio packet AUDIO:", format, packetTS, prevAudioTS, packetSize, Level.INFO);
}
if (!audio) audio = true;
break;
case VIDEO:
if (packetTS > prevVideoTS - FRAMEGAP_DURATION * 5) {
byte FrameInfo = newflvTag[tagPos + tagHeaderLen];
byte FrameType = (byte) ((FrameInfo & 0xF0) >> 4);
byte CodecID = (byte) (FrameInfo & 0x0F);
if (FrameType == Tag.FRAME_TYPE_INFO.hex) {
logOutput("Skipping video info frame VIDEO:", format, packetTS, prevVideoTS, packetSize, Level.WARNING);
break;
}
if (CodecID == Tag.CODEC_ID_AVC.hex) {
AVC_PacketType = newflvTag[tagPos + tagHeaderLen + 1];
if (AVC_PacketType == Tag.AVC_SEQUENCE_HEADER.hex) {
if (AVCHeaderWritten) {
logOutput("Skipping AVC sequence header VIDEO:", format, packetTS, prevVideoTS, packetSize, Level.INFO);
break;
} else {
logger.info("Writing AVC sequence header");
AVCHeaderWritten = true;
}
}
if (!AVCHeaderWritten) {
logOutput("Discarding video packet received before AVC sequence header VIDEO:", format, packetTS, prevVideoTS, packetSize, Level.WARNING);
break;
}
}
if (packetSize > 0) {
/* Check for packets with non-monotonic video timestamps and fix them */
if (!(CodecID == Tag.CODEC_ID_AVC.hex && (AVC_PacketType == Tag.AVC_SEQUENCE_HEADER.hex || AVC_PacketType == Tag.AVC_SEQUENCE_END.hex || prevAVCHeader))) {
if (prevVideoTS != INVALID_TIMESTAMP && packetTS <= prevVideoTS) {
logOutput("Fixing video timestamp VIDEO:", format, packetTS, prevVideoTS, packetSize, Level.INFO);
packetTS += FRAMEGAP_DURATION + (prevVideoTS - packetTS);
writeFlvTimestamp(packetTS, flvTag);
}
}
pVideoTagPos = fos.getChannel().position();
fos.write(newflvTag);
if (DEBUG) logOutput("VIDEO:", formatDebug, packetTS, prevVideoTS, packetSize, pVideoTagPos, Level.FINEST);
if (!(CodecID == Tag.CODEC_ID_AVC.hex && AVC_PacketType == Tag.AVC_SEQUENCE_HEADER.hex)) {
prevAVCHeader = false;
prevVideoTS = packetTS;
} else {
prevAVCHeader = true;
}
} else {
logOutput("Skipping small sized video packet VIDEO:", format, packetTS, prevVideoTS, packetSize, Level.INFO);
}
} else {
logOutput("Skipping video packet VIDEO:", format, packetTS, prevVideoTS, packetSize, Level.INFO);
}
if (!video) video = true;
break;
case SCRIPT_DATA:
if (metadata) {
pMetaTagPos = fos.getChannel().position();
fos.write(newflvTag);
if (DEBUG) logOutput("META :", formatDebug, packetTS, 0, packetSize, pMetaTagPos, Level.FINEST);
}
break;
}
filePos += totalTagLen;
int cFilePos = (int) filePos / (1024 * 1024);
if (cFilePos > pFilePos) {
// System.out.printf("Processed %d/%.2f MB\r", cFilePos, fileSize);
pFilePos = cFilePos;
}
}
/* Fix flv header when required */
if (!(audio && video)) {
if (audio && !video) {
flvHeader[4] = 4;
} else if (video && !audio) {
flvHeader[4] = 1;
}
fos.getChannel().position(0l);
fos.write(flvHeader, 0, flvHeader.length);
logger.info("Fix flv header --> " + (audio ? "audio" : "video"));
}
} catch (Throwable e) {
logger.severe("#### FlvFixer: an error has occurred! " + e.getMessage());
return false;
}
} finally {
try {
fis.close();
} catch (final Throwable e) {
}
try {
fos.close();
} catch (final Throwable e) {
}
}
logger.info("#### FlvFixer: scan process done! ####");
return true;
}
private void logOutput(String msg, String formatter, Integer a, Integer b, Integer c, Level l) {
logger.log(l, String.format(msg + formatter, a, b, c));
}
private void logOutput(String msg, String formatter, Object a, Object b, Object c, Object d, Level l) {
logger.log(l, String.format(msg + formatter, a, b, c, d));
}
private void writeFlvTimestamp(int baseTS, byte[] flvTag) {
System.arraycopy(JDHexUtils.getByteArray(String.format("%08x", baseTS)), 0, flvTag, 4, 4);
}
private int getInt(byte[] array, int offset) {
return ((0x00 & 0xff) << 24) | ((array[offset] & 0xff) << 16) | ((array[offset + 1] & 0xff) << 8) | (array[offset + 2] & 0xff);
}
}

View File

@ -9,12 +9,14 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jd.network.rtmp.url.RtmpUrlConnection;
import jd.nutils.JDHash;
import jd.plugins.DownloadLink;
import jd.plugins.LinkStatus;
import jd.plugins.PluginException;
import jd.plugins.PluginForHost;
import jd.plugins.hoster.RTMPDownload;
import org.appwork.storage.config.JsonConfig;
import org.appwork.utils.Application;
import org.appwork.utils.Regex;
import org.appwork.utils.formatter.SizeFormatter;
@ -23,6 +25,7 @@ import org.appwork.utils.net.throttledconnection.ThrottledConnectionHandler;
import org.appwork.utils.os.CrossSystem;
import org.appwork.utils.speedmeter.SpeedMeterInterface;
import org.jdownloader.nativ.NativeProcess;
import org.jdownloader.settings.RtmpdumpSettings;
import org.jdownloader.translate._JDT;
public class RtmpDump extends RTMPDownload {
@ -32,7 +35,7 @@ public class RtmpDump extends RTMPDownload {
private ThrottledConnectionHandler handler;
public ThrottledConnectionHandler getHandler() {
return this.handler;
return handler;
}
public int getLimit() {
@ -50,7 +53,7 @@ public class RtmpDump extends RTMPDownload {
}
public void setHandler(final ThrottledConnectionHandler manager) {
this.handler = manager;
handler = manager;
}
public void setLimit(final int kpsLimit) {
@ -63,18 +66,28 @@ public class RtmpDump extends RTMPDownload {
}
private Chunk CHUNK;
private volatile long BYTESLOADED = 0l;
private long SPEED = 0l;
private int PID = -1;
private static String RTMPDUMP = null;
private static String RTMPVERSION = null;
private NativeProcess NP;
private Process P;
private InputStreamReader R;
private RtmpdumpSettings config;
public RtmpDump(final PluginForHost plugin, final DownloadLink downloadLink, final String rtmpURL) throws IOException, PluginException {
super(plugin, downloadLink, rtmpURL);
config = JsonConfig.create(RtmpdumpSettings.class);
}
/**
@ -111,14 +124,19 @@ public class RtmpDump extends RTMPDownload {
private void getProcessId() {
try {
final Field pidField = this.P.getClass().getDeclaredField("pid");
final Field pidField = P.getClass().getDeclaredField("pid");
pidField.setAccessible(true);
this.PID = pidField.getInt(this.P);
PID = pidField.getInt(P);
} catch (final Exception e) {
this.PID = -1;
PID = -1;
}
}
public String getRtmpDumpChecksum() throws Exception {
if (!findRtmpDump()) return null;
return JDHash.getMD5(new File(RTMPDUMP));
}
/**
* Attempt to locate a rtmpdump executable and parse the version number from the 'rtmpdump -h' output.
*
@ -126,7 +144,7 @@ public class RtmpDump extends RTMPDownload {
*/
public synchronized String getRtmpDumpVersion() throws Exception {
if (RTMPVERSION != null) { return RTMPVERSION; }
if (!this.findRtmpDump()) { throw new PluginException(LinkStatus.ERROR_FATAL, "RTMPDump not found!"); }
if (!findRtmpDump()) throw new PluginException(LinkStatus.ERROR_FATAL, "RTMPDump not found!");
final String arg = " -h";
NativeProcess verNP = null;
Process verP = null;
@ -170,45 +188,48 @@ public class RtmpDump extends RTMPDownload {
@Override
public long getTotalLinkBytesLoadedLive() {
return this.BYTESLOADED;
return BYTESLOADED;
}
private void sendSIGINT() {
this.getProcessId();
if (this.PID >= 0) {
getProcessId();
if (PID >= 0) {
try {
Runtime.getRuntime().exec("kill -SIGINT " + String.valueOf(this.PID));
Runtime.getRuntime().exec("kill -SIGINT " + String.valueOf(PID));
} catch (final Throwable e1) {
}
}
}
public boolean start(final RtmpUrlConnection rtmpConnection) throws Exception {
if (!this.findRtmpDump()) { throw new PluginException(LinkStatus.ERROR_FATAL, "Error " + RTMPDUMP + " not found!"); }
if (!findRtmpDump()) { throw new PluginException(LinkStatus.ERROR_FATAL, "Error " + RTMPDUMP + " not found!"); }
boolean debug = config.isDebugModeEnabled();
final ThrottledConnection tcon = new RTMPCon() {
@Override
public long getSpeedMeter() {
return RtmpDump.this.SPEED;
return SPEED;
}
@Override
public long transfered() {
return RtmpDump.this.BYTESLOADED;
return BYTESLOADED;
}
};
try {
this.getManagedConnetionHandler().addThrottledConnection(tcon);
this.addChunksDownloading(1);
this.downloadLink.getLinkStatus().addStatus(LinkStatus.DOWNLOADINTERFACE_IN_PROGRESS);
getManagedConnetionHandler().addThrottledConnection(tcon);
addChunksDownloading(1);
downloadLink.getLinkStatus().addStatus(LinkStatus.DOWNLOADINTERFACE_IN_PROGRESS);
try {
this.downloadLink.getDownloadLinkController().getConnectionHandler().addConnectionHandler(this.getManagedConnetionHandler());
downloadLink.getDownloadLinkController().getConnectionHandler().addConnectionHandler(getManagedConnetionHandler());
} catch (final Throwable e) {
}
rtmpConnection.connect();
File tmpFile = new File(this.downloadLink.getFileOutput() + ".part");
File tmpFile = new File(downloadLink.getFileOutput() + ".part");
if (!CrossSystem.isWindows()) {
tmpFile = new File(this.downloadLink.getFileOutput().replaceAll("\\s", "\\\\s") + ".part");
tmpFile = new File(downloadLink.getFileOutput().replaceAll("\\s", "\\\\s") + ".part");
}
String line = "", error = "";
long iSize = 0;
@ -228,24 +249,24 @@ public class RtmpDump extends RTMPDownload {
}
if (cmd.contains(" -e ")) {
this.setResume(true);
setResume(true);
}
try {
if (CrossSystem.isWindows()) {
this.NP = new NativeProcess(RTMPDUMP, cmd);
this.R = new InputStreamReader(this.NP.getErrorStream());
NP = new NativeProcess(RTMPDUMP, cmd);
R = new InputStreamReader(NP.getErrorStream());
} else {
this.P = Runtime.getRuntime().exec(RTMPDUMP + cmd);
this.R = new InputStreamReader(this.P.getErrorStream());
P = Runtime.getRuntime().exec(RTMPDUMP + cmd);
R = new InputStreamReader(P.getErrorStream());
}
final BufferedReader br = new BufferedReader(this.R);
final BufferedReader br = new BufferedReader(R);
int sizeCalulateBuffer = 0;
float progressFloat = 0;
boolean runTimeSize = false;
long tmplen = 0, fixedlen = 0, calc = 0;
while ((line = br.readLine()) != null) {
// System.out.println(line);
if (debug) logger.finest(line);
if (!line.equals("") && line.startsWith("ERROR:")) {
error = line;
}
@ -255,29 +276,9 @@ public class RtmpDump extends RTMPDownload {
String size = new Regex(line, ".*?(\\d.+)").getMatch(0);
iSize = SizeFormatter.getSize(size);
}
// handle redirect
if (!this.downloadLink.getBooleanProperty("REDIRECT", false)) {
if (line.startsWith("DEBUG:")) {
String debugOutput = line.replaceAll("\\s", "");
if (debugOutput.startsWith("DEBUG:Property:")) {
if (debugOutput.matches("DEBUG:Property:<Name:redirect,STRING:[^>]+>")) {
String redirectUrl = new Regex(debugOutput, "STRING:([^>]+)").getMatch(0);
this.downloadLink.setProperty("REDIRECT", true);
this.downloadLink.setProperty("REDIRECTURL", redirectUrl);
if (tmpFile.exists() && tmpFile.length() == 0) {
if (!tmpFile.delete()) {
this.logger.severe("Could not delete part file " + tmpFile);
this.error(LinkStatus.ERROR_LOCAL_IO, _JDT._.system_download_errors_couldnotdelete());
}
}
return false;
}
}
}
}
} else {
if (this.downloadLink.getDownloadSize() == 0) {
this.downloadLink.setDownloadSize(iSize);
if (downloadLink.getDownloadSize() == 0) {
downloadLink.setDownloadSize(iSize);
}
// is resumed
if (iSize == 0) iSize = downloadLink.getDownloadSize();
@ -285,38 +286,38 @@ public class RtmpDump extends RTMPDownload {
int pos1 = line.indexOf("(");
int pos2 = line.indexOf(")");
if (line.toUpperCase().matches("\\d+\\.\\d+\\sKB\\s/\\s\\d+\\.\\d+\\sSEC(\\s\\(\\d+\\.\\d%\\))?")) {
progressFloat = (float) (Math.round(this.BYTESLOADED * 100.0F / (float) iSize * 10) / 10.0F);
progressFloat = (float) (Math.round(BYTESLOADED * 100.0F / (float) iSize * 10) / 10.0F);
if (runTimeSize && pos1 != -1 && pos2 != -1) {
progressFloat = Float.parseFloat(line.substring(pos1 + 1, pos2 - 1));
}
this.BYTESLOADED = SizeFormatter.getSize(line.substring(0, line.toUpperCase().indexOf("KB") + 2));
BYTESLOADED = SizeFormatter.getSize(line.substring(0, line.toUpperCase().indexOf("KB") + 2));
if (Thread.currentThread().isInterrupted()) {
if (CrossSystem.isWindows()) {
this.NP.sendCtrlCSignal();
NP.sendCtrlCSignal();
} else {
this.sendSIGINT();
sendSIGINT();
}
return true;
}
if (sizeCalulateBuffer > 6 && runTimeSize) {
tmplen = (long) (this.BYTESLOADED * 100.0F / progressFloat);
fixedlen = this.downloadLink.getDownloadSize();
tmplen = (long) (BYTESLOADED * 100.0F / progressFloat);
fixedlen = downloadLink.getDownloadSize();
calc = Math.abs(((fixedlen / 1024) - (tmplen / 1024)) % 1024);
if (calc > 768 && calc < 960) {
this.downloadLink.setDownloadSize(tmplen);
downloadLink.setDownloadSize(tmplen);
}
} else {
sizeCalulateBuffer++;
}
if (System.currentTimeMillis() - lastTime > 1000) {
this.SPEED = (this.BYTESLOADED - before) / (System.currentTimeMillis() - lastTime) * 1000l;
SPEED = (BYTESLOADED - before) / (System.currentTimeMillis() - lastTime) * 1000l;
lastTime = System.currentTimeMillis();
before = this.BYTESLOADED;
before = BYTESLOADED;
// downloadLink.requestGuiUpdate();
this.downloadLink.setChunksProgress(new long[] { this.BYTESLOADED });
downloadLink.setChunksProgress(new long[] { BYTESLOADED });
}
}
}
@ -326,11 +327,11 @@ public class RtmpDump extends RTMPDownload {
// autoresuming when FMS sends NetStatus.Play.Stop and
// progress less than 100%
if (progressFloat < 99.8 && !line.toLowerCase().contains("download complete")) {
System.out.println("Versuch Nr.: " + this.downloadLink.getLinkStatus().getRetryCount() + " ::: " + this.plugin.getMaxRetries(this.downloadLink, null));
if (this.downloadLink.getLinkStatus().getRetryCount() >= this.plugin.getMaxRetries(this.downloadLink, null)) {
this.downloadLink.getLinkStatus().setRetryCount(0);
System.out.println("Versuch Nr.: " + downloadLink.getLinkStatus().getRetryCount() + " ::: " + plugin.getMaxRetries(downloadLink, null));
if (downloadLink.getLinkStatus().getRetryCount() >= plugin.getMaxRetries(downloadLink, null)) {
downloadLink.getLinkStatus().setRetryCount(0);
}
this.downloadLink.getLinkStatus().setStatus(LinkStatus.ERROR_DOWNLOAD_INCOMPLETE);
downloadLink.getLinkStatus().setStatus(LinkStatus.ERROR_DOWNLOAD_INCOMPLETE);
}
Thread.sleep(500);
break;
@ -339,55 +340,79 @@ public class RtmpDump extends RTMPDownload {
rtmpConnection.disconnect();
try {
/* make sure we destroyed the process */
this.P.destroy();
P.destroy();
} catch (final Throwable e) {
}
try {
/* close InputStreamReader */
this.R.close();
R.close();
} catch (final Throwable e) {
}
if (this.NP != null) {
if (NP != null) {
/* close Streams from native */
this.NP.closeStreams();
NP.closeStreams();
}
}
if (this.downloadLink.getLinkStatus().getStatus() == LinkStatus.ERROR_DOWNLOAD_INCOMPLETE) {
return false;
} else if (line != null && line.toLowerCase().contains("download complete")) {
this.downloadLink.setDownloadSize(this.BYTESLOADED);
this.logger.finest("no errors : rename");
if (!tmpFile.renameTo(new File(this.downloadLink.getFileOutput()))) {
this.logger.severe("Could not rename file " + tmpFile + " to " + this.downloadLink.getFileOutput());
this.error(LinkStatus.ERROR_LOCAL_IO, _JDT._.system_download_errors_couldnotrename());
if (downloadLink.getLinkStatus().getStatus() == LinkStatus.ERROR_DOWNLOAD_INCOMPLETE) return false;
if (line != null) {
if (line.toLowerCase().contains("download complete")) {
downloadLink.setDownloadSize(BYTESLOADED);
logger.finest("no errors : rename");
if (!tmpFile.renameTo(new File(downloadLink.getFileOutput()))) {
logger.severe("Could not rename file " + tmpFile + " to " + downloadLink.getFileOutput());
error(LinkStatus.ERROR_LOCAL_IO, _JDT._.system_download_errors_couldnotrename());
}
downloadLink.getLinkStatus().addStatus(LinkStatus.FINISHED);
/* Stream is succesfully downloaded */
return true;
}
this.downloadLink.getLinkStatus().addStatus(LinkStatus.FINISHED);
} else if (error != null && error.toLowerCase().contains("last tag size must be greater/equal zero")) {
this.downloadLink.getLinkStatus().addStatus(LinkStatus.ERROR_DOWNLOAD_INCOMPLETE);
this.downloadLink.reset();
return false;
} else if (error != null && error.toLowerCase().contains("rtmp_readpacket, failed to read rtmp packet header")) {
this.downloadLink.getLinkStatus().addStatus(LinkStatus.ERROR_TEMPORARILY_UNAVAILABLE);
return false;
} else if (line == null && error.isEmpty()) {
this.downloadLink.getLinkStatus().addStatus(LinkStatus.ERROR_RETRY);
this.downloadLink.reset();
return false;
} else {
this.logger.severe("cmd: " + cmd);
this.logger.severe(error);
if (this.downloadLink.hasProperty("REDIRECT")) this.downloadLink.setProperty("REDIRECT", false);
throw new PluginException(LinkStatus.ERROR_FATAL, error);
}
return true;
if (error != null) {
if (error.toLowerCase().contains("last tag size must be greater/equal zero")) {
FlvFixer flvfix = new FlvFixer();
flvfix.setInputFile(tmpFile);
if (debug) flvfix.setDebug(true);
if (!flvfix.scan()) return false;
File fixedFile = flvfix.getoutputFile();
if (!fixedFile.exists()) {
logger.severe("File " + fixedFile.getAbsolutePath() + " not found!");
error(LinkStatus.ERROR_LOCAL_IO, _JDT._.downloadlink_status_error_file_not_found());
}
if (!tmpFile.delete()) {
logger.severe("Could not delete part file " + tmpFile);
error(LinkStatus.ERROR_LOCAL_IO, _JDT._.system_download_errors_couldnotdelete());
}
if (!fixedFile.renameTo(tmpFile)) {
logger.severe("Could not rename file " + tmpFile + " to " + downloadLink.getFileOutput());
error(LinkStatus.ERROR_LOCAL_IO, _JDT._.system_download_errors_couldnotrename());
}
downloadLink.getLinkStatus().addStatus(LinkStatus.ERROR_DOWNLOAD_INCOMPLETE);
} else if (error.toLowerCase().contains("rtmp_readpacket, failed to read rtmp packet header")) {
downloadLink.getLinkStatus().addStatus(LinkStatus.ERROR_TEMPORARILY_UNAVAILABLE);
} else if (error.toLowerCase().contains("netstream.play.streamnotfound")) {
downloadLink.deleteFile(true, false);
downloadLink.getLinkStatus().addStatus(LinkStatus.ERROR_FILE_NOT_FOUND);
} else {
logger.severe("cmd: " + cmd);
logger.severe(error);
throw new PluginException(LinkStatus.ERROR_FATAL, error);
}
}
if (error.isEmpty() && line == null) {
logger.severe("RtmpDump: An unknown error has occured!");
downloadLink.getLinkStatus().addStatus(LinkStatus.ERROR_RETRY);
downloadLink.reset();
}
return false;
} finally {
this.downloadLink.setDownloadCurrent(this.BYTESLOADED);
this.downloadLink.getLinkStatus().removeStatus(LinkStatus.DOWNLOADINTERFACE_IN_PROGRESS);
this.downloadLink.setDownloadInstance(null);
this.downloadLink.getLinkStatus().setStatusText(null);
this.getManagedConnetionHandler().removeThrottledConnection(tcon);
downloadLink.setDownloadCurrent(BYTESLOADED);
downloadLink.getLinkStatus().removeStatus(LinkStatus.DOWNLOADINTERFACE_IN_PROGRESS);
downloadLink.setDownloadInstance(null);
downloadLink.getLinkStatus().setStatusText(null);
getManagedConnetionHandler().removeThrottledConnection(tcon);
try {
this.downloadLink.getDownloadLinkController().getConnectionHandler().removeConnectionHandler(this.getManagedConnetionHandler());
downloadLink.getDownloadLinkController().getConnectionHandler().removeConnectionHandler(getManagedConnetionHandler());
} catch (final Throwable e) {
}
}

View File

@ -34,6 +34,7 @@ public class RtmpUrlConnection extends URLConnection {
private static final String KEY_PLAYPATH = "y"; // playpath
private static final String KEY_LIVE = "v"; // live
private static final String KEY_SUBSCRIBE = "d"; // subscribe
private static final String KEY_REALTIME = "R"; // realtime
private static final String KEY_START = "A"; // start
private static final String KEY_STOP = "B"; // stop
private static final String KEY_BUFFER = "b"; // buffer
@ -102,23 +103,17 @@ public class RtmpUrlConnection extends URLConnection {
}
/**
* Opens a communications link to the resource referenced by this URL, if
* such a connection has not already been established.
* Opens a communications link to the resource referenced by this URL, if such a connection has not already been established.
* <p>
* If the <code>connect</code> method is called when the connection has
* already been opened (indicated by the <code>connected</code> field having
* the value <code>true</code>), the call is ignored.
* If the <code>connect</code> method is called when the connection has already been opened (indicated by the <code>connected</code>
* field having the value <code>true</code>), the call is ignored.
* <p>
* URLConnection objects go through two phases: first they are created, then
* they are connected. After being created, and before being connected,
* various options can be specified (e.g., doInput and UseCaches). After
* connecting, it is an error to try to set them. Operations that depend on
* being connected, like getContentLength, will implicitly perform the
* connection, if necessary.
* URLConnection objects go through two phases: first they are created, then they are connected. After being created, and before being
* connected, various options can be specified (e.g., doInput and UseCaches). After connecting, it is an error to try to set them.
* Operations that depend on being connected, like getContentLength, will implicitly perform the connection, if necessary.
*
* @throws SocketTimeoutException
* if the timeout expires before the connection can be
* established
* if the timeout expires before the connection can be established
* @exception IOException
* if an I/O error occurs while opening the connection.
* @see java.net.URLConnection#connected
@ -131,9 +126,8 @@ public class RtmpUrlConnection extends URLConnection {
}
/**
* Indicates that other requests to the server are unlikely in the near
* future. Calling disconnect() should not imply that this RtmpURLConnection
* instance can be reused for other requests.
* Indicates that other requests to the server are unlikely in the near future. Calling disconnect() should not imply that this
* RtmpURLConnection instance can be reused for other requests.
*/
public void disconnect() {
connected = false;
@ -160,8 +154,7 @@ public class RtmpUrlConnection extends URLConnection {
/**
* Returns the value of the <code>content-length</code>.
*
* @return the content length of the resource that this connection's URL
* references, or <code>-1</code> if the content length is not
* @return the content length of the resource that this connection's URL references, or <code>-1</code> if the content length is not
* known.
*/
@Override
@ -173,8 +166,7 @@ public class RtmpUrlConnection extends URLConnection {
/**
* Returns the value of the <code>content-type</code>.
*
* @return the content type of the resource that the URL references, or
* <code>null</code> if not known.
* @return the content type of the resource that the URL references, or <code>null</code> if not known.
*/
@Override
public String getContentType() {
@ -209,9 +201,8 @@ public class RtmpUrlConnection extends URLConnection {
}
/**
* Name of application to connect to on the RTMP server. Overrides the app
* in the RTMP URL. Sometimes the librtmp URL parser cannot determine the
* app name automatically, so it must be given explicitly using this option.
* Name of application to connect to on the RTMP server. Overrides the app in the RTMP URL. Sometimes the librtmp URL parser cannot
* determine the app name automatically, so it must be given explicitly using this option.
*
* @param value
*/
@ -229,14 +220,10 @@ public class RtmpUrlConnection extends URLConnection {
}
/**
* Append arbitrary AMF data to the Connect message. The type must be B for
* Boolean, N for number, S for string, O for object, or Z for null. For
* Booleans the data must be either 0 or 1 for FALSE or TRUE, respectively.
* Likewise for Objects the data must be 0 or 1 to end or begin an object,
* respectively. Data items in subobjects may be named, by prefixing the
* type with 'N' and specifying the name before the value, e.g. NB:myFlag:1.
* This option may be used multiple times to construct arbitrary AMF
* sequences. E.g.
* Append arbitrary AMF data to the Connect message. The type must be B for Boolean, N for number, S for string, O for object, or Z for
* null. For Booleans the data must be either 0 or 1 for FALSE or TRUE, respectively. Likewise for Objects the data must be 0 or 1 to
* end or begin an object, respectively. Data items in subobjects may be named, by prefixing the type with 'N' and specifying the name
* before the value, e.g. NB:myFlag:1. This option may be used multiple times to construct arbitrary AMF sequences. E.g.
* <p>
* <tt>
* conn=B:1 conn=S:authMe conn=O:1 conn=NN:code:1.23 conn=NS:flag:ok conn=O:0
@ -258,8 +245,7 @@ public class RtmpUrlConnection extends URLConnection {
}
/**
* Version of the Flash plugin used to run the SWF player. The default is
* "LNX 10,0,32,18".
* Version of the Flash plugin used to run the SWF player. The default is "LNX 10,0,32,18".
*
* @param value
*/
@ -268,8 +254,7 @@ public class RtmpUrlConnection extends URLConnection {
}
/**
* Specify that the media is a live stream. No resuming or seeking in live
* streams is possible.
* Specify that the media is a live stream. No resuming or seeking in live streams is possible.
*
* @param value
*/
@ -278,8 +263,7 @@ public class RtmpUrlConnection extends URLConnection {
}
/**
* URL of the web page in which the media was embedded. By default no value
* will be sent.
* URL of the web page in which the media was embedded. By default no value will be sent.
*
* @param value
*/
@ -288,9 +272,8 @@ public class RtmpUrlConnection extends URLConnection {
}
/**
* Overrides the playpath parsed from the RTMP URL. Sometimes the rtmpdump
* URL parser cannot determine the correct playpath automatically, so it
* must be given explicitly using this option.
* Overrides the playpath parsed from the RTMP URL. Sometimes the rtmpdump URL parser cannot determine the correct playpath
* automatically, so it must be given explicitly using this option.
*
* @param value
*/
@ -368,10 +351,17 @@ public class RtmpUrlConnection extends URLConnection {
}
/**
* Specify how many days to use the cached SWF info before re-checking. Use
* 0 to always check the SWF URL. Note that if the check shows that the SWF
* file has the same modification timestamp as before, it will not be
* retrieved again.
* Don't attempt to speed up download via the Pause/Unpause BUFX hack
*
* @param value
*/
public void setRealTime() {
parameterMap.put(KEY_REALTIME, null);
}
/**
* Specify how many days to use the cached SWF info before re-checking. Use 0 to always check the SWF URL. Note that if the check shows
* that the SWF file has the same modification timestamp as before, it will not be retrieved again.
*
* @param value
*/
@ -407,8 +397,7 @@ public class RtmpUrlConnection extends URLConnection {
}
/**
* Timeout the session after num seconds without receiving any data from the
* server. The default is 120.
* Timeout the session after num seconds without receiving any data from the server. The default is 120.
*
* @param value
*/
@ -417,8 +406,7 @@ public class RtmpUrlConnection extends URLConnection {
}
/**
* Key for SecureToken response, used if the server requires SecureToken
* authentication.
* Key for SecureToken response, used if the server requires SecureToken authentication.
*
* @param value
*/

View File

@ -28,7 +28,9 @@ import jd.plugins.DownloadLink;
import jd.plugins.FilePackage;
import jd.plugins.PluginForDecrypt;
@DecrypterPlugin(revision = "$Revision$", interfaceVersion = 2, names = { "1000eb.com" }, urls = { "http://(www\\.)?([A-Za-z0-9\\-_]+\\.)?1000eb\\.com/[A-Za-z0-9\\-_]+\\.htm?" }, flags = { 0 })
import org.appwork.utils.formatter.SizeFormatter;
@DecrypterPlugin(revision = "$Revision$", interfaceVersion = 2, names = { "1000eb.com" }, urls = { "http://([\\w\\-\\.]+)?(1000eb\\.com/[\\w\\-]+\\.htm(\\?p=\\d+)?|[\\w\\-\\.]+1000eb\\.com/)" }, flags = { 0 })
public class OneThousandEbComFolder extends PluginForDecrypt {
public OneThousandEbComFolder(final PluginWrapper wrapper) {
@ -37,42 +39,72 @@ public class OneThousandEbComFolder extends PluginForDecrypt {
public ArrayList<DownloadLink> decryptIt(CryptedLink param, ProgressController progress) throws Exception {
ArrayList<DownloadLink> decryptedLinks = new ArrayList<DownloadLink>();
ArrayList<String> pages = new ArrayList<String>();
pages.add("1");
String parameter = param.toString();
br.getPage(parameter);
String fpName = br.getRegex("\">我的空间</a>\\&nbsp;\\&gt;\\&gt;\\&nbsp;<a href=\"[^<>\"\\']+\" title=\"([^<>\"\\']+)\">").getMatch(0);
if (fpName == null) fpName = br.getRegex("<meta name=\"keywords\" content=\"([^,\"]+)").getMatch(0);
int maxCount = 1;
int maxCount = 1, minCount = 1;
String lastPage = br.getRegex("class=\"pager\\-golast\"><a href=\"/[A-Za-z0-9\\-_]+\\.htm\\?p=(\\d+)\"").getMatch(0);
if (lastPage != null) maxCount = Integer.parseInt(lastPage);
for (int i = 1; i <= maxCount; i++) {
String firstPage = new Regex(parameter, "\\?p=(\\d+)").getMatch(0);
if (firstPage != null) minCount = Integer.parseInt(firstPage);
parameter = parameter.replaceAll("\\?p=\\d+", "");
if (minCount > maxCount) maxCount = minCount;
String fpName = br.getRegex("\">我的空间</a>\\&nbsp;\\&gt;\\&gt;\\&nbsp;<a href=\"[^<>\"\\']+\" title=\"([^<>\"\\']+)\">").getMatch(0);
if (fpName == null) fpName = br.getRegex("<meta name=\"keywords\" content=\"([^,\"]+)").getMatch(0);
final FilePackage fp = FilePackage.getInstance();
fp.setName(Encoding.htmlDecode(fpName.trim()));
for (int i = minCount; i <= maxCount; i++) {
logger.info("Decrypting page " + i + " of " + maxCount);
if (i > 1) br.getPage(parameter + "?p=" + i);
final String[] links = br.getRegex("class=\"li\\-name\"><a title=\"[^<>\"\\']+\" href=\\'(http://1000eb\\.com/[a-z0-9]+)\\'").getColumn(0);
final String[] folderLinks = br.getRegex("\"(/mydirectory[^<>\"]*?)\"").getColumn(0);
if ((links == null || links.length == 0) && (folderLinks == null || folderLinks.length == 0)) {
logger.warning("Decrypter broken for link: " + parameter);
return null;
try {
if (i > minCount) br.getPage(parameter + "?p=" + i);
} catch (Throwable e) {
logger.warning("1000eb.com: " + e.getMessage());
return decryptedLinks;
}
if (links != null && links.length > 0) {
for (final String singleLink : links)
decryptedLinks.add(createDownloadlink(singleLink));
for (final String[] singleLink : br.getRegex("class=\"li\\-name\"><a title=\"[^\"]+\" href=\'(http://1000eb\\.com/[^\']+)\' target=\"_blank\" class=\"ellipsis\">([^<]+)</a></span> <span class=\"li\\-size\">([^<]+)</span>").getMatches()) {
DownloadLink dLink = createDownloadlink(singleLink[0]);
dLink.setFinalFileName(singleLink[1].trim());
try {
dLink.setDownloadSize(SizeFormatter.getSize(singleLink[2].replace("M", "MB").replace("K", "KB")));
} catch (Throwable e) {
}
dLink.setAvailable(true);
fp.add(dLink);
try {
if (isAbort()) return decryptedLinks;
distribute(dLink);
} catch (final Throwable e) {
/* does not exist in 09581 */
}
decryptedLinks.add(dLink);
}
if (folderLinks != null && folderLinks.length > 0) {
final String mainlink = new Regex(parameter, "(http://(www\\.)?[A-Za-z0-9\\-_]+\\.1000eb\\.com)").getMatch(0);
for (final String folderLink : folderLinks)
decryptedLinks.add(createDownloadlink(mainlink + folderLink));
sleep(2 * 1000l, param); // prevent a java.out.of.memory error ;-)
final String mainlink = new Regex(parameter, "(http://(www\\.)?[A-Za-z0-9\\-_]+\\.1000eb\\.com)/?").getMatch(0);
for (final String folderLink : br.getRegex("class=\"li\\-name\"><a title=\"[^\"]+\" href=\"([^\"]+)\">[^<]+</a><span class=\"list\\-dir\\-files\">").getColumn(0)) {
DownloadLink dLink = createDownloadlink(mainlink + folderLink);
fp.add(dLink);
try {
distribute(dLink);
} catch (final Throwable e) {
/* does not exist in 09581 */
}
decryptedLinks.add(dLink);
}
}
if (fpName != null) {
final FilePackage fp = FilePackage.getInstance();
fp.setName(Encoding.htmlDecode(fpName.trim()));
fp.addLinks(decryptedLinks);
if (decryptedLinks == null || decryptedLinks.size() == 0) {
logger.warning("Decrypter broken for link: " + parameter);
return null;
}
return decryptedLinks;
}
}
}

View File

@ -325,7 +325,8 @@ public class OldRAFDownload extends DownloadInterface {
if (verifiedSize == false || this.getChunkNum() == 1) {
/* we only request a single range */
openRangeRequested = true;
request.getHeaders().put("Range", "bytes= " + (0) + "-");
/* Workaround for server responses != 206 */
if (this.downloadLink.getBooleanProperty("ServerComaptibleForByteRangeRequest", true)) request.getHeaders().put("Range", "bytes= " + (0) + "-");
} else {
/* we request multiple ranges */
openRangeRequested = false;
@ -369,8 +370,8 @@ public class OldRAFDownload extends DownloadInterface {
if (doFilesizeCheck() && (totalLinkBytesLoaded <= 0 || totalLinkBytesLoaded != getFileSize() && getFileSize() > 0)) {
if (totalLinkBytesLoaded > getFileSize()) {
/*
* workaround for old bug deep in this downloadsystem. more data got loaded (maybe just counting bug) than filesize. but in most cases the file
* is okay! WONTFIX because new downloadsystem is on its way
* workaround for old bug deep in this downloadsystem. more data got loaded (maybe just counting bug) than filesize. but in
* most cases the file is okay! WONTFIX because new downloadsystem is on its way
*/
logger.severe("Filesize: " + getFileSize() + " Loaded: " + totalLinkBytesLoaded);
if (!linkStatus.isFailed()) {
@ -432,7 +433,8 @@ public class OldRAFDownload extends DownloadInterface {
}
/**
* Wartet bis alle Chunks fertig sind, aktuelisiert den downloadlink regelmaesig und fordert beim Controller eine aktualisierung des links an
* Wartet bis alle Chunks fertig sind, aktuelisiert den downloadlink regelmaesig und fordert beim Controller eine aktualisierung des
* links an
*/
protected void onChunkFinished() {
synchronized (this) {
@ -731,7 +733,8 @@ public class OldRAFDownload extends DownloadInterface {
}
/**
* Setzt vor ! dem download dden requesttimeout. Sollte nicht zu niedrig sein weil sonst das automatische kopieren der Connections fehl schlaegt.,
* Setzt vor ! dem download dden requesttimeout. Sollte nicht zu niedrig sein weil sonst das automatische kopieren der Connections fehl
* schlaegt.,
*/
public void setRequestTimeout(int requestTimeout) {
this.requestTimeout = requestTimeout;

View File

@ -67,8 +67,10 @@ public class OneThousandEbCom extends PluginForHost {
// br.getRegex("src=\"(http://static\\.1000eb\\.com/combo/[^<>]+/file\\.js\\&t=\\d+)\">").getMatch(0);
final String dllink = requestDownloadLink("http://1000eb.com/base.js");
if (dllink == null) { throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT); }
downloadLink.setProperty("ServerComaptibleForByteRangeRequest", false);
dl = jd.plugins.BrowserAdapter.openDownload(br, downloadLink, dllink, true, 1);
if (dl.getConnection().getContentType().contains("html")) {
downloadLink.setProperty("ServerComaptibleForByteRangeRequest", true);
br.followConnection();
throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT);
}

View File

@ -45,6 +45,9 @@ public class RTL2De extends PluginForHost {
if (urlTmp != null && urlTmp.length < 5) { throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT); }
dl = new RTMPDownload(this, downloadLink, DLCONTENT);
String checksum = ((RTMPDownload) dl).getRtmpDumpChecksum();
if (checksum != null && !"422e35de6fb8b333fee3f1fc894ab6e2".equals(checksum)) throw new PluginException(LinkStatus.ERROR_TEMPORARILY_UNAVAILABLE, "JD2 beta update noch nicht vollständig", 24 * 60 * 60 * 1000l);
String protocol = urlTmp[0];
String host = urlTmp[2];
String app = urlTmp[3];
@ -58,7 +61,7 @@ public class RTL2De extends PluginForHost {
DLCONTENT = url + "@" + playpath;
setupRTMPConnection(dl);
if (!((RTMPDownload) dl).startDownload()) throw new PluginException(LinkStatus.ERROR_TEMPORARILY_UNAVAILABLE, 60 * 1000l);
((RTMPDownload) dl).startDownload();
} else {
throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT);
@ -138,8 +141,8 @@ public class RTL2De extends PluginForHost {
rtmp.setFlashVer("WIN 10,1,102,64");
rtmp.setUrl(DLCONTENT.split("@")[0]);
rtmp.setResume(true);
rtmp.setTimeOut(-5);
rtmp.setBuffer(60 * 1000);
rtmp.setRealTime();
rtmp.setTimeOut(-10);
}
}

View File

@ -7,11 +7,12 @@ import jd.network.rtmp.RtmpDump;
import jd.network.rtmp.url.CustomUrlStreamHandlerFactory;
import jd.network.rtmp.url.RtmpUrlConnection;
import jd.plugins.DownloadLink;
import jd.plugins.LinkStatus;
import jd.plugins.PluginException;
import jd.plugins.PluginForHost;
import jd.plugins.download.RAFDownload;
//Old librtmp handling in revision < 13938
/* Old librtmp handling in revision < 13938 */
/**
* This is a wrapper for RTMP
@ -33,7 +34,6 @@ public class RTMPDownload extends RAFDownload {
// TODO Auto-generated constructor stub
url = new URL(rtmpURL);
rtmpConnection = (RtmpUrlConnection) url.openConnection();
// setResume(false);
downloadLink.setDownloadInstance(this);
}
@ -42,7 +42,18 @@ public class RTMPDownload extends RAFDownload {
}
public boolean startDownload() throws Exception {
/* Workaround for retry count loop */
if (downloadLink.getLinkStatus().getRetryCount() == plugin.getMaxRetries(downloadLink, null)) { throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT); }
final RtmpDump rtmpdump = new RtmpDump(plugin, downloadLink, String.valueOf(url));
return rtmpdump.start(rtmpConnection);
}
public String getRtmpDumpChecksum() throws Exception {
return new RtmpDump(plugin, downloadLink, String.valueOf(url)).getRtmpDumpChecksum();
}
public String getRtmpDumpVersion() throws Exception {
return new RtmpDump(plugin, downloadLink, String.valueOf(url)).getRtmpDumpVersion();
}
}

View File

@ -223,36 +223,21 @@ public class VideoPremiumNet extends PluginForHost {
private void setupRTMPConnection(String stream, DownloadInterface dl, DownloadLink downloadLink) {
jd.network.rtmp.url.RtmpUrlConnection rtmp = ((RTMPDownload) dl).getRtmpConnection();
/* videopremium.net uses redirections in streams. rtmpdump can't handle this. */
String url = stream.split("@")[0];
if (downloadLink.getBooleanProperty("REDIRECT", false)) url = downloadLink.getStringProperty("REDIRECTURL", null);
rtmp.setPlayPath(stream.split("@")[1]);
rtmp.setUrl(url);
rtmp.setSwfVfy(stream.split("@")[2]);
rtmp.setPageUrl(downloadLink.getDownloadURL());
rtmp.setResume(true);
rtmp.setVerbose(); // needed for redirect feature in rtmpdump.class
}
private void download(DownloadLink downloadLink, String dllink) throws Exception {
maxFree.set(10);
dl = new RTMPDownload(this, downloadLink, dllink);
setupRTMPConnection(dllink, dl, downloadLink);
try {
if (!((RTMPDownload) dl).startDownload()) {
if (downloadLink.getBooleanProperty("REDIRECT", false)) throw new PluginException(LinkStatus.ERROR_RETRY);
} else {
downloadLink.setProperty("REDIRECT", false);
}
} catch (PluginException e) {
if (e.getLinkStatus() == 4) {
logger.info("RTMP: Redirect found! Start download with new url.");
} else if (e.getErrorMessage().contains("NetStream.Play.StreamNotFound")) {
throw new PluginException(LinkStatus.ERROR_FILE_NOT_FOUND);
} else {
throw new PluginException(LinkStatus.ERROR_DOWNLOAD_FAILED);
}
}
((RTMPDownload) dl).startDownload();
}
@Override

View File

@ -0,0 +1,17 @@
package org.jdownloader.settings;
import org.appwork.storage.config.ConfigInterface;
import org.appwork.storage.config.annotations.AboutConfig;
import org.appwork.storage.config.annotations.DefaultBooleanValue;
import org.appwork.storage.config.annotations.DescriptionForConfigEntry;
public interface RtmpdumpSettings extends ConfigInterface {
@AboutConfig
@DefaultBooleanValue(false)
@DescriptionForConfigEntry("Enable debug mode, nearly everything will be logged!")
boolean isDebugModeEnabled();
void setDebugModeEnabled(boolean b);
}

View File

@ -27,6 +27,7 @@ import org.jdownloader.settings.AccountSettings;
import org.jdownloader.settings.GeneralSettings;
import org.jdownloader.settings.GraphicalUserInterfaceSettings;
import org.jdownloader.settings.InternetConnectionSettings;
import org.jdownloader.settings.RtmpdumpSettings;
public class AdvancedConfigManager {
private static final AdvancedConfigManager INSTANCE = new AdvancedConfigManager();
@ -36,7 +37,7 @@ public class AdvancedConfigManager {
}
private java.util.List<AdvancedConfigEntry> configInterfaces;
private AdvancedConfigEventSender eventSender;
private AdvancedConfigEventSender eventSender;
private AdvancedConfigManager() {
configInterfaces = new ArrayList<AdvancedConfigEntry>();
@ -57,6 +58,7 @@ public class AdvancedConfigManager {
register(JsonConfig.create(StatsManagerConfig.class));
register(JsonConfig.create(LogConfig.class));
register(JsonConfig.create(ShortcutSettings.class));
register(JsonConfig.create(RtmpdumpSettings.class));
}

View File

@ -0,0 +1,3 @@
# with redirect support and other improvements
#
# https://github.com/svnpenn/rtmpdump