临时倍速(按下按键临时改变视频速度)

一个按下键盘按键时改变视频速度松开还原的插件,可以自定义快捷键和自定义速度

  1. // ==UserScript==
  2. // @name 临时倍速(按下按键临时改变视频速度)
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.21
  5. // @description 一个按下键盘按键时改变视频速度松开还原的插件,可以自定义快捷键和自定义速度
  6. // @author CloudTree
  7. // @grant GM_setValue
  8. // @grant GM_getValue
  9. // @grant GM_registerMenuCommand
  10. // @match http://*/*
  11. // @include *
  12. // @license GPL-3.0 License
  13. // ==/UserScript==
  14.  
  15. (function () {
  16. 'use strict';
  17. /*-------------------对象---------------------------- */
  18.  
  19. //储存用户设置
  20. var Data = (function () {
  21. //构造
  22. var NewData = function () {
  23. this.dataList = [];
  24. this.version = version;
  25. var that = this;
  26. var loaded = this.load();
  27. if (loaded === false) {
  28. this.defaultData();
  29. this.save();
  30. }
  31. eventLoop.addListener(function () {
  32. that.save()
  33. })
  34. }
  35. //----------私有对象--------
  36. //储存一套信息
  37. var DataCell = (function () {
  38. //构造
  39. var NewDataCell = function (archiveCell) {
  40. if (NewDataCell[archiveCell[0]]) {
  41. return new NewDataCell[archiveCell[0]](archiveCell);
  42. }
  43. };
  44. //创建一个shortTimeVup,用于临时加速
  45. NewDataCell.shortTimeVup = (function () {
  46. var NewShortTimeVup = function (archiveCell) {
  47. this.type = archiveCell[0];
  48. if (archiveCell.length > 1) {
  49. this.multiSpeed = new MultiSpeed(archiveCell[1]);
  50. this.comboKey = new ComboKey(archiveCell[2]);
  51. } else {
  52. this.multiSpeed = new MultiSpeed(3.5);
  53. this.comboKey = new ComboKey(["c"]);
  54. }
  55. };
  56. NewShortTimeVup.prototype.save = function () {
  57. var archiveCell = [];
  58. archiveCell.push(this.type);
  59. archiveCell.push(this.multiSpeed.save());
  60. archiveCell.push(this.comboKey.save());
  61. return archiveCell;
  62. }
  63. return NewShortTimeVup;
  64. })();
  65. return NewDataCell;
  66. })();
  67. /**
  68. * -------基础data类型----
  69. * 接口
  70. * 构造()
  71. * copyKey(event)从键盘事件中提取信息,提取成功返回"true",失败返回event.key.toLowerCase();
  72. * newObj()返回一个新的实例
  73. * copy(obj)复制同类实例的数据,成功返回true,失败返回false
  74. * toString()返回用于显示的字符串
  75. * save()返回用于存入储存中的数据
  76. */
  77. // 储存倍速的信息
  78. var MultiSpeed = (function () {
  79. // 构造
  80. var NewMultiSpeed = function (speed) {
  81. this.speed = speed;
  82. this.str = "";
  83. }
  84. NewMultiSpeed.prototype.copyKey = function (event) {
  85. if (/^[\d]$/.test(event.key)) {
  86. this.str += event.key;
  87. this.speed = +this.str;
  88. return "true";
  89. } else if (event.key === ".") {
  90. if (/\./.test(this.str)) {
  91. return "true";
  92. } else {
  93. this.str += ".";
  94. this.speed = +this.str;
  95. return "true";
  96. }
  97. } else if (event.key === "Backspace") {
  98. this.str = this.str.replace(/.$/, "");
  99. this.speed = +this.str;
  100. return "true";
  101. } else if (event.key === "Delete") {
  102. this.str = "";
  103. this.speed = +this.str;
  104. return "true";
  105. }
  106. return event.key.toLowerCase();
  107. }
  108. //新建一个实例
  109. NewMultiSpeed.prototype.newObj = function () {
  110. return new NewMultiSpeed();
  111. }
  112. //用于从另一个实例中拷贝信息
  113. NewMultiSpeed.prototype.copy = function (obj) {
  114. if (obj.speed > 0 && obj.speed < 16) {
  115. this.speed = obj.speed;
  116. } else {
  117. this.speed = 3;
  118. }
  119. eventLoop.sendEvent();
  120. return true;
  121. };
  122. // 输出用于显示速度的字符串
  123. NewMultiSpeed.prototype.toString = function () {
  124. if (this.speed) {
  125. var str;
  126. // https://www.cnblogs.com/NazLee/p/11646023.html
  127. str = this.speed //.toFixed(2);
  128. // e.g. int 2 => "2.00" float 1.1 => "1.10"
  129. str = "\u2716 " + str;
  130. // e.g. "2.00" => "x 2.00"
  131. return str;
  132. } else {
  133. return ". . .";
  134. }
  135. }
  136. //输出用于储存的信息
  137. NewMultiSpeed.prototype.save = function () {
  138. return this.speed;
  139. }
  140. return NewMultiSpeed;
  141. })();
  142. // 储存组合键的对象的构造函数
  143. var ComboKey = (function () {
  144. // 静态成员
  145. var counter = 0,
  146. NewComboKey;
  147. // 新构造函数的实现(调用counter,创建了一个"闭包")
  148. NewComboKey = function ([key, shiftKey, ctrlKey, altKey]) {
  149. this.key = key ? key.toUpperCase() : "";
  150. this.shiftKey = shiftKey ? true : false;
  151. this.ctrlKey = ctrlKey ? true : false;
  152. this.altKey = altKey ? true : false;
  153. counter++;
  154. }
  155. // ----------------静态方法-------------
  156. // 获得实例总数
  157. NewComboKey.getCounter =
  158. NewComboKey.prototype.getCounter = function () {
  159. return counter;
  160. }
  161. // ---------------实例方法---------------
  162. //读取键盘事件
  163. NewComboKey.prototype.copyKey = function (event) {
  164. // if(event.key ===">"){
  165. // return event.key.toLowerCase();
  166. // }else
  167. if ((event.key.length < 2) && Boolean(event.key)) {
  168. this.key = event.key.toUpperCase();
  169. this.shiftKey = event.shiftKey;
  170. this.ctrlKey = event.ctrlKey;
  171. this.altKey = event.altKey;
  172. return "true";
  173. } else if (event.key === "Delete") {
  174. this.key = "";
  175. return "true";
  176. } else if (event.key === "Backspace") {
  177. this.key = null;
  178. return "true";
  179. } else {
  180. return event.key.toLowerCase();
  181. }
  182. }
  183. //新建一个实例
  184. NewComboKey.prototype.newObj = function () {
  185. return new NewComboKey([]);
  186. }
  187. //用于从另一个实例中拷贝信息
  188. NewComboKey.prototype.copy = function (obj) {
  189. if (obj.key) {
  190. this.key = obj.key.toUpperCase();
  191. this.shiftKey = obj.shiftKey;
  192. this.ctrlKey = obj.ctrlKey;
  193. this.altKey = obj.altKey;
  194. eventLoop.sendEvent();
  195. return true;
  196. }
  197. return false;
  198. };
  199. // 转为字符串
  200. NewComboKey.prototype.toString = function () {
  201. if (this.key) {
  202. var str = "";
  203. str += this.shiftKey ? "shift + " : "";
  204. str += this.ctrlKey ? "ctrl + " : "";
  205. str += this.altKey ? "alt + " : "";
  206. str += this.key ? this.key : "";
  207. //.toLowerCase()
  208. return str;
  209. } else {
  210. return ". . ."
  211. }
  212. }
  213. //输出用于储存的信息
  214. NewComboKey.prototype.save = function () {
  215. return [this.key, this.shiftKey, this.ctrlKey, this.altKey];
  216. }
  217. // 按下的键是否满足条件,支持返回true
  218. NewComboKey.prototype.isKeyDown = function (event) {
  219. var isDown = (this.key === event.key.toUpperCase()) &&
  220. (this.shiftKey === event.shiftKey) &&
  221. (this.ctrlKey === event.ctrlKey) &&
  222. (this.altKey === event.altKey);
  223. return isDown;
  224. };
  225. // 松开键后是否已不满足条件,不支持返回true
  226. NewComboKey.prototype.isKeyUp = function (event) {
  227. var isUp = (this.key === event.key.toUpperCase()) ||
  228. (this.shiftKey !== event.shiftKey) ||
  229. (this.ctrlKey !== event.ctrlKey) ||
  230. (this.altKey !== event.altKey);
  231. return isUp;
  232. }
  233. // 是否为有效组合键
  234. NewComboKey.prototype.isNormCombo = function (event) {
  235. return ((event.key.length < 2) && Boolean(event.key));
  236. }
  237. return NewComboKey;
  238. })();
  239. //---------实例方法---------
  240. //插入一套设置
  241. NewData.prototype.append = function (archiveCell, index) {
  242. if (index === undefined) {
  243. this.dataList.push(new DataCell(archiveCell))
  244. }
  245. };
  246. //删除一套设置
  247. NewData.prototype.delete = function () {};
  248. //读取储存中的数据
  249. NewData.prototype.load = function () {
  250. var archiveList = GM_getValue("data" + this.version);
  251. console.log(archiveList);
  252. if (archiveList) {
  253. archiveList.forEach(archiveCell => {
  254. this.append(archiveCell)
  255. });
  256. eventLoop.sendEvent();
  257. return true;
  258. } else {
  259. return false;
  260. }
  261. };
  262. //写入数据到储存中
  263. NewData.prototype.save = function () {
  264. var archiveList = [];
  265. for (let index = 0; index < this.dataList.length; index++) {
  266. archiveList.push(this.dataList[index].save());
  267. }
  268. GM_setValue("data" + this.version, archiveList);
  269. this.timeStamp = new Date().getTime();
  270. GM_setValue("timeStamp" + this.version, this.timeStamp)
  271. };
  272. //生成一套初始数据
  273. NewData.prototype.defaultData = function () {
  274. this.append(["shortTimeVup"])
  275. };
  276. //数据更新
  277. NewData.prototype.refresh = function () {};
  278. //---------私有方法---------
  279. return NewData;
  280. })();
  281.  
  282. //用于实现功能
  283. var Controller = (function () {
  284. var NewController = function (dataObj) {
  285. //console.log("Controller 创建成功");
  286. this.dataObj = dataObj;
  287. this.controllerList = [];
  288. for (let index = 0; index < dataObj.dataList.length; index++) {
  289. let cell = dataObj.dataList[index]
  290. if (makeController[cell.type]) {
  291. this.controllerList.push(new makeController[cell.type](cell))
  292. }
  293. }
  294. //console.log(dataObj);
  295. };
  296. var makeController = {};
  297. makeController.shortTimeVup = (function () {
  298. //构造
  299. var NewShortTimeVup = function (dataCell) {
  300. var videoInitialSpeed = [];
  301. //保存数据
  302. this.dataCell = dataCell;
  303. //更改速度
  304. function speedChange(event) {
  305. //console.log(event);
  306. //console.log(dataCell.comboKey.isKeyDown(event));
  307. if (dataCell.comboKey.isKeyDown(event)) {
  308. //console.log(event);
  309. // 获取video列表
  310. var videoList = document.getElementsByTagName("video");
  311. for (let i = 0; i < videoList.length; i++) {
  312. // 如果速度未改变设置视频速度
  313. if (videoList[i].playbackRate != dataCell.multiSpeed.speed) {
  314. console.log(videoList[i] + "开始加速");
  315. videoInitialSpeed[i] = videoList[i].playbackRate;
  316. videoList[i].playbackRate = dataCell.multiSpeed.speed;
  317. }
  318. }
  319. document.body.removeEventListener("keydown", speedChange);
  320. document.body.addEventListener("keyup", speedRestore);
  321. }
  322. };
  323.  
  324. //还原速度
  325. function speedRestore(event) {
  326. // console.log(event.key);
  327. if (dataCell.comboKey.isKeyUp(event)) {
  328. // 获取video列表
  329. var videoList = document.getElementsByTagName("video");
  330. for (let i = 0; i < videoList.length; i++) {
  331. console.log(videoList[i] + "停止加速");
  332. videoList[i].playbackRate = videoInitialSpeed[i];
  333. videoInitialSpeed[i] = undefined;
  334. //重新设定播放位置,用于解决音画不同步,导致卡顿
  335. //videoList[i].currentTime = videoList[i].currentTime;
  336. }
  337. document.body.addEventListener("keydown", speedChange);
  338. document.body.removeEventListener("keyup", speedRestore);
  339. }
  340. };
  341. document.body.addEventListener("keydown", speedChange);
  342. document.body.addEventListener("keyup", speedRestore);
  343. };
  344. return NewShortTimeVup;
  345. })();
  346. return NewController;
  347. })();
  348.  
  349. //用户界面
  350. var Ui = (function () {
  351. //构造
  352. var NewUi = function (dataObj) {
  353. this.menu = NewDiv(document.body, myBodyStyle);
  354. //创建cardList,保存所有card
  355. this.cardList = [];
  356. //遍历datalist,并创建
  357. for (let index = 0; index < dataObj.dataList.length; index++) {
  358. this.cardList.push(new Card(dataObj.dataList[index], this.menu));
  359. }
  360.  
  361. /*
  362. // 点击空白处隐藏菜单
  363. document.addEventListener("mousedown", nodeList.close);
  364. parent.onmousedown = function (event) {
  365. // 防止事件冒泡,导致菜单隐藏
  366. event.stopPropagation();
  367. }
  368. */
  369. new closeButton(this.menu);
  370. }
  371. //-----------------私有对象----------------
  372. //生成一个卡片
  373. var Card = (function () {
  374. var NewCard = function (dataCell, parent) {
  375. if (newCardList[dataCell.type]) {
  376. return new newCardList[dataCell.type](dataCell, parent);
  377. }
  378. };
  379. //储存各种card构造函数的对象
  380. var newCardList = {};
  381. newCardList.shortTimeVup = (function () {
  382. var newShortTimeVup = function (dataCell, parent) {
  383. // 返回一个Menu对象
  384. //包含当前对象所有元素的对象
  385. var nodeList = {};
  386. this.nodeList = nodeList;
  387. // 生成"倍速:"
  388. this.speedInputDiv = new inputDiv(parent, "倍速:", dataCell.multiSpeed);
  389. // 生成"快捷键:"
  390. this.keyInputDiv = new inputDiv(parent, "快捷键:", dataCell.comboKey);
  391. };
  392. //-----------------------私有对象------------------------------
  393. //生成一个 完整的输入栏(包括标题,按键,占位符,输入栏)
  394. var inputDiv = (function () {
  395. //构造
  396. var Div = function (parent, title, value) {
  397. //包含当前对象所有元素的对象
  398. var nodeList = {};
  399. this.nodeList = nodeList;
  400. this.value = value;
  401. this.displayValue = value;
  402. var that = this;
  403. // 生成title
  404. nodeList.textDiv = NewDiv(parent, myTextStyle, title);
  405. // 生成输入栏
  406. nodeList.inputDiv = NewDiv(parent, myInputDivStyle);
  407. // 使能聚焦
  408. nodeList.inputDiv.tabIndex = 0;
  409. // 栏内按键
  410. nodeList.buttonDiv = NewDiv(nodeList.inputDiv, myInnerButtonStyle, "\u21BB");
  411. // 占位
  412. nodeList.buttonDiv2 = NewDiv(nodeList.inputDiv, myInnerButtonStyle, "\u21BB");
  413. nodeList.buttonDiv2.style.float = "left";
  414. nodeList.buttonDiv2.style.visibility = "hidden";
  415. // 分割线
  416. nodeList.boundaryDiv1 = NewDiv(parent, myBetweenLineStyle);
  417. // 绑定inputDiv的事件
  418. nodeList.inputDiv.addEventListener("focus", isFocus);
  419. nodeList.inputDiv.addEventListener("blur", isBlur);
  420. //绑定事件的函数
  421. //成为焦点时,创建value缓存,将显示值设置为value缓存
  422. function isFocus() {
  423. //新建一个按键缓存
  424. that.displayValue = value.newObj();
  425. that.refresh();
  426. //读取键盘事件
  427. document.body.addEventListener("keydown", copyKey);
  428. //设置栏内按键
  429. nodeList.buttonDiv.setText("\u2714");
  430. nodeList.buttonDiv.addEventListener("mouseup", save);
  431. }
  432. //取消焦点时,清除缓存.刷新显示值
  433. function isBlur() {
  434. //重新连接到实际value
  435. that.displayValue = that.value;
  436. that.refresh();
  437. // 停止读取键盘事件
  438. document.body.removeEventListener("keydown", copyKey);
  439. //设置栏内按键
  440. nodeList.buttonDiv.setText("\u21BB");
  441. nodeList.buttonDiv.removeEventListener("mouseup", save);
  442. console.log("blur!");
  443. }
  444. //value缓存读取输入值
  445. function copyKey(event) {
  446. var result = that.displayValue.copyKey(event);
  447. if (result === "true") {
  448. that.refresh();
  449. } else if (result === "escape") {
  450. nodeList.inputDiv.blur();
  451. } else if (result === "enter") {
  452. save();
  453. } else {}
  454. }
  455. //储存输入值
  456. function save() {
  457. that.value.copy(that.displayValue);
  458. nodeList.inputDiv.blur();
  459. }
  460. };
  461. //---------------实例方法-----------
  462. //设置内容
  463. Div.prototype.setText = function (text) {
  464. this.nodeList.inputDiv.setText(text);
  465. return this;
  466. }
  467. //刷新内容
  468. Div.prototype.refresh = function () {
  469. this.setText(this.displayValue.toString());
  470. }
  471. return Div;
  472. /*
  473. nodeList.speedInputDiv.onmousedown = function (event) {
  474. // 清空文本
  475. setDivText(nodeList.speedInputDiv);
  476. // 防止冒泡到Menu
  477. event.stopPropagation();
  478. // 如果点击别处,恢复原状
  479. parent.addEventListener("mousedown", openSetMenu);
  480. }
  481. */
  482. })();
  483. //-----------------------实例方法------------------------------
  484. //刷新内容
  485. newShortTimeVup.prototype.refresh = function () {
  486. this.keyInputDiv.refresh();
  487. this.speedInputDiv.refresh();
  488. }
  489. return newShortTimeVup;
  490. })();
  491. return NewCard;
  492. })();
  493. // 生成一个设置过style的div
  494. // style格式注意addStyle内注释
  495. var NewDiv = (function () {
  496. //构造
  497. var Div = function (parent, style, text) {
  498. var div = document.createElement("div");
  499. parent.appendChild(div);
  500. div.setText = setText;
  501. if (style) {
  502. addStyle(div, style)
  503. };
  504. if (text) {
  505. div.setText(text)
  506. };
  507. return div;
  508. };
  509. //-------------------私有函数------------------
  510. //注入外联样式的函数
  511. var addStyle = (function () {
  512. // 给元素注入css的函数,
  513. // 构造函数接收element,styleStr//暂无,important
  514. // id插入element
  515. // stylrNode插入的style节点插入element
  516. // 私有静态变量
  517. var timeStamp = new Date().getTime();
  518. // 私有函数
  519. /*添加伪类名对应的类名,
  520. *被替换的伪类前为my开头的class,
  521. *名称中只能有-,_,a-z,A-Z,0-9*/
  522. function addPseudoInClass(style) {
  523. var regexp = /(\.my[a-z0-9\_\-]*):([a-z]+\b)/gi;
  524. var newSubStr = "$1:$2,$1.$2";
  525. return style.replace(regexp, newSubStr);
  526. };
  527. // 获得一个新时间戳
  528. // 生成不重复的时间戳
  529. function createTimeStamp() {
  530. var newTimeStamp = new Date().getTime();
  531. while (newTimeStamp == timeStamp) {
  532. newTimeStamp = new Date().getTime();
  533. }
  534. timeStamp = newTimeStamp;
  535. return newTimeStamp;
  536. };
  537. // 获取一个不会重复的id
  538. function createId() {
  539. var handName = "my-Video-Controller-";
  540. return handName +
  541. (createTimeStamp() * 36)
  542. .toString(36);
  543. };
  544. // 去掉字符串中的注释
  545. function delNote(str) {
  546. var regexp = /\/\*.*?\*\//g;
  547. return str.replace(regexp, "");
  548. }
  549. // 用id替换str中的my开头的class
  550. // 名称中只能有-,_,a-z,A-Z,0-9
  551. // id前不要加#,使用createId提供的id
  552. function classToId(style, id) {
  553. var regexp = /\.my[a-z][a-z0-9\_\-]*/gi;
  554. return style.replace(regexp, "#" + id);
  555. }
  556. // 将style注入head
  557. function injectStyle(style) {
  558. var myStyleNode = document.createElement("style");
  559. myStyleNode.innerHTML += style;
  560. document.head.appendChild(myStyleNode);
  561. return myStyleNode;
  562. }
  563.  
  564. // 返回函数,形成闭包
  565. return function addStyle(elemt, styleStr) {
  566. // 设置元素id
  567. elemt.id = createId();
  568. // 去掉字符串中的注释
  569. styleStr = delNote(styleStr);
  570. // 添加伪类名对应的类名
  571. styleStr = addPseudoInClass(styleStr);
  572. // 用id替换str中的字母开头的class
  573. styleStr = classToId(styleStr, elemt.id);
  574. // 注入style
  575. elemt.styleNode = injectStyle(styleStr);
  576. }
  577. })();
  578. // 修改div内文本,如果text为空,则改为空
  579. function setText(text) {
  580. if (!this.textSpan) {
  581. this.textSpan = document.createElement("span");
  582. this.appendChild(this.textSpan);
  583. }
  584. this.textSpan.innerHTML = text;
  585. return this;
  586. }
  587. return Div;
  588. })();
  589. //生成关闭按钮
  590. var closeButton = (function () {
  591. var Div = function (parent) {
  592. this.buttonFClose = NewDiv(parent, myBackButtonStyle, "\u2716");
  593. this.buttonFClose.addEventListener("mouseup", function () {
  594. close(parent);
  595. });
  596. };
  597. return Div;
  598. })();
  599. //---------------私有变量------------------
  600. // 样式表
  601. {
  602. var myBodyStyle = ".myBodyStyle {/* 相对于视口定位的 */position: fixed;/* 设置相对视窗位置 */top: 50px;right: 50px;/* 透明背景 */background: #1112;/* 设置元素的堆叠顺序 */z-index: 99999;/* 毛玻璃特效 */backdrop-filter: blur(1.5px);/* 内边距 */Padding: 0px;/* 溢出部分隐藏 */overflow: hidden;/* 圆角 */border-radius: 5px;/* 宽度 */width: 250px;/* transition: all 250ms cubic-bezier(.02, .01, .47, 1); *//* 应用过渡属性的属性名称 */transition-property: all;/* 过渡效果的速度曲线 */transition-timing-function: ease;/* 过渡动画所需的时间 */transition-duration: 0.5s;/* 过渡效果开始作用之前需要等待的时间 */transition-delay: 0.1s;/* 设置字体 */font-family: 'Microsoft YaHei', 'Segoe UI Symbol';/* 行高 */line-height: 1.6;/* 字间距 */letter-spacing: 0.163em;/* 粗细 */font-weight: 400;/* 字形 */font-style: normal;}.myBodyStyle:hover {/* x偏移量 | y偏移量 | 阴影模糊半径 | 阴影扩散半径 | 阴影颜色 */box-shadow: 5px 5px 8px 0px #0005;/* 毛玻璃特效 */backdrop-filter: blur(5px);/* 平移 */transform: translate(-1px, -1px);/* 过渡效果开始作用之前需要等待的时间 */transition-delay: 0s;}"
  603. var myTextStyle = ".myTextStyle {/* 宽度,高度 */width: 30%;height: 18px;/* 轮廓线 */border: 0;/* 转为块元素 */display: block;/* 外边距 *//* 上边 | 右边 | 下边 | 左边 */margin: 5px auto 5px 5px;/* 背景颜色 */background: #FFF;/* 内边距 */padding: 2px auto;/* 字号 */font-size: 12px;/* 圆角 */border-radius: 8px;/* 文字居中 */text-align: center;line-height: 150%;/* 禁止选中 */user-select: none;}"
  604. var myBetweenLineStyle = ".myBetweenLineStyle {/* 宽度,高度 */width: 90%;height: 4px;/* 轮廓线 */border: 0;/* 转为块元素 */display: block;/* 外边距 *//* 上边 | 右边 | 下边 | 左边 */margin: 7px auto;/* 毛玻璃特效 */backdrop-filter: blur(5px);/* 背景颜色 */background: #fff3;/* 圆角 */border-radius: 4px;}"
  605. var myBackButtonStyle = ".myBackButtonStyle {/* 宽度,高度 */width: 17px;height: 17px;/* 手形标志 */cursor: pointer;/* 背景颜色 */background: #FFF;/* 文字居中 */text-align: center;/* 字符大小 */font-size: 12px;/* 行高 */line-height: 1.4;/* 字间距 */letter-spacing: 0.011em;/* 粗细 */font-weight: 400;/* 字体样式 */font-style: normal;/* 字体颜色 */color: #999;/* 圆角 */border-radius: 100%;/* 外边距 *//* 上边 | 右边 | 下边 | 左边 */margin: 5px auto;/* 禁止选中 */user-select: none;/* 应用过渡属性的属性名称 */transition-property: all;/* 过渡效果的速度曲线 */transition-timing-function: ease;/* 过渡动画所需的时间 */transition-duration: 0.3s;/* 过渡效果开始作用之前需要等待的时间 */transition-delay: 0.1s;}.myBackButtonStyle:hover {/* x偏移量 | y偏移量 | 阴影模糊半径 | 阴影扩散半径 | 阴影颜色 */box-shadow: 2px -2px 5px 0px #0005;/* 平移 放大 */transform: translate(-1px, -1px) rotate(0.25turn);/* 过渡动画所需的时间 */transition-duration: 0.2s;/* 过渡效果开始作用之前需要等待的时间 */transition-delay: 0s;}.myBackButtonStyle:active {/* x偏移量 | y偏移量 | 阴影模糊半径 | 阴影扩散半径 | 阴影颜色 */box-shadow: none;/* 过渡动画所需的时间 */transition-duration: 0.1s;/* 平移 */transform: rotate(0.25turn);/* 过渡效果开始作用之前需要等待的时间 */transition-delay: 0s;}"
  606. var myInputDivStyle = ".myInputDivStyle {/* 隐藏输入光标 */caret-color: #0000;/* 隐藏多余 */overflow: hidden;/* 宽度,高度 */width: 96%;height: 22px;/* 手型标准 */cursor: pointer;/* 轮廓线 */border: 0;/* 转为块元素 */display: block;/* 外边距 */margin: 5px auto;/* 背景颜色 */background: #FFF;/* 内边距上边 | 右边 | 下边 | 左边*/padding: 2px auto;/* 字号 */font-size: 14px;/* 圆角 */border-radius: 8px;/* 文字居中 */text-align: center;/* 禁止选中 */user-select: none;/* 应用过渡属性的属性名称 */transition-property: all;/* 过渡效果的速度曲线 */transition-timing-function: ease;/* 过渡动画所需的时间 */transition-duration: 0.3s;/* 过渡效果开始作用之前需要等待的时间 */transition-delay: 0.1s;}.myInputDivStyle:hover,.myInputDivStyle:focus {/* x偏移量 | y偏移量 | 阴影模糊半径 | 阴影扩散半径 | 阴影颜色 */box-shadow: 2px 2px 5px 0px #0005;/* 平移 放大 */transform: translate(-1px, -1px);/* 过渡动画所需的时间 */transition-duration: 0.2s;/* 过渡效果开始作用之前需要等待的时间 */transition-delay: 0s;}.myInputDivStyle:active {/* x偏移量 | y偏移量 | 阴影模糊半径 | 阴影扩散半径 | 阴影颜色 */box-shadow: none;/* 过渡动画所需的时间 */transition-duration: 0.1s;/* 平移 */transform: none;/* 过渡效果开始作用之前需要等待的时间 */transition-delay: 0s;}.myInputDivStyle:focus {/* 颜色 | 样式 | 宽度 */outline: rgb(88, 88, 88) solid 1px;}"
  607. var myInnerButtonStyle = ".myInnerButtonStyle {/* 浮动 */float: right;/* 宽度,高度 */width: 17px;height: 17px;/* 背景颜色 */background: #888;/* 文字居中 */text-align: center;/* 字符大小 */font-size: 12px;/* 行高 */line-height: 1.2;/* 字间距 */letter-spacing: 0.011em;/* 粗细 */font-weight: 400;/* 字体样式 */font-style: normal;/* 字体颜色 */color: #eee;/* 圆角 */border-radius: 100%;/* 外边距上边 | 右边 | 下边 | 左边 */margin: 2px 4px 2px auto;/* 过渡动画所需的时间 */transition-duration: 0.5s;}.myInnerButtonStyle:hover {/* 背景颜色 */background: #666;}"
  608. }
  609. //-----------------实例方法-----------------
  610. //打开菜单
  611. NewUi.prototype.open = function () {
  612. open(this.menu);
  613. this.refresh();
  614. }
  615. //刷新菜单
  616. NewUi.prototype.refresh = function () {
  617. this.cardList.forEach(card => {
  618. card.refresh();
  619. });
  620. }
  621. //切换显示状态,建议改为rotateDisplay
  622. NewUi.prototype.overturnPlay = function () {
  623. if (this.menu.style.display) {
  624. this.open();
  625. } else {
  626. close(this.menu);
  627. }
  628. }
  629.  
  630. //-----------------私有方法--------------------
  631. //显示div
  632. function open(div) {
  633. // (function () {
  634. // this.style.setProperty("display", "", "");
  635. // }).call(div)
  636. div.style.setProperty("display", "", "");
  637. }
  638. //隐藏div
  639. function close(div) {
  640. // (function () {
  641. // this.style.setProperty("display", "none", "");
  642. // }).call(div)
  643. div.style.setProperty("display", "none", "");
  644. }
  645. return NewUi;
  646. })();
  647.  
  648. /*------------------------程序体---------------------------- */
  649. console.log("临时倍速 开始运行");
  650. //用于传递事件的载体
  651. var eventLoop = {};
  652. //发送和接收事件的载体
  653. eventLoop.eventLoop = document.createElement("div");
  654. //发出一个自定义事件
  655. eventLoop.sendEvent = function () {
  656. var myEvent = new Event("dataChange");
  657. this.eventLoop.dispatchEvent(myEvent);
  658. }
  659. //绑定函数到自己的自定义事件
  660. eventLoop.addListener = function (fun) {
  661. this.eventLoop.addEventListener("dataChange", fun);
  662. }
  663. //版本号,用于设置迁移
  664. var version = 0;
  665. // 火狐浏览器超过4倍速会没有声音,我没办法处理
  666. var myData = new Data();
  667. var myController = new Controller(myData);
  668. var myMenu;
  669.  
  670.  
  671. // 生成tampermonkey菜单
  672. GM_registerMenuCommand("显示设置面板", openSetMenu, '');
  673.  
  674. /*--------------------------函数---------------------------*/
  675. // 显示设置面板
  676. function openSetMenu() {
  677. if (!myMenu) {
  678. myMenu = new Ui(myData);
  679. myMenu.open();
  680. } else {
  681. myMenu.overturnPlay();
  682. }
  683. }
  684. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址