mirror of
https://github.com/mirror/jdownloader.git
synced 2024-11-26 21:40:38 +00:00
RTMP:
-removed support via rtmpdump git-svn-id: svn://svn.jdownloader.org/jdownloader/trunk@45422 ebf7c1c2-ba36-0410-9fe8-c592906822b4 Former-commit-id: 7d49ac39ade1431c05e806e2b1b8907e5722cf6a
This commit is contained in:
parent
e49f7d5434
commit
3f9a8cb4b7
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -315,8 +315,6 @@ public class AboutDialog extends AbstractDialog<Integer> {
|
||||
stats.add(disable("Copyright \u00A9 2009-2022 JDownloader Community"));
|
||||
stats.add(new JLabel("Java Native Access:"), "");
|
||||
stats.add(disable("JNA 5.9.0", "https://github.com/java-native-access/jna"));
|
||||
stats.add(new JLabel("RTMP Support:"), "");
|
||||
stats.add(disable("RtmpDump", "https://rtmpdump.mplayerhq.hu"));
|
||||
stats.add(new JLabel("UPNP:"), "");
|
||||
stats.add(disable("Cling", "https://github.com/4thline/cling"));
|
||||
stats.add(new JLabel("Extraction:"));
|
||||
|
@ -1,555 +0,0 @@
|
||||
package jd.network.rtmp;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
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;
|
||||
import org.appwork.utils.net.throttledconnection.ThrottledConnection;
|
||||
import org.appwork.utils.net.throttledconnection.ThrottledConnectionHandler;
|
||||
import org.appwork.utils.os.CrossSystem;
|
||||
import org.appwork.utils.speedmeter.SpeedMeterInterface;
|
||||
import org.jdownloader.controlling.FileCreationManager;
|
||||
import org.jdownloader.nativ.NativeProcess;
|
||||
import org.jdownloader.plugins.DownloadPluginProgress;
|
||||
import org.jdownloader.settings.RtmpdumpSettings;
|
||||
import org.jdownloader.translate._JDT;
|
||||
|
||||
public class RtmpDump extends RTMPDownload {
|
||||
private static class RTMPCon implements SpeedMeterInterface, ThrottledConnection {
|
||||
private ThrottledConnectionHandler handler;
|
||||
|
||||
public ThrottledConnectionHandler getHandler() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
public int getLimit() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long getValue(Resolution resolution) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void putBytes(final long bytes, final long time) {
|
||||
}
|
||||
|
||||
public void resetSpeedmeter() {
|
||||
}
|
||||
|
||||
public void setHandler(final ThrottledConnectionHandler manager) {
|
||||
handler = manager;
|
||||
}
|
||||
|
||||
public void setLimit(final int kpsLimit) {
|
||||
}
|
||||
|
||||
public long transfered() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resolution getResolution() {
|
||||
return Resolution.SECONDS;
|
||||
}
|
||||
}
|
||||
|
||||
private volatile long BYTESLOADED = 0l;
|
||||
private volatile long SPEED = 0l;
|
||||
private float progressFloat = 0;
|
||||
|
||||
protected float getProgressFloat() {
|
||||
return progressFloat;
|
||||
}
|
||||
|
||||
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);
|
||||
downloadable.setDownloadInterface(this);
|
||||
config = JsonConfig.create(RtmpdumpSettings.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to locate a rtmpdump executable. The *nix /usr bin folders is searched first, then local tools folder. If found, the path
|
||||
* will is saved to the variable RTMPDUMP.
|
||||
*
|
||||
* @return Whether or not rtmpdump executable was found
|
||||
*/
|
||||
private synchronized boolean findRtmpDump() {
|
||||
String ret = RTMPDUMP;
|
||||
if (ret != null) {
|
||||
return ret.length() > 0;
|
||||
}
|
||||
if (CrossSystem.isUnix() || CrossSystem.isMac()) {
|
||||
if (new File("/usr/local/bin/rtmpdump").isFile()) {
|
||||
ret = "/usr/local/bin/rtmpdump";
|
||||
} else if (new File("/usr/bin/rtmpdump").isFile()) {
|
||||
ret = "/usr/bin/rtmpdump";
|
||||
}
|
||||
}
|
||||
if (CrossSystem.isWindows()) {
|
||||
ret = Application.getResource("tools/Windows/rtmpdump/rtmpdump.exe").getAbsolutePath();
|
||||
} else if (CrossSystem.isLinux() && ret == null) {
|
||||
ret = Application.getResource("tools/linux/rtmpdump/rtmpdump").getAbsolutePath();
|
||||
} else if (CrossSystem.isMac() && ret == null) {
|
||||
ret = Application.getResource("tools/mac/rtmpdump/rtmpdump").getAbsolutePath();
|
||||
}
|
||||
if (ret != null && new File(ret).isFile()) {
|
||||
new File(ret).setExecutable(true);
|
||||
RTMPDUMP = ret;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void getProcessId() {
|
||||
try {
|
||||
final Field pidField = P.getClass().getDeclaredField("pid");
|
||||
pidField.setAccessible(true);
|
||||
PID = pidField.getInt(P);
|
||||
} catch (final Exception e) {
|
||||
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.
|
||||
*
|
||||
* @return The version number of the RTMPDump executable
|
||||
*/
|
||||
public synchronized String getRtmpDumpVersion() throws Exception {
|
||||
if (RTMPVERSION != null) {
|
||||
return RTMPVERSION;
|
||||
}
|
||||
if (!findRtmpDump()) {
|
||||
throw new PluginException(LinkStatus.ERROR_FATAL, "Error: rtmpdump executable not found!");
|
||||
}
|
||||
final String arg = " -h";
|
||||
NativeProcess verNP = null;
|
||||
Process verP = null;
|
||||
InputStreamReader verR = null;
|
||||
try {
|
||||
if (CrossSystem.isWindows()) {
|
||||
verNP = new NativeProcess(RTMPDUMP, arg);
|
||||
verR = new InputStreamReader(verNP.getErrorStream());
|
||||
} else {
|
||||
verP = Runtime.getRuntime().exec(RTMPDUMP + arg);
|
||||
verR = new InputStreamReader(verP.getErrorStream());
|
||||
}
|
||||
final BufferedReader br = new BufferedReader(verR);
|
||||
final Pattern reg = Pattern.compile("RTMPDump v([0-9.]+)");
|
||||
String line = null;
|
||||
while ((line = br.readLine()) != null) {
|
||||
final Matcher match = reg.matcher(line);
|
||||
if (match.find()) {
|
||||
RTMPVERSION = match.group(1);
|
||||
return RTMPVERSION;
|
||||
}
|
||||
}
|
||||
throw new PluginException(LinkStatus.ERROR_FATAL, "Error " + RTMPDUMP + " version not found!");
|
||||
} finally {
|
||||
try {
|
||||
/* make sure we destroyed the process */
|
||||
verP.destroy();
|
||||
} catch (final Throwable e) {
|
||||
}
|
||||
try {
|
||||
/* close InputStreamReader */
|
||||
verR.close();
|
||||
} catch (final Throwable e) {
|
||||
}
|
||||
if (verNP != null) {
|
||||
/* close Streams from native */
|
||||
verNP.closeStreams();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTotalLinkBytesLoadedLive() {
|
||||
return BYTESLOADED;
|
||||
}
|
||||
|
||||
private void sendSIGINT() {
|
||||
getProcessId();
|
||||
if (PID >= 0) {
|
||||
try {
|
||||
Runtime.getRuntime().exec("kill -SIGINT " + String.valueOf(PID));
|
||||
} catch (final Throwable e1) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void kill() {
|
||||
if (CrossSystem.isWindows()) {
|
||||
if (NP != null) {
|
||||
NP.sendCtrlCSignal();
|
||||
}
|
||||
} else {
|
||||
sendSIGINT();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean FixFlv(File tmpFile) throws Exception {
|
||||
FlvFixer flvfix = new FlvFixer();
|
||||
flvfix.setInputFile(tmpFile);
|
||||
if (config.isFlvFixerDebugModeEnabled()) {
|
||||
flvfix.setDebug(true);
|
||||
}
|
||||
if (!flvfix.scan(dLink)) {
|
||||
return false;
|
||||
}
|
||||
File fixedFile = flvfix.getoutputFile();
|
||||
if (!fixedFile.exists()) {
|
||||
logger.severe("File " + fixedFile.getAbsolutePath() + " not found!");
|
||||
throw new PluginException(LinkStatus.ERROR_DOWNLOAD_FAILED, _JDT.T.downloadlink_status_error_file_not_found(), LinkStatus.VALUE_LOCAL_IO_ERROR);
|
||||
}
|
||||
if (!FileCreationManager.getInstance().delete(tmpFile, null)) {
|
||||
logger.severe("Could not delete part file " + tmpFile);
|
||||
FileCreationManager.getInstance().delete(fixedFile, null);
|
||||
throw new PluginException(LinkStatus.ERROR_DOWNLOAD_FAILED, _JDT.T.system_download_errors_couldnotdelete(), LinkStatus.VALUE_LOCAL_IO_ERROR);
|
||||
}
|
||||
if (!fixedFile.renameTo(tmpFile)) {
|
||||
logger.severe("Could not rename file " + fixedFile.getName() + " to " + tmpFile.getName());
|
||||
FileCreationManager.getInstance().delete(fixedFile, null);
|
||||
throw new PluginException(LinkStatus.ERROR_DOWNLOAD_FAILED, _JDT.T.system_download_errors_couldnotrename(), LinkStatus.VALUE_LOCAL_IO_ERROR);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isReadPacketError(final String errorMessage) {
|
||||
if (errorMessage != null) {
|
||||
final String e = errorMessage.toLowerCase(Locale.ENGLISH);
|
||||
return e.contains("rtmp_readpacket, failed to read rtmp packet header") || e.contains("rtmp_readpacket, failed to read RTMP packet body");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isTimeoutError(final String errorMessage) {
|
||||
if (errorMessage != null) {
|
||||
final String e = errorMessage.toLowerCase(Locale.ENGLISH);
|
||||
return e.contains("rtmpdump timed out while waiting for a reply after");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean start(final RtmpUrlConnection rtmpConnection) throws Exception {
|
||||
if (!findRtmpDump()) {
|
||||
throw new PluginException(LinkStatus.ERROR_FATAL, "Error: rtmpdump executable not found!");
|
||||
}
|
||||
// rtmpe not supported
|
||||
/** TODO: Add a nicer error message... */
|
||||
if (rtmpConnection.protocolIsRtmpe()) {
|
||||
logger.warning("Protocol rtmpe:// not supported");
|
||||
throw new PluginException(LinkStatus.ERROR_FATAL, "rtmpe:// not supported!");
|
||||
}
|
||||
boolean debug = config.isRtmpDumpDebugModeEnabled();
|
||||
if (debug) {
|
||||
rtmpConnection.setVerbose();
|
||||
}
|
||||
final ThrottledConnection tcon = new RTMPCon() {
|
||||
@Override
|
||||
public long getValue(Resolution resolution) {
|
||||
return SPEED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long transfered() {
|
||||
return BYTESLOADED;
|
||||
}
|
||||
};
|
||||
final File tmpFile = new File(downloadable.getFileOutput() + ".part");
|
||||
final DownloadPluginProgress downloadPluginProgress = new DownloadPluginProgress(downloadable, this, Color.GREEN.darker()) {
|
||||
@Override
|
||||
public long getTotal() {
|
||||
return 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCurrent() {
|
||||
return (long) getProgressFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getPercent() {
|
||||
return getProgressFloat();
|
||||
}
|
||||
};
|
||||
try {
|
||||
getManagedConnetionHandler().addThrottledConnection(tcon);
|
||||
downloadable.setConnectionHandler(getManagedConnetionHandler());
|
||||
downloadable.addPluginProgress(downloadPluginProgress);
|
||||
rtmpConnection.connect();
|
||||
String line = "";
|
||||
String error = "";
|
||||
long iSize = 0;
|
||||
long before = 0;
|
||||
long lastTime = System.currentTimeMillis();
|
||||
boolean complete = false;
|
||||
long readerTimeOut = 10000l;
|
||||
String cmdArgsWindows = rtmpConnection.getCommandLineParameter();
|
||||
final List<String> cmdArgsMacAndLinux = new ArrayList<String>();
|
||||
if (CrossSystem.isWindows()) {
|
||||
// MAX_PATH Fix --> \\?\ + Path
|
||||
if (String.valueOf(tmpFile).length() >= 260 || config.isWindowsPathWorkaroundEnabled()) {
|
||||
// https://msdn.microsoft.com/en-us/library/aa365247.aspx
|
||||
cmdArgsWindows += " \"\\\\?\\" + String.valueOf(tmpFile) + "\"";
|
||||
} else {
|
||||
cmdArgsWindows += " \"" + String.valueOf(tmpFile) + "\"";
|
||||
}
|
||||
} else {
|
||||
cmdArgsMacAndLinux.add(RTMPDUMP);
|
||||
cmdArgsMacAndLinux.addAll(rtmpConnection.getCommandLineParameterAsArray());
|
||||
cmdArgsMacAndLinux.add(String.valueOf(tmpFile));
|
||||
}
|
||||
setResume(rtmpConnection.isResume());
|
||||
final ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
try {
|
||||
if (CrossSystem.isWindows()) {
|
||||
logger.info(cmdArgsWindows);
|
||||
NP = new NativeProcess(RTMPDUMP, cmdArgsWindows);
|
||||
R = new InputStreamReader(NP.getErrorStream());
|
||||
} else {
|
||||
logger.info(cmdArgsMacAndLinux.toString());
|
||||
P = Runtime.getRuntime().exec(cmdArgsMacAndLinux.toArray(new String[cmdArgsMacAndLinux.size()]));
|
||||
R = new InputStreamReader(P.getErrorStream());
|
||||
}
|
||||
final BufferedReader br = new BufferedReader(R);
|
||||
/* prevents input buffer timed out */
|
||||
Future<String> future;
|
||||
Callable<String> readTask = new Callable<String>() {
|
||||
@Override
|
||||
public String call() throws Exception {
|
||||
return br.readLine();
|
||||
}
|
||||
};
|
||||
long tmplen = 0, fixedlen = 0, calc = 0;
|
||||
while (true) {
|
||||
if (externalDownloadStop()) {
|
||||
return true;
|
||||
}
|
||||
future = executor.submit(readTask);
|
||||
try {
|
||||
if (!debug && error.isEmpty() && line.startsWith("ERROR")) {
|
||||
error = line;
|
||||
}
|
||||
line = future.get(readerTimeOut, TimeUnit.MILLISECONDS);
|
||||
} catch (TimeoutException e) {
|
||||
throw new PluginException(LinkStatus.ERROR_TEMPORARILY_UNAVAILABLE, "rtmpdump timed out while waiting for a reply after " + readerTimeOut + " ms");
|
||||
} catch (InterruptedException e) {
|
||||
throw e;
|
||||
}
|
||||
if (line == null) {
|
||||
break;
|
||||
}
|
||||
if (debug || true) {
|
||||
logger.finest(line);
|
||||
}
|
||||
if (line.startsWith("ERROR:")) {
|
||||
error = line;
|
||||
}
|
||||
if (!new Regex(line, "^[0-9]").matches()) {
|
||||
if (line.contains("length") || line.contains("lastkeyframelocation") || line.contains("filesize")) {
|
||||
String size = new Regex(line, ".*?(\\d.+)").getMatch(0);
|
||||
iSize = SizeFormatter.getSize(size);
|
||||
}
|
||||
} else {
|
||||
if (downloadable.getDownloadTotalBytes() == 0) {
|
||||
downloadable.setDownloadTotalBytes(iSize);
|
||||
}
|
||||
// is resumed
|
||||
if (iSize == 0) {
|
||||
iSize = downloadable.getDownloadTotalBytes();
|
||||
}
|
||||
int pos1 = line.indexOf("(");
|
||||
int pos2 = line.indexOf(")");
|
||||
if (line.toUpperCase().matches("\\d+\\.\\d+\\sKB\\s/\\s\\d+\\.\\d+\\sSEC(\\s\\(\\d+\\.\\d%\\))?")) {
|
||||
if (pos1 != -1 && pos2 != -1) {
|
||||
progressFloat = Float.parseFloat(line.substring(pos1 + 1, pos2 - 1));
|
||||
} else {
|
||||
progressFloat = Math.round(BYTESLOADED * 100.0F / iSize * 10) / 10.0F;
|
||||
}
|
||||
BYTESLOADED = SizeFormatter.getSize(line.substring(0, line.toUpperCase().indexOf("KB") + 2));
|
||||
if (pos1 != -1 && pos2 != -1) {
|
||||
if (progressFloat > 0.0) {
|
||||
tmplen = (long) (BYTESLOADED * 100.0F / progressFloat);
|
||||
fixedlen = downloadable.getDownloadTotalBytes();
|
||||
calc = Math.abs(((fixedlen / 1024) - (tmplen / 1024)) % 1024);
|
||||
if (calc > 768 && calc < 960) {
|
||||
downloadable.setDownloadTotalBytes(tmplen);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (System.currentTimeMillis() - lastTime > 1000) {
|
||||
SPEED = (BYTESLOADED - before) / (System.currentTimeMillis() - lastTime) * 1000l;
|
||||
lastTime = System.currentTimeMillis();
|
||||
before = BYTESLOADED;
|
||||
// downloadable.setChunksProgress(new long[] { BYTESLOADED });
|
||||
downloadable.setDownloadBytesLoaded(BYTESLOADED);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (progressFloat >= 99.8 && progressFloat < 100) {
|
||||
if (line.toLowerCase().contains("download may be incomplete")) {
|
||||
complete = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (line.toLowerCase().contains("couldn't resume flv file")) {
|
||||
downloadable.setLinkStatus(LinkStatus.ERROR_DOWNLOAD_INCOMPLETE);
|
||||
break;
|
||||
}
|
||||
if (line.toLowerCase().contains("download complete")) {
|
||||
// autoresuming when FMS sends NetStatus.Play.Stop and progress less than 100%
|
||||
if (progressFloat < 99.8 && !line.toLowerCase().contains("download complete")) {
|
||||
downloadable.setLinkStatus(LinkStatus.ERROR_DOWNLOAD_INCOMPLETE);
|
||||
}
|
||||
Thread.sleep(1000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
kill();
|
||||
try {
|
||||
downloadable.removePluginProgress(downloadPluginProgress);
|
||||
executor.shutdownNow();
|
||||
if (rtmpConnection != null) {
|
||||
rtmpConnection.disconnect();
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
/* make sure we destroyed the process */
|
||||
P.destroy();
|
||||
} catch (final Throwable e) {
|
||||
}
|
||||
try {
|
||||
/* close InputStreamReader */
|
||||
R.close();
|
||||
} catch (final Throwable e) {
|
||||
}
|
||||
if (NP != null) {
|
||||
/* close Streams from native */
|
||||
NP.closeStreams();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (downloadable.getLinkStatus() == LinkStatus.ERROR_DOWNLOAD_INCOMPLETE) {
|
||||
return false;
|
||||
}
|
||||
if (error.isEmpty() && line == null) {
|
||||
if (dLink.getBooleanProperty("FLVFIXER", false)) {
|
||||
if (!FixFlv(tmpFile)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
logger.severe("RtmpDump: An unknown error has occured!");
|
||||
throw new PluginException(LinkStatus.ERROR_RETRY);
|
||||
}
|
||||
if (line != null) {
|
||||
if (line.toLowerCase().contains("download complete") || complete) {
|
||||
downloadable.setDownloadTotalBytes(BYTESLOADED);
|
||||
downloadable.setDownloadTotalBytes(BYTESLOADED);
|
||||
if (dLink.getBooleanProperty("FLVFIXER", false)) {
|
||||
if (!FixFlv(tmpFile)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
logger.finest("rtmpdump: no errors -> rename");
|
||||
if (!tmpFile.renameTo(new File(downloadable.getFileOutput()))) {
|
||||
logger.severe("Could not rename file " + tmpFile + " to " + downloadable.getFileOutput());
|
||||
throw new PluginException(LinkStatus.ERROR_DOWNLOAD_FAILED, _JDT.T.system_download_errors_couldnotrename(), LinkStatus.VALUE_LOCAL_IO_ERROR);
|
||||
}
|
||||
downloadable.setLinkStatus(LinkStatus.FINISHED);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (error != null) {
|
||||
String e = error.toLowerCase();
|
||||
/* special ArteTv handling */
|
||||
if (this.plg.getLazyP().getClassName().endsWith("ArteTv")) {
|
||||
if (e.contains("netstream.failed")) {
|
||||
if (downloadable.getDownloadTotalBytes() > 0) {
|
||||
dLink.setProperty("STREAMURLISEXPIRED", true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (e.contains("last tag size must be greater/equal zero")) {
|
||||
if (!FixFlv(tmpFile)) {
|
||||
return false;
|
||||
}
|
||||
throw new PluginException(LinkStatus.ERROR_DOWNLOAD_INCOMPLETE);
|
||||
} else if (isReadPacketError(e)) {
|
||||
throw new PluginException(LinkStatus.ERROR_TEMPORARILY_UNAVAILABLE, e);
|
||||
} else if (e.contains("netstream.play.streamnotfound")) {
|
||||
FileCreationManager.getInstance().delete(tmpFile, null);
|
||||
throw new PluginException(LinkStatus.ERROR_FILE_NOT_FOUND);
|
||||
} else {
|
||||
String cmd = cmdArgsWindows;
|
||||
if (!CrossSystem.isWindows()) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String s : cmdArgsMacAndLinux) {
|
||||
sb.append(s);
|
||||
sb.append(" ");
|
||||
}
|
||||
cmd = sb.toString();
|
||||
}
|
||||
logger.severe("cmd: " + cmd);
|
||||
logger.severe(error);
|
||||
throw new PluginException(LinkStatus.ERROR_FATAL, error);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} finally {
|
||||
if (BYTESLOADED > 0) {
|
||||
downloadable.setDownloadBytesLoaded(BYTESLOADED);
|
||||
}
|
||||
plg.setDownloadInterface(null);
|
||||
downloadable.removePluginProgress(downloadPluginProgress);
|
||||
getManagedConnetionHandler().removeThrottledConnection(tcon);
|
||||
downloadable.removeConnectionHandler(getManagedConnetionHandler());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,496 +0,0 @@
|
||||
package jd.network.rtmp.url;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.SocketPermission;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.security.Permission;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.appwork.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* <tt>UrlConnection</tt> for the rtmp protocol
|
||||
*
|
||||
* @author mike0007
|
||||
* @author bismarck
|
||||
*/
|
||||
public class RtmpUrlConnection extends URLConnection {
|
||||
|
||||
private final static int DEFAULT_PORT = 1935;
|
||||
|
||||
// Connection Parameters
|
||||
private static final String KEY_APP = "a"; // app
|
||||
private static final String KEY_TC_URL = "t"; // tcUrl
|
||||
private static final String KEY_PAGE_URL = "p"; // pageUrl
|
||||
private static final String KEY_FLASH_VER = "f"; // flashVer
|
||||
private static final String KEY_SWF_URL = "s"; // swfUrl
|
||||
private static final String KEY_CONN = "C"; // conn
|
||||
private static final String KEY_RTMP = "r"; // Url
|
||||
private static final String KEY_PORT = "c"; // Port
|
||||
private static final String KEY_PROTOCOL = "l"; // protocol
|
||||
|
||||
// Session Parameters
|
||||
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
|
||||
private static final String KEY_TIMEOUT = "m"; // timeout
|
||||
private static final String KEY_RESUME = "e"; // resume
|
||||
|
||||
// Security Parameters
|
||||
private static final String KEY_SWF_VFY = "W"; // swfVfy
|
||||
private static final String KEY_SWF_AGE = "X"; // swfAge"
|
||||
private static final String KEY_TOKEN = "T"; // token
|
||||
|
||||
// Network Parameters
|
||||
private static final String KEY_SOCKS = "S"; // socks
|
||||
|
||||
// Debug Parameters
|
||||
private static final String KEY_DEBUG = "z"; // debug
|
||||
private static final String KEY_VERBOSE = "V"; // verbose
|
||||
|
||||
protected HashMap<String, String> parameterMap = null;
|
||||
|
||||
public HashMap<String, String> getParameterMap() {
|
||||
return parameterMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* <p>
|
||||
* An example character string suitable for use with RtmpDump:
|
||||
* <p>
|
||||
* <tt>
|
||||
* "rtmp://flashserver:1935/ondemand/___the_file___"
|
||||
* </tt>
|
||||
* </p>
|
||||
* <p>
|
||||
* <tt>
|
||||
* "<----------Host--------><--App--><--Playpath-->"
|
||||
* </tt>
|
||||
* </p>
|
||||
* <p>
|
||||
* <tt>
|
||||
* "<--------------TcUrl------------>"
|
||||
* </tt>
|
||||
* </p>
|
||||
*
|
||||
* @param url
|
||||
* rtmp <tt>URL</tt> to the rtmp source
|
||||
*/
|
||||
public RtmpUrlConnection(final URL url) {
|
||||
this(url, new HashMap<String, String>());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* <p>
|
||||
* An example character string suitable for use with RTMP_SetupURL():
|
||||
* <p>
|
||||
* <tt>
|
||||
* "rtmp://flashserver:1935/ondemand/thefile swfUrl=http://flashserver/player.swf swfVfy=1"
|
||||
* </tt>
|
||||
* </p>
|
||||
*
|
||||
* @param url
|
||||
* rtmp <tt>URL</tt> to the rtmp source
|
||||
* @param parameterMap
|
||||
* <tt>HashMap</tt> with parameters for the stream
|
||||
*/
|
||||
public RtmpUrlConnection(final URL url, final HashMap<String, String> parameterMap) {
|
||||
super(url);
|
||||
this.parameterMap = parameterMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* <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.
|
||||
*
|
||||
* @throws SocketTimeoutException
|
||||
* 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
|
||||
* @see #getConnectTimeout()
|
||||
* @see #setConnectTimeout(int)
|
||||
*/
|
||||
@Override
|
||||
public void connect() throws IOException {
|
||||
connected = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create command line parameters for Windows.
|
||||
*/
|
||||
public String getCommandLineParameter() {
|
||||
final StringBuilder cmdargs = new StringBuilder("");
|
||||
String ret = null;
|
||||
if (parameterMap != null) {
|
||||
final Iterator<String> keyIter = parameterMap.keySet().iterator();
|
||||
while (keyIter.hasNext()) {
|
||||
final String key = keyIter.next();
|
||||
if (parameterMap.get(key) != null) {
|
||||
if (KEY_CONN.equals(key)) { // example: -C B:0 -C S:String -C N:1234
|
||||
for (String s : parameterMap.get(key).split("#")) {
|
||||
cmdargs.append(" -").append(key).append(" " + s);
|
||||
}
|
||||
} else {
|
||||
cmdargs.append(" -").append(key).append(" \"").append(parameterMap.get(key)).append("\"");
|
||||
}
|
||||
} else {
|
||||
cmdargs.append(" -").append(key);
|
||||
}
|
||||
}
|
||||
ret = cmdargs.toString() + " -o";
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create command line parameters for Uni*.
|
||||
*/
|
||||
public List<String> getCommandLineParameterAsArray() {
|
||||
List<String> cmdargs = new ArrayList<String>();
|
||||
if (parameterMap != null) {
|
||||
final Iterator<String> keyIter = parameterMap.keySet().iterator();
|
||||
while (keyIter.hasNext()) {
|
||||
final String key = keyIter.next();
|
||||
if (parameterMap.get(key) != null) {
|
||||
if (KEY_CONN.equals(key)) { // example: -C B:0 -C S:String -C N:1234
|
||||
for (String s : parameterMap.get(key).split("#")) {
|
||||
cmdargs.add("-" + key);
|
||||
cmdargs.add(s);
|
||||
}
|
||||
} else {
|
||||
cmdargs.add("-" + key);
|
||||
cmdargs.add(parameterMap.get(key));
|
||||
}
|
||||
} else {
|
||||
cmdargs.add("-" + key);
|
||||
}
|
||||
}
|
||||
cmdargs.add("-o");
|
||||
}
|
||||
return cmdargs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* known.
|
||||
*/
|
||||
@Override
|
||||
public int getContentLength() {
|
||||
// Use RTMP_GetDuration and recalculate the seconds to byte!?
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@Override
|
||||
public String getContentType() {
|
||||
// For now we don't know which content we have
|
||||
// For the future one of these may be right (adobe stuff)
|
||||
|
||||
// File extension:
|
||||
// .flv
|
||||
// .f4v
|
||||
// .f4p
|
||||
// .f4a
|
||||
// .f4b
|
||||
|
||||
// Internet media type:
|
||||
// video/x-flv
|
||||
// video/mp4
|
||||
// video/x-m4v
|
||||
// audio/mp4a-latm
|
||||
// video/3gpp
|
||||
// video/quicktime
|
||||
// audio/mp4
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Permission getPermission() throws IOException {
|
||||
int port = url.getPort();
|
||||
port = port < 0 ? DEFAULT_PORT : port;
|
||||
final String host = url.getHost() + ":" + port;
|
||||
final Permission permission = new SocketPermission(host, "connect");
|
||||
return permission;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public void setApp(final String value) {
|
||||
parameterMap.put(KEY_APP, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set buffer time to num milliseconds. The default is 36000000.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setBuffer(final int value) {
|
||||
parameterMap.put(KEY_BUFFER, String.valueOf(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* </tt>
|
||||
* </p>
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setConn(final String value) {
|
||||
if (parameterMap.containsKey(KEY_CONN)) {
|
||||
parameterMap.put(KEY_CONN, parameterMap.get(KEY_CONN) + "#" + value);
|
||||
} else {
|
||||
parameterMap.put(KEY_CONN, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug level command output.
|
||||
*
|
||||
*/
|
||||
public void setDebug() {
|
||||
parameterMap.put(KEY_DEBUG, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Version of the Flash plugin used to run the SWF player. The default is "LNX 10,0,32,18".
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setFlashVer(final String value) {
|
||||
parameterMap.put(KEY_FLASH_VER, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that the media is a live stream. No resuming or seeking in live streams is possible.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setLive(final boolean value) {
|
||||
parameterMap.put(KEY_LIVE, (value ? "1" : "0"));
|
||||
}
|
||||
|
||||
/**
|
||||
* URL of the web page in which the media was embedded. By default no value will be sent.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setPageUrl(final String value) {
|
||||
parameterMap.put(KEY_PAGE_URL, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public void setPlayPath(final String value) {
|
||||
parameterMap.put(KEY_PLAYPATH, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the port in the rtmp url.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setPort(final int value) {
|
||||
parameterMap.put(KEY_PORT, String.valueOf(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the protocol in the rtmp url.
|
||||
*
|
||||
* @param value
|
||||
* (0 - RTMP, 3 - RTMPE)
|
||||
*/
|
||||
public void setProtocol(final int value) {
|
||||
if (value == 0 || value == 3) {
|
||||
parameterMap.put(KEY_PROTOCOL, String.valueOf(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume an incomplete RTMP download.
|
||||
*
|
||||
* @param boolean
|
||||
*/
|
||||
public void setResume(final boolean value) {
|
||||
if (value) {
|
||||
parameterMap.put(KEY_RESUME, null);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isResume() {
|
||||
return parameterMap.containsKey(KEY_RESUME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the specified SOCKS proxy.
|
||||
*
|
||||
* @param value
|
||||
* host:port
|
||||
*/
|
||||
public void setSocks(final String value) {
|
||||
parameterMap.put(KEY_SOCKS, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start at num seconds into the stream. Not valid for live streams.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setStart(final int value) {
|
||||
parameterMap.put(KEY_START, String.valueOf(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop at num seconds into the stream.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setStop(final int value) {
|
||||
parameterMap.put(KEY_STOP, String.valueOf(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of live stream to subscribe to. Defaults to playpath.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setSubscribe(final String value) {
|
||||
parameterMap.put(KEY_SUBSCRIBE, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public void setSwfAge(final String value) {
|
||||
parameterMap.put(KEY_SWF_AGE, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* URL of the SWF player for the media. By default no value will be sent.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setSwfUrl(final String value) {
|
||||
parameterMap.put(KEY_SWF_URL, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to player swf file, compute hash/size automatically.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setSwfVfy(final String value) {
|
||||
parameterMap.put(KEY_SWF_VFY, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* URL of the target stream. Defaults to rtmp[t][e|s]://host[:port]/app.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setTcUrl(final String value) {
|
||||
parameterMap.put(KEY_TC_URL, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Timeout the session after num seconds without receiving any data from the server. The default is 120.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setTimeOut(final int value) {
|
||||
parameterMap.put(KEY_TIMEOUT, String.valueOf(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Key for SecureToken response, used if the server requires SecureToken authentication.
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setToken(final String value) {
|
||||
parameterMap.put(KEY_TOKEN, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* URL (e.g. rtmp[t][e|s]://hostname[:port]/app/).
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public void setUrl(final String value) {
|
||||
parameterMap.put(KEY_RTMP, value);
|
||||
}
|
||||
|
||||
public boolean protocolIsRtmpe() {
|
||||
final String url = parameterMap.get(KEY_RTMP);
|
||||
if (url != null) {
|
||||
if (StringUtils.startsWithCaseInsensitive(url, "rtmpe")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verbose command output.
|
||||
*
|
||||
*/
|
||||
public void setVerbose() {
|
||||
parameterMap.put(KEY_VERBOSE, null);
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package jd.plugins.components;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLStreamHandler;
|
||||
|
||||
import jd.network.rtmp.url.RtmpUrlConnection;
|
||||
|
||||
public class RTMPStreamHandler extends URLStreamHandler {
|
||||
|
||||
@Override
|
||||
protected URLConnection openConnection(URL url) throws IOException {
|
||||
return new RtmpUrlConnection(url);
|
||||
}
|
||||
|
||||
}
|
@ -23,18 +23,6 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.appwork.storage.JSonStorage;
|
||||
import org.appwork.storage.TypeRef;
|
||||
import org.appwork.uio.ConfirmDialogInterface;
|
||||
import org.appwork.uio.UIOManager;
|
||||
import org.appwork.utils.Application;
|
||||
import org.appwork.utils.StringUtils;
|
||||
import org.appwork.utils.os.CrossSystem;
|
||||
import org.appwork.utils.swing.dialog.ConfirmDialog;
|
||||
import org.jdownloader.controlling.ffmpeg.json.StreamInfo;
|
||||
import org.jdownloader.downloader.hls.HLSDownloader;
|
||||
import org.jdownloader.plugins.components.hls.HlsContainer;
|
||||
|
||||
import jd.PluginWrapper;
|
||||
import jd.config.ConfigContainer;
|
||||
import jd.config.ConfigEntry;
|
||||
@ -56,9 +44,20 @@ import jd.plugins.Plugin;
|
||||
import jd.plugins.PluginException;
|
||||
import jd.plugins.PluginForHost;
|
||||
import jd.plugins.decrypter.DailyMotionComDecrypter;
|
||||
import jd.plugins.download.DownloadInterface;
|
||||
import jd.utils.locale.JDL;
|
||||
|
||||
import org.appwork.storage.JSonStorage;
|
||||
import org.appwork.storage.TypeRef;
|
||||
import org.appwork.uio.ConfirmDialogInterface;
|
||||
import org.appwork.uio.UIOManager;
|
||||
import org.appwork.utils.Application;
|
||||
import org.appwork.utils.StringUtils;
|
||||
import org.appwork.utils.os.CrossSystem;
|
||||
import org.appwork.utils.swing.dialog.ConfirmDialog;
|
||||
import org.jdownloader.controlling.ffmpeg.json.StreamInfo;
|
||||
import org.jdownloader.downloader.hls.HLSDownloader;
|
||||
import org.jdownloader.plugins.components.hls.HlsContainer;
|
||||
|
||||
@HostPlugin(revision = "$Revision$", interfaceVersion = 2, names = { "dailymotion.com" }, urls = { "https?://dailymotiondecrypted\\.com/video/\\w+" })
|
||||
public class DailyMotionCom extends PluginForHost {
|
||||
public String getVideosource(final Browser br, final String videoID) throws Exception {
|
||||
@ -253,11 +252,7 @@ public class DailyMotionCom extends PluginForHost {
|
||||
dl = new HLSDownloader(downloadLink, br, this.dllink);
|
||||
dl.startDownload();
|
||||
} else if (dllink.startsWith("rtmp")) {
|
||||
downloadLink.setFinalFileName(getFormattedFilename(downloadLink));
|
||||
String[] stream = dllink.split("@");
|
||||
dl = new RTMPDownload(this, downloadLink, stream[0]);
|
||||
setupRTMPConnection(stream, dl);
|
||||
((RTMPDownload) dl).startDownload();
|
||||
throw new PluginException(LinkStatus.ERROR_PLUGIN_DEFECT);
|
||||
} else {
|
||||
downloadDirect(downloadLink);
|
||||
}
|
||||
@ -503,13 +498,6 @@ public class DailyMotionCom extends PluginForHost {
|
||||
return dl.getBooleanProperty("type_subtitle", false);
|
||||
}
|
||||
|
||||
private void setupRTMPConnection(String[] stream, DownloadInterface dl) {
|
||||
jd.network.rtmp.url.RtmpUrlConnection rtmp = ((RTMPDownload) dl).getRtmpConnection();
|
||||
rtmp.setUrl(stream[0]);
|
||||
rtmp.setSwfVfy(stream[1]);
|
||||
rtmp.setResume(true);
|
||||
}
|
||||
|
||||
public static Browser prepBrowser(final Browser br) {
|
||||
br.getHeaders().put("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0");
|
||||
br.getHeaders().put("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
|
||||
|
@ -1,93 +0,0 @@
|
||||
package jd.plugins.hoster;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
import jd.http.Request;
|
||||
import jd.network.rtmp.RtmpDump;
|
||||
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.components.RTMPStreamHandler;
|
||||
import jd.plugins.download.RAFDownload;
|
||||
|
||||
/* Old librtmp handling in revision < 13938 */
|
||||
|
||||
/**
|
||||
* This is a wrapper for RTMP
|
||||
*
|
||||
* @author thomas
|
||||
* @author bismarck
|
||||
*
|
||||
*/
|
||||
public class RTMPDownload extends RAFDownload {
|
||||
|
||||
protected final RtmpUrlConnection rtmpConnection;
|
||||
|
||||
private final URL url;
|
||||
// don't name it plugin!
|
||||
protected final PluginForHost plg;
|
||||
// don't name it downloadLink
|
||||
protected final DownloadLink dLink;
|
||||
|
||||
public RTMPDownload(final PluginForHost plugin, final DownloadLink downloadLink, final String rtmpURL) throws IOException, PluginException {
|
||||
super(plugin, downloadLink, null);
|
||||
this.plg = plugin;
|
||||
this.dLink = downloadLink;
|
||||
url = new URL(null, rtmpURL, new RTMPStreamHandler());
|
||||
rtmpConnection = new RtmpUrlConnection(url);
|
||||
}
|
||||
|
||||
public void setInitialRequest(Request initialRequest) {
|
||||
}
|
||||
|
||||
public RtmpUrlConnection getRtmpConnection() {
|
||||
return rtmpConnection;
|
||||
}
|
||||
|
||||
public boolean startDownload() throws Exception {
|
||||
/*
|
||||
* Remove/replace chars which will cause rtmpdump to fail to find our download destination! TODO: Invalid download destination will
|
||||
* cause plugin defect - maybe catch this and show invalid download path instead!
|
||||
*/
|
||||
String finalfilename = this.plg.getDownloadLink().getFinalFileName();
|
||||
if (finalfilename == null) {
|
||||
finalfilename = this.plg.getDownloadLink().getName();
|
||||
}
|
||||
finalfilename = finalfilename.replace("⁄", "_");
|
||||
this.plg.getDownloadLink().setFinalFileName(finalfilename);
|
||||
long before = 0;
|
||||
while (!externalDownloadStop()) {
|
||||
before = Math.max(before, downloadable.getDownloadBytesLoaded());
|
||||
final RtmpDump rtmpDump = rtmpDump();
|
||||
try {
|
||||
return rtmpDump.start(rtmpConnection);
|
||||
} catch (PluginException e) {
|
||||
logger.log(e);
|
||||
if (e.getLinkStatus() == LinkStatus.ERROR_TEMPORARILY_UNAVAILABLE && (rtmpDump.isReadPacketError(e.getMessage()) || rtmpDump.isTimeoutError(e.getMessage()))) {
|
||||
if (downloadable.getDownloadBytesLoaded() > before && rtmpConnection.isResume()) {
|
||||
Thread.sleep(1000);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getRtmpDumpChecksum() throws Exception {
|
||||
return rtmpDump().getRtmpDumpChecksum();
|
||||
}
|
||||
|
||||
public String getRtmpDumpVersion() throws Exception {
|
||||
return rtmpDump().getRtmpDumpVersion();
|
||||
}
|
||||
|
||||
private RtmpDump rtmpDump() throws Exception {
|
||||
return new RtmpDump(plg, dLink, String.valueOf(url));
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
@ -1,3 +0,0 @@
|
||||
# with redirect support and other improvements
|
||||
#
|
||||
# https://github.com/svnpenn/rtmpdump
|
@ -1,524 +0,0 @@
|
||||
/* Getopt for Microsoft C
|
||||
This code is a modification of the Free Software Foundation, Inc.
|
||||
Getopt library for parsing command line argument the purpose was
|
||||
to provide a Microsoft Visual C friendly derivative. This code
|
||||
provides functionality for both Unicode and Multibyte builds.
|
||||
|
||||
Date: 02/03/2011 - Ludvik Jerabek - Initial Release
|
||||
Version: 1.0
|
||||
Comment: Supports getopt, getopt_long, and getopt_long_only
|
||||
and POSIXLY_CORRECT environment flag
|
||||
License: LGPL
|
||||
|
||||
Revisions:
|
||||
|
||||
02/03/2011 - Ludvik Jerabek - Initial Release
|
||||
02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4
|
||||
|
||||
**DISCLAIMER**
|
||||
THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
||||
EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE
|
||||
EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT
|
||||
APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY
|
||||
DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY
|
||||
USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST
|
||||
PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON
|
||||
YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE
|
||||
EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "getopt.h"
|
||||
|
||||
enum ENUM_ORDERING { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER };
|
||||
|
||||
struct _getopt_data
|
||||
{
|
||||
int optind;
|
||||
int opterr;
|
||||
int optopt;
|
||||
TCHAR *optarg;
|
||||
int __initialized;
|
||||
TCHAR *__nextchar;
|
||||
int __ordering;
|
||||
int __posixly_correct;
|
||||
int __first_nonopt;
|
||||
int __last_nonopt;
|
||||
};
|
||||
|
||||
static struct _getopt_data getopt_data;
|
||||
|
||||
TCHAR *optarg;
|
||||
|
||||
int optind = 1;
|
||||
int opterr = 1;
|
||||
int optopt = _T('?');
|
||||
|
||||
static void exchange(TCHAR **argv, struct _getopt_data *d)
|
||||
{
|
||||
int bottom = d->__first_nonopt;
|
||||
int middle = d->__last_nonopt;
|
||||
int top = d->optind;
|
||||
TCHAR *tem;
|
||||
while (top > middle && middle > bottom)
|
||||
{
|
||||
if (top - middle > middle - bottom)
|
||||
{
|
||||
int len = middle - bottom;
|
||||
register int i;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tem = argv[bottom + i];
|
||||
argv[bottom + i] = argv[top - (middle - bottom) + i];
|
||||
argv[top - (middle - bottom) + i] = tem;
|
||||
}
|
||||
top -= len;
|
||||
}
|
||||
else
|
||||
{
|
||||
int len = top - middle;
|
||||
register int i;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
tem = argv[bottom + i];
|
||||
argv[bottom + i] = argv[middle + i];
|
||||
argv[middle + i] = tem;
|
||||
}
|
||||
bottom += len;
|
||||
}
|
||||
}
|
||||
d->__first_nonopt += (d->optind - d->__last_nonopt);
|
||||
d->__last_nonopt = d->optind;
|
||||
}
|
||||
|
||||
|
||||
static const TCHAR *_getopt_initialize (const TCHAR *optstring, struct _getopt_data *d, int posixly_correct)
|
||||
{
|
||||
d->__first_nonopt = d->__last_nonopt = d->optind;
|
||||
d->__nextchar = NULL;
|
||||
d->__posixly_correct = posixly_correct | !!_tgetenv(_T("POSIXLY_CORRECT"));
|
||||
|
||||
|
||||
if (optstring[0] == _T('-'))
|
||||
{
|
||||
d->__ordering = RETURN_IN_ORDER;
|
||||
++optstring;
|
||||
}
|
||||
else if (optstring[0] == _T('+'))
|
||||
{
|
||||
d->__ordering = REQUIRE_ORDER;
|
||||
++optstring;
|
||||
}
|
||||
else if (d->__posixly_correct)
|
||||
d->__ordering = REQUIRE_ORDER;
|
||||
else
|
||||
d->__ordering = PERMUTE;
|
||||
return optstring;
|
||||
}
|
||||
|
||||
int _getopt_internal_r (int argc, TCHAR *const *argv, const TCHAR *optstring, const struct option *longopts, int *longind, int long_only, struct _getopt_data *d, int posixly_correct)
|
||||
{
|
||||
int print_errors = d->opterr;
|
||||
|
||||
if (argc < 1)
|
||||
return -1;
|
||||
|
||||
d->optarg = NULL;
|
||||
|
||||
if (d->optind == 0 || !d->__initialized)
|
||||
{
|
||||
if (d->optind == 0)
|
||||
d->optind = 1;
|
||||
optstring = _getopt_initialize (optstring, d, posixly_correct);
|
||||
d->__initialized = 1;
|
||||
}
|
||||
else if (optstring[0] == _T('-') || optstring[0] == _T('+'))
|
||||
optstring++;
|
||||
if (optstring[0] == _T(':'))
|
||||
print_errors = 0;
|
||||
|
||||
if (d->__nextchar == NULL || *d->__nextchar == _T('\0'))
|
||||
{
|
||||
if (d->__last_nonopt > d->optind)
|
||||
d->__last_nonopt = d->optind;
|
||||
if (d->__first_nonopt > d->optind)
|
||||
d->__first_nonopt = d->optind;
|
||||
|
||||
if (d->__ordering == PERMUTE)
|
||||
{
|
||||
if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
|
||||
exchange ((TCHAR **) argv, d);
|
||||
else if (d->__last_nonopt != d->optind)
|
||||
d->__first_nonopt = d->optind;
|
||||
|
||||
while (d->optind < argc && (argv[d->optind][0] != _T('-') || argv[d->optind][1] == _T('\0')))
|
||||
d->optind++;
|
||||
d->__last_nonopt = d->optind;
|
||||
}
|
||||
|
||||
if (d->optind != argc && !_tcscmp(argv[d->optind], _T("--")))
|
||||
{
|
||||
d->optind++;
|
||||
|
||||
if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
|
||||
exchange ((TCHAR **) argv, d);
|
||||
else if (d->__first_nonopt == d->__last_nonopt)
|
||||
d->__first_nonopt = d->optind;
|
||||
d->__last_nonopt = argc;
|
||||
|
||||
d->optind = argc;
|
||||
}
|
||||
|
||||
if (d->optind == argc)
|
||||
{
|
||||
if (d->__first_nonopt != d->__last_nonopt)
|
||||
d->optind = d->__first_nonopt;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((argv[d->optind][0] != _T('-') || argv[d->optind][1] == _T('\0')))
|
||||
{
|
||||
if (d->__ordering == REQUIRE_ORDER)
|
||||
return -1;
|
||||
d->optarg = argv[d->optind++];
|
||||
return 1;
|
||||
}
|
||||
|
||||
d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == _T('-')));
|
||||
}
|
||||
|
||||
if (longopts != NULL && (argv[d->optind][1] == _T('-') || (long_only && (argv[d->optind][2] || !_tcschr(optstring, argv[d->optind][1])))))
|
||||
{
|
||||
TCHAR *nameend;
|
||||
const struct option *p;
|
||||
const struct option *pfound = NULL;
|
||||
int exact = 0;
|
||||
int ambig = 0;
|
||||
int indfound = -1;
|
||||
int option_index;
|
||||
|
||||
for (nameend = d->__nextchar; *nameend && *nameend != _T('='); nameend++);
|
||||
|
||||
for (p = longopts, option_index = 0; p->name; p++, option_index++)
|
||||
if (!_tcsncmp(p->name, d->__nextchar, nameend - d->__nextchar))
|
||||
{
|
||||
if ((unsigned int)(nameend - d->__nextchar) == (unsigned int)_tcslen(p->name))
|
||||
{
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
exact = 1;
|
||||
break;
|
||||
}
|
||||
else if (pfound == NULL)
|
||||
{
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
}
|
||||
else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
|
||||
ambig = 1;
|
||||
}
|
||||
|
||||
if (ambig && !exact)
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
_ftprintf(stderr, _T("%s: option '%s' is ambiguous\n"),
|
||||
argv[0], argv[d->optind]);
|
||||
}
|
||||
d->__nextchar += _tcslen(d->__nextchar);
|
||||
d->optind++;
|
||||
d->optopt = 0;
|
||||
return _T('?');
|
||||
}
|
||||
|
||||
if (pfound != NULL)
|
||||
{
|
||||
option_index = indfound;
|
||||
d->optind++;
|
||||
if (*nameend)
|
||||
{
|
||||
if (pfound->has_arg)
|
||||
d->optarg = nameend + 1;
|
||||
else
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
if (argv[d->optind - 1][1] == _T('-'))
|
||||
{
|
||||
_ftprintf(stderr, _T("%s: option '--%s' doesn't allow an argument\n"),argv[0], pfound->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
_ftprintf(stderr, _T("%s: option '%c%s' doesn't allow an argument\n"),argv[0], argv[d->optind - 1][0],pfound->name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
d->__nextchar += _tcslen(d->__nextchar);
|
||||
|
||||
d->optopt = pfound->val;
|
||||
return _T('?');
|
||||
}
|
||||
}
|
||||
else if (pfound->has_arg == 1)
|
||||
{
|
||||
if (d->optind < argc)
|
||||
d->optarg = argv[d->optind++];
|
||||
else
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
_ftprintf(stderr,_T("%s: option '--%s' requires an argument\n"),argv[0], pfound->name);
|
||||
}
|
||||
d->__nextchar += _tcslen(d->__nextchar);
|
||||
d->optopt = pfound->val;
|
||||
return optstring[0] == _T(':') ? _T(':') : _T('?');
|
||||
}
|
||||
}
|
||||
d->__nextchar += _tcslen(d->__nextchar);
|
||||
if (longind != NULL)
|
||||
*longind = option_index;
|
||||
if (pfound->flag)
|
||||
{
|
||||
*(pfound->flag) = pfound->val;
|
||||
return 0;
|
||||
}
|
||||
return pfound->val;
|
||||
}
|
||||
|
||||
if (!long_only || argv[d->optind][1] == _T('-') || _tcschr(optstring, *d->__nextchar) == NULL)
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
if (argv[d->optind][1] == _T('-'))
|
||||
{
|
||||
/* --option */
|
||||
_ftprintf(stderr, _T("%s: unrecognized option '--%s'\n"),argv[0], d->__nextchar);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* +option or -option */
|
||||
_ftprintf(stderr, _T("%s: unrecognized option '%c%s'\n"),argv[0], argv[d->optind][0], d->__nextchar);
|
||||
}
|
||||
}
|
||||
d->__nextchar = (TCHAR *) "";
|
||||
d->optind++;
|
||||
d->optopt = 0;
|
||||
return _T('?');
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
TCHAR c = *d->__nextchar++;
|
||||
TCHAR *temp = (TCHAR*)_tcschr(optstring, c);
|
||||
|
||||
if (*d->__nextchar == _T('\0'))
|
||||
++d->optind;
|
||||
|
||||
if (temp == NULL || c == _T(':') || c == _T(';'))
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
_ftprintf(stderr, _T("%s: invalid option -- '%c'\n"), argv[0], c);
|
||||
}
|
||||
d->optopt = c;
|
||||
return _T('?');
|
||||
}
|
||||
if (temp[0] == _T('W') && temp[1] == _T(';'))
|
||||
{
|
||||
TCHAR *nameend;
|
||||
const struct option *p;
|
||||
const struct option *pfound = NULL;
|
||||
int exact = 0;
|
||||
int ambig = 0;
|
||||
int indfound = 0;
|
||||
int option_index;
|
||||
|
||||
if (*d->__nextchar != _T('\0'))
|
||||
{
|
||||
d->optarg = d->__nextchar;
|
||||
d->optind++;
|
||||
}
|
||||
else if (d->optind == argc)
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
_ftprintf(stderr,
|
||||
_T("%s: option requires an argument -- '%c'\n"),
|
||||
argv[0], c);
|
||||
}
|
||||
d->optopt = c;
|
||||
if (optstring[0] == _T(':'))
|
||||
c = _T(':');
|
||||
else
|
||||
c = _T('?');
|
||||
return c;
|
||||
}
|
||||
else
|
||||
d->optarg = argv[d->optind++];
|
||||
|
||||
for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != _T('='); nameend++);
|
||||
|
||||
for (p = longopts, option_index = 0; p->name; p++, option_index++)
|
||||
if (!_tcsncmp(p->name, d->__nextchar, nameend - d->__nextchar))
|
||||
{
|
||||
if ((unsigned int) (nameend - d->__nextchar) == _tcslen(p->name))
|
||||
{
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
exact = 1;
|
||||
break;
|
||||
}
|
||||
else if (pfound == NULL)
|
||||
{
|
||||
pfound = p;
|
||||
indfound = option_index;
|
||||
}
|
||||
else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
|
||||
ambig = 1;
|
||||
}
|
||||
if (ambig && !exact)
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
_ftprintf(stderr, _T("%s: option '-W %s' is ambiguous\n"),
|
||||
argv[0], d->optarg);
|
||||
}
|
||||
d->__nextchar += _tcslen(d->__nextchar);
|
||||
d->optind++;
|
||||
return _T('?');
|
||||
}
|
||||
if (pfound != NULL)
|
||||
{
|
||||
option_index = indfound;
|
||||
if (*nameend)
|
||||
{
|
||||
if (pfound->has_arg)
|
||||
d->optarg = nameend + 1;
|
||||
else
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
_ftprintf(stderr, _T("\
|
||||
%s: option '-W %s' doesn't allow an argument\n"),
|
||||
argv[0], pfound->name);
|
||||
}
|
||||
|
||||
d->__nextchar += _tcslen(d->__nextchar);
|
||||
return _T('?');
|
||||
}
|
||||
}
|
||||
else if (pfound->has_arg == 1)
|
||||
{
|
||||
if (d->optind < argc)
|
||||
d->optarg = argv[d->optind++];
|
||||
else
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
_ftprintf(stderr, _T("\
|
||||
%s: option '-W %s' requires an argument\n"),
|
||||
argv[0], pfound->name);
|
||||
}
|
||||
d->__nextchar += _tcslen(d->__nextchar);
|
||||
return optstring[0] == _T(':') ? _T(':') : _T('?');
|
||||
}
|
||||
}
|
||||
else
|
||||
d->optarg = NULL;
|
||||
d->__nextchar += _tcslen(d->__nextchar);
|
||||
if (longind != NULL)
|
||||
*longind = option_index;
|
||||
if (pfound->flag)
|
||||
{
|
||||
*(pfound->flag) = pfound->val;
|
||||
return 0;
|
||||
}
|
||||
return pfound->val;
|
||||
}
|
||||
d->__nextchar = NULL;
|
||||
return _T('W');
|
||||
}
|
||||
if (temp[1] == _T(':'))
|
||||
{
|
||||
if (temp[2] == _T(':'))
|
||||
{
|
||||
if (*d->__nextchar != _T('\0'))
|
||||
{
|
||||
d->optarg = d->__nextchar;
|
||||
d->optind++;
|
||||
}
|
||||
else
|
||||
d->optarg = NULL;
|
||||
d->__nextchar = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*d->__nextchar != _T('\0'))
|
||||
{
|
||||
d->optarg = d->__nextchar;
|
||||
d->optind++;
|
||||
}
|
||||
else if (d->optind == argc)
|
||||
{
|
||||
if (print_errors)
|
||||
{
|
||||
_ftprintf(stderr,
|
||||
_T("%s: option requires an argument -- '%c'\n"),
|
||||
argv[0], c);
|
||||
}
|
||||
d->optopt = c;
|
||||
if (optstring[0] == _T(':'))
|
||||
c = _T(':');
|
||||
else
|
||||
c = _T('?');
|
||||
}
|
||||
else
|
||||
d->optarg = argv[d->optind++];
|
||||
d->__nextchar = NULL;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
int _getopt_internal (int argc, TCHAR *const *argv, const TCHAR *optstring, const struct option *longopts, int *longind, int long_only, int posixly_correct)
|
||||
{
|
||||
int result;
|
||||
getopt_data.optind = optind;
|
||||
getopt_data.opterr = opterr;
|
||||
result = _getopt_internal_r (argc, argv, optstring, longopts,longind, long_only, &getopt_data,posixly_correct);
|
||||
optind = getopt_data.optind;
|
||||
optarg = getopt_data.optarg;
|
||||
optopt = getopt_data.optopt;
|
||||
return result;
|
||||
}
|
||||
|
||||
int getopt (int argc, TCHAR *const *argv, const TCHAR *optstring)
|
||||
{
|
||||
return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0, 0);
|
||||
}
|
||||
|
||||
int getopt_long (int argc, TCHAR *const *argv, const TCHAR *options, const struct option *long_options, int *opt_index)
|
||||
{
|
||||
return _getopt_internal (argc, argv, options, long_options, opt_index, 0, 0);
|
||||
}
|
||||
|
||||
int _getopt_long_r (int argc, TCHAR *const *argv, const TCHAR *options, const struct option *long_options, int *opt_index, struct _getopt_data *d)
|
||||
{
|
||||
return _getopt_internal_r (argc, argv, options, long_options, opt_index,0, d, 0);
|
||||
}
|
||||
|
||||
int getopt_long_only (int argc, TCHAR *const *argv, const TCHAR *options, const struct option *long_options, int *opt_index)
|
||||
{
|
||||
return _getopt_internal (argc, argv, options, long_options, opt_index, 1, 0);
|
||||
}
|
||||
|
||||
int _getopt_long_only_r (int argc, TCHAR *const *argv, const TCHAR *options, const struct option *long_options, int *opt_index, struct _getopt_data *d)
|
||||
{
|
||||
return _getopt_internal_r (argc, argv, options, long_options, opt_index, 1, d, 0);
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
/* Getopt for Microsoft C
|
||||
This code is a modification of the Free Software Foundation, Inc.
|
||||
Getopt library for parsing command line argument the purpose was
|
||||
to provide a Microsoft Visual C friendly derivative. This code
|
||||
provides functionality for both Unicode and Multibyte builds.
|
||||
|
||||
Date: 02/03/2011 - Ludvik Jerabek - Initial Release
|
||||
Version: 1.0
|
||||
Comment: Supports getopt, getopt_long, and getopt_long_only
|
||||
and POSIXLY_CORRECT environment flag
|
||||
License: LGPL
|
||||
|
||||
Revisions:
|
||||
|
||||
02/03/2011 - Ludvik Jerabek - Initial Release
|
||||
02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4
|
||||
|
||||
**DISCLAIMER**
|
||||
THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
|
||||
EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE
|
||||
EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT
|
||||
APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY
|
||||
DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY
|
||||
USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST
|
||||
PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON
|
||||
YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE
|
||||
EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
#ifndef __GETOPT_H_
|
||||
#define __GETOPT_H_
|
||||
|
||||
#include <tchar.h>
|
||||
|
||||
#define ARG_NULL 0 /*Argument Null*/
|
||||
#define ARG_NONE 0 /*Argument Switch Only*/
|
||||
#define ARG_REQ 1 /*Argument Required*/
|
||||
#define ARG_OPT 2 /*Argument Optional*/
|
||||
|
||||
// Change behavior for C\C++
|
||||
#ifdef __cplusplus
|
||||
#define _BEGIN_EXTERN_C extern "C" {
|
||||
#define _END_EXTERN_C }
|
||||
#define _GETOPT_THROW throw()
|
||||
#else
|
||||
#define _BEGIN_EXTERN_C
|
||||
#define _END_EXTERN_C
|
||||
#define _GETOPT_THROW
|
||||
#endif
|
||||
|
||||
_BEGIN_EXTERN_C
|
||||
extern TCHAR *optarg;
|
||||
extern int optind;
|
||||
extern int opterr;
|
||||
extern int optopt;
|
||||
struct option
|
||||
{
|
||||
const TCHAR* name;
|
||||
int has_arg;
|
||||
int *flag;
|
||||
TCHAR val;
|
||||
};
|
||||
extern int getopt(int argc, TCHAR *const *argv, const TCHAR *optstring) _GETOPT_THROW;
|
||||
extern int getopt_long(int ___argc, TCHAR *const *___argv, const TCHAR *__shortopts, const struct option *__longopts, int *__longind) _GETOPT_THROW;
|
||||
extern int getopt_long_only(int ___argc, TCHAR *const *___argv, const TCHAR *__shortopts, const struct option *__longopts, int *__longind) _GETOPT_THROW;
|
||||
_END_EXTERN_C
|
||||
|
||||
// Undefine so the macros are not included
|
||||
#undef _BEGIN_EXTERN_C
|
||||
#undef _END_EXTERN_C
|
||||
#undef _GETOPT_THROW
|
||||
|
||||
#endif // __GETOPT_H_
|
@ -1,111 +0,0 @@
|
||||
Index: rtmpdump.c
|
||||
===================================================================
|
||||
--- rtmpdump.c (revision 256)
|
||||
+++ rtmpdump.c (working copy)
|
||||
@@ -25,9 +25,11 @@
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
+#include <tchar.h>
|
||||
+#include <stdarg.h>
|
||||
|
||||
#include <signal.h> // to catch Ctrl-C
|
||||
-#include <getopt.h>
|
||||
+#include "getopt.h"
|
||||
|
||||
#include "rtmp.h"
|
||||
#include "log.h"
|
||||
@@ -38,6 +40,7 @@
|
||||
#define ftello ftello64
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
+#include <windows.h>
|
||||
#define SET_BINMODE(f) setmode(fileno(f), O_BINARY)
|
||||
#else
|
||||
#define SET_BINMODE(f)
|
||||
@@ -542,7 +545,7 @@
|
||||
}
|
||||
|
||||
int
|
||||
-OpenResumeFile(const char *flvFile, // file name [in]
|
||||
+OpenResumeFile(const wchar_t *flvFile, // file name [in]
|
||||
FILE ** file, // opened file [out]
|
||||
off_t * size, // size of the file [out]
|
||||
char **metaHeader, // meta data read from the file [out]
|
||||
@@ -555,7 +558,7 @@
|
||||
*nMetaHeaderSize = 0;
|
||||
*size = 0;
|
||||
|
||||
- *file = fopen(flvFile, "r+b");
|
||||
+ *file = _wfopen(flvFile, L"r+b");
|
||||
if (!*file)
|
||||
return RD_SUCCESS; // RD_SUCCESS, because we go to fresh file mode instead of quiting
|
||||
|
||||
@@ -1164,7 +1167,7 @@
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
- extern char *optarg;
|
||||
+ extern TCHAR *optarg;
|
||||
|
||||
int nStatus = RD_SUCCESS;
|
||||
double percent = 0;
|
||||
@@ -1222,7 +1225,7 @@
|
||||
unsigned char hash[HASHLEN];
|
||||
#endif
|
||||
|
||||
- char *flvFile = 0;
|
||||
+ wchar_t *flvFile = 0;
|
||||
|
||||
#undef OSS
|
||||
#ifdef WIN32
|
||||
@@ -1264,6 +1267,24 @@
|
||||
|
||||
/* sleep(30); */
|
||||
|
||||
+ // parsing filepath and converting to unicode
|
||||
+ wchar_t *uflvFile = 0;
|
||||
+ #ifdef WIN32
|
||||
+ wchar_t *cmdstr;
|
||||
+ wchar_t **wargv;
|
||||
+ int i;
|
||||
+ // print parameters, including Unicode.
|
||||
+ cmdstr = GetCommandLineW();
|
||||
+ wargv = CommandLineToArgvW(cmdstr, &argc);
|
||||
+ for (i = 0; i < argc; i++) {
|
||||
+ if (wcscmp(wargv[i], L"-o") == 0)
|
||||
+ {
|
||||
+ uflvFile = wargv[i + 1];
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ #endif
|
||||
+
|
||||
int opt;
|
||||
struct option longopts[] = {
|
||||
{"help", 0, NULL, 'h'},
|
||||
@@ -1535,10 +1556,12 @@
|
||||
STR2AVAL(flashVer, optarg);
|
||||
break;
|
||||
case 'o':
|
||||
- flvFile = optarg;
|
||||
- if (strcmp(flvFile, "-"))
|
||||
+ flvFile = (wchar_t*)optarg;
|
||||
+ if (wcscmp(flvFile, L"-"))
|
||||
bStdoutMode = false;
|
||||
-
|
||||
+#ifdef WIN32
|
||||
+ flvFile = uflvFile;
|
||||
+#endif
|
||||
break;
|
||||
case 'e':
|
||||
bResume = true;
|
||||
@@ -1749,7 +1772,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
- file = fopen(flvFile, "w+b");
|
||||
+ file = _wfopen(flvFile, L"w+b");
|
||||
if (file == 0)
|
||||
{
|
||||
LogPrintf("Failed to open file! %s\n", flvFile);
|
Loading…
Reference in New Issue
Block a user