您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
Скачивание видео одним кликом, правильные названия видео при скачивании
当前为
// ==UserScript== // @name Download Sibnet Video as MP4 // @namespace http://video.sibnet.ru // @description Скачивание видео одним кликом, правильные названия видео при скачивании // @include *://video.sibnet.ru/* // @include *://cv*.sibnet.ru/* // @include *://dv*.sibnet.ru/* // @connect sibnet.ru // @version 1.4.2 // @author Iron_man // @grant GM_xmlhttpRequest // @grant GM.xmlHttpRequest // @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js // @run-at document-start // ==/UserScript== (function(){ console.log("Download Sibnet Videos start.."); var userOptions = initOptions(); userOptions.set({ clickCancel : true,// автоматически нажать на отмену в конец видео removeAds : true,// удалить рекламу addVideoId : true,// добавить видео id в название файла useGMDownloader : false,// всегда использовать GM.xmlHttpRequest для скачивания файла (не рекомендуется) maxSize : 16 * 1024 * 1024,// (16 Mb) максимальный размер файла для скачивания с помощью GM.xmlHttpRequest delay : 500,// задержка в мс перед закрытием загрузочного iframe'a style: 0,// номер стиля диалогового окна }); var RANDOM = '1669048',// Math.round(Math.random() * 1000000 + 1000000), isSourcePage = downloadFromSourcePage(); if( !isSourcePage ) document.addEventListener('DOMContentLoaded', start, false ); function downloadFromSourcePage() { var href = window.location.href, match = href.match(/^((https?\:)?\/\/(([^\/\?\#\.]+)\.([^\/\?\#]+)))([^\?\#]+)([^\#]+)(.*)/); if( match[4] !== 'video' && match[8] && match[8].indexOf('.mp4') != -1 ) { var fileName = match[8].slice(1), fileUrl = href.match(/([^\#]+)(.*)/)[1], sendMessage = function(){window.parent.postMessage( 'closeIFrame', '*' );}, closeWindow = function(){window.close();}, videoClose = function(){ if( window.self !== window.parent ) setTimeout( sendMessage, userOptions.val('delay') ); else setTimeout( closeWindow, userOptions.val('delay') ); }; fileName = decodeURIComponent(fileName); document.addEventListener('readystatechange', function(event){ if( this.readyState === 'interactive' ) { downloadFile( fileName, fileUrl ); var video = $('video'); if( video ) video.addEventListener('error', videoClose, false); } else if( this.readyState === 'complete' ) videoClose(); }, false); return true; } return false; } function downloadFile( name, resource ) { var a = document.createElement('a'); $attr(a, {'download': name}); a.href = resource; $('body').appendChild(a); a.click(); a.parentNode.removeChild(a); } function $( selector, element ) { element = element || document; return element.querySelector(selector); } function $$( selector, element ) { element = element || document; return element.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 start() { if( userOptions.val('removeAds') ) removeAds(); if( userOptions.val('clickCancel') ) setCancelPostvideo(); var pladform = detectPladformIFrames(); if( pladform ) { console.log('embeded video from pladform.ru'); return; } var video_path = getVideoPath();// get video path name '/v/{numbers}/{videoid}.mpd' from current html source page console.log("video path: " + video_path); if( video_path ) { GM.xmlHttpRequest({ url: video_path, method: 'HEAD', onload: makeVideoLink, }); } newCssClasses('dsv-style-id'); } function getVideoPath() { 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 makeVideoLink( xhr ) { var video_link = xhr.finalUrl.replace('/manifest.mpd', '.mp4');// get downloadable video link console.log("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 = '' + '<a id="video_file_' + RANDOM + '" class="video_file_active" href="' + source_link + '" ' + 'title="Скачать">' + size_mb + '</a>'; 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'), videoIdStr = (userOptions.val('addVideoId') ? " " + getVideoId() : ""); if( fileName ) return fileName.innerHTML + videoIdStr + ".mp4"; fileName = $('meta[property="og:title"]'); if( fileName ) return $attr(fileName, 'content') + videoIdStr + ".mp4"; return "video_name_" + getVideoId() + ".mp4"; } function getVideoId() { var href = window.location.href; return href.match(/video(id\=|)(\d+)/)[2]; } 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 = '' + '<div id="confirm-filename"></div>' + '<div id="confirm-filesize"></div>' + '<div id="confirm-bottom">' + '<button id="confirm-download-button-true" class="confirm-button">Скачать</button>' + '<button id="open-video-source-file" class="confirm-button">Открыть</button>' + '<button id="confirm-download-button-false" class="confirm-button">Отмена</button>' + '</div>' + /* '<div id="color-style-id" style="text-align: center;">' + '<button id="change-color-style" class="confirm-button">Сменить стиль</button>' + '</div>' + */ ''; confirmWnd.innerHTML = html; confirmWnd.addEventListener('click', handleConfirmEvent, false); } confirmWnd.style.display = 'block'; return confirmWnd; } function setConfirmWindow( fileName, fileSize, fileUrl ) { var confirmWnd = $('#confirm_downlaod_window_' + RANDOM) || makeConfirmWindow(); var fileNameDiv = $('#confirm-filename', confirmWnd), fileSizeDiv = $('#confirm-filesize', confirmWnd); fileNameDiv.innerHTML = 'Имя файла: ' + shortenFileName(fileName); $attr(fileNameDiv, {'title': fileName}); fileSizeDiv.innerHTML = 'Размер файла: ' + bytesToMB(fileSize, 1) + ' Mb'; if( fileSize ) $attr(fileSizeDiv,{'title': bytesToKB(fileSize) + ' Kb'} ); $attr( $('#open-video-source-file', confirmWnd), {'title': fileUrl}); $attr( confirmWnd, { 'file-name': fileName, 'file-size': fileSize, 'file-source': fileUrl, }); confirmWnd.style.display = 'block'; } function bytesToKB( bytes, precision ) { if( bytes ) return (bytes/1024).toFixed(precision || 0); return '--'; } function shortenFileName( fileName ) { this.maxLen = this.maxLen || 25; var nameLen = fileName.length; if( nameLen > this.maxLen ) { var nameEnd = fileName.slice(-11); fileName = fileName.slice(0, (this.maxLen - nameEnd.length) ); fileName += '...' + nameEnd; } return fileName; } function handleConfirmEvent(event) { var t = event.target; if( t.tagName !== 'BUTTON' ) return; if( t.id === 'confirm-download-button-false' ) this.style.display = 'none'; else if( t.id === 'confirm-download-button-true' ) { this.style.display = 'none'; smartDownloadFile( $attr(this, 'file-name'), $attr(this, 'file-source'), $attr(this, 'file-size') ); } else if( t.id === 'open-video-source-file' ) window.open( $attr(this, 'file-source') ); /* else if( t.id === 'change-color-style' ) { var idx = userOptions.data.style.idx; userOptions.val('style', idx+1); resetCssClasses('dsv-style-id'); } */ } function getContentLength( headersStr ) { var headers = headersStr.split('\r\n'); for( var i = 0, h; i < headers.length; ++i ) { h = headers[i]; if( h.indexOf('Content-Length') != -1 ) return parseInt(h.match(/\d+/)[0], 10); } return 0; } function makeIFrame( name, source ) { var iframe = $('#video_download_iframe_' + RANDOM); if( !iframe ) { iframe = document.createElement('iframe'); $attr(iframe, {'id': 'video_download_iframe_' + RANDOM}); $('body').appendChild(iframe); } name = encodeURIComponent(name); iframe.src = (source + '#' + name); } function closeIFrame() { var ifr = $('#video_download_iframe_' + RANDOM); if( ifr ) ifr.parentNode.removeChild(ifr); } function GM_downloadFile( name, source ) { GM.xmlHttpRequest({ url: source, method: 'GET', responseType: 'blob', onload: function(xhr){ if( xhr.status !== 200 ) { console.error("xhr.status: ", xhr.status); console.error("url: ", source); return; } console.log("source: " + source); console.log("name: " + name); var wURL = window.webkitURL || window.URL, resource = wURL.createObjectURL(xhr.response); downloadFile( name, resource ); var video_file = $('#video_file_' + RANDOM); if( video_file ) video_file.classList.add('video_file_active'); wURL.revokeObjectURL(resource); }, onprogress: function(xhr){ if( !xhr.lengthComputable ) return; showDownloadWindow(xhr.total, xhr.loaded); } }); } function showDownloadWindow(total, loaded) { var dlWnd = $('#download_window_' + RANDOM); if( !dlWnd ) { dlWnd = document.createElement('div'); $attr(dlWnd, { 'id': 'download_window_' + RANDOM, 'class': 'video_download_window', }); dlWnd = $('body').appendChild(dlWnd); } dlWnd.style.display = ''; var html = bytesToMB(loaded, 1) + ' Mb / ' + bytesToMB(total, 1) + ' Mb' + ' (' + (loaded/total*100).toPrecision(3) + '%)'; dlWnd.innerHTML = html; if( total === loaded ) { setTimeout(function(){ dlWnd.style.display = 'none'; }, 3000 ); } } function bytesToMB( bytes, precision ) { if( bytes ) return (bytes/(1024*1024)).toFixed(precision || 0); return '--'; } function addCssClass( cssClass, id ) { var style = document.createElement('style'); style.type = 'text/css'; if( id ) style.id = id; if( style.styleSheets ) style.styleSheets.cssText = cssClass; else style.appendChild(document.createTextNode(cssClass)); $('head').appendChild(style); } function resetCssClasses( id ) { if( !id ) return; var style = document.getElementById(id); if( style ) style.parentNode.removeChild( style ); newCssClasses( id ); } function newCssClasses( id ) { addCssClass(` .confirm-button { background-color: ${userOptions.val('style')['background-color']}; color: #c7c7c7; font-size: 1.0em; border-radius: 5px; font-family: sans-serif; border: 2px solid #c7c7c7; cursor: pointer; margin: 0.4% 2%; padding: 0 3px; test-align: center; } .confirm-button:hover { background-color: ${userOptions.val('style')['background-color-hover']}; border-color: white; color: white; } #confirm-bottom { padding: 3px 0 2px 0; } #confirm-bottom { text-align: center; } .confirm_download_window, .video_download_window { position: fixed; bottom: 20px; right: 20px; z-index: 9999; background-color: ${userOptions.val('style')['background-color']}; color: white; //box-shadow: 5px 5px 5px #555555; font-size: 1.0em; font-family: sans-serif; border-radius: 5px; padding: 2px 10px; display:; cursor: default; border: 2px solid #c7c7c7; } `, id); } function removeAds() { var tbody = $('.main tbody'); if( tbody && tbody.children && tbody.children[0] ) tbody.children[0].innerHTML = '<td style="height:0px"></td>'; } function setCancelPostvideo() { var player_container = $('#player_container'); if( player_container ) { player_container.addEventListener('ended', function(event) { var postvideo_cancel = $('.vjs-postvideo-cancel'); if( postvideo_cancel ) setTimeout( function(){postvideo_cancel.click();}, 1000 ); }, true ); } } function detectPladformIFrames() { var iFrames = $$('iframe'), count = 0; for( var i = 0; i < iFrames.length; ++i ) { if( iFrames[i].src.indexOf('pladform.ru') != -1 ) { $attr(iFrames[i], { 'id': 'pladform' + i, 'name': 'pladform' + i, }); ++count; } } return count; } function recieveMessage(event) { if(event.origin.search(/(cv|dv).*\.sibnet\.ru/) != -1 ){ console.log( "origin: " + event.origin ); if( event.data === 'closeIFrame' ) setTimeout( closeIFrame, userOptions.val('delay') ); }else{ //console.info('[recieveMessage] message from ' + event.origin + ' is ignored'); } } window.addEventListener('message', recieveMessage, false ); function initOptions() { function _setDef(){this.val = this.def;} var wndStyle = []; function addColor( bg, bgh ) { wndStyle.push({ 'background-color': bg, 'background-color-hover': bgh, }); } addColor('#16a085', '#058f74' ); addColor('#0b72aa', '#095d8c' ); addColor('#2091d8', '#2080c7' ); addColor('#3678cc', '#2668bc' ); var retVal = { data: { 'clickCancel' : { val: null, def: true,// автоматически нажать на отмену в конец видео setDef: _setDef, }, 'removeAds' : { val: null, def: true,// удалить рекламу setDef: _setDef, }, 'addVideoId' : { val: null, def: true,// добавить видео id в название файла setDef: _setDef, }, 'useGMDownloader' : { val: null, def: false,// всегда использовать GM.xmlHttpRequest для скачивания файла (не рекомендуется) setDef: _setDef, }, 'maxSize' : { val: null, def: 16 * 1024 * 1024,// (16 Mb) максимальный размер файла для скачивания с помощью GM.xmlHttpRequest setDef: _setDef, validator: function(v){ return v < 268435456;// 256 * 1024 * 1024 } }, 'delay' : { val: null, def: 500,// задержка в мс перед закрытием загрузочного iframe'a setDef: _setDef, validator: function(v){ return v > 99; } }, 'style': { get val(){return wndStyle[this.idx];}, set val(n){ this.idx = n%wndStyle.length;}, def: 0,// номер стиля setDef: function(){ this.idx = this.def; }, validator: function(n){ return n >= 0; } }, }, val: function( prop, v ){ if( this.data[prop] ) { if( v !== undefined ) { if( this.data[prop].validator && this.data[prop].validator(v) ) this.data[prop].val = v; else this.data[prop].val = v; }else return this.data[prop].val; }else return null; }, setDefs: function(){ for( var key in this.data ) this.data[key].setDef(); }, set: function( opts ){ for( var key in opts ) this.val( key, opts[key] ); }, }; retVal.setDefs(); return retVal; } })();