Timing Click

倒计时自动点击,电商抢东西专用

  1. // ==UserScript==
  2. // @name Timing Click
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.3.1
  5. // @description 倒计时自动点击,电商抢东西专用
  6. // @author Cherokeeli
  7. // @match *://*.taobao.com/*
  8. // @match *://*.jd.com/*
  9. // @match *://*.tmall.com/*
  10. // @require https://code.jquery.com/jquery-latest.js
  11. // @run-at document-idle
  12. // @grant GM_addStyle
  13. // @grant GM_getResourceText
  14. // @grant GM_xmlhttpRequest
  15. // @connect githubusercontent.com
  16. // @connect gitee.com
  17.  
  18. // ==/UserScript==
  19.  
  20. (function() {
  21. 'use strict';
  22. var $ = $ || window.$;
  23. var _$ = $.noConflict(true);
  24. var countWoker = "https://gitee.com/erokee/monkey-lib/raw/master/timing-click/count-worker.js";
  25. var avatar = "https://gitee.com/erokee/monkey-lib/raw/master/timing-click/image/1.pic.png";
  26.  
  27. var mainCss = `#ql-panel #counterClickTime {
  28. position:relative;
  29. z-index:999;
  30. height: 20px !important;
  31. width: 150px !important;
  32. font-size: 1em !important;
  33. padding: 5px !important;
  34. border: none !important;
  35. margin: 0 !important;
  36. }
  37.  
  38. #ql-panel #counterClickSelector {
  39. position:relative;
  40. z-index:999;
  41. height: 20px !important;
  42. width: 150px !important;
  43. font-size: 1em !important;
  44. padding: 5px !important;
  45. border: none !important;
  46. margin: 0 !important;
  47. }
  48.  
  49. #ql-panel #listenButton {
  50. position:relative;
  51. z-index:999;
  52. width: 100% !important;
  53. border: none !important;
  54. color: red !important;
  55. font-size: 1em !important;
  56. margin: 0 !important;
  57. background-color: #fff;
  58. }
  59.  
  60. #ql-panel #triggerButton {
  61. height:50px;
  62. width:50px;
  63. position:relative;
  64. z-index:9999;
  65. background-position:center;
  66. background-size:100%;
  67. background-image:url(${avatar});
  68. }
  69.  
  70. #ql-panel {
  71. position:fixed;
  72. z-index:9999;
  73. top: 10vh;
  74. left: 5vw;
  75. }
  76.  
  77. #ql-panel #hidePanel {
  78. position:absolute;
  79. z-index:9999;
  80. display:none;
  81. border: solid 1px rgb(238,238,238) !important;
  82. box-shadow: 0 0 5px rgb(213,210,210) !important;
  83. }`;
  84.  
  85. /*拖动*/
  86. class DragObj {
  87. constructor(dom) {
  88. this.mouse = {
  89. x: 0,
  90. y: 0
  91. };
  92. this.obj = {
  93. x: 0,
  94. y: 0
  95. };
  96. this.isClicked = false;
  97. if(dom) {
  98. this.dom = dom;
  99. } else {
  100. throw new Error('不存在的dom节点');
  101. }
  102. }
  103.  
  104. init(options={}) {
  105. document.addEventListener('mousedown', this.down.bind(this));
  106. document.addEventListener('mousemove', this.move.bind(this));
  107. document.addEventListener('mouseup', this.end.bind(this));
  108. if(typeof options.click ==='function') {
  109. this.clickCb = options.click;
  110. }
  111. if(typeof options.exclude === 'object') {
  112. this.excludeDom = options.exclude;
  113. }
  114. if(typeof options.include === 'object') {
  115. this.includeDom = options.include;
  116. }
  117. }
  118.  
  119. down(event) {
  120. if(this.includeDom.contains(event.target)) {
  121. this.isClicked = true;
  122. this.mouse.x = event.clientX;
  123. this.mouse.y = event.clientY;
  124. this.obj.x = this.dom.offsetLeft;
  125. this.obj.y = this.dom.offsetTop;
  126. }
  127. }
  128.  
  129. move(event) {
  130. if(this.isClicked) {
  131. let moveX = event.clientX - this.mouse.x;
  132. let moveY = event.clientY - this.mouse.y;
  133. this.dom.style.left = `${this.obj.x+moveX}px`;
  134. this.dom.style.top = `${this.obj.y+moveY}px`;
  135. }
  136. }
  137.  
  138. end(event) {
  139. this.isClicked = false;
  140. if(this.clickCb && (event.clientX === this.mouse.x && event.clientY===this.mouse.y)) {
  141. if(!this.excludeDom.contains(event.target) && this.includeDom.contains(event.target)) {
  142. this.clickCb(event);
  143. }
  144. }
  145. }
  146. }
  147.  
  148. GM_addStyle(mainCss);
  149.  
  150. let timeInput = _$('<input id="counterClickTime" placeholder="输入开抢时间" type="datetime-local" step="1" value="2019-10-12T07:22:00" />');
  151. let selectorInput = _$('<input id="counterClickSelector" placeholder="输入抢按钮选择器" type="text" />');
  152. let listenButton = _$('<button id="listenButton">准备开抢</button>');
  153. let triggerButton = _$('<div id="triggerButton"></div>');
  154. let panel = _$('<div id="ql-panel"></div>');
  155. let hidePanel = _$('<div id="hidePanel"></div>');
  156.  
  157. hidePanel.append(timeInput.val(dateFormatter.call(new Date(), 'yyyy-MM-ddThh:mm:ss')));
  158. hidePanel.append(selectorInput);
  159. hidePanel.append(listenButton);
  160.  
  161. panel.append(triggerButton);
  162. panel.append(hidePanel);
  163.  
  164. _$(document.body).append(panel);
  165.  
  166. (new DragObj(panel[0])).init({
  167. click: function(event) {
  168. hidePanel.toggle('slow');
  169. },
  170. exclude: hidePanel[0],
  171. include: panel[0]
  172. });
  173.  
  174. function dateFormatter(fmt) {
  175. var o = {
  176. "M+": this.getMonth() + 1, //月份
  177. "d+": this.getDate(), //日
  178. "h+": this.getHours(), //小时
  179. "m+": this.getMinutes(), //分
  180. "s+": this.getSeconds(), //秒
  181. "q+": Math.floor((this.getMonth() + 3) / 3), //季度
  182. "S": this.getMilliseconds() //毫秒
  183. };
  184. if (/(y+)/.test(fmt))
  185. fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
  186. for (var k in o)
  187. if (new RegExp("(" + k + ")").test(fmt))
  188. fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
  189. return fmt;
  190. }
  191.  
  192. function fireEvent(dom, eventName) {
  193. let event = new MouseEvent(eventName);
  194. return dom.dispatchEvent(event);
  195. }
  196.  
  197. function createWorkerFromExternalURL(url, callback) {
  198. GM_xmlhttpRequest({
  199. method: 'GET',
  200. url: url,
  201. onload: function (response) {
  202. var script, dataURL, worker = null;
  203. if (response.status === 200) {
  204. script = response.responseText;
  205. dataURL = 'data:text/javascript;base64,' + btoa(script);
  206. worker = new unsafeWindow.Worker(dataURL);
  207. }
  208. callback(worker);
  209. },
  210. onerror: function () {
  211. callback(null);
  212. }
  213. });
  214. }
  215.  
  216. function stepClick(times, stepInterval, clickFn) {
  217. if (!times) return;
  218. if (clickFn) clickFn();
  219. setTimeout(function () {
  220. stepClick(--times, stepInterval, clickFn);
  221. }, stepInterval);
  222. }
  223.  
  224. /*开始抢*/
  225. listenButton.click(function(e) {
  226. let time = timeInput.val();
  227. let targetTime = Date.parse(new Date(time));
  228. let currentTime = Date.now();
  229. let timeout = targetTime-currentTime;
  230. console.log(timeout, selectorInput.val());
  231. createWorkerFromExternalURL(countWoker, function (worker) {
  232. if (!worker) throw Error('Create webworker failed');
  233. let btn = listenButton[0];
  234. worker.onmessage = function (event) {
  235. if (event.data === -1) {
  236. btn.disabled = false;
  237. stepClick(3, 100, function () {
  238. _$(selectorInput.val()).trigger('click');
  239. fireEvent(document.querySelector(selectorInput.val()), 'click');
  240. });
  241. worker.terminate();
  242. } else {
  243. btn.disabled = true;
  244. btn.innerHTML = `距离开抢还有${Math.ceil(event.data / 1000)}秒`;
  245. }
  246. };
  247. worker.postMessage(timeout);
  248. });
  249. });
  250.  
  251. })();