您需要先安装一个扩展,例如 篡改猴、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;
- };
- });
- })();