// ==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 // @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 // @include *://video.sibnet.ru/* // @include *://myvi.ru/* // @include *://www.myvi.ru/* // @include *://cv*.sibnet.ru/* // @include *://dv*.sibnet.ru/* // @include *://fs*.myvi.ru/* // @include *://fs*.myvi.ru:8090/* // @connect sibnet.ru // @connect myvi.ru // @version 2.1.5 // @author Iron_man // @grant GM_xmlhttpRequest // @grant GM.xmlHttpRequest // @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js // @run-at document-start // @downloadURL none // ==/UserScript== var DEBUG = false, RANDOM = '1669048',// Math.round(Math.random() * 1000000 + 1000000), scriptName = 'Download Video as MP4', scriptVersion = '2.1.5', blank = function(){}, consoleLog = function(){window.console.log.apply(this, arguments);}, clog = blank, clog2 = consoleLog, userOptions, siteObject; if(DEBUG) clog = consoleLog; (function(window){ if( /^(cv|dv|fs)\d+\.(sibnet|myvi)\.ru/.test(location.hostname) ) { clog2("[window:child] origin: ", location.origin); DOMReady(function(){ executor(); }); }else{ clog2("[window:parent] start " + scriptName + " v" + scriptVersion + ".."); clog2("[window:parent] origin: ", location.origin); userOptions = initOptions(); siteObject = getSiteObject(); userOptions.set({ clickCancel : true,// автоматически нажать на отмену в конец видео removeAds : true,// удалить рекламу addVideoId : true,// добавить видео id в название файла addSiteName: false,// добавить название сайта useGMDownloader : false,// всегда использовать GM.xmlHttpRequest для скачивания файла (не рекомендуется) maxSize : 16 * 1024 * 1024,// (0 Mb) максимальный размер файла для скачивания с помощью GM.xmlHttpRequest delay : 500,// задержка в мс перед закрытием загрузочного iframe'a style: 0,// номер стиля диалогового окна }); document.addEventListener('readystatechange', main, false); } })(window); function DOMReady(callback) { var isDone = false, isBound = false; var handler = function() { switch(document.readyState) { case 'loading': if( !isBound ) { isBound = true; document.addEventListener('readystatechange', handler, false); } break; case 'interactive': case 'complete': if( !isDone ) { isDone = true; if( typeof callback === 'function' ) callback(); } if( isBound ) document.removeEventListener('readystatechange', handler, false); } }; callback(); } function executor() { try{ clog("[executor] origin: ", location.origin); var s = location.hash, t, ext, a; if( s.indexOf('#DV::') !== 0 ) return 1; t = JSON.parse(decodeURIComponent(s.slice(5))); t.complete = 1; t.code = 0; clog("[executor] data: ", t); clog("[executor] readyState: ", document.readyState); t.ext = t.ext || getLocation(t.source, 'pathname').match(/\.([^.\/]+)/)[1]; if( t.name.match(/\.([^.]+)/)[1] != t.ext ) t.name += '.' + t.ext; downloadFile( t.name, t.source ); if(t.code) console.error("[executor] error, data: ", t, ", code", t.code); setTimeout(function(){ window.parent.postMessage(t, '*'); }, t.delay); }catch(er){ console.error("[window:child] error: ", er); window.parent.postMessage({complete: 1}, '*'); } } function main() { switch(this.readyState) { case 'interactive': if( siteObject.siteName.indexOf('sibnet') != -1 ) { if( userOptions.val('removeAds') ) removeAds(); if( userOptions.val('clickCancel') ) setCancelPostvideo(); var pladform = detectPladformIFrames(); if( pladform ) { clog('embeded video from pladform.ru'); return; } } // get video path name from current html source page: // site:video.sibnet.ru '/v/{numbers}/{videoid}.mpd' // site:myvi.ru '/video/{videoid}.mp4?uid=&puid=&ref={encoded href}&d=1&rnd={random number}&sig={number} var video_path = siteObject.getVideoPath(); clog2("video path: ", video_path); if( video_path ) { GM.xmlHttpRequest({ url: video_path, method: 'HEAD', onload: makeVideoLink, }); } newCssClasses('dv-style-id'); window.addEventListener('message', recieveMessage, false ); break; } } function getLocation(url, property) { window.__link__ = window.__link__ || document.createElement('a'); __link__.href = url; return __link__[property]; } function downloadFile( name, resource ) { var a = document.createElement('a'); a.download = name; a.href = resource; $('body').appendChild(a); a.click(); return a.parentNode.removeChild(a); } function $(selector, element) { return (element || document).querySelector(selector); } function $$(selector, element) { return (element || document).querySelectorAll(selector); } function $attr(element, attributes) { if( typeof attributes == 'string' ) return element.getAttribute(attributes); for( var key in attributes ) element.setAttribute(key, attributes[key]); return element; } function getSiteObject() { var hostname = window.location.hostname; if( hostname.indexOf('myvi.ru') != -1 ) { return { siteName: 'myvi', getVideoPath: getMyviPath, getVideoId: function(){return this.id;}, id: null, }; } else if( hostname.indexOf('sibnet.ru') != -1 ) { return { siteName: 'sibnet', getVideoPath: getSibnetPath, getVideoId: getSibnetId, }; }else return {}; } function getSibnetPath() { var video, source_str, pos, end; video = $('#video'); if( video ) source_str = video.innerHTML; else source_str = $('body').innerHTML; pos = source_str.indexOf( "player.src([{src: \"" ); if( pos == -1 ) return null; pos = source_str.indexOf("/v/", pos); end = source_str.indexOf(".mpd", pos); if( end == -1 ) return null; return source_str.substring(pos, end+4); } function getMyviPath() { var scriptList = $$('script'), regex = /createPlayer/, pathRegex = /((https?\:)?\/\/(fs\.myvi\.ru))([^\?\#\\]+)([^\#\\]+)/, match; for( var i = 0, len = scriptList.length, script, html; i < len; ++i ) { script = scriptList[i]; html = script.innerHTML; if( regex.test(html) ) { html = decodeURIComponent(html); match = html.match(pathRegex); if( !match ) { console.error("invalid match: ", match); break; } siteObject.id = match[4].match(/\d+/)[0]; siteObject.path = match[0]; return match[0]; } } return null; } function makeVideoLink( xhr ) { var video_link = xhr.finalUrl.replace('/manifest.mpd', '.mp4');// get downloadable video link clog2("video file: ", video_link); if( !video_link ) { console.error("[makeVideoLink] can't find video source link"); return; } var st = insertLink( video_link );// try to insert the link into 'video_size' element of html source page if( st !== 0 ) confirmDownloadFile( video_link ); } function insertLink( source_link, size_mb ) // insert hyper reference into video_size element { var video_size = $('.video_size'); if( !video_size ) return 1; size_mb = size_mb || video_size.innerHTML; video_size.innerHTML = '' + '' + size_mb + ''; var video_file = $('#video_file_' + RANDOM), bytes = (parseInt(size_mb.match(/\d+/)[0], 10) || 0) * 1024 * 1024; if( bytes ) $attr(video_file, {'file-size': bytes}); video_file.addEventListener('click', handleDownloadFileEvent, false); return 0; } function handleDownloadFileEvent(event) { var t = event.target; if( event.ctrlKey ) return; else if( !t.classList.contains('video_file_active') ) return; event.preventDefault(); if( t.classList.contains('video_file_active') ) smartDownloadFile( getFileName(), t.href, $attr(t, 'file-size') ); } function smartDownloadFile( name, source, size ) { if( userOptions.val('useGMDownloader') || (size && size < userOptions.val('maxSize')) ) GM_downloadFile(name, source); else makeIFrame( name, source ); } function getFileName() { var fileName = $('td.video_name > h1'), videoId = siteObject.getVideoId(), siteName = siteObject.siteName, nameEnd = ''; if( userOptions.val('addSiteName') ) nameEnd += (' ' + siteName); if( userOptions.val('addVideoId') && videoId ) nameEnd += (' ' + videoId); nameEnd += '.mp4'; if( fileName ) return fileName.innerHTML.replace(/\.mp4$/, '') + nameEnd; fileName = $('meta[property="og:title"]'); if( fileName ) return $attr(fileName, 'content').replace(/\.mp4$/, '') + nameEnd; fileName = ( siteName.indexOf('myvi') != -1 ? $('title').innerHTML : null ); if( fileName ) return fileName.replace(/\.mp4$/, '') + nameEnd; return siteName + '_' + videoId + '.mp4'; } function getSibnetId() { var href = window.location.href; try{ return decodeURIComponent(href).match(/video(id\s?\=\s?|)(\d+)/)[2]; }catch(e){ return ''; } } function confirmDownloadFile( source ) { var fileName = getFileName(); makeConfirmWindow(); setConfirmWindow( fileName, 0, source); GM.xmlHttpRequest({ url: source, method: 'HEAD', context: {'url': source, 'name': fileName}, onload: function(xhr){ if( xhr.status !== 200 ) { console.error("xhr.status: ", xhr.status, xhr.statusText ); console.error("url: " + source); console.error("method: " + 'HEAD'); return; } var fileSize = getContentLength( xhr.responseHeaders ); setConfirmWindow( xhr.context.name, fileSize, xhr.context.url ); } }); } function makeConfirmWindow() { var confirmWnd = $('#confirm_downlaod_window_' + RANDOM); if( !confirmWnd ) { confirmWnd = document.createElement('div'); $attr(confirmWnd, { 'id': 'confirm_downlaod_window_' + RANDOM, 'class': 'confirm_download_window', }); $('body').appendChild(confirmWnd); var html = '' + '
' + '' + '