Warning: fopen(/www/sites/update.greasyfork.icu/index/store/forever/84b1b4f5c4c483642d7e559cc57d15b2.js): failed to open stream: No space left on device in /www/sites/update.greasyfork.icu/index/scriptControl.php on line 65
// ==UserScript== // @name 全能视频播放器速度控制(最大16倍速) // @namespace http://tampermonkey.net/ // @version 4.1.0 // @author 不会起名 // @description 支持【B站】【爱奇艺】【腾讯视频】【优酷】...等网站 // @license MIT // @icon https://vitejs.dev/logo.svg // @match *://*.youtube.com/watch* // @match *://*.bilibili.com/video/* // @match *://v.qq.com/x/cover/* // @match *://www.youku.com/video?* // @match *://*.netflix.com/watch/* // @match *://*.dailymotion.com/video/* // @match *://*.twitch.tv/*/videos/* // @match *://*.vimeo.com/* // @match *://*.huya.com/* // @match *://*.douyu.com/* // @match *://*.tudou.com/listplay/* // @match *://*.tudou.com/albumplay/* // @match *://*.tudou.com/programs/view/* // @match *://*.tudou.com/v* // @match *://*.bilibili.com/anime/* // @match *://*.bilibili.com/bangumi/play/* // @match *://m.youku.com/v* // @match *://m.youku.com/a* // @match *://v.youku.com/v_* // @match *://v.youku.com/pad_show* // @match *://*.iqiyi.com/v_* // @match *://*.iqiyi.com/w_* // @match *://*.iqiyi.com/a_* // @match *://*.iqiyi.com/adv* // @match *://*.iq.com/play/* // @match *://v.yinyuetai.com/video/* // @match *://v.yinyuetai.com/playlist/* // @match *://*.pptv.com/show/* // @match *://www.yuque.com/r/goto* // @match *://*.xiaohongshu.com/explore* // @match *://tv.wandhi.com/go.html* // @match *://tv.wandhi.com/check.html // @match *://*.zhihu.com/question* // @require https://cdn.jsdelivr.net/npm/vue@3.5.14/dist/vue.global.prod.js // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @downloadURL none // ==/UserScript== (e=>{if(typeof GM_addStyle=="function"){GM_addStyle(e);return}const o=document.createElement("style");o.textContent=e,document.head.append(o)})(" #speed-control.light[data-v-6c9df88d]{--bg-color: #e4ebf5;--text-color: #9baacf;--Shadow-color1: #c8d0e7;--Shadow-color2: #ffffff}#speed-control.dark[data-v-6c9df88d]{--bg-color: #696969;--text-color: #ffffff;--Shadow-color1: #4a4a4a;--Shadow-color2: #929292}#speed-control.fold[data-v-6c9df88d]{--width: 200px;--height: 147px}#speed-control.unfold[data-v-6c9df88d]{--width: 140px;--height: 22px}#speed-control[data-v-6c9df88d]{--controlBorder: #dddddd;position:fixed;top:20px;left:20px;z-index:9999;border-radius:5px;padding:10px;width:var(--width);height:var(--height);font-size:12px;line-height:1.5;background-color:var(--bg-color);color:var(--text-color);border:1px solid #ffbdbd;transition:width .3s,height .3s,background-color .3s,color .3s,opacity .3s;overflow:hidden;-webkit-user-select:none;user-select:none;box-sizing:content-box;opacity:.7}#speed-control[data-v-6c9df88d]:hover{opacity:1;animation:borderShadow-6c9df88d 3s linear infinite}#speed-control .header[data-v-6c9df88d]{display:flex;justify-content:space-between;align-items:center;cursor:move}#speed-control .headerBtn[data-v-6c9df88d]{display:flex;justify-content:space-between;align-items:center;gap:10px}#speed-control .headerBtn button[data-v-6c9df88d]{width:35px;line-height:22px}#speed-control button[data-v-6c9df88d]{border-radius:3px;background-color:transparent;border:none;line-height:22px;box-shadow:3px 3px 6px var(--Shadow-color1),-2px -2px 5px var(--Shadow-color2);color:var(--text-color);cursor:pointer}#speed-control button[data-v-6c9df88d] :focus{outline:none}#speed-control button[data-v-6c9df88d]:focus,#speed-control button[data-v-6c9df88d]:focus-visible{outline:none}#speed-control button[data-v-6c9df88d]:active,#speed-control .numInputSpeed[data-v-6c9df88d]{box-shadow:inset 2px 2px 5px var(--Shadow-color1),inset -2px -2px 5px var(--Shadow-color2)!important}#speed-control .speedBtnList[data-v-6c9df88d]{display:flex;flex-wrap:wrap;margin:15px 0;justify-content:space-between;row-gap:10px}.speedBtnList button[data-v-6c9df88d]{width:30%}#speed-control .slider[data-v-6c9df88d]{--slider-width: 100%;--slider-height: 6px;--slider-border-radius: 999px;--level-transition-duration: .1s;--level-color: var(--Shadow-color2)}#speed-control .slider[data-v-6c9df88d]{display:flex;align-items:center;cursor:pointer}#speed-control .slider .level[data-v-6c9df88d]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:var(--slider-width);height:var(--slider-height);background-color:var(--text-color);overflow:hidden;border-radius:var(--slider-border-radius);-webkit-transition:height var(--level-transition-duration);-o-transition:height var(--level-transition-duration);transition:height var(--level-transition-duration);cursor:pointer}#speed-control .level[data-v-6c9df88d]::-webkit-slider-thumb{-webkit-appearance:none;width:0;height:0;-webkit-box-shadow:-200px 0 0 200px var(--level-color);box-shadow:-200px 0 0 200px var(--level-color)}#speed-control .slider:hover .level[data-v-6c9df88d]{height:calc(var(--slider-height) * 2)}#speed-control .numInputSpeed[data-v-6c9df88d]{position:relative;width:42px;height:22px;margin-left:10px;padding:3px 6px;text-align:center;border-radius:4px;border:none;color:var(--text-color);background-color:transparent}#speed-control .numInputSpeed[data-v-6c9df88d]::-webkit-inner-spin-button,#speed-control .numInputSpeed[data-v-6c9df88d]::-webkit-outer-spin-button{-webkit-appearance:none;display:none;margin:0}#speed-control .number-input[data-v-6c9df88d]{display:flex;align-items:center;gap:5px}#speed-control .controls[data-v-6c9df88d]{display:flex;flex-direction:column;gap:5px}#speed-control .controls button[data-v-6c9df88d]{border:none;cursor:pointer;padding:0 5px;font-size:10px;line-height:1.2}#speed-control .controls button[data-v-6c9df88d]:hover{color:#000}@keyframes borderShadow-6c9df88d{0%{filter:hue-rotate(0deg)}to{filter:hue-rotate(360deg)}} "); (function (vue) { 'use strict'; var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)(); var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)(); const _export_sfc = (sfc, props) => { const target = sfc.__vccOpts || sfc; for (const [key, val] of props) { target[key] = val; } return target; }; const _hoisted_1 = { class: "headerBtn" }; const _hoisted_2 = ["textContent"]; const _hoisted_3 = ["textContent"]; const _hoisted_4 = { class: "speedBtnList" }; const _hoisted_5 = ["onClick", "textContent"]; const _hoisted_6 = { class: "slider" }; const _hoisted_7 = ["min", "max", "step"]; const _hoisted_8 = { class: "number-input" }; const _hoisted_9 = ["min", "max", "step"]; const _hoisted_10 = { class: "controls" }; const _sfc_main = { __name: "App", setup(__props) { const SPEED = { MIN: 0.1, MAX: 16, STEP: 0.05 }; const PRESET = [0.5, 0.65, 0.85, 1, 1.15, 1.25]; const theme = vue.ref(_GM_getValue("theme", "light")); const isFold = vue.ref(_GM_getValue("isFold", "fold")); const position = vue.ref(_GM_getValue("savedPosition", { x: 20, y: 20 })); const speed = vue.ref(1); const numInputSpeed = vue.ref(null); const mediaElements = vue.ref([]); const updatePlaybackRate = () => { mediaElements.value = [...document.querySelectorAll("video, audio")]; mediaElements.value.forEach((media) => { console.log("mediaElements.value"); try { console.log("media", media); media.playbackRate = speed.value; } catch (e) { console.error("Error setting playback rate:", e); } }); }; const toggleTheme = () => { theme.value = theme.value === "light" ? "dark" : "light"; _GM_setValue("theme", theme.value); }; const toggleFold = () => { isFold.value = isFold.value === "fold" ? "unfold" : "fold"; _GM_setValue("isFold", isFold.value); }; const toggleSpeed = (speedVal) => { speed.value = speedVal; updatePlaybackRate(); }; const onMousedown = (e) => { const offsetX = e.clientX - position.value.x; const offsetY = e.clientY - position.value.y; const onMousemove = (e2) => { position.value.x = e2.clientX - offsetX; position.value.y = e2.clientY - offsetY; }; const onMouseup = () => { document.removeEventListener("mousemove", onMousemove); document.removeEventListener("mouseup", onMouseup); _GM_setValue("savedPosition", { ...position.value }); }; document.addEventListener("mousemove", onMousemove); document.addEventListener("mouseup", onMouseup); }; const increment = () => { speed.value = Math.min(SPEED.MAX, Math.round((speed.value + SPEED.STEP) * 100) / 100); updatePlaybackRate(); }; const decrement = () => { speed.value = Math.max(SPEED.MIN, Math.round((speed.value - SPEED.STEP) * 100) / 100); updatePlaybackRate(); }; const handleWheel = (event) => { requestAnimationFrame(() => { if (event.deltaY < 0) { increment(); } else { decrement(); } }); }; return (_ctx, _cache) => { return vue.openBlock(), vue.createElementBlock("div", { id: "speed-control", ref: "dragElement", class: vue.normalizeClass([vue.unref(theme), vue.unref(isFold)]), style: vue.normalizeStyle({ transform: `translate(${vue.unref(position).x}px, ${vue.unref(position).y}px)` }) }, [ vue.createElementVNode("div", { class: "header", onMousedown }, [ _cache[8] || (_cache[8] = vue.createElementVNode("div", null, "播放控制", -1)), vue.createElementVNode("div", _hoisted_1, [ vue.createElementVNode("button", { type: "button", onClick: _cache[0] || (_cache[0] = ($event) => toggleFold()), textContent: vue.toDisplayString(vue.unref(isFold) === "unfold" ? "▶" : "▼") }, null, 8, _hoisted_2), vue.createElementVNode("button", { type: "button", onClick: _cache[1] || (_cache[1] = ($event) => toggleTheme()), textContent: vue.toDisplayString(vue.unref(theme) === "dark" ? "🌞" : "🌙") }, null, 8, _hoisted_3) ]) ], 32), vue.createElementVNode("div", _hoisted_4, [ (vue.openBlock(), vue.createElementBlock(vue.Fragment, null, vue.renderList(PRESET, (item) => { return vue.createElementVNode("button", { type: "button", onClick: ($event) => toggleSpeed(item), key: item, textContent: vue.toDisplayString(item) }, null, 8, _hoisted_5); }), 64)) ]), vue.createElementVNode("div", null, "当前速度:" + vue.toDisplayString(vue.unref(speed)) + "x", 1), vue.createElementVNode("div", _hoisted_6, [ vue.withDirectives(vue.createElementVNode("input", { type: "range", min: SPEED.MIN, max: SPEED.MAX, step: SPEED.STEP, class: "level", onChange: _cache[2] || (_cache[2] = ($event) => { updatePlaybackRate(); }), "onUpdate:modelValue": _cache[3] || (_cache[3] = ($event) => vue.isRef(speed) ? speed.value = $event : null) }, null, 40, _hoisted_7), [ [ vue.vModelText, vue.unref(speed), void 0, { number: true } ] ]), vue.createElementVNode("div", _hoisted_8, [ vue.withDirectives(vue.createElementVNode("input", { type: "number", min: SPEED.MIN, max: SPEED.MAX, step: SPEED.STEP, ref_key: "numInputSpeed", ref: numInputSpeed, class: "numInputSpeed", onWheel: _cache[4] || (_cache[4] = vue.withModifiers(($event) => handleWheel($event), ["prevent"])), "onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => vue.isRef(speed) ? speed.value = $event : null) }, null, 40, _hoisted_9), [ [ vue.vModelText, vue.unref(speed), void 0, { number: true } ] ]), vue.createElementVNode("div", _hoisted_10, [ vue.createElementVNode("button", { class: "increment", onClick: _cache[6] || (_cache[6] = ($event) => increment()) }, "▲"), vue.createElementVNode("button", { class: "decrement", onClick: _cache[7] || (_cache[7] = ($event) => decrement()) }, "▼") ]) ]) ]) ], 6); }; } }; const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-6c9df88d"]]); vue.createApp(App).mount( (() => { const app = document.createElement("div"); document.body.append(app); return app; })() ); })(Vue);