nile.js
Version:
A tool for scalable peer-to-peer video streaming using WebTorrent
1,506 lines (1,321 loc) • 746 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define("Viewer", [], factory);
else if(typeof exports === 'object')
exports["Viewer"] = factory();
else
root["Viewer"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // identity function for calling harmony imports with the correct context
/******/ __webpack_require__.i = function(value) { return value; };
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "dist";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 35);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var g;
// This works in non-strict mode
g = function () {
return this;
}();
try {
// This works if eval is allowed (see CSP)
g = g || Function("return this")() || (1, eval)("this");
} catch (e) {
// This works if the window reference is available
if ((typeof window === "undefined" ? "undefined" : _typeof(window)) === "object") g = window;
}
// g can still be undefined, but nothing to do about it...
// We return undefined, instead of nothing here, so it's
// easier to handle this case. if(!global) { ...}
module.exports = g;
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree.
*/
/* eslint-env node */
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var logDisabled_ = true;
// Utility methods.
var utils = {
disableLog: function disableLog(bool) {
if (typeof bool !== 'boolean') {
return new Error('Argument type: ' + (typeof bool === 'undefined' ? 'undefined' : _typeof(bool)) + '. Please use a boolean.');
}
logDisabled_ = bool;
return bool ? 'adapter.js logging disabled' : 'adapter.js logging enabled';
},
log: function log() {
if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object') {
if (logDisabled_) {
return;
}
if (typeof console !== 'undefined' && typeof console.log === 'function') {
console.log.apply(console, arguments);
}
}
},
/**
* Extract browser version out of the provided user agent string.
*
* @param {!string} uastring userAgent string.
* @param {!string} expr Regular expression used as match criteria.
* @param {!number} pos position in the version string to be returned.
* @return {!number} browser version.
*/
extractVersion: function extractVersion(uastring, expr, pos) {
var match = uastring.match(expr);
return match && match.length >= pos && parseInt(match[pos], 10);
},
/**
* Browser detector.
*
* @return {object} result containing browser and version
* properties.
*/
detectBrowser: function detectBrowser() {
// Returned result object.
var result = {};
result.browser = null;
result.version = null;
// Fail early if it's not a browser
if (typeof window === 'undefined' || !window.navigator) {
result.browser = 'Not a browser.';
return result;
}
// Firefox.
if (navigator.mozGetUserMedia) {
result.browser = 'firefox';
result.version = this.extractVersion(navigator.userAgent, /Firefox\/(\d+)\./, 1);
} else if (navigator.webkitGetUserMedia) {
// Chrome, Chromium, Webview, Opera, all use the chrome shim for now
if (window.webkitRTCPeerConnection) {
result.browser = 'chrome';
result.version = this.extractVersion(navigator.userAgent, /Chrom(e|ium)\/(\d+)\./, 2);
} else {
// Safari (in an unpublished version) or unknown webkit-based.
if (navigator.userAgent.match(/Version\/(\d+).(\d+)/)) {
result.browser = 'safari';
result.version = this.extractVersion(navigator.userAgent, /AppleWebKit\/(\d+)\./, 1);
} else {
// unknown webkit-based browser.
result.browser = 'Unsupported webkit-based browser ' + 'with GUM support but no WebRTC support.';
return result;
}
}
} else if (navigator.mediaDevices && navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) {
// Edge.
result.browser = 'edge';
result.version = this.extractVersion(navigator.userAgent, /Edge\/(\d+).(\d+)$/, 2);
} else if (navigator.mediaDevices && navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) {
// Safari, with webkitGetUserMedia removed.
result.browser = 'safari';
result.version = this.extractVersion(navigator.userAgent, /AppleWebKit\/(\d+)\./, 1);
} else {
// Default fallthrough: not supported.
result.browser = 'Not a supported browser.';
return result;
}
return result;
},
// shimCreateObjectURL must be called before shimSourceObject to avoid loop.
shimCreateObjectURL: function shimCreateObjectURL() {
if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.HTMLMediaElement && 'srcObject' in window.HTMLMediaElement.prototype)) {
// Only shim CreateObjectURL using srcObject if srcObject exists.
return undefined;
}
var nativeCreateObjectURL = URL.createObjectURL.bind(URL);
var nativeRevokeObjectURL = URL.revokeObjectURL.bind(URL);
var streams = new Map(),
newId = 0;
URL.createObjectURL = function (stream) {
if ('getTracks' in stream) {
var url = 'polyblob:' + ++newId;
streams.set(url, stream);
console.log('URL.createObjectURL(stream) is deprecated! ' + 'Use elem.srcObject = stream instead!');
return url;
}
return nativeCreateObjectURL(stream);
};
URL.revokeObjectURL = function (url) {
nativeRevokeObjectURL(url);
streams.delete(url);
};
var dsc = Object.getOwnPropertyDescriptor(window.HTMLMediaElement.prototype, 'src');
Object.defineProperty(window.HTMLMediaElement.prototype, 'src', {
get: function get() {
return dsc.get.apply(this);
},
set: function set(url) {
this.srcObject = streams.get(url) || null;
return dsc.set.apply(this, [url]);
}
});
var nativeSetAttribute = HTMLMediaElement.prototype.setAttribute;
HTMLMediaElement.prototype.setAttribute = function () {
if (arguments.length === 2 && ('' + arguments[0]).toLowerCase() === 'src') {
this.srcObject = streams.get(arguments[1]) || null;
}
return nativeSetAttribute.apply(this, arguments);
};
}
};
// Export.
module.exports = {
log: utils.log,
disableLog: utils.disableLog,
browserDetails: utils.detectBrowser(),
extractVersion: utils.extractVersion,
shimCreateObjectURL: utils.shimCreateObjectURL,
detectBrowser: utils.detectBrowser.bind(utils)
};
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/* WEBPACK VAR INJECTION */(function(global) {
/**
* Module dependencies.
*/
var keys = __webpack_require__(48);
var hasBinary = __webpack_require__(19);
var sliceBuffer = __webpack_require__(37);
var after = __webpack_require__(36);
var utf8 = __webpack_require__(71);
var base64encoder;
if (global && global.ArrayBuffer) {
base64encoder = __webpack_require__(39);
}
/**
* Check if we are running an android browser. That requires us to use
* ArrayBuffer with polling transports...
*
* http://ghinda.net/jpeg-blob-ajax-android/
*/
var isAndroid = typeof navigator !== 'undefined' && /Android/i.test(navigator.userAgent);
/**
* Check if we are running in PhantomJS.
* Uploading a Blob with PhantomJS does not work correctly, as reported here:
* https://github.com/ariya/phantomjs/issues/11395
* @type boolean
*/
var isPhantomJS = typeof navigator !== 'undefined' && /PhantomJS/i.test(navigator.userAgent);
/**
* When true, avoids using Blobs to encode payloads.
* @type boolean
*/
var dontSendBlobs = isAndroid || isPhantomJS;
/**
* Current protocol version.
*/
exports.protocol = 3;
/**
* Packet types.
*/
var packets = exports.packets = {
open: 0 // non-ws
, close: 1 // non-ws
, ping: 2,
pong: 3,
message: 4,
upgrade: 5,
noop: 6
};
var packetslist = keys(packets);
/**
* Premade error packet.
*/
var err = { type: 'error', data: 'parser error' };
/**
* Create a blob api even for blob builder when vendor prefixes exist
*/
var Blob = __webpack_require__(40);
/**
* Encodes a packet.
*
* <packet type id> [ <data> ]
*
* Example:
*
* 5hello world
* 3
* 4
*
* Binary is encoded in an identical principle
*
* @api private
*/
exports.encodePacket = function (packet, supportsBinary, utf8encode, callback) {
if ('function' == typeof supportsBinary) {
callback = supportsBinary;
supportsBinary = false;
}
if ('function' == typeof utf8encode) {
callback = utf8encode;
utf8encode = null;
}
var data = packet.data === undefined ? undefined : packet.data.buffer || packet.data;
if (global.ArrayBuffer && data instanceof ArrayBuffer) {
return encodeArrayBuffer(packet, supportsBinary, callback);
} else if (Blob && data instanceof global.Blob) {
return encodeBlob(packet, supportsBinary, callback);
}
// might be an object with { base64: true, data: dataAsBase64String }
if (data && data.base64) {
return encodeBase64Object(packet, callback);
}
// Sending data as a utf-8 string
var encoded = packets[packet.type];
// data fragment is optional
if (undefined !== packet.data) {
encoded += utf8encode ? utf8.encode(String(packet.data)) : String(packet.data);
}
return callback('' + encoded);
};
function encodeBase64Object(packet, callback) {
// packet data is an object { base64: true, data: dataAsBase64String }
var message = 'b' + exports.packets[packet.type] + packet.data.data;
return callback(message);
}
/**
* Encode packet helpers for binary types
*/
function encodeArrayBuffer(packet, supportsBinary, callback) {
if (!supportsBinary) {
return exports.encodeBase64Packet(packet, callback);
}
var data = packet.data;
var contentArray = new Uint8Array(data);
var resultBuffer = new Uint8Array(1 + data.byteLength);
resultBuffer[0] = packets[packet.type];
for (var i = 0; i < contentArray.length; i++) {
resultBuffer[i + 1] = contentArray[i];
}
return callback(resultBuffer.buffer);
}
function encodeBlobAsArrayBuffer(packet, supportsBinary, callback) {
if (!supportsBinary) {
return exports.encodeBase64Packet(packet, callback);
}
var fr = new FileReader();
fr.onload = function () {
packet.data = fr.result;
exports.encodePacket(packet, supportsBinary, true, callback);
};
return fr.readAsArrayBuffer(packet.data);
}
function encodeBlob(packet, supportsBinary, callback) {
if (!supportsBinary) {
return exports.encodeBase64Packet(packet, callback);
}
if (dontSendBlobs) {
return encodeBlobAsArrayBuffer(packet, supportsBinary, callback);
}
var length = new Uint8Array(1);
length[0] = packets[packet.type];
var blob = new Blob([length.buffer, packet.data]);
return callback(blob);
}
/**
* Encodes a packet with binary data in a base64 string
*
* @param {Object} packet, has `type` and `data`
* @return {String} base64 encoded message
*/
exports.encodeBase64Packet = function (packet, callback) {
var message = 'b' + exports.packets[packet.type];
if (Blob && packet.data instanceof global.Blob) {
var fr = new FileReader();
fr.onload = function () {
var b64 = fr.result.split(',')[1];
callback(message + b64);
};
return fr.readAsDataURL(packet.data);
}
var b64data;
try {
b64data = String.fromCharCode.apply(null, new Uint8Array(packet.data));
} catch (e) {
// iPhone Safari doesn't let you apply with typed arrays
var typed = new Uint8Array(packet.data);
var basic = new Array(typed.length);
for (var i = 0; i < typed.length; i++) {
basic[i] = typed[i];
}
b64data = String.fromCharCode.apply(null, basic);
}
message += global.btoa(b64data);
return callback(message);
};
/**
* Decodes a packet. Changes format to Blob if requested.
*
* @return {Object} with `type` and `data` (if any)
* @api private
*/
exports.decodePacket = function (data, binaryType, utf8decode) {
if (data === undefined) {
return err;
}
// String data
if (typeof data == 'string') {
if (data.charAt(0) == 'b') {
return exports.decodeBase64Packet(data.substr(1), binaryType);
}
if (utf8decode) {
data = tryDecode(data);
if (data === false) {
return err;
}
}
var type = data.charAt(0);
if (Number(type) != type || !packetslist[type]) {
return err;
}
if (data.length > 1) {
return { type: packetslist[type], data: data.substring(1) };
} else {
return { type: packetslist[type] };
}
}
var asArray = new Uint8Array(data);
var type = asArray[0];
var rest = sliceBuffer(data, 1);
if (Blob && binaryType === 'blob') {
rest = new Blob([rest]);
}
return { type: packetslist[type], data: rest };
};
function tryDecode(data) {
try {
data = utf8.decode(data);
} catch (e) {
return false;
}
return data;
}
/**
* Decodes a packet encoded in a base64 string
*
* @param {String} base64 encoded message
* @return {Object} with `type` and `data` (if any)
*/
exports.decodeBase64Packet = function (msg, binaryType) {
var type = packetslist[msg.charAt(0)];
if (!base64encoder) {
return { type: type, data: { base64: true, data: msg.substr(1) } };
}
var data = base64encoder.decode(msg.substr(1));
if (binaryType === 'blob' && Blob) {
data = new Blob([data]);
}
return { type: type, data: data };
};
/**
* Encodes multiple messages (payload).
*
* <length>:data
*
* Example:
*
* 11:hello world2:hi
*
* If any contents are binary, they will be encoded as base64 strings. Base64
* encoded strings are marked with a b before the length specifier
*
* @param {Array} packets
* @api private
*/
exports.encodePayload = function (packets, supportsBinary, callback) {
if (typeof supportsBinary == 'function') {
callback = supportsBinary;
supportsBinary = null;
}
var isBinary = hasBinary(packets);
if (supportsBinary && isBinary) {
if (Blob && !dontSendBlobs) {
return exports.encodePayloadAsBlob(packets, callback);
}
return exports.encodePayloadAsArrayBuffer(packets, callback);
}
if (!packets.length) {
return callback('0:');
}
function setLengthHeader(message) {
return message.length + ':' + message;
}
function encodeOne(packet, doneCallback) {
exports.encodePacket(packet, !isBinary ? false : supportsBinary, true, function (message) {
doneCallback(null, setLengthHeader(message));
});
}
map(packets, encodeOne, function (err, results) {
return callback(results.join(''));
});
};
/**
* Async array map using after
*/
function map(ary, each, done) {
var result = new Array(ary.length);
var next = after(ary.length, done);
var eachWithIndex = function eachWithIndex(i, el, cb) {
each(el, function (error, msg) {
result[i] = msg;
cb(error, result);
});
};
for (var i = 0; i < ary.length; i++) {
eachWithIndex(i, ary[i], next);
}
}
/*
* Decodes data when a payload is maybe expected. Possible binary contents are
* decoded from their base64 representation
*
* @param {String} data, callback method
* @api public
*/
exports.decodePayload = function (data, binaryType, callback) {
if (typeof data != 'string') {
return exports.decodePayloadAsBinary(data, binaryType, callback);
}
if (typeof binaryType === 'function') {
callback = binaryType;
binaryType = null;
}
var packet;
if (data == '') {
// parser error - ignoring payload
return callback(err, 0, 1);
}
var length = '',
n,
msg;
for (var i = 0, l = data.length; i < l; i++) {
var chr = data.charAt(i);
if (':' != chr) {
length += chr;
} else {
if ('' == length || length != (n = Number(length))) {
// parser error - ignoring payload
return callback(err, 0, 1);
}
msg = data.substr(i + 1, n);
if (length != msg.length) {
// parser error - ignoring payload
return callback(err, 0, 1);
}
if (msg.length) {
packet = exports.decodePacket(msg, binaryType, true);
if (err.type == packet.type && err.data == packet.data) {
// parser error in individual packet - ignoring payload
return callback(err, 0, 1);
}
var ret = callback(packet, i + n, l);
if (false === ret) return;
}
// advance cursor
i += n;
length = '';
}
}
if (length != '') {
// parser error - ignoring payload
return callback(err, 0, 1);
}
};
/**
* Encodes multiple messages (payload) as binary.
*
* <1 = binary, 0 = string><number from 0-9><number from 0-9>[...]<number
* 255><data>
*
* Example:
* 1 3 255 1 2 3, if the binary contents are interpreted as 8 bit integers
*
* @param {Array} packets
* @return {ArrayBuffer} encoded payload
* @api private
*/
exports.encodePayloadAsArrayBuffer = function (packets, callback) {
if (!packets.length) {
return callback(new ArrayBuffer(0));
}
function encodeOne(packet, doneCallback) {
exports.encodePacket(packet, true, true, function (data) {
return doneCallback(null, data);
});
}
map(packets, encodeOne, function (err, encodedPackets) {
var totalLength = encodedPackets.reduce(function (acc, p) {
var len;
if (typeof p === 'string') {
len = p.length;
} else {
len = p.byteLength;
}
return acc + len.toString().length + len + 2; // string/binary identifier + separator = 2
}, 0);
var resultArray = new Uint8Array(totalLength);
var bufferIndex = 0;
encodedPackets.forEach(function (p) {
var isString = typeof p === 'string';
var ab = p;
if (isString) {
var view = new Uint8Array(p.length);
for (var i = 0; i < p.length; i++) {
view[i] = p.charCodeAt(i);
}
ab = view.buffer;
}
if (isString) {
// not true binary
resultArray[bufferIndex++] = 0;
} else {
// true binary
resultArray[bufferIndex++] = 1;
}
var lenStr = ab.byteLength.toString();
for (var i = 0; i < lenStr.length; i++) {
resultArray[bufferIndex++] = parseInt(lenStr[i]);
}
resultArray[bufferIndex++] = 255;
var view = new Uint8Array(ab);
for (var i = 0; i < view.length; i++) {
resultArray[bufferIndex++] = view[i];
}
});
return callback(resultArray.buffer);
});
};
/**
* Encode as Blob
*/
exports.encodePayloadAsBlob = function (packets, callback) {
function encodeOne(packet, doneCallback) {
exports.encodePacket(packet, true, true, function (encoded) {
var binaryIdentifier = new Uint8Array(1);
binaryIdentifier[0] = 1;
if (typeof encoded === 'string') {
var view = new Uint8Array(encoded.length);
for (var i = 0; i < encoded.length; i++) {
view[i] = encoded.charCodeAt(i);
}
encoded = view.buffer;
binaryIdentifier[0] = 0;
}
var len = encoded instanceof ArrayBuffer ? encoded.byteLength : encoded.size;
var lenStr = len.toString();
var lengthAry = new Uint8Array(lenStr.length + 1);
for (var i = 0; i < lenStr.length; i++) {
lengthAry[i] = parseInt(lenStr[i]);
}
lengthAry[lenStr.length] = 255;
if (Blob) {
var blob = new Blob([binaryIdentifier.buffer, lengthAry.buffer, encoded]);
doneCallback(null, blob);
}
});
}
map(packets, encodeOne, function (err, results) {
return callback(new Blob(results));
});
};
/*
* Decodes data when a payload is maybe expected. Strings are decoded by
* interpreting each byte as a key code for entries marked to start with 0. See
* description of encodePayloadAsBinary
*
* @param {ArrayBuffer} data, callback method
* @api public
*/
exports.decodePayloadAsBinary = function (data, binaryType, callback) {
if (typeof binaryType === 'function') {
callback = binaryType;
binaryType = null;
}
var bufferTail = data;
var buffers = [];
var numberTooLong = false;
while (bufferTail.byteLength > 0) {
var tailArray = new Uint8Array(bufferTail);
var isString = tailArray[0] === 0;
var msgLength = '';
for (var i = 1;; i++) {
if (tailArray[i] == 255) break;
if (msgLength.length > 310) {
numberTooLong = true;
break;
}
msgLength += tailArray[i];
}
if (numberTooLong) return callback(err, 0, 1);
bufferTail = sliceBuffer(bufferTail, 2 + msgLength.length);
msgLength = parseInt(msgLength);
var msg = sliceBuffer(bufferTail, 0, msgLength);
if (isString) {
try {
msg = String.fromCharCode.apply(null, new Uint8Array(msg));
} catch (e) {
// iPhone Safari doesn't let you apply to typed arrays
var typed = new Uint8Array(msg);
msg = '';
for (var i = 0; i < typed.length; i++) {
msg += String.fromCharCode(typed[i]);
}
}
}
buffers.push(msg);
bufferTail = sliceBuffer(bufferTail, msgLength);
}
var total = buffers.length;
buffers.forEach(function (buffer, i) {
callback(exports.decodePacket(buffer, binaryType, true), i, total);
});
};
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)))
/***/ }),
/* 3 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/**
* Expose `Emitter`.
*/
if (true) {
module.exports = Emitter;
}
/**
* Initialize a new `Emitter`.
*
* @api public
*/
function Emitter(obj) {
if (obj) return mixin(obj);
};
/**
* Mixin the emitter properties.
*
* @param {Object} obj
* @return {Object}
* @api private
*/
function mixin(obj) {
for (var key in Emitter.prototype) {
obj[key] = Emitter.prototype[key];
}
return obj;
}
/**
* Listen on the given `event` with `fn`.
*
* @param {String} event
* @param {Function} fn
* @return {Emitter}
* @api public
*/
Emitter.prototype.on = Emitter.prototype.addEventListener = function (event, fn) {
this._callbacks = this._callbacks || {};
(this._callbacks['$' + event] = this._callbacks['$' + event] || []).push(fn);
return this;
};
/**
* Adds an `event` listener that will be invoked a single
* time then automatically removed.
*
* @param {String} event
* @param {Function} fn
* @return {Emitter}
* @api public
*/
Emitter.prototype.once = function (event, fn) {
function on() {
this.off(event, on);
fn.apply(this, arguments);
}
on.fn = fn;
this.on(event, on);
return this;
};
/**
* Remove the given callback for `event` or all
* registered callbacks.
*
* @param {String} event
* @param {Function} fn
* @return {Emitter}
* @api public
*/
Emitter.prototype.off = Emitter.prototype.removeListener = Emitter.prototype.removeAllListeners = Emitter.prototype.removeEventListener = function (event, fn) {
this._callbacks = this._callbacks || {};
// all
if (0 == arguments.length) {
this._callbacks = {};
return this;
}
// specific event
var callbacks = this._callbacks['$' + event];
if (!callbacks) return this;
// remove all handlers
if (1 == arguments.length) {
delete this._callbacks['$' + event];
return this;
}
// remove specific handler
var cb;
for (var i = 0; i < callbacks.length; i++) {
cb = callbacks[i];
if (cb === fn || cb.fn === fn) {
callbacks.splice(i, 1);
break;
}
}
return this;
};
/**
* Emit `event` with the given args.
*
* @param {String} event
* @param {Mixed} ...
* @return {Emitter}
*/
Emitter.prototype.emit = function (event) {
this._callbacks = this._callbacks || {};
var args = [].slice.call(arguments, 1),
callbacks = this._callbacks['$' + event];
if (callbacks) {
callbacks = callbacks.slice(0);
for (var i = 0, len = callbacks.length; i < len; ++i) {
callbacks[i].apply(this, args);
}
}
return this;
};
/**
* Return array of callbacks for `event`.
*
* @param {String} event
* @return {Array}
* @api public
*/
Emitter.prototype.listeners = function (event) {
this._callbacks = this._callbacks || {};
return this._callbacks['$' + event] || [];
};
/**
* Check if this emitter has `event` handlers.
*
* @param {String} event
* @return {Boolean}
* @api public
*/
Emitter.prototype.hasListeners = function (event) {
return !!this.listeners(event).length;
};
/***/ }),
/* 4 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
// shim for using process in browser
var process = module.exports = {};
// cached from whatever global is present so that test runners that stub it
// don't break things. But we need to wrap it in a try catch in case it is
// wrapped in strict mode code which doesn't define any globals. It's inside a
// function because try/catches deoptimize in certain engines.
var cachedSetTimeout;
var cachedClearTimeout;
function defaultSetTimout() {
throw new Error('setTimeout has not been defined');
}
function defaultClearTimeout() {
throw new Error('clearTimeout has not been defined');
}
(function () {
try {
if (typeof setTimeout === 'function') {
cachedSetTimeout = setTimeout;
} else {
cachedSetTimeout = defaultSetTimout;
}
} catch (e) {
cachedSetTimeout = defaultSetTimout;
}
try {
if (typeof clearTimeout === 'function') {
cachedClearTimeout = clearTimeout;
} else {
cachedClearTimeout = defaultClearTimeout;
}
} catch (e) {
cachedClearTimeout = defaultClearTimeout;
}
})();
function runTimeout(fun) {
if (cachedSetTimeout === setTimeout) {
//normal enviroments in sane situations
return setTimeout(fun, 0);
}
// if setTimeout wasn't available but was latter defined
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
cachedSetTimeout = setTimeout;
return setTimeout(fun, 0);
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedSetTimeout(fun, 0);
} catch (e) {
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedSetTimeout.call(null, fun, 0);
} catch (e) {
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
return cachedSetTimeout.call(this, fun, 0);
}
}
}
function runClearTimeout(marker) {
if (cachedClearTimeout === clearTimeout) {
//normal enviroments in sane situations
return clearTimeout(marker);
}
// if clearTimeout wasn't available but was latter defined
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
cachedClearTimeout = clearTimeout;
return clearTimeout(marker);
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedClearTimeout(marker);
} catch (e) {
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedClearTimeout.call(null, marker);
} catch (e) {
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
// Some versions of I.E. have different rules for clearTimeout vs setTimeout
return cachedClearTimeout.call(this, marker);
}
}
}
var queue = [];
var draining = false;
var currentQueue;
var queueIndex = -1;
function cleanUpNextTick() {
if (!draining || !currentQueue) {
return;
}
draining = false;
if (currentQueue.length) {
queue = currentQueue.concat(queue);
} else {
queueIndex = -1;
}
if (queue.length) {
drainQueue();
}
}
function drainQueue() {
if (draining) {
return;
}
var timeout = runTimeout(cleanUpNextTick);
draining = true;
var len = queue.length;
while (len) {
currentQueue = queue;
queue = [];
while (++queueIndex < len) {
if (currentQueue) {
currentQueue[queueIndex].run();
}
}
queueIndex = -1;
len = queue.length;
}
currentQueue = null;
draining = false;
runClearTimeout(timeout);
}
process.nextTick = function (fun) {
var args = new Array(arguments.length - 1);
if (arguments.length > 1) {
for (var i = 1; i < arguments.length; i++) {
args[i - 1] = arguments[i];
}
}
queue.push(new Item(fun, args));
if (queue.length === 1 && !draining) {
runTimeout(drainQueue);
}
};
// v8 likes predictible objects
function Item(fun, array) {
this.fun = fun;
this.array = array;
}
Item.prototype.run = function () {
this.fun.apply(null, this.array);
};
process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];
process.version = ''; // empty string to avoid regexp issues
process.versions = {};
function noop() {}
process.on = noop;
process.addListener = noop;
process.once = noop;
process.off = noop;
process.removeListener = noop;
process.removeAllListeners = noop;
process.emit = noop;
process.prependListener = noop;
process.prependOnceListener = noop;
process.listeners = function (name) {
return [];
};
process.binding = function (name) {
throw new Error('process.binding is not supported');
};
process.cwd = function () {
return '/';
};
process.chdir = function (dir) {
throw new Error('process.chdir is not supported');
};
process.umask = function () {
return 0;
};
/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/* WEBPACK VAR INJECTION */(function(global, setImmediate) {var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var require;var require;
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
!function (e) {
if ("object" == ( false ? "undefined" : _typeof(exports)) && "undefined" != typeof module) module.exports = e();else if (true) !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (e),
__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));else {
var t;t = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof self ? self : this, t.WebTorrent = e();
}
}(function () {
var e;return function e(t, n, r) {
function o(s, a) {
if (!n[s]) {
if (!t[s]) {
var u = "function" == typeof require && require;if (!a && u) return require(s, !0);if (i) return require(s, !0);var c = new Error("Cannot find module '" + s + "'");throw c.code = "MODULE_NOT_FOUND", c;
}var f = n[s] = { exports: {} };t[s][0].call(f.exports, function (e) {
var n = t[s][1][e];return o(n || e);
}, f, f.exports, e, t, n, r);
}return n[s].exports;
}for (var i = "function" == typeof require && require, s = 0; s < r.length; s++) {
o(r[s]);
}return o;
}({ 1: [function (e, t, n) {
function r(e, t) {
s.Readable.call(this, t), this.destroyed = !1, this._torrent = e._torrent;var n = t && t.start || 0,
r = t && t.end && t.end < e.length ? t.end : e.length - 1,
o = e._torrent.pieceLength;this._startPiece = (n + e.offset) / o | 0, this._endPiece = (r + e.offset) / o | 0, this._piece = this._startPiece, this._offset = n + e.offset - this._startPiece * o, this._missing = r - n + 1, this._reading = !1, this._notifying = !1, this._criticalLength = Math.min(1048576 / o | 0, 2);
}t.exports = r;var o = e("debug")("webtorrent:file-stream"),
i = e("inherits"),
s = e("readable-stream");i(r, s.Readable), r.prototype._read = function () {
this._reading || (this._reading = !0, this._notify());
}, r.prototype._notify = function () {
var e = this;if (e._reading && 0 !== e._missing) {
if (!e._torrent.bitfield.get(e._piece)) return e._torrent.critical(e._piece, e._piece + e._criticalLength);if (!e._notifying) {
e._notifying = !0;var t = e._piece;e._torrent.store.get(t, function (n, r) {
if (e._notifying = !1, !e.destroyed) {
if (n) return e._destroy(n);o("read %s (length %s) (err %s)", t, r.length, n && n.message), e._offset && (r = r.slice(e._offset), e._offset = 0), e._missing < r.length && (r = r.slice(0, e._missing)), e._missing -= r.length, o("pushing buffer of length %s", r.length), e._reading = !1, e.push(r), 0 === e._missing && e.push(null);
}
}), e._piece += 1;
}
}
}, r.prototype.destroy = function (e) {
this._destroy(null, e);
}, r.prototype._destroy = function (e, t) {
this.destroyed || (this.destroyed = !0, this._torrent.destroyed || this._torrent.deselect(this._startPiece, this._endPiece, !0), e && this.emit("error", e), this.emit("close"), t && t());
};
}, { debug: 30, inherits: 41, "readable-stream": 82 }], 2: [function (e, t, n) {
(function (n) {
function r(e, t) {
i.call(this), this._torrent = e, this._destroyed = !1, this.name = t.name, this.path = t.path, this.length = t.length, this.offset = t.offset, this.done = !1;var n = t.offset,
r = n + t.length - 1;this._startPiece = n / this._torrent.pieceLength | 0, this._endPiece = r / this._torrent.pieceLength | 0, 0 === this.length && (this.done = !0, this.emit("done"));
}t.exports = r;var o = e("end-of-stream"),
i = e("events").EventEmitter,
s = e("./file-stream"),
a = e("inherits"),
u = e("path"),
c = e("render-media"),
f = e("readable-stream"),
d = e("stream-to-blob"),
h = e("stream-to-blob-url"),
l = e("stream-with-known-length-to-buffer");a(r, i), Object.defineProperty(r.prototype, "downloaded", { get: function get() {
if (!this._torrent.bitfield) return 0;for (var e = 0, t = this._startPiece; t <= this._endPiece; ++t) {
if (this._torrent.bitfield.get(t)) e += this._torrent.pieceLength;else {
var n = this._torrent.pieces[t];e += n.length - n.missing;
}
}return e;
} }), r.prototype.select = function (e) {
0 !== this.length && this._torrent.select(this._startPiece, this._endPiece, e);
}, r.prototype.deselect = function () {
0 !== this.length && this._torrent.deselect(this._startPiece, this._endPiece, !1);
}, r.prototype.createReadStream = function (e) {
var t = this;if (0 === this.length) {
var r = new f.PassThrough();return n.nextTick(function () {
r.end();
}), r;
}var i = new s(t, e);return t._torrent.select(i._startPiece, i._endPiece, !0, function () {
i._notify();
}), o(i, function () {
t._destroyed || t._torrent.destroyed || t._torrent.deselect(i._startPiece, i._endPiece, !0);
}), i;
}, r.prototype.getBuffer = function (e) {
l(this.createReadStream(), this.length, e);
}, r.prototype.getBlob = function (e) {
if ("undefined" == typeof window) throw new Error("browser-only method");d(this.createReadStream(), this._getMimeType(), e);
}, r.prototype.getBlobURL = function (e) {
if ("undefined" == typeof window) throw new Error("browser-only method");h(this.createReadStream(), this._getMimeType(), e);
}, r.prototype.appendTo = function (e, t, n) {
if ("undefined" == typeof window) throw new Error("browser-only method");c.append(this, e, t, n);
}, r.prototype.renderTo = function (e, t, n) {
if ("undefined" == typeof window) throw new Error("browser-only method");c.render(this, e, t, n);
}, r.prototype._getMimeType = function () {
return c.mime[u.extname(this.name).toLowerCase()];
}, r.prototype._destroy = function () {
this._destroyed = !0, this._torrent = null;
};
}).call(this, e("_process"));
}, { "./file-stream": 1, _process: 66, "end-of-stream": 33, events: 34, inherits: 41, path: 63, "readable-stream": 82, "render-media": 83, "stream-to-blob": 100, "stream-to-blob-url": 99, "stream-with-known-length-to-buffer": 101 }], 3: [function (e, t, n) {
function r(e, t) {
var n = this;n.id = e, n.type = t, s("new Peer %s", e), n.addr = null, n.conn = null, n.swarm = null, n.wire = null, n.connected = !1, n.destroyed = !1, n.timeout = null, n.retries = 0, n.sentHandshake = !1;
}function o() {}var i = e("unordered-array-remove"),
s = e("debug")("webtorrent:peer"),
a = e("bittorrent-protocol"),
u = e("./webconn");n.createWebRTCPeer = function (e, t) {
var n = new r(e.id, "webrtc");return n.conn = e, n.swarm = t, n.conn.connected ? n.onConnect() : (n.conn.once("connect", function () {
n.onConnect();
}), n.conn.once("error", function (e) {
n.destroy(e);
}), n.startConnectTimeout()), n;
}, n.createTCPIncomingPeer = function (e) {
var t = e.remoteAddress + ":" + e.remotePort,
n = new r(t, "tcpIncoming");return n.conn = e, n.addr = t, n.onConnect(), n;
}, n.createTCPOutgoingPeer = function (e, t) {
var n = new r(e, "tcpOutgoing");return n.addr = e, n.swarm = t, n;
}, n.createWebSeedPeer = function (e, t) {
var n = new r(e, "webSeed");return n.swarm = t, n.conn = new u(e, t), n.onConnect(), n;
}, r.prototype.onConnect = function () {
var e = this;if (!e.destroyed) {
e.connected = !0, s("Peer %s connected", e.id), clearTimeout(e.connectTimeout);var t = e.conn;t.once("end", function () {
e.destroy();
}), t.once("close", function () {
e.destroy();
}), t.once("finish", function () {
e.destroy();
}), t.once("error", function (t) {
e.destroy(t);
});var n = e.wire = new a();n.type = e.type, n.once("end", function () {
e.destroy();
}), n.once("close", function () {
e.destroy();
}), n.once("finish", function () {
e.destroy();
}), n.once("error", function (t) {
e.destroy(t);
}), n.once("handshake", function (t, n) {
e.onHandshake(t, n);
}), e.startHandshakeTimeout(), t.pipe(n).pipe(t), e.swarm && !e.sentHandshake && e.handshake();
}
}, r.prototype.onHandshake = function (e, t) {
var n = this;if (n.swarm && !n.destroyed) {
if (n.swarm.destroyed) return n.destroy(new Error("swarm already destroyed"));if (e !== n.swarm.infoHash) return n.destroy(new Error("unexpected handshake info hash for this swarm"));if (t === n.swarm.peerId) return n.destroy(new Error("refusing to connect to ourselves"));s("Peer %s got handshake %s", n.id, e), clearTimeout(n.handshakeTimeout), n.retries = 0;var r = n.addr;!r && n.conn.remoteAddress && (r = n.conn.remoteAddress + ":" + n.conn.remotePort), n.swarm._onWire(n.wire, r), n.swarm && !n.swarm.destroyed && (n.sentHandshake || n.handshake());
}
}, r.prototype.handshake = function () {
var e = this,
t = { dht: !e.swarm.private && !!e.swarm.client.dht };e.wire.handshake(e.swarm.infoHash, e.swarm.client.peerId, t), e.sentHandshake = !0;
}, r.prototype.startConnectTimeout = function () {
var e = this;clearTimeout(e.connectTimeout), e.connectTimeout = setTimeout(function () {
e.destroy(new Error("connect timeout"));
}, "webrtc" === e.type ? 25e3 : 5e3), e.connectTimeout.unref && e.connectTimeout.unref();
}, r.prototype.startHandshakeTimeout = function () {
var e = this;clearTimeout(e.handshakeTimeout), e.handshakeTimeout = setTimeout(function () {
e.destroy(new Error("handshake timeout"));
}, 25e3), e.handshakeTimeout.unref && e.handshakeTimeout.unref();
}, r.prototype.destroy = function (e) {
var t = this;if (!t.destroyed) {
t.destroyed = !0, t.connected = !1, s("destroy %s (error: %s)", t.id, e && (e.message || e)), clearTimeout(t.connectTimeout), clearTimeout(t.handshakeTimeout);var n = t.swarm,
r = t.conn,
a = t.wire;t.swarm = null, t.conn = null, t.wire = null, n && a && i(n.wires, n.wires.indexOf(a)), r && (r.on("error", o), r.destroy()), a && a.destroy(), n && n.removePeer(t.id);
}
};
}, { "./webconn": 6, "bittorrent-protocol": 14, debug: 30, "unordered-array-remove": 111 }], 4: [function (e, t, n) {
function r(e) {
var t = this;t._torrent = e, t._numPieces = e.pieces.length, t._pieces = [], t._onWire = function (e) {
t.recalculate(), t._initWire(e);
}, t._onWireHave = function (e) {
t._pieces[e] += 1;
}, t._onWireBitfield = function () {
t.recalculate();
}, t._torrent.wires.forEach(function (e) {
t._initWire(e);
}), t._torrent.on("wire", t._onWire), t.recalculate();
}function o() {
return !0;
}t.exports = r, r.prototype.getRarestPiece = function (e) {
e || (e = o);for (var t = [], n = 1 / 0, r = 0; r < this._numPieces; ++r) {
if (e(r)) {
var i = this._pieces[r];i === n ? t.push(r) : i < n && (t = [r], n = i);
}
}return t.length > 0 ? t[Math.random() * t.length | 0] : -1;
}, r.prototype.destroy = function () {
var e = this;e._torrent.removeListener("wire", e._onWire), e._torrent.wires.forEach(function (t) {
e._cleanupWireEvents(t);
}), e._torrent = null, e._pieces = null, e._onWire = null, e._onWireHave = null, e._onWireBitfield = null;
}, r.prototype._initWire = function (e) {
var t = this;e._onClose = function () {
t._cleanupWireEvents(e);for (var n = 0; n < this._numPieces; ++n) {
t._pieces[n] -= e.peerPieces.get(n);
}
}, e.on("have", t._onWireHave), e.on("bitfield", t._onWireBitfield), e.once("close", e._onClose);
}, r.prototype.recalculate = function () {
var e;for (e = 0; e < this._numPieces; ++e) {
this._pieces[e] = 0;
}var t = this._torrent.wires.length;for (e = 0; e < t; ++e) {
for (var n = this._torrent.wires[e], r = 0; r < this._numPieces; ++r) {
this._pieces[r] += n.peerPieces.get(r);
}
}
}, r.prototype._cleanupWireEvents = function (e) {
e.removeListener("have", this._onWireHave), e.removeListener("bitfield", this._onWireBitfield), e._onClose && e.removeListener("close", e._onClose), e._onClose = null;
};
}, {}], 5: [function (e, t, n) {
(function (n, r) {
function o(e, t, n) {
m.call(this), this._debugId = "unknown infohash", this.client = t, this.announce = n.announce, this.urlList = n.urlList, this.path = n.path, this._store = n.store || v, this._getAnnounceOpts = n.getAnnounceOpts, this.strategy = n.strategy || "sequential", this.maxWebConns = n.maxWebConns || 4, this._rechokeNumSlots = !1 === n.uploads || 0 === n.uploads ? 0 : +n.uploads || 10, this._rechokeOptimisticWire = null, this._rechokeOptimisticTime = 0, this._rechokeIntervalId = null, this.ready = !1, this.destroyed = !1, this.paused = !1, this.done = !1, this.metadata = null, this.store = null, this.files = [], this.pieces = [], this._amInterested = !1, this._selections = [], this._critical = [], this.wires = [], this._queue = [], this._peers = {}, this._peersLength = 0, this.received = 0, this.uploaded = 0, this._downloadSpeed = O(), this._uploadSpeed = O(), this._servers = [], this._xsRequests = [], this._fileModtimes = n.fileModtimes, null !== e && this._onTorrentId(e), this._debug("new torrent");
}function i(e, t) {
return 2 + Math.ceil(t * e.downloadSpeed() / T.BLOCK_LENGTH);
}function s(e, t, n) {
return 1 + Math.ceil(t * e.downloadSpeed() / n);
}function a(e) {
return Math.random() * e | 0;
}function u() {}t.exports = o;var c,
f = e("addr-to-ip-port"),
d = e("bitfield"),
h = e("chunk-store-stream/write"),
l = e("debug")("webtorrent:torrent"),
p = e("torrent-discovery"),
m = e("events").EventEmitter,
g = e("xtend"),
y = e("xtend/mutable"),
_ = e("fs"),
v = e("fs-chunk-store"),
b = e("simple-get"),
w = e("immediate-chunk-store"),
E = e("inherits"),
k = e("multistream"),
x = e("net"),
S = e("os"),
I = e("run-parallel"),
B = e("run-parallel-limit"),
A = e("parse-torrent"),
C = e("path"),
T = e("torrent-piece"),
L = e("pump"),
U = e("random-iterate"),
R = e("simple-sha1"),
O = e("speedometer"),
M = e("uniq"),
P = e("ut_metadata"),
j = e("ut_pex"),
H = e("./file"),
N = e("./peer"),
q = e("./rarity-map"),
D = e("./server"),
W = 5e3,
z = 3 * T.BLOCK_LENGTH,
F = [1e3, 5e3, 15e3],
V = e("../package.json").version,
G = "WebTorrent/" + V + " (https://webtorrent.io)";try {
c = C.join(_.statSync("/tmp") && "/tmp", "webtorrent");
} catch (e) {
c = C.join("function" == typeof S.tmpdir ? S.tmpdir() : "/", "webtorrent");
}E(o, m), Object.defineProperty(o.prototype, "timeRemaining", { get: function get() {
return this.done ? 0 : 0 === this.downloadSpeed ? 1 / 0 : (this.length - this.downloaded) / this.