// ==UserScript==
// @name Download Video as MP4 [video.sibnet.ru+myvi.ru]
// @name:en Download Video as MP4 [video.sibnet.ru+myvi.ru]
// @namespace http://video.sibnet.ru
// @version 3.0.0
// @description Скачать видео с myvi.ru, video.sibnet.ru одним кликом, правильные названия видео при скачивании
// @description:en Download video from myvi.ru and video.sibnet.ru by a simple click, true filenames of downloaded videos
// @author EisenStein
// @include https://video.sibnet.ru/*
// @include https://cv*.sibnet.ru/*
// @include https://dv*.sibnet.ru/*
// @include https://myvi.ru/*
// @include https://www.myvi.ru/*
// @include https://fs*.myvi.ru*
// @include https://myvi.tv/*
// @include https://www.myvi.tv/*
// @include https://fs*.myvi.tv*
// @include https://fs.mikadox.com*
// @connect sibnet.ru
// @connect myvi.tv
// @connect myvi.ru
// @connect mikadox.com
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant GM_addStyle
// @grant GM_info
// @grant GM_download
// @grant GM_xmlhttpRequest
// @grant GM.getValue
// @grant GM.setValue
// @grant GM.deleteValue
// @grant GM.addStyle
// @grant GM.info
// @grant GM.download
// @grant GM.xmlHttpRequest
// @grant unsafeWindow
// @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
// @run-at document-start
// ==/UserScript==
(function(window, WINDOW) {
(function(e, a) { for(var i in a) e[i] = a[i]; }(exports, (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;
// define getter function for harmony exports
__webpack_require__.d = function(exports, name, getter) {
if(!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, { enumerable: true, get: getter });
}
};
// define __esModule on exports
__webpack_require__.r = function(exports) {
if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
}
Object.defineProperty(exports, '__esModule', { value: true });
};
// create a fake namespace object
// mode & 1: value is a module id, require it
// mode & 2: merge all properties of value into the ns
// mode & 4: return value when already ns object
// mode & 8|1: behave like require
__webpack_require__.t = function(value, mode) {
if(mode & 1) value = __webpack_require__(value);
if(mode & 8) return value;
if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
var ns = Object.create(null);
__webpack_require__.r(ns);
Object.defineProperty(ns, 'default', { enumerable: true, value: value });
if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
return ns;
};
// 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 = "";
// Load entry module and return exports
return __webpack_require__(__webpack_require__.s = 14);
})
([
/* 0 */
(function(module, exports, __webpack_require__) {
var eventEmitter = __webpack_require__(8)
var LOGGER = {
log: window.console.log.bind(window.console),
info: window.console.info.bind(window.console),
warn: window.console.warn.bind(window.console),
error: window.console.error.bind(window.console),
debug: window.console.debug.bind(window.console),
}
var noop = function () {}
function Logger(logger) {
this.logger = Object.assign({}, LOGGER, logger, { debug: noop })
var _this = this
eventEmitter.on('logger', function (options) {
try {
_this.update(options)
} catch (e) {
console.error(e)
}
})
}
/**
* @param {{ [x: string]: boolean | (...args: any[]) => void}} logger
*/
Logger.prototype.update = function (logger) {
var keys = Object.keys(logger)
for (var key of keys) {
if (logger[key] === true) {
this.logger[key] = LOGGER[key] || noop
} else if (typeof logger[key] === 'function') {
this.logger[key] = logger[key]
}
}
}
Logger.prototype.log = function () {
return this.logger.log.apply(this.logger, arguments)
}
Logger.prototype.debug = function () {
return this.logger.debug.apply(this.logger, arguments)
}
Logger.prototype.info = function () {
return this.logger.info.apply(this.logger, arguments)
}
Logger.prototype.warn = function () {
return this.logger.warn .apply(this.logger, arguments)
}
Logger.prototype.error = function () {
return this.logger.error.apply(this.logger, arguments)
}
module.exports = Logger
}),
/* 1 */
(function(module, exports) {
const time = function() {
return '[' + new Date().toISOString() + ']'
}
module.exports = time
}),
/* 2 */
(function(module, exports, __webpack_require__) {
var Logger = __webpack_require__(0)
var time = __webpack_require__(1)
var parseAJAXHeaders = __webpack_require__(17)
var parseAJAXResponse = __webpack_require__(18)
/**
* @typedef {{
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'HEAD' | 'PATCH';
url: string;
headers?: { [x: string]: (string | number) };
responseType?: string;
data?: any;
onprogress?: (loaded: number, total: number) => void;
}} IRequestDetails
* @typedef {{
ok: boolean;
status: number;
headers: { [x: string]: string };
problem?: string;
data?: T;
}} IResponse<T = any>
*/
/**
* @param {IRequestDetails} details
* @return {XMLHttpRequest | ActiveXObject} details
*/
function __XMLHttpRequest(details) {
var xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest()
} else if (window.ActiveXObject) {
xhr = new ActiveXObject('Msxml2.XMLHTTP.6.0')
} else {
return null
}
xhr.open(details.method, details.url, true)
Object.keys(details.headers).forEach(function (key) {
xhr.setRequestHeader(key, details.headers[key])
})
if (details.responseType) {
xhr.responseType = details.responseType
}
if (details.timeout) {
xhr.timeout = details.timeout
}
return xhr
}
/**
* @param {string | IRequestDetails} details
* @param {boolean} [useGM]
* @return {Promise<IResponse>}
*/
function makeRequest(options, useGM = false) {
var logger = new Logger()
logger.debug(time(), 'makeRequest options', options, { useGM: useGM })
var details = {
method: 'GET',
headers: {},
}
if (typeof details === 'string') {
details = Object.assign(details, { url: options })
} else {
details = Object.assign(details, options)
}
// Response
var response = {
ok: false,
problem: undefined,
headers: {},
status: 0,
data: undefined,
finalUrl: details.url,
}
var resolve
var promise = new Promise(function (r) {
resolve = r
})
var onLoad = function (e) {
var isGM = !e.target
var req = isGM ? e : e.target
response.status = req.status
response.headers = parseAJAXHeaders(isGM ? req.responseHeaders : req.getAllResponseHeaders())
response.ok = req.status >= 200 && req.status < 300
response.problem = response.ok ? undefined : response.problem
var isText = !req.responseType || req.responseType.toLowerCase() === 'text'
response.data = parseAJAXResponse(isText && !isGM ? req.responseText : req.response, response.headers, req.responseType)
response.finalUrl = req.finalUrl || req.responseURL || response.finalUrl
logger.debug(time(), 'makeRequest response: ', response, details)
return response
}
var onTimeout = function (e) {
var isGM = !e.target
var req = isGM ? e : e.target
logger.error(time(), 'makeRequest timeout', req.status, req.readyState)
response.status = req.status
response.ok = false
response.problem = 'TIMEOUT'
return response
}
var onError = function (e) {
var isGM = !e.target
var req = isGM ? e : e.target
logger.error(time(), 'makeRequest error', req.status, req.readyState)
response.status = req.status
response.problem = req.status.toString()
response.ok = false
return response
}
var onProgress = function (e) {
if (typeof details.onprogress === 'function') {
details.onprogress(e.loaded, e.total)
}
}
if (!useGM || typeof GM === 'undefined' || typeof GM.xmlHttpRequest === 'undefined') {
var xhr = new __XMLHttpRequest(details)
xhr.addEventListener('load', function (e) {
onLoad(e)
})
xhr.addEventListener('timeout', function (e) {
onTimeout(e)
})
xhr.addEventListener('error', function (e) {
onError(e)
})
xhr.addEventListener('loadend', function (e) {
resolve(response)
})
xhr.addEventListener('progress', function (e) {
onProgress(e)
})
xhr.send(details.data)
} else {
GM.xmlHttpRequest(Object.assign({}, details, {
onload: function (req) {
var r = onLoad(req)
resolve(r)
},
onerror: function (req) {
var r = onError(req)
resolve(r)
},
ontimeout: function (req) {
var r = onTimeout(req)
resolve(r)
},
onprogress: function (req) {
onProgress(req)
},
}))
}
return promise
}
module.exports = makeRequest
}),
/* 3 */
(function(module, exports) {
/**
* @param {number} timeout
* @return {Promise<void>}
*/
function delay(timeout) {
return new Promise(function (resolve) {
setTimeout(resolve, timeout)
})
}
module.exports = delay
}),
/* 4 */
(function(module, exports) {
const noop = function(){}
/**
* @param {() => void} [callback]
* @return {Promise<void>}
*/
function DOMReady(callback) {
callback = typeof callback === 'function' ? callback : noop
if (document.readyState === 'loading') {
var resolve
var promise = new Promise(function(r){
resolve = r
})
document.addEventListener('DOMContentLoaded', function(){
callback()
resolve()
})
return promise
}
callback()
return Promise.resolve()
}
module.exports = DOMReady
}),
/* 5 */
(function(module, exports) {
var link
/**
* @param {string} url
* @return {HTMLElement}
*/
function URLParse(url) {
link = link || document.createElement('a')
link.href = url
return link.cloneNode()
}
module.exports = URLParse
}),
/* 6 */
(function(module, exports, __webpack_require__) {
var eventEmitter = __webpack_require__(8)
var Logger = __webpack_require__(0)
var time = __webpack_require__(1)
/**
* @param {{
videoId: string;
url: string;
filename: string;
name: string;
ext: string;
event: string;
}} IEventData
*/
var iframeChannel = {
logger: new Logger(),
init: function () {
window.addEventListener('message', iframeChannel.onMessage)
},
/** @param {IEventData} data */
getEventName: function (data) {
return data && data.videoId && data.event ? (data.videoId + '-' + data.event) : ''
},
/** @param {IEventData} data */
request: function (data) {
var event = iframeChannel.getEventName(data)
var logger = iframeChannel.logger;
logger.debug(time(), 'iframeChannel event = ', event, data)
if (!event) {
logger.error(time(), 'iframeChannel request: invalid data', data)
return Promise.reject(new Error('invalid data'))
}
var resolve
var promise = new Promise(function (res) {
resolve = res
})
eventEmitter.once(event, function (response) {
logger.debug(time(), 'iframeChannel response ', event, response)
resolve(response)
})
iframeChannel.send(data)
return promise
},
/** @param {IEventData} data */
send: function (data) {
var videoId = data.videoId
var id = 'video_iframe_' + videoId
var iframe = document.querySelector('#' + id)
var link = document.createElement('a')
link.href = data.url
if (!iframe) {
iframe = document.createElement('iframe')
iframe.id = id
iframe.src = link.href + '#DM:' + encodeURIComponent(JSON.stringify(data))
iframe.style.width = '1px'
iframe.style.height = '1px'
iframe.style.visibility = 'hidden'
document.body.appendChild(iframe)
} else {
iframe.contentWindow.postMessage(data, '*')
}
return iframe
},
onMessage: function (e) {
var event = iframeChannel.getEventName(e.data)
if (event) {
eventEmitter.emit(event, e.data)
}
},
}
module.exports = iframeChannel
}),
/* 7 */
(function(module, exports) {
var has_gm_info = function () {
return typeof GM !== 'undefined' && typeof GM.info !== 'undefined'
}
function getScriptName() {
if (has_gm_info()) {
return GM.info.script.name
}
return 'Video Download Manager'
}
function getScriptVersion() {
if (has_gm_info()) {
return GM.info.script.version
}
return '1.0.0';
}
function getScriptAuthor() {
if (has_gm_info()) {
return GM.info.script.author
}
return 'eisen-stein'
}
function getScriptHandler() {
if (has_gm_info()) {
return GM.info.scriptHandler
}
return 'none'
}
module.exports = {
script_name: getScriptName() || 'Video Download Manager',
script_version: getScriptVersion() ? ('v' + getScriptVersion()) : 'v3.0.0',
script_author: getScriptAuthor() || 'eisen-stein',
script_handler: getScriptHandler() || 'none',
}
}),
/* 8 */
(function(module, exports, __webpack_require__) {
var EventEmitter = __webpack_require__(15)
module.exports = new EventEmitter()
}),
/* 9 */
(function(module, exports, __webpack_require__) {
var URLParse = __webpack_require__(5)
var time = __webpack_require__(1)
var Logger = __webpack_require__(0)
var downloadFile = __webpack_require__(16)
var makeRequest = __webpack_require__(2)
var DOMReady = __webpack_require__(4)
var delay = __webpack_require__(3)
var iframeController = {
logger: new Logger(),
start: function () {
var logger = this.logger
var _this = this
var onData = function (data) {
if (data && data.videoId && data.event === 'url') {
logger.debug(time(), 'iframe getUrl', location.href)
return _this.getUrl(data)
}
if (data && data.videoId && data.event === 'size') {
logger.debug(time(), 'iframe getSize', location.href)
return _this.getSize(data)
}
if (data && data.videoId && data.event === 'download') {
logger.debug(time(), 'iframe download', location.href)
return _this.download(data)
}
return Promise.resolve()
}
window.addEventListener('message', function (e) {
logger.debug(time(), 'iframe onmessage: ', e.origin, e.data)
onData(e.data)
})
return Promise.all([
_this.removeVideo().catch(function() {}),
onData(_this.getData()),
]).then(function () {
logger.debug(time(), 'iframe started')
}).catch(function (e) {
logger.error(time(), 'iframe error: ', e)
})
},
download: function (dt) {
var data = dt || this.getData()
var link = URLParse(location.href)
var _this = this
link.hash = ''
return downloadFile(link.href, data.filename, function onProgress(loaded, total) {
_this.onProgress(loaded, total, data)
}).then(function () {
_this.sendMessage(Object.assign({}, data, { event: 'download' }))
})
},
getUrl: function (dt) {
var data = dt || this.getData()
var response = {
ok: true,
finalUrl: location.href,
status: 200,
readyState: 4,
headers: {},
event: 'url',
videoId: data.videoId,
}
this.sendMessage(response)
},
getSize: function (dt) {
var data = dt || this.getData()
var _this = this
return makeRequest({
method: 'HEAD',
url: location.href,
headers: {
range: 'bytes=0-10',
},
}).then(function (response) {
_this.sendMessage(
Object.assign(
{},
response,
{
event: 'size',
videoId: data.videoId,
},
)
)
})
},
/** @param {number} [timeout] */
removeVideo: function (timeout) {
if (!location.hash || !location.hash.match(/^#DM\:/)) {
return Promise.resolve()
}
return DOMReady().then(function () {
var video = document.querySelector('video')
video.removeAttribute('autoplay')
video.setAttribute('preload', 'none')
video.pause(0)
video.src = ''
video.parentNode.removeChild(video)
return video
})
},
sendMessage: function (message) {
this.logger.debug(time(), 'iframe sending.. ', message)
if (window.parent) {
this.logger.debug(time(), 'iframe send window', window.parent)
window.parent.postMessage(message, '*')
}
},
onProgress: function (loaded, total, dt) {
var data = dt || this.getData()
this.sendMessage(Object.assign(data, {
event: 'progress',
loaded: loaded,
total: total,
}))
},
/**
* @return {{
url: string;
name: string;
filename: string;
videoId: string;
ext: string;
event: string;
}}
*/
getData: function () {
if (this._data) {
return Object.assign({}, this._data)
}
if (location.hash && location.hash.match(/^#DM\:/)) {
this._data = JSON.parse(decodeURIComponent(location.hash.slice(4)))
location.hash = '';
this._data.url = location.href
return Object.assign({}, this._data)
}
},
}
module.exports = iframeController
}),
/* 10 */
(function(module, exports, __webpack_require__) {
var Logger = __webpack_require__(0)
var time = __webpack_require__(1)
var smartSize = __webpack_require__(21)
__webpack_require__(22)
/**
* @typedef {{
id?: string | number;
visible?: boolean;
title: string;
onDownload?: (onProgress?: (loaded: number, total: number) => void) => void;
getSize?: () => void;
getUrl?: () => void;
videoId?: number;
filename?: string;
filesize?: number | string;
fileurl?: string;
progress?: number;
disabled?: boolean;
icon?: { width?: number; height?: number; color?: string };
}} IMainViewProps
*/
var baseView = {
logger: new Logger(),
/** @param {IMainViewProps} props */
create: function (props) {
/** @type {IMainViewProps} */
this.props = props
this._createDOM()
this.onDownload = this.onDownload.bind(this)
this.onClose = this.onClose.bind(this)
this.getSize = this.getSize.bind(this)
this.getUrl = this.getUrl.bind(this)
this.getId = this.getId.bind(this)
this.init = this.init.bind(this)
document.body.insertBefore(this._root, document.body.firstElementChild)
this.render()
this.init()
},
init: function () {
var _this = this
this.getId()
return this.getUrl().then(function () {
return _this.getSize()
})
},
_createDOM: function () {
var div = document.createElement('div')
this.id = this.props.id || ('vdm-' + Math.floor(Math.random() * 1e5))
div.innerHTML = [
'<div id="' + this.id + '" class="vdm-root">',
'<div class="vdm-container">',
'<div class="vdm-header">',
'<span class="vdm-title">',
(this.props.title || ''),
'</span>',
'<div class="vdm-close-btn">',
'<div></div>',
'</div>',
'</div>',
'<div class="vdm-content">',
'<div class="vdm-item vdm-filename">',
'<span>Название: <span>{filename}</span></span>',
'</div>',
'<div class="vdm-item vdm-filesize">',
'<span>Размер: <span>{filesize}</span></span>',
'</div>',
'<div class="vdm-item vdm-fileurl">',
'<span>',
'<input type="checkbox" style="display:none" id="video_href" ></input>',
'<span>',
'<label class="show_link" for="video_href">Показать ссылку</label>',
'<label class="video_link" for="video_href">Ссылка: </label>',
'<a target="_blank">{fileurl}</a>',
'</span>',
'</span>',
'</div>',
'<div class="vdm-controllers">',
'<div class="vdm-progress">',
'</div>',
'<div class="vdm-button vdm-download">',
'<span>Скачать</span>',
'</div>',
'</div>',
'</div>',
'</div>',
'</div>'].join('');
this._root = div.firstElementChild
return this._root
},
onDownload: function (e) {
var logger = this.logger
if (this.props.onDownload && !this.props.disabled && !this.props.isFetching) {
this.update({ isFetching: true })
var _this = this
logger.debug(time(), 'downloading..')
return this.props.onDownload(function onProgress(loaded, total) {
_this.update({ progress: loaded / total })
}).then(function () {
_this.update({ isFetching: false, progress: 0 })
logger.debug(time(), 'download complete')
return true
})
}
return Promise.resolve()
},
getSize: function () {
var logger = this.logger
if (this.props.getSize && !this.props.isFetching) {
this.update({ isFetching: true })
var _this = this
return this.props.getSize().then(function (size) {
logger.debug(time(), 'size: ', size)
var filesize = smartSize(size)
logger.info(time(), 'filesize: ', filesize)
_this.update({ filesize: filesize, isFetching: false })
return size
})
}
return Promise.resolve()
},
getUrl: function () {
var logger = this.logger;
if (this.props.getUrl && !this.props.isFetching) {
var _this = this
this.update({ isFetching: true })
return this.props.getUrl().then(function (fileurl) {
logger.info(time(), 'fileurl: ', fileurl)
_this.update({ fileurl: fileurl, isFetching: false })
return fileurl
})
}
return Promise.resolve()
},
getId: function () {
var videoId = this.props.getId()
this.update({ videoId: videoId, visible: Boolean(videoId) && this.props.visible })
},
onClose: function (e) {
if (this.props.onClose) {
this.props.onClose()
}
this.update({ visible: false })
},
loadingImage: function () {
var icon = this.props.icon
return `<svg
xmlns="http://www.w3.org/2000/svg"
version="1.1"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:svgjs="http://svgjs.com/svgjs"
width="${icon && icon.width || '512'}"
height="${icon && icon.height || '512'}"
x="0"
y="0"
viewBox="0 0 16 16"
style="enable-background:new 0 0 512 512"
xml:space="preserve"
class="loading"
>
<g>
<path
xmlns="http://www.w3.org/2000/svg"
fill="${icon && icon.color || '#ffffff'}"
d="M9.9 0.2l-0.2 1c3 0.8 5.3 3.5 5.3 6.8 0 3.9-3.1 7-7 7s-7-3.1-7-7c0-3.3 2.3-6 5.3-6.8l-0.2-1c-3.5 0.9-6.1 4.1-6.1 7.8 0 4.4 3.6 8 8 8s8-3.6 8-8c0-3.7-2.6-6.9-6.1-7.8z"
style=""
class=""
>
</path>
</g>
</svg>`;
},
render: function () {
var visible = this.props.visible
var root = this._root = this._root || this._createDOM()
root.style.visibility = visible ? 'initial' : 'hidden'
root.querySelector('.vdm-title').innerHTML = this.props.title
if (this.props.filename) {
root.querySelector('.vdm-filename span span').innerHTML = this.props.filename
}
if (this.props.filesize) {
root.querySelector('.vdm-filesize span span').innerHTML = this.props.filesize
}
var link = root.querySelector('.vdm-fileurl span a')
link.href = this.props.fileurl || '#'
if (this.props.fileurl) {
link.innerHTML = this.props.fileurl
}
root.querySelector('.vdm-close-btn').addEventListener('click', this.onClose)
root.querySelector('.vdm-download').addEventListener('click', this.onDownload)
if (!this.props.isFetching) {
root.querySelector('.vdm-download').innerHTML = '<span>Скачать</span>'
} else if (!root.querySelector('.vdm-download .loading')) {
root.querySelector('.vdm-download').innerHTML = this.loadingImage()
}
if (!this.props.progress) {
root.querySelector('.vdm-progress').style.display = 'none'
} else {
var progress = root.querySelector('.vdm-progress')
progress.style.display = ''
progress.style.width = Math.floor(this.props.progress * 100) + '%';
}
return root
},
/** @param {IMainViewProps} props */
update: function (props) {
this.props = Object.assign(this.props, props)
this.render()
},
}
module.exports = baseView
}),
/* 11 */
(function(module, exports) {
/**
* @param {string} url
* @return {string}
*/
function getExtension(url) {
var link = document.createElement('a')
link.href = url
var match = link.pathname.match(/\.([^.]+)$/)
return match ? match[1] : '';
}
module.exports = getExtension
}),
/* 12 */
(function(module, exports) {
module.exports = {}
}),
/* 13 */
(function(module, exports, __webpack_require__) {
var URLParse = __webpack_require__(5)
var makeRequest = __webpack_require__(2)
var delay = __webpack_require__(3)
var time = __webpack_require__(1)
var Logger = __webpack_require__(0)
var iframeChannel = __webpack_require__(6)
var eventEmitter = __webpack_require__(8)
var info = __webpack_require__(7)
/**
* @typedef {{
url: string;
videoId: string;
name?: string;
filename?: string;
size?: number;
ext?: string;
saveAs?: boolean;
headers?: { [x: string]: string };
onProgress?: (loaded: number, total: number) => void;
* }} IDownloadDetails
* @typedef {{
url: string;
name: string;
filename: string;
videoId: string;
ext: string;
event: string;
* }} IVideoData
*/
var downloadManager = {
__DEBUG__: false,
logger: new Logger(),
/**
* @param {IDownloadDetails} details
* @return {Promise<IVideoData>}
*/
download: function (details) {
var _this = this
var logger = this.logger
if (details.debug) {
return this.DEBUG_download(details)
}
var promise = Promise.reject()
if (
(
(typeof GM !== 'undefined' && typeof GM.download !== 'undefined')
|| typeof GM_download !== 'undefined'
)
&& info.script_handler.toLowerCase() !== 'violentmonkey'
) {
promise = this.GM_download(details)
}
return promise.catch(function (e) {
if (e) {
logger.error(time(), 'GM_download error: ', e)
}
var link = URLParse(details.url)
if (location.origin === link.origin) {
return _this.URL_download(details)
}
var p = Promise.reject()
if (
(
(typeof GM !== 'undefined' && typeof GM.xmlHttpRequest !== 'undefined')
|| typeof GM_xmlhttpRequest !== 'undefined'
) && (typeof details.size === 'undefined' || details.size < (16 * 1024 * 1024))
) {
p = _this.XHR_download(details)
}
return p.catch(function (e) {
if (e) {
logger.error(time(), 'XHR_download error: ', e)
}
return _this.IFrame_download(details)
})
}).then(function (response) {
logger.info(time(), 'downloaded', details.url)
return response
}).catch(function (e) {
logger.error(time(), 'failed to download', details.url, e)
})
},
/**
* @param {IDownloadDetails} details
* @return {IVideoData}
*/
getData: function (details) {
var link = URLParse(details.url)
return {
url: link.href,
name: details.name,
filename: details.filename,
videoId: details.videoId,
ext: details.ext,
event: 'download',
}
},
/**
* @param {IDownloadDetails} details
* @return {Promise<IVideoData>}
*/
GM_download: function (details) {
var logger = this.logger
logger.info(time(), 'GM_download', details.url)
var data = this.getData(details)
var resolve
var reject
var promise = new Promise(function (res, rej) {
resolve = res
reject = rej
})
GM_download({
url: details.url,
name: details.filename,
saveAs: Boolean(details.saveAs),
onerror: function (r) {
reject(r)
},
onload: function () {
resolve(data)
},
onprogress: function (e) {
if (details.onProgress) {
details.onProgress(e.loaded, e.total)
}
},
ontimeout: function () {
reject({ error: 'timeout' })
},
})
return promise
},
/**
* @param {IDownloadDetails} details
* @return {Promise<IVideoData>}
*/
XHR_download: function (details) {
var logger = this.logger
logger.info(time(), 'XHR_download', details.url)
var data = this.getData(details)
var _this = this
return makeRequest({
method: 'GET',
url: data.url,
headers: details.headers,
responseType: 'blob',
onprogress: details.onProgress,
}, true).then(function (response) {
if (!response.ok) {
return Promise.reject(response)
}
var URL = window.URL || window.webkitURL
var resource = URL.createObjectURL(response.data);
return _this.URL_download(
Object.assign({}, details, { url: resource })
).then(function () {
URL.revokeObjectURL(resource)
})
}).then(function () {
return data;
})
},
/**
* @param {IDownloadDetails} details
* @return {Promise<IVideoData>}
*/
IFrame_download: function (details) {
var logger = this.logger
logger.info(time(), 'IFrame_download', details.url)
var data = this.getData(details)
var onProgress = details.onProgress
var progressEvent = iframeChannel.getEventName(
Object.assign({}, data, { event: 'progress' })
);
eventEmitter.on(progressEvent, function (e) {
onProgress && onProgress(e.loaded, e.total)
})
var promise = iframeChannel.request(
Object.assign(
{},
data,
{
event: 'download',
},
)
).then(function (response) {
eventEmitter.off(progressEvent)
return response;
});
return promise
},
/**
* @param {IDownloadDetails} details
* @return {Promise<IVideoData>}
*/
URL_download: function (details) {
var logger = this.logger
logger.info(time(), 'URL_download', details.url)
var data = this.getData(details)
var link = URLParse(data.url)
link.download = data.filename || ('video' + details.videoId + '.mp4')
link.innerHTML = data.filename
document.body.appendChild(link)
link.click()
return delay(300).then(function () {
document.body.removeChild(link)
return data
})
},
DEBUG_download: function (details) {
var logger = this.logger
logger.info(time(), 'DEBUG_download', details.url)
var data = this.getData(details)
return new Promise(function (resolve) {
var _onProgress = details.onProgress || function (){}
var total = 200 * 1024 * 1024
var size = Math.floor(5000 / 300)
var step = 1 / size
var _progress = 0
var interval = setInterval(function () {
_progress += step
_onProgress(_progress * total, total)
}, 300)
setTimeout(function () {
_onProgress(total, total)
clearInterval(interval)
resolve(data)
}, 5000)
})
},
}
module.exports = downloadManager
}),
/* 14 */
(function(module, exports, __webpack_require__) {
var DOMReady = __webpack_require__(4)
var Logger = __webpack_require__(0)
var iframeController = __webpack_require__(9)
var iframeChannel = __webpack_require__(6)
var sibnetView = __webpack_require__(20)
var myviView = __webpack_require__(24)
var time = __webpack_require__(1)
var info = __webpack_require__(7)
var logger = new Logger()
function app() {
if(/^(cv|dv|fs)[a-z\d]+\.(sibnet|myvi)\.(ru|tv)/.test(location.hostname)) {
logger.debug(time(), '(iframe)', location.href)
return Promise.resolve().then(function () {
return iframeController.start()
})
} else {
logger.info(time(), info.script_name, info.script_version, '(c) ' + info.script_author)
logger.debug(time(), '(top)', location.href)
iframeChannel.init()
return DOMReady(function () {
if (location.origin.indexOf('sibnet') > -1) {
sibnetView()
} else {
myviView()
}
})
}
return Promise.reject()
}
app().catch(function (e) {
logger.error(time(), 'error', e)
})
module.exports = app
}),
/* 15 */
(function(module, exports) {
function EventEmitter() {
this._listenerMap = {}
}
/**
* @param {string} event
* @param {(...args: any[]) => void} callback
*/
EventEmitter.prototype.addListener = function addListener(event, callback) {
var listeners = this._listenerMap[event]
listeners = Array.isArray(listeners) ? listeners : []
var index = listeners.indexOf(callback)
if (index === -1) {
listeners.push(callback)
}
this._listenerMap[event] = listeners
}
/**
* @param {string} [event]
* @param {(...args: any[]) => void} [callback]
*/
EventEmitter.prototype.removeListener = function removeListener(event, callback) {
if (!event) {
var events = Object.keys(this._listenerMap)
for (var ev of events) {
this._listenerMap[ev].length = 0
delete this._listenerMap[ev]
}
return
}
if (!callback && Array.isArray(this._listenerMap[event])) {
this._listenerMap[event].length = 0
delete this._listenerMap[event]
return
}
if (Array.isArray(this._listenerMap[event])) {
var index = this._listenerMap[event].indexOf(callback)
if (index !== -1) {
this._listenerMap[event].splice(index, 1)
}
if (!this._listenerMap[event].length) {
delete this._listenerMap[event]
}
}
}
/**
* @param {string} event
*/
EventEmitter.prototype.emit = function emit(event) {
var listeners = this._listenerMap[event]
if (Array.isArray(listeners) && listeners.length) {
var args = Array.prototype.slice.call(arguments, 1)
for (var callback of listeners) {
callback.apply(null, args)
}
}
}
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
/**
* @param {string} event
* @param {(...args: any[]) => void} callback
*/
EventEmitter.prototype.once = function once(event, callback) {
var _this = this
var listener = function () {
callback.apply(null, arguments)
_this.off(event, listener)
}
this.on(event, listener)
}
module.exports = EventEmitter
}),
/* 16 */
(function(module, exports, __webpack_require__) {
var makeRequest = __webpack_require__(2)
var delay = __webpack_require__(3)
var Logger = __webpack_require__(0)
var time = __webpack_require__(1)
var logger = new Logger()
/**
* @param {any} resource
* @param {string} [name]
* @param {(loaded: number, total: number) => void} [onprogress]
*/
function downloadFile(source, name, onprogress) {
var link = document.createElement('a')
link.href = source
if (link.origin === location.origin) {
link.download = name || 'download'
link.innerHTML = name || 'download'
document.body.appendChild(link)
link.click()
logger.info(time(), 'downloadFile URL_download', link.href)
return delay(300).then(function () {
onprogress && onprogress(1, 1)
})
}
logger.info(time(), 'downloadFile XHR_download', link.href)
return makeRequest({
method: 'GET',
url: link.href,
responseType: 'blob',
onprogress: onprogress,
}, true).then(function (response) {
if (!response.ok) {
return response
}
var URL = window.URL || window.webkitURL
var resource = URL.createObjectURL(response.data);
return downloadFile(resource, name).then(function () {
URL.revokeObjectURL(resource)
return response
})
})
}
module.exports = downloadFile
}),
/* 17 */
(function(module, exports) {
/**
* @param {string} headersString
* @return {{ [x: string]: string }}
*/
function parseAJAXHeaders(headersString) {
if (typeof headersString !== 'string') {
return headersString
}
return headersString.split(/\r?\n/g)
.map(function (s) { return s.trim() })
.filter(Boolean)
.reduce(function (acc, cur) {
var res = cur.split(':')
var key, val
if (res[0]) {
key = res[0].trim().toLowerCase()
val = res.slice(1).join('').trim()
acc[key] = val
}
return acc
}, {})
}
module.exports = parseAJAXHeaders
}),
/* 18 */
(function(module, exports, __webpack_require__) {
var createDocument = __webpack_require__(19)
/**
* @param {string} responseText
* @param {{ [x: string]: string }} headers
* @param {string} [responseType]
*/
function parseAJAXResponse(responseText, headers, responseType) {
var isText = !responseType || responseType.toLowerCase() === 'text'
var contentType = headers['content-type']
if (
isText
&& contentType.indexOf('application/json') > -1
) {
return JSON.parse(responseText)
}
if (
isText &&
(
contentType.indexOf('text/html') > -1
|| contentType.indexOf('text/xml') > -1
)
) {
return createDocument(responseText)
}
return responseText
}
module.exports = parseAJAXResponse
}),
/* 19 */
(function(module, exports) {
/**
* @param {string} text
* @param {string} [title]
* @return {Document}
*/
function createDocument(text, title) {
title = title || ''
var doc = document.implementation.createHTMLDocument(title);
doc.documentElement.innerHTML = text
return doc
}
module.exports = createDocument
}),
/* 20 */
(function(module, exports, __webpack_require__) {
var DOMReady = __webpack_require__(4)
var Logger = __webpack_require__(0)
var baseView = __webpack_require__(10)
var sibnetController = __webpack_require__(23)
var iframeController = __webpack_require__(9)
var time = __webpack_require__(1)
var info = __webpack_require__(7)
function sibnetView() {
sibnetController.logger.info(time(), 'name:', sibnetController.getVideoName())
baseView.create({
title: info.script_name + ' ' + info.script_version,
filename: sibnetController.getVideoName(),
visible: true,
icon: { width: 20, height: 20, color: '#ffffff' },
onDownload: function (onProgress) {
return sibnetController.downloadVideoFile(onProgress)
},
getId: function () {
return sibnetController.getVideoId()
},
getUrl: function () {
return sibnetController.getVideoUrl()
},
getSize: function () {
return sibnetController.getVideoSize()
},
})
return baseView
}
module.exports = sibnetView
}),
/* 21 */
(function(module, exports) {
/**
* @param {number} size
* @return {string}
*/
function smartSize(size) {
var rest = size
var mib = Math.floor(rest / (1024 * 1024))
rest -= mib * 1024 * 1024
var kib = Math.floor(rest / 1024)
rest -= kib * 1024
var bytes = rest
var filesize;
if (mib) {
filesize = (size / (1024 * 1024)).toFixed(1) + ' MiB'
} else if (kib) {
filesize = (size / 1024).toFixed(1) + ' KiB'
} else if (bytes) {
filesize = bytes + ' bytes'
} else {
filesize = 'unknown'
}
return filesize
}
module.exports = smartSize
}),
/* 22 */
(function(module, exports, __webpack_require__) {
// extracted by mini-css-extract-plugin
}),
/* 23 */
(function(module, exports, __webpack_require__) {
var Logger = __webpack_require__(0)
var URLParse = __webpack_require__(5)
var makeRequest = __webpack_require__(2)
var getExtension = __webpack_require__(11)
var VIDEOS = __webpack_require__(12)
var delay = __webpack_require__(3)
var time = __webpack_require__(1)
var downloadManager = __webpack_require__(13)
var iframeChannel = __webpack_require__(6)
var sibnetVideoController = {
logger: new Logger(),
document: document,
location: location,
/**
* @param {(size: number) => void} [onLoad]
*/
getVideoSize: function (onLoad) {
var videoId = this.getVideoId()
var logger = this.logger
logger.debug(time(), 'getVideoSize..', videoId)
if (VIDEOS[videoId] && VIDEOS[videoId].size) {
logger.debug(time(), 'getVideoSize', VIDEOS[videoId].size)
return Promise.resolve(VIDEOS[videoId].size)
}
var self = this
return this.getVideoUrl().then(function (url) {
if (VIDEOS[videoId] && VIDEOS[videoId].size) {
var size = VIDEOS[videoId].size
logger.debug(time(), 'getVideoSize', size)
onLoad && onLoad(size)
return size;
}
return makeRequest({
method: 'HEAD',
url: url,
headers: {
referer: self.location.href,
range: 'bytes=0-10',
},
}, true).then(function (response) {
if (response.ok) {
return response
}
return iframeChannel.request({
event: 'size',
videoId: videoId,
url: url,
})
}).then(function (response) {
var size = 0
var contentRange = response.headers['content-range']
if (contentRange) {
size = parseInt(contentRange.split('/')[1], 10)
}
VIDEOS[videoId].size = size
logger.debug(time(), 'getVideoSize', size)
onLoad && onLoad(size)
return size
})
}).catch(function (e) {
logger.error(time(), 'getVideoSize error: ', e)
return 0
})
},
/**
* @return {Promise<string>}
*/
getVideoUrl: function () {
var videoId = this.getVideoId()
var logger = this.logger
logger.debug(time(), 'getVideoUrl..', videoId)
var finalUrl = VIDEOS[videoId] && VIDEOS[videoId].finalUrl
if (finalUrl) {
logger.debug(time(), 'getVideoUrl', finalUrl)
return Promise.resolve(finalUrl)
}
var url = this.getVideoPath()
return makeRequest({
method: 'HEAD',
url: url,
headers: {
range: 'bytes=0-',
referer: this.location.href,
},
}, true).then(function (response) {
if (response.ok) {
return response
}
return iframeChannel.request({
event: 'url',
videoId: videoId,
url: url,
})
}).then(function (response) {
VIDEOS[videoId].finalUrl = response.finalUrl
var contentRange = response.headers['content-range']
var contentLength = response.headers['content-length']
if (contentRange) {
VIDEOS[videoId].size = parseInt(contentRange.split('/')[1], 10)
} else if (contentLength) {
VIDEOS[videoId].size = parseInt(contentLength, 10)
}
logger.debug(time(), 'getVideoUrl', response.finalUrl)
return response.finalUrl
}).catch(function (e) {
logger.error(time(), 'getVideoUrl error: ', e)
return url;
})
},
/**
* @param {(loaded: number, total: number) => void} [onProgress]
*/
downloadVideoFile: function (onProgress) {
var logger = this.logger
var _this = this
logger.debug(time(), 'downloadVideoFile...')
return this.getVideoUrl().then(function (url) {
if (!url) {
logger.error(time(), 'downloadVideoFile', new Error('video url not found, url = ' + url))
return
}
var ext = getExtension(url)
if (!ext) {
logger.warn(time(), 'downloadVideoFile: can not get extension from url = ', url)
logger.warn(time(), 'downloadVideoFile: mp4 will be used as defualt extension')
ext = 'mp4'
}
var name = _this.getVideoName()
var filename = name + '.' + ext
var videoId = _this.getVideoId()
var data = {
url: url,
name: name,
filename: filename,
ext: ext,
size: VIDEOS[videoId].size,
videoId: videoId,
event: 'download',
}
return downloadManager.download(
Object.assign(
{},
data,
{
onProgress: onProgress,
headers: {
referer: _this.location.href,
range: 'bytes=0-',
},
saveAs: false,
},
{
debug: Boolean(downloadManager.__DEBUG__),
},
)
);
}).catch(function (e) {
logger.error(time(), 'downloadVideoFile error: ', e)
})
},
/** @return {string | undefined} */
getVideoPath: function () {
var document = this.document
var logger = this.logger
var videoId = this.getVideoId()
VIDEOS[videoId] = VIDEOS[videoId] || {}
if (VIDEOS[videoId].url) {
return VIDEOS[videoId].url
}
var video = document.querySelector('video')
if (video && video.src) {
var link = URLParse(video.src)
if (link.pathname.match(/\.mp4$/)) {
VIDEOS[videoId].url = link.href
return link.href
}
}
// backward compatibility
video = document.querySelector('#video')
var html = video ? video.innerHTML : document.body.innerHTML
html = html.split(/player\.src\(\s?\[\s?\{\s?src\s?\:\s?\"/)[1];
var match = html ? html.match(/(\/v\/.*\.(mpd|mp4))/) : null
if(html && match) {
var link = URLParse(match[0])
VIDEOS[videoId].url = link.href
return link.href
}
logger.error(time(), 'url not found')
},
/** @return {string | undefined} */
getVideoId: function () {
var link = URLParse(this.location.href)
var match = link.href.match(/video(id\s?\=\s?|)(\d+)/)
var videoId = match ? match[2] : null
if (videoId && !VIDEOS[videoId]) {
VIDEOS[videoId] = { videoId: videoId }
}
return videoId
},
/** @return {string} */
getVideoName: function () {
var document = this.document
var logger = this.logger
var meta = document.querySelector('meta[property="og:title"]')
var title = meta && meta.getAttribute('content')
if (title) {
return title
}
var h1 = document.querySelector('td.video_name > h1')
var name = h1 && h1.innerHTML.replace(/\.mp4$/, '')
if (name) {
title = name + '_' + this.getVideoId()
return title
}
title = 'sibnet_video_' + this.getVideoId()
return title
},
updateVideoId: function (videoId, isForce) {
this.logger.debug(time(), 'updateVideoId..', { videoId: videoId, isForce: isForce })
if (videoId !== this.getVideoId()) {
var pageUrl = 'https://video.sibnet.ru/shell.php?videoid=' + videoId
var link = URLParse(pageUrl)
var useGM = link.origin !== location.origin
var _this = this
return makeRequest({
url: pageUrl,
headers: {
referer: pageUrl,
},
}, useGM).then(function (response) {
if (response.ok) {
_this.document = response.data
_this.location = link
}
return response.ok
})
}
return Promise.resolve()
},
clone: function () {
return Object.assign({}, this)
},
/** @param {Logger} logger */
setLogger: function (logger) {
this.logger = logger
},
/** @param {HTMLDocument} document */
setDocument: function(document) {
this.document = document
},
/** @param {any} location */
setLocation: function(location) {
this.location = location;
},
}
module.exports = sibnetVideoController
}),
/* 24 */
(function(module, exports, __webpack_require__) {
var DOMReady = __webpack_require__(4)
var Logger = __webpack_require__(0)
var baseView = __webpack_require__(10)
var myviController = __webpack_require__(25)
var iframeController = __webpack_require__(9)
var time = __webpack_require__(1)
var info = __webpack_require__(7)
function myviView() {
myviController.logger.info(time(), 'name:', myviController.getVideoName())
baseView.create({
title: info.script_name + ' ' + info.script_version,
filename: myviController.getVideoName(),
visible: true,
icon: { width: 20, height: 20, color: '#ffffff' },
onDownload: function (onProgress) {
return myviController.downloadVideoFile(onProgress)
},
getId: function () {
return myviController.getVideoId()
},
getUrl: function () {
return myviController.getVideoUrl()
},
getSize: function () {
return myviController.getVideoSize()
},
})
return baseView
}
module.exports = myviView
}),
/* 25 */
(function(module, exports, __webpack_require__) {
var Logger = __webpack_require__(0)
var URLParse = __webpack_require__(5)
var makeRequest = __webpack_require__(2)
var getExtension = __webpack_require__(11)
var VIDEOS = __webpack_require__(12)
var delay = __webpack_require__(3)
var time = __webpack_require__(1)
var downloadManager = __webpack_require__(13)
var iframeChannel = __webpack_require__(6)
var myviVideoController = {
logger: new Logger(),
document: document,
location: location,
/**
* @param {(size: number) => void} [onLoad]
*/
getVideoSize: function (onLoad) {
var videoId = this.getVideoId()
var logger = this.logger
if (VIDEOS[videoId] && VIDEOS[videoId].size) {
return Promise.resolve(VIDEOS[videoId].size)
}
var self = this
logger.debug(time(), 'getVideoSize..', videoId)
return this.getVideoUrl().then(function (url) {
if (VIDEOS[videoId] && VIDEOS[videoId].size) {
var size = VIDEOS[videoId].size
onLoad && onLoad(size)
return size;
}
return makeRequest({
method: 'GET',
url: url,
headers: {
referer: self.location.origin,
range: 'bytes=0-10',
},
}, true).then(function (response) {
if (response.ok) {
return response
}
return iframeChannel.request({
event: 'size',
url: url,
videoId: videoId,
})
}).then(function (response) {
var contentRange = response.headers['content-range']
var size = 0
if (contentRange && response.ok) {
size = parseInt(contentRange.split('/')[1], 10)
}
VIDEOS[videoId].size = size
logger.debug(time(), 'getVideoSize', size)
onLoad && onLoad(size)
return size
})
}).catch(function (e) {
logger.error(time(), 'getVideoSize error: ', e)
return 0
})
},
/**
* @return {Promise<string>}
*/
getVideoUrl: function () {
var videoId = this.getVideoId()
var logger = this.logger
logger.debug(time(), 'getVideoUrl..', videoId)
var finalUrl = VIDEOS[videoId] && VIDEOS[videoId].finalUrl
if (finalUrl) {
logger.debug(time(), 'getVideoUrl', finalUrl)
return Promise.resolve(finalUrl)
}
var url = this.getVideoPath()
var promise = Promise.resolve()
var _this = this
if (!url) {
return _this.updateVideoId(videoId, true).then(function (ok) {
if (ok) {
return _this.getVideoUrl()
}
logger.error(time(), 'getVideoUrl failed')
})
}
return makeRequest({
method: 'GET',
url: url,
headers: {
range: 'bytes=0-10',
referer: location.origin,
},
}, true).then(function (response) {
if (response.ok) {
return response
}
return iframeChannel.request({
event: 'url',
videoId: videoId,
url: url,
})
}).then(function (response) {
VIDEOS[videoId].finalUrl = response.finalUrl
var contentRange = response.headers['content-range']
if (contentRange) {
VIDEOS[videoId].size = parseInt(contentRange.split('/')[1], 10)
}
logger.debug(time(), 'getVideoUrl', response.finalUrl)
return response.finalUrl
}).catch(function (e) {
logger.error(time(), 'getVideoUrl error: ', e)
return url
})
},
/**
* @param {(loaded: number, total: number) => void} [onProgress]
*/
downloadVideoFile: function (onProgress) {
var logger = this.logger
var _this = this
logger.info(time(), 'downloadVideoFile...')
return this.getVideoUrl().then(function (url) {
if (!url) {
logger.error(time(), 'downloadVideoFile', new Error('video url not found, url = ' + url))
return
}
var ext = getExtension(url)
if (!ext) {
logger.warn(time(), 'downloadVideoFile: can not get extension from url = ', url)
logger.warn(time(), 'downloadVideoFile: mp4 will be used as defualt extension')
ext = 'mp4'
}
var name = _this.getVideoName()
var filename = name + '.' + ext
var videoId = _this.getVideoId()
var data = {
url: url,
name: name,
filename: filename,
ext: ext,
size: VIDEOS[videoId].size,
videoId: videoId,
event: 'download',
}
return downloadManager.download(
Object.assign(
{},
data,
{
onProgress: onProgress,
headers: {
referer: _this.location.href,
range: 'bytes=0-',
},
saveAs: false,
},
{
debug: Boolean(downloadManager.__DEBUG__),
},
)
);
}).catch(function (e) {
logger.error(time(), 'downloadVideoFile error: ', e)
})
},
/** @return {string | undefined} */
getVideoPath: function () {
var document = this.document
var logger = this.logger
var videoId = this.getVideoId()
VIDEOS[videoId] = VIDEOS[videoId] || {}
if (VIDEOS[videoId].url) {
return VIDEOS[videoId].url
}
var scripts = Array.prototype.slice.call(document.querySelectorAll('script'))
var textarea = document.createElement('textarea')
var html, match, urlencoded,
regex = /PlayerLoader\.CreatePlayer\s?\(\s?(?:\"|\')([^"']+)/i
for (var script of scripts) {
html = script.innerHTML
if (!html) {
continue
}
textarea.innerHTML = html
match = textarea.value.match(regex)
if (match) {
urlencoded = match[1]
break
}
}
if (urlencoded) {
var obj = urlencoded.split(/\u0026/g).reduce(function (acc, cur){
var arr = cur.split('=')
var key = arr[0], val = arr[1]
if (key) {
acc[key] = val
}
return acc
}, {})
var v = decodeURIComponent(obj.v)
v = v.split(/\\u0026/g)[0]
var link = URLParse(v)
VIDEOS[videoId].url = link.href
return link.href
}
var video = document.querySelector('video')
if (video && video.src) {
var link = URLParse(video.src)
if (link.pathname.match(/\.mp4$/)) {
VIDEOS[videoId].url = link.href
return link.href
}
}
logger.error(time(), 'url not found')
},
/** @return {string | undefined} */
getVideoId: function () {
var link = URLParse(this.location.href)
var match = link.pathname.match(/(?:embed\/(.+))/) || link.search.match(/v\=([^?&#=]+)/)
var videoId = match ? match[1] : null;
if (videoId && !VIDEOS[videoId]) {
VIDEOS[videoId] = { videoId: videoId }
}
return videoId
},
/** @return {string} */
getVideoName: function () {
var document = this.document
var logger = this.logger
var title = document.querySelector('title')
if (title) {
title = title.innerHTML
return title
}
title = 'myvi_video_' + this.getVideoId()
return title
},
clone: function () {
return Object.assign({}, this)
},
/** @param {Logger} logger */
setLogger: function (logger) {
this.logger = logger
},
/** @param {HTMLDocument} document */
setDocument: function(document) {
this.document = document
},
/** @param {any} location */
setLocation: function(location) {
this.location = location;
},
updateVideoId: function (videoId, isForce) {
this.logger.debug(time(), 'updateVideoId..', { videoId: videoId, isForce: isForce })
if (videoId !== this.getVideoId() || isForce) {
var pageUrl = 'https://www.myvi.tv/embed/' + videoId
var link = URLParse(pageUrl)
var useGM = link.origin !== location.origin
var _this = this
return makeRequest({
url: pageUrl,
headers: {
referer: pageUrl,
},
}, useGM).then(function (response) {
if (response.ok) {
_this.document = response.data
_this.location = link
}
return response.ok
})
}
return Promise.resolve()
},
}
module.exports = myviVideoController
})
])));
})(typeof unsafeWindow !== 'undefined' ? unsafeWindow : window, window);
(function () {
const style = `
.vdm-root {
margin: 0;
padding: 0;
background-color: #1e1a1a;
z-index: 9999;
bottom: 10px;
right: 10px;
border-radius: 5px;
overflow: hidden;
min-width: 400px;
position: fixed;
color: white;
font-family: sans-serif;
font-size: 14px;
max-width: 600px;
}
.vdm-root span {
word-break: break-all;
}
.vdm-container {
display: flex;
margin: 0;
padding: 0;
flex-direction: column;
justify-content: space-between;
align-items: center;
margin-left: 24px;
margin-right: 24px;
}
.vdm-header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
width: 100%;
margin: 10px;
}
.vdm-title {
flex: 1;
text-align: center;
}
.vdm-close-btn {
z-index: 12;
cursor: pointer;
}
.vdm-close-btn div {
display: flex;
flex-direction: row;
justify-content: center;
}
.vdm-close-btn,
.vdm-close-btn div,
.vdm-close-btn div:after,
.vdm-close-btn div:before {
height: 16px;
}
.vdm-close-btn,
.vdm-close-btn div {
width: 16px;
}
.vdm-close-btn div:after,
.vdm-close-btn div:before {
content: "";
position: absolute;
background: #fff;
width: 1.5px;
display: block;
transform: rotate(45deg);
}
.vdm-close-btn div:before {
transform: rotate(-45deg);
}
.vdm-controllers {
width: 100%;
margin-top: 10px;
}
.vdm-button {
cursor: pointer;
background-color: green;
border-radius: 5px;
margin: 10px 0;
text-align: center;
font-weight: bold;
display: flex;
justify-content: center;
align-items: center;
min-height: 20px;
}
.vdm-button:active {
background-color: blue;
}
.vdm-button:hover {
opacity: 0.95;
}
.vdm-content {
display: flex;
flex-direction: column;
width: 100%;
justify-content: space-between;
align-items: center;
}
.vdm-filesize {
margin-top: 5px;
margin-bottom: 5px;
}
.vdm-item {
align-self: flex-start;
}
.vdm-item a {
color: #666;
}
.vdm-item a:hover {
opacity: 0.8;
}
.vdm-item span label {
cursor: pointer;
}
.vdm-item label:hover {
opacity: 0.8;
}
.vdm-item label.show_link {
color: #666;
}
.vdm-item input[type=checkbox] + span label.show_link,
.vdm-item input[type=checkbox]:checked + span label.video_link,
.vdm-item input[type=checkbox]:checked + span a {
display: initial;
}
.vdm-item input[type=checkbox]:checked + span label.show_link,
.vdm-item input[type=checkbox] + span label.video_link,
.vdm-item input[type=checkbox] + span a {
display: none;
}
.vdm-progress {
height: 10px;
background-color: #3838ea;
border-radius: 2px;
}
.vdm-download .loading {
-webkit-animation: spin 2s linear infinite;
-moz-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
}
.vdm-button > * {
padding: 10px;
line-height: 20px;
}
@-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } }
@-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } }
@keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } }
`;
if (typeof GM !== 'undefined' && typeof GM.addStyle !== 'undefined') {
GM.addStyle(style)
} else {
var _addStyle = function (textCss) {
var el = document.createElement('style')
el.setAttribute('type', 'text/css')
el.innerHTML = textCss
return document.head.appendChild(el)
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () {
_addStyle(style)
})
} else {
_addStyle(style)
}
}
})();