-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:
jiaz 2022-01-27 13:40:51 +00:00
parent e49f7d5434
commit 3f9a8cb4b7
17 changed files with 13 additions and 1900 deletions

View File

@ -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:"));

View File

@ -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());
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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");

View File

@ -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.

View File

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

View File

@ -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);
}

View File

@ -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_

View File

@ -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);