H5移动视频播放器增强

使视频元素支持长按倍速、上/下滑调节音量、左/右滑调节进度

// ==UserScript==
// @name         H5移动视频播放器增强
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  使视频元素支持长按倍速、上/下滑调节音量、左/右滑调节进度
// @author       tutu辣么可爱(greasyfork)/IcedWatermelonJuice(github)
// @run-at       document-start
// @match        *://*/*
// @require      https://greasyfork.org/scripts/455704-js-extensions-touchjs/code/js-Extensions-touchJS.js?version=1123827
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_setClipboard
// @grant        GM_notification
// @grant        GM_registerMenuCommand
// @grant        GM_info
// @icon         https://icedwatermelonjuice.github.io/Tools-Hub/favicon.ico
// @license      MIT
// ==/UserScript==

(function() {
	'use strict';
	const dataKey = "h5VideoMPlayerExtend";
	const scriptName = GM_info.script.name;
	var config = Object.assign({
		darkList: [],
	}, GM_getValue(dataKey) ? JSON.parse(GM_getValue(dataKey)) : {})
	var enable = true;
	var tempClose=false;
	var timer = -1;
	
	function vControl(target, v0, v1, cb) {
		var t = target,
			r = undefined;
		if (!target || typeof target !== "object" || !/video/i.test(t.tagName)) {
			return false
		}
		switch (v0) {
			case "p+":
				t.play();
				setTimeout(() => {
					t.play();
				}, 100);
				r = true;
				break;
			case "p-":
				t.pause();
				setTimeout(() => {
					t.pause();
				}, 100)
				r = false;
				break;
			case "p":
				r = !t.paused;
				break;
			case "v+":
				v1 = v1 ? parseFloat(v1) : 0.1;
				t.volume = (t.volume + v1).toFixed(2) <= 1 ? (t.volume + v1).toFixed(2) : 1;
				r = t.volume;
				break;
			case "v-":
				v1 = v1 ? parseFloat(v1) : 0.1;
				t.volume = (t.volume - v1).toFixed(2) >= 0 ? (t.volume - v1).toFixed(2) : 0;
				r = t.volume;
				break;
			case "v":
				if (parseFloat(v1)) {
					t.volume = v1;
				}
				r = t.volume;
				break;
			case "t+":
				v1 = parseFloat(v1) ? parseFloat(v1) : 0.1;
				t.currentTime = (t.currentTime + v1) <= t.duration ? (t.currentTime + v1) : t.duration;
				r = t.currentTime;
				break;
			case "t-":
				v1 = parseFloat(v1) ? parseFloat(v1) : 0.1;
				t.currentTime = (t.currentTime - v1) >= 0 ? (t.currentTime - v1) : 0;
				r = t.currentTime;
				break;
			case "t":
				if (parseFloat(v1)) {
					t.currentTime = v1;
				}
				r = t.currentTime;
				break;
			case "f+":
				t.webkitEnterFullScreen();
				r = true;
				break;
			case "f-":
				t.webkitExitFullScreen();
				r = false;
				break;
			case "f":
				r = (document.fullscreenElement === t);
				break;
			case "r":
				t.playbackRate = parseFloat(v1) ? parseFloat(v1) : 1;
				r = t.playbackRate;
				break;
			default:
				console.log(t);
				r = t;
				break;
		}
		typeof cb === "function" && cb(r)
		return r;
	}

	function videoExtend(target) {
		var longPressTimer = -1;
		target.setAttribute("mplayer-extended", "");
		touchJS.bind(target, "left", () => {
			enable && vControl(target, "t-");
		})
		touchJS.bind(target, "right", () => {
			enable && vControl(target, "t+");
		})
		touchJS.bind(target, "up", () => {
			enable && vControl(target, "v+");
		})
		touchJS.bind(target, "down", () => {
			enable && vControl(target, "v-");
		})
		touchJS.bind(target, "longPress", () => {
			longPressTimer = setInterval(() => {
				enable && vControl(target, "r", 3);
			}, 200)
		})
		touchJS.bind(target, "longPressCancel", () => {
			longPressTimer !== -1 && clearInterval(longPressTimer)
			longPressTimer = -1;
			enable && vControl(target, "r");
		})
	}

	try {
		if(config.darkList){
			config.darkList.forEach((url) => {
				if (location.href.search(url) !== -1) {
					throw Error()
				}
			})
		}
	} catch (e) {
		enable = false;
	}
	GM_registerMenuCommand('临时关闭功能', function() {
		if(enable){
			enable=false;
			tempClose=true;
			GM_notification(`临时关闭脚本功能,刷新网页恢复`, scriptName);
		}else{
			alert("此域名已经在黑名单内");
		}
	});
	GM_registerMenuCommand('添加到黑名单', function() {
		enable = false;
		tempClose=false;
		config.darkList.push(location.hostname);
		GM_setValue(dataKey, JSON.stringify(config));
		GM_notification(`已添加 ${location.hostname} 到黑名单,脚本功能关闭`, scriptName);
	});
	GM_registerMenuCommand('清空已有黑名单', function() {
		config.darkList = [];
		GM_setValue(dataKey, JSON.stringify(config));
		GM_notification(`清空域名黑名单成功,请刷新网页以应用新配置`, scriptName);
	});
	GM_registerMenuCommand('导出配置信息', function() {
		GM_setClipboard(JSON.stringify(config), "text");
		GM_notification(`导出配置信息成功`, scriptName);
	});
	GM_registerMenuCommand('导入配置信息', function() {
		let data = prompt("请粘贴配置信息");
		if (data && data.trim()) {
			try {
				data = JSON.parse(data);
				config = Object.assign(config, data);
				GM_setValue(dataKey, JSON.stringify(config));
			} catch (e) {
				GM_notification(`导入配置信息失败`, scriptName);
				return false
			}
			GM_notification(`导入配置信息成功`, scriptName);
		}
	});
	GM_registerMenuCommand('重置脚本配置', function() {
		config={}
		GM_setClipboard(JSON.stringify(config), "text");
		GM_notification(`重置脚本配置成功`, scriptName);
	});
	GM_registerMenuCommand('脚本相关信息', function() {
		let data=`脚本相关信息:\n名称:${scriptName}\n作者:${GM_info.script.author}\n版本:${GM_info.script.version}\n状态:${enable?"正常启用":(tempClose?"临时关闭":"黑名单")}`
		alert(data)
	});
	timer = setInterval(() => {
		let v = document.querySelectorAll("video:not([mplayer-extended])");
		v.forEach((e) => {
			videoExtend(e);
		})
	}, 500)
	console.log(`${scriptName} 主程序500ms定时器ID:${timer}`)
})();