Cangshi-TimerHooker was reported 2021-06-07 by msoop as an unauthorized copy of TimerHooker.

TimerHooker uses the GPL-3.0-or-later license. Visit tldrlegal.com for help understanding what this license means.

msoop said:
The description of the original script: "转载,复用,修改该插件需注明出处".

This script should contain a link to the original script.
Script License Created Updated
Reported Cangshi-TimerHooker GPL-3.0-or-later 2021-01-24 14:16:13 UTC 2021-01-24 14:16:13 UTC
Original TimerHooker GPL-3.0-or-later 2018-09-29 02:18:11 UTC 2021-04-17 12:14:02 UTC
  • // ==UserScript==
  • -// @name 计时器掌控者|视频广告跳过|视频广告加速器
  • -// @name:en TimerHooker
  • -// @namespace https://gitee.com/HGJing/everthing-hook/
  • -// @updateURL https://gitee.com/HGJing/everthing-hook/raw/master/src/plugins/timeHooker.js
  • -// @version 1.0.62
  • -// @description 控制网页计时器速度|加速跳过页面计时广告|视频快进(慢放)|跳过广告|支持几乎所有网页.
  • -// @description:en it can hook the timer speed to change.
  • -
  • +// @name Cangshi-TimerHooker
  • +// @namespace https://greasyfork.org/en/users/104201
  • +// @version 1.0.57
  • +// @description 黄盐改版的→控制网页计时器速度|加速跳过页面计时广告|视频快进(慢放)|跳过广告|支持几乎所有网页.
  • // @include *
  • -// @require https://greasyfork.org/scripts/372672-everything-hook/code/Everything-Hook.js?version=881251
  • -// @author Cangshi
  • +// @author Cangshi,黄盐
  • // @match http://*/*
  • // @run-at document-start
  • // @grant none
  • * Time: 2017/11/20 19:28.
  • * Author: Cangshi
  • * View: http://palerock.cn
  • + *
  • + * 需要预加载脚本 https://gitee.com/HGJing/everthing-hook/raw/master/src/everything-hook.js
  • + * 黄盐 修改于 2021-1-24 21:07:48
  • + * @license GPL-3.0-or-later
  • * ---------------------------
  • */
  • -
  • -/**
  • - * 1. hook Object.defineProperty | Object.defineProperties
  • - * 2. set configurable: true
  • - * 3. delete property
  • - * 4. can set property for onxx event method
  • - */
  • -
  • window.isDOMLoaded = false;
  • window.isDOMRendered = false;
  • });
  • ~function (global) {
  • -
  • var workerURLs = [];
  • var extraElements = [];
  • - var suppressEvents = {};
  • var helper = function (eHookContext, timerContext, util) {
  • return {
  • + /***************禁用 BY 黄盐, PART 2 BEGIN
  • applyUI: function () {
  • var style = '._th-container ._th-item{margin-bottom:3px;position:relative;width:0;height:0;cursor:pointer;opacity:.3;background-color:aquamarine;border-radius:100%;text-align:center;line-height:30px;-webkit-transition:all .35s;-o-transition:all .35s;transition:all .35s;right:30px}._th-container ._th-item,._th-container ._th-click-hover,._th_cover-all-show-times ._th_times{-webkit-box-shadow:-3px 4px 12px -5px black;box-shadow:-3px 4px 12px -5px black}._th-container:hover ._th-item._item-x2{margin-left:18px;width:40px;height:40px;line-height:40px}._th-container:hover ._th-item._item-x-2{margin-left:17px;width:38px;height:38px;line-height:38px}._th-container:hover ._th-item._item-xx2{width:36px;height:36px;margin-left:16px;line-height:36px}._th-container:hover ._th-item._item-xx-2{width:32px;height:32px;line-height:32px;margin-left:14px}._th-container:hover ._th-item._item-reset{width:30px;line-height:30px;height:30px;margin-left:10px}._th-click-hover{position:relative;-webkit-transition:all .5s;-o-transition:all .5s;transition:all .5s;height:45px;width:45px;cursor:pointer;opacity:.3;border-radius:100%;background-color:aquamarine;text-align:center;line-height:45px;right:0}._th-container:hover{left:-5px}._th-container{font-size:12px;-webkit-transition:all .5s;-o-transition:all .5s;transition:all .5s;left:-35px;top:20%;position:fixed;-webkit-box-sizing:border-box;box-sizing:border-box;z-index:100000;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}._th-container ._th-item:hover{opacity:.8;background-color:#5fb492;color:aliceblue}._th-container ._th-item:active{opacity:.9;background-color:#1b3a26;color:aliceblue}._th-container:hover ._th-click-hover{opacity:.8}._th-container:hover ._th-item{opacity:.6;right:0}._th-container ._th-click-hover:hover{opacity:.8;background-color:#5fb492;color:aliceblue}._th_cover-all-show-times{position:fixed;top:0;right:0;width:100%;height:100%;z-index:99999;opacity:1;font-weight:900;font-size:30px;color:#4f4f4f;background-color:rgba(0,0,0,0.1)}._th_cover-all-show-times._th_hidden{z-index:-99999;opacity:0;-webkit-transition:1s all;-o-transition:1s all;transition:1s all}._th_cover-all-show-times ._th_times{width:300px;height:300px;border-radius:50%;background-color:rgba(127,255,212,0.51);text-align:center;line-height:300px;position:absolute;top:50%;right:50%;margin-top:-150px;margin-right:-150px}';
  • };
  • global.changeTime = timer.changeTime;
  • },
  • +
  • + ****************禁用 BY 黄盐, PART 2 END*/
  • applyHooking: function () {
  • - var _this = this;
  • // 劫持循环计时器
  • eHookContext.hookReplace(window, 'setInterval', function (setInterval) {
  • - return _this.getHookedTimerFunction('interval', setInterval);
  • - });
  • - // 劫持单次计时
  • - eHookContext.hookReplace(window, 'setTimeout', function (setTimeout) {
  • - return _this.getHookedTimerFunction('timeout', setTimeout)
  • + return function () {
  • + // 储存原始时间间隔
  • + var originMS = arguments[1];
  • + // 获取变速时间间隔
  • + arguments[1] *= timerContext._percentage;
  • + var resultId = setInterval.apply(window, arguments);
  • + // 保存每次使用计时器得到的id以及参数等
  • + timerContext._intervalIds[resultId] = {
  • + args: arguments,
  • + originMS: originMS,
  • + nowId: resultId
  • + };
  • + return resultId;
  • + };
  • });
  • // 劫持循环计时器的清除方法
  • eHookContext.hookBefore(window, 'clearInterval', function (method, args) {
  • - _this.redirectNewestId(args);
  • + var id = args[0];
  • + if (timerContext._intervalIds[id]) {
  • + args[0] = timerContext._intervalIds[id].nowId;
  • + }
  • + // 清除该记录id
  • + delete timerContext._intervalIds[id];
  • });
  • // 劫持循环计时器的清除方法
  • eHookContext.hookBefore(window, 'clearTimeout', function (method, args) {
  • - _this.redirectNewestId(args);
  • + var id = args[0];
  • + if (timerContext._intervalIds[id]) {
  • + args[0] = timerContext._intervalIds[id].nowId;
  • + }
  • + // 清除该记录id
  • + delete timerContext._intervalIds[id];
  • + });
  • + // 劫持单次计时器setTimeout
  • + eHookContext.hookBefore(window, 'setTimeout', function (method, args) {
  • + args[1] *= timerContext._percentage;
  • });
  • var newFunc = this.getHookedDateConstructor();
  • eHookContext.hookClass(window, 'Date', newFunc, '_innerDate', ['now']);
  • eHookContext.hookedToString(timerContext._setTimeout, setTimeout);
  • eHookContext.hookedToString(timerContext._clearInterval, clearInterval);
  • timerContext._mDate = window.Date;
  • +
  • + /***************禁用 BY 黄盐, PART 2 BEGIN
  • this.hookShadowRoot();
  • + ****************禁用 BY 黄盐, PART 2 END*/
  • },
  • getHookedDateConstructor: function () {
  • return function () {
  • });
  • };
  • },
  • - getHookedTimerFunction: function (type, timer) {
  • - var property = '_' + type + 'Ids';
  • - return function () {
  • - var uniqueId = timerContext.genUniqueId();
  • - var callback = arguments[0];
  • - if (typeof callback === 'string') {
  • - callback += ';timer.notifyExec(' + uniqueId + ')';
  • - arguments[0] = callback;
  • - }
  • - if (typeof callback === 'function') {
  • - arguments[0] = function () {
  • - var returnValue = callback.apply(this, arguments);
  • - timerContext.notifyExec(uniqueId);
  • - return returnValue;
  • - }
  • - }
  • - // 储存原始时间间隔
  • - var originMS = arguments[1];
  • - // 获取变速时间间隔
  • - arguments[1] *= timerContext._percentage;
  • - var resultId = timer.apply(window, arguments);
  • - // 保存每次使用计时器得到的id以及参数等
  • - timerContext[property][resultId] = {
  • - args: arguments,
  • - originMS: originMS,
  • - originId: resultId,
  • - nowId: resultId,
  • - uniqueId: uniqueId,
  • - oldPercentage: timerContext._percentage,
  • - exceptNextFireTime: timerContext._Date.now() + originMS
  • - };
  • - return resultId;
  • - };
  • - },
  • - redirectNewestId: function (args) {
  • - var id = args[0];
  • - if (timerContext._intervalIds[id]) {
  • - args[0] = timerContext._intervalIds[id].nowId;
  • - // 清除该记录id
  • - delete timerContext._intervalIds[id];
  • - }
  • - if (timerContext._timeoutIds[id]) {
  • - args[0] = timerContext._timeoutIds[id].nowId;
  • - // 清除该记录id
  • - delete timerContext._timeoutIds[id];
  • - }
  • - },
  • + /***************禁用 BY 黄盐, PART 3 BEGIN
  • registerShortcutKeys: function (timer) {
  • // 快捷键注册
  • addEventListener('keydown', function (e) {
  • }
  • });
  • },
  • + this.hookShadowRoot();
  • + ****************禁用 BY 黄盐, PART 3 END*/
  • /**
  • * 当计时器速率被改变时调用的回调方法
  • * @param percentage
  • percentageChangeHandler: function (percentage) {
  • // 改变所有的循环计时
  • util.ergodicObject(timerContext, timerContext._intervalIds, function (idObj, id) {
  • - idObj.args[1] = Math.floor((idObj.originMS || 1) * percentage);
  • + idObj.args[1] = Math.floor(idObj.originMS || 1 * percentage);
  • // 结束原来的计时器
  • this._clearInterval.call(window, idObj.nowId);
  • // 新开一个计时器
  • idObj.nowId = this._setInterval.apply(window, idObj.args);
  • });
  • - // 改变所有的延时计时
  • - util.ergodicObject(timerContext, timerContext._timeoutIds, function (idObj, id) {
  • - var now = this._Date.now();
  • - var exceptTime = idObj.exceptNextFireTime;
  • - var oldPercentage = idObj.oldPercentage;
  • - var time = exceptTime - now;
  • - if (time < 0) {
  • - time = 0;
  • - }
  • - var changedTime = Math.floor(percentage / oldPercentage * time);
  • - idObj.args[1] = changedTime;
  • - // 重定下次执行时间
  • - idObj.exceptNextFireTime = now + changedTime;
  • - idObj.oldPercentage = percentage;
  • - // 结束原来的计时器
  • - this._clearTimeout.call(window, idObj.nowId);
  • - // 新开一个计时器
  • - idObj.nowId = this._setTimeout.apply(window, idObj.args);
  • - });
  • },
  • + /***************禁用 BY 黄盐, PART 4 BEGIN
  • hookShadowRoot: function () {
  • var origin = Element.prototype.attachShadow;
  • eHookContext.hookAfter(Element.prototype, 'attachShadow',
  • return result;
  • }, false);
  • eHookContext.hookedToString(origin, Element.prototype.attachShadow);
  • - },
  • - hookDefine: function () {
  • - const _this = this;
  • - eHookContext.hookBefore(Object, 'defineProperty', function (m, args) {
  • - var option = args[2];
  • - var ele = args[0];
  • - var key = args[1];
  • - var afterArgs = _this.hookDefineDetails(ele, key, option);
  • - afterArgs.forEach((arg, i) => {
  • - args[i] = arg;
  • - })
  • - });
  • - eHookContext.hookBefore(Object, 'defineProperties', function (m, args) {
  • - var option = args[1];
  • - var ele = args[0];
  • - if (ele && ele instanceof Element) {
  • - Object.keys(option).forEach(key => {
  • - var o = option[key];
  • - var afterArgs = _this.hookDefineDetails(ele, key, o);
  • - args[0] = afterArgs[0];
  • - delete option[key];
  • - option[afterArgs[1]] = afterArgs[2]
  • - })
  • - }
  • - })
  • - },
  • - hookDefineDetails: function (target, key, option) {
  • - if (option && target && target instanceof Element && typeof key === 'string' && key.indexOf('on') >= 0) {
  • - option.configurable = true;
  • - }
  • - if (target instanceof HTMLVideoElement && key === 'playbackRate') {
  • - option.configurable = true;
  • - console.warn('[Timer Hook]', '已阻止默认操作视频倍率');
  • - key = 'playbackRate_hooked'
  • - }
  • - return [target, key, option];
  • - },
  • - suppressEvent: function (ele, eventName) {
  • - if (ele) {
  • - delete ele['on' + eventName];
  • - delete ele['on' + eventName];
  • - delete ele['on' + eventName];
  • - ele['on' + eventName] = undefined;
  • - }
  • - if (!suppressEvents[eventName]) {
  • - eHookContext.hookBefore(EventTarget.prototype, 'addEventListener',
  • - function (m, args) {
  • - var eName = args[0];
  • - if (eventName === eName) {
  • - console.warn(eventName, 'event suppressed.')
  • - args[0] += 'suppressed';
  • - }
  • - }, false);
  • - suppressEvents[eventName] = true;
  • - }
  • - },
  • - changePlaybackRate: function (ele, rate) {
  • - delete ele.playbackRate;
  • - delete ele.playbackRate;
  • - delete ele.playbackRate;
  • - ele.playbackRate = rate
  • - if (rate !== 1) {
  • - timerContext.defineProperty.call(Object, ele, 'playbackRate', {
  • - configurable: true,
  • - get: function () {
  • - return 1;
  • - },
  • - set: function () {
  • - }
  • - });
  • - }
  • }
  • + ****************禁用 BY 黄盐, PART 4 END*/
  • }
  • };
  • var timerHooker = {
  • // 用于储存计时器的id和参数
  • _intervalIds: {},
  • - _timeoutIds: {},
  • - _auoUniqueId: 1,
  • // 计时器速率
  • __percentage: 1.0,
  • // 劫持前的原始的方法
  • __lastDatetime: new Date().getTime(),
  • __lastMDatetime: new Date().getTime(),
  • videoSpeedInterval: 1000,
  • - defineProperty: Object.defineProperty,
  • - defineProperties: Object.defineProperties,
  • - genUniqueId: function () {
  • - return this._auoUniqueId++;
  • - },
  • - notifyExec: function (uniqueId) {
  • - var _this = this;
  • - if (uniqueId) {
  • - // 清除 timeout 所储存的记录
  • - var timeoutInfos = Object.values(this._timeoutIds).filter(
  • - function (info) {
  • - return info.uniqueId === uniqueId;
  • - }
  • - );
  • - timeoutInfos.forEach(function (info) {
  • - _this._clearTimeout.call(window, info.nowId);
  • - delete _this._timeoutIds[info.originId]
  • - })
  • - }
  • - // console.log(uniqueId, 'called')
  • - },
  • /**
  • * 初始化方法
  • */
  • var timerContext = this;
  • var h = helper(eHookContext, timerContext, util);
  • - h.hookDefine();
  • h.applyHooking();
  • // 设定百分比属性被修改的回调
  • if (!normalUtil.isInIframe()) {
  • console.log('[TimeHooker]', 'loading outer window...');
  • + /***************禁用 BY 黄盐, PART 5 BEGIN
  • h.applyUI();
  • h.applyGlobalAction(timerContext);
  • h.registerShortcutKeys(timerContext);
  • + ****************禁用 BY 黄盐, PART 5 END*/
  • } else {
  • console.log('[TimeHooker]', 'loading inner window...');
  • normalUtil.listenParentEvent((function (percentage) {
  • * @param percentage
  • */
  • change: function (percentage) {
  • + var _this = this;
  • this.__lastMDatetime = this._mDate.now();
  • + // console.log(this._mDate.toString());
  • + // console.log(new this._mDate());
  • this.__lastDatetime = this._Date.now();
  • + // debugger;
  • + //---------------------------------//
  • this._percentage = percentage;
  • + /***************禁用 BY 黄盐, PART 6 BEGIN
  • var oldNode = document.getElementsByClassName('_th-click-hover');
  • var oldNode1 = document.getElementsByClassName('_th_times');
  • var displayNum = (1 / this._percentage).toFixed(2);
  • (oldNode[0] || {}).innerHTML = 'x' + displayNum;
  • (oldNode1[0] || {}).innerHTML = 'x' + displayNum;
  • var a = document.getElementsByClassName('_th_cover-all-show-times')[0] || {};
  • + // console.log(a.className);
  • a.className = '_th_cover-all-show-times';
  • this._setTimeout.bind(window)(function () {
  • a.className = '_th_cover-all-show-times _th_hidden';
  • }, 100);
  • + ****************禁用 BY 黄盐, PART 6 END*/
  • this.changeVideoSpeed();
  • + this._clearInterval.bind(window)(this.videoSpeedIntervalId);
  • + this.videoSpeedIntervalId = this._setInterval.bind(window)(function () {
  • + _this.changeVideoSpeed();
  • + var rate = 1 / _this._percentage;
  • + if (rate === 1) {
  • + _this._clearInterval.bind(window)(_this.videoSpeedIntervalId);
  • + }
  • + }, this.videoSpeedInterval);
  • normalUtil.sentChangesToIframe(percentage);
  • },
  • changeVideoSpeed: function () {
  • - var timerContext = this;
  • - var h = helper(eHookContext, timerContext, util);
  • var rate = 1 / this._percentage;
  • - rate > 16 && (rate = 16);
  • + /***************修改 BY 黄盐, PART 7 BEGIN */
  • + rate > 20 && (rate = 20);
  • rate < 0.065 && (rate = 0.065);
  • + // console.log(rate);
  • + /****************修改 BY 黄盐, PART 7 END */
  • +
  • var videos = querySelectorAll(document, 'video', true) || [];
  • if (videos.length) {
  • for (var i = 0; i < videos.length; i++) {
  • - h.changePlaybackRate(videos[i], rate);
  • + /***************修改 BY 黄盐, PART 8 BEGIN */
  • + try {
  • + videos[i].playbackRate = rate
  • + } catch (error) {
  • + console.log("可能是设置播放速度超出支持的范围了", rate, error)
  • + }
  • + /****************修改 BY 黄盐, PART 8 END */
  • }
  • }
  • }

This report has been upheld by a moderator.

The concept of open source doesn't mean you can modify and publish code without proper attribution. The script should specify the URL, author, license of the original, describe the major changes you've made. After you fix and update your existing script, ask a moderator to undelete it.