您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a download button to the HTML5 Vimeo Player (embeded or not)
当前为
// ==UserScript== // @name Vimeo Download Button // @namespace larochematthias // @version 1.0.0 // @description Adds a download button to the HTML5 Vimeo Player (embeded or not) // @author Matthias Laroche // @license https://creativecommons.org/licenses/by/4.0/ // @include *//vimeo.com/* // @include *//player.vimeo.com/video/* // @run-at document-start // @grant unsafeWindow // @compatible Tampermonkey // @incompatible Greasemonkey // ==/UserScript== (function() { 'use strict'; // Syntactic sugar for getting a single node with XPath function getSingleNode(node, xpath) { var doc = node.ownerDocument || node; return doc.evaluate(xpath, node, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; } // Syntactic sugar for XMLHttpRequest function ajax(url, postData, onSuccess, onError) { var xhr = new XMLHttpRequest(); xhr.open(postData ? 'POST' : 'GET', url); if (onSuccess || onError) { xhr.onreadystatechange = function() { if (xhr.readyState != 4) return; if (xhr.status == 200 && onSuccess) onSuccess(xhr); if (xhr.status != 200 && onError) onError(xhr); }; } xhr.send(postData || null); } // Wraps a property with a callback that convert the value each time the property is set function wrapProperty(o, propName, callback) { if (o.hasOwnProperty(propName)) return; var value; Object.defineProperty(o, propName, { get: function() { return value; }, set: function(newValue) { value = callback(newValue); }, enumerable: true, configurable: false }); } // SVG icon of the download button // Icon made by Elegant Themes from www.flaticon.com // Icon pack: http://www.flaticon.com/packs/elegant-font // Published by: https://www.elegantthemes.com/ // License: https://creativecommons.org/licenses/by/3.0/ var downloadIcon = '<svg viewBox="0 0 455.992 455.992" width="14px" height="14px">' + '<polygon class="fill" points="227.996,334.394 379.993,182.397 288.795,182.397 288.795,0 167.197,0 167.744,182.397 75.999,182.397" />' + '<polygon class="fill" points="349.594,334.394 349.594,395.193 106.398,395.193 106.398,334.394 45.599,334.394 45.599,395.193 45.599,455.992 410.393,455.992 410.393,334.394" />' + '</svg>'; // Create HTML div element to add to the controls bar function createButton(document, link) { var div = document.createElement('div'); div.style.marginLeft = '7px'; div.style.marginTop = '-1px'; div.setAttribute('class', 'download'); var a = document.createElement('a'); a.setAttribute('href', link.url); a.setAttribute('download', (link.title || '').replace(/[\x00-\x1F"*\/:<>?\\|]+/g, '')); a.setAttribute('target', '_blank'); a.setAttribute('title', 'Download ' + link.quality); a.setAttribute('aria-label', 'Download'); a.setAttribute('referrerpolicy', 'origin'); a.innerHTML = downloadIcon; div.appendChild(a); return div; } // Get url, quality and title of the video from the config parameter of the player function getVideoLink(config) { var title = config && config.video && config.video.title || ''; var progressive = config && config.request && config.request.files && config.request.files.progressive; if (progressive) { var file = progressive.reduce(function(a, b) { return (b.width || 0) > a.width ? b : a; }, { width: -1 }); if (file.url) { return { url:file.url, title: title, quality: file.quality}; } } return null; } // Called by the MutationObserver, keep adding the download button to the DOM if it disappears function showVideoLink(controls, link) { var download = getSingleNode(controls, "//div[@class = 'download']"); if (download) { if (download.nextSibling) { download.parentNode.appendChild(download); } return; } var playBar = getSingleNode(controls, "//div[contains(@class, 'play-bar')]"); if (!playBar) return; download = createButton(controls.ownerDocument, link); playBar.appendChild(download); } // Get the config if it's a URL, then get the link // and set a MutationObserver to add the download button when the controls are ready function tryShowVideoLink(player, config) { if (!player || !config) return; if (typeof(config) === 'string') { ajax(config, null, function(xhr) { var result = JSON.parse(xhr.responseText); tryShowVideoLink(player, result); }); return; } var link = getVideoLink(config); if (!link) return; var controls = getSingleNode(player, "//div[@class = 'controls-wrapper']//div[@class = 'controls']"); if (!controls) return; var observer = new MutationObserver(function() { showVideoLink(controls, link); }); observer.observe(controls, { childList: true, subtree: true, attributes: false, characterData: false }); showVideoLink(controls, link); } // Wrap the VimeoPlayer constructor and intercepts the arguments needed to install the download button wrapProperty(unsafeWindow, 'VimeoPlayer', function(newValue) { return newValue && function() { var player = arguments && arguments[0]; var config = arguments && arguments[1]; var result = newValue.apply(this, arguments); if (player && config) { tryShowVideoLink(player, config); } return result; }; }); })();