Time sleep prediction

Keep track of time spent on any website

当前为 2023-02-27 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Time sleep prediction
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.4
  5. // @description Keep track of time spent on any website
  6. // @icon https://www.iconsdb.com/icons/preview/gray/clock-10-xxl.png
  7. // @author moony
  8. // @match *://*/*
  9. // @grant GM_registerMenuCommand
  10. // @grant GM_setValue
  11. // @grant GM_getValue
  12. // @grant GM_listValues
  13. // @grant GM_deleteValue
  14. // @grant window.onurlchange
  15. // @require https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@4.2.0/dist/tf.min.js
  16. // @license GPL-3.0
  17. // ==/UserScript==
  18.  
  19. (function() {
  20. let sleepTimeDisplay = false; let sleepTimeDiv = document.createElement("div");
  21. let Index_lastTime_usec = 0; let MaxIndex_lastTime_usec; let counter = 0; let typeAlgorithme = GM_getValue("typeAlgorithme", null);
  22. var predictionSleep;
  23. let diffTime = 0; let minSleep = 6; let maxSleep = 24;
  24. let CurrentDate = new Date();
  25. let SleepingTimeArray = []; let WakeUpTimeArray = [];
  26. const tf = window.tf; let model = tf.sequential(); tf.setBackend('webgl'); let _TrainOnce = true;
  27.  
  28. document.addEventListener("keypress", arrayTimeUpdate);
  29. document.addEventListener("mousemove", arrayTimeUpdate);
  30. document.addEventListener("mousedown", arrayTimeUpdate);
  31.  
  32. function arrayTimeUpdate() {
  33. let wakeTimer = GM_getValue("wakeTimer", null);
  34. let oldDate = GM_getValue("oldDate", null);
  35. if (oldDate == null) { oldDate = CurrentDate.getTime(); GM_setValue("SleepingTimeArray", [8.1, 9.1, 10.1]); GM_setValue("WakeUpTimeArray", [16.1, 15.1, 14.1]); } //first time run
  36. CurrentDate = new Date();
  37. diffTime = CurrentDate.getTime() - oldDate;
  38. diffTime = diffTime/(1000*60*60);
  39. if (diffTime > minSleep && diffTime < maxSleep) {
  40. SleepingTimeArray = GM_getValue("SleepingTimeArray", null);
  41. WakeUpTimeArray = GM_getValue("WakeUpTimeArray", null);
  42. if (SleepingTimeArray == null) { SleepingTimeArray = [diffTime]; } //first time store
  43. else { SleepingTimeArray.push(diffTime); }
  44. if (WakeUpTimeArray == null) { WakeUpTimeArray = [wakeTimer]; }
  45. else { WakeUpTimeArray.push(wakeTimer); }
  46. GM_setValue("SleepingTimeArray", SleepingTimeArray);
  47. GM_setValue("WakeUpTimeArray", WakeUpTimeArray);
  48. wakeTimer = 0;
  49. }
  50. else if (diffTime <= minSleep) {
  51. if (wakeTimer == null) { wakeTimer = diffTime; }
  52. else { wakeTimer += diffTime; }
  53. }
  54. else { wakeTimer = 0; }
  55. GM_setValue("wakeTimer", wakeTimer);
  56. GM_setValue("oldDate", CurrentDate.getTime());
  57. }
  58.  
  59. function predictSleep() {
  60. if ( typeAlgorithme == "Avg" ) { return predictSleepAvg(); } else { return predictSleepML(); }
  61. }
  62.  
  63. function predictSleepML() {
  64. if (_TrainOnce)
  65. { _TrainOnce = false;
  66. let sleepingTimeArray = GM_getValue("SleepingTimeArray", null);
  67. let wakeUpTimeArray = GM_getValue("WakeUpTimeArray", null);
  68. let index = sleepingTimeArray.length - 1;
  69. while (index > -1) {
  70. sleepingTimeArray[index] = sleepingTimeArray[index] / maxSleep;
  71. wakeUpTimeArray[index] = wakeUpTimeArray[index] / maxSleep;
  72. index--;
  73. }
  74. sleepingTimeArray = tf.tensor2d(sleepingTimeArray, [sleepingTimeArray.length, 1]);
  75. wakeUpTimeArray = tf.tensor2d(wakeUpTimeArray, [wakeUpTimeArray.length, 1]);
  76. //const inputTensor = tf.stack([sleepingTimeArray, wakeUpTimeArray], 1).reshape([1, -1, 2]);
  77. //model.add(tf.layers.gru({units: 16, inputShape: [wakeUpTimeArray.length, 1]}));
  78. model.add(tf.layers.dense({ units: 128, inputShape: [1], activation: 'swish' })); // sigmoid, hardSigmoid, softplus, softsign, tanh, softmax, linear, relu, relu6, selu, elu, swish | https://www.tensorflow.org/js/tutorials/training/linear_regression
  79. model.add(tf.layers.dense({ units: 64, activation: 'softsign' }));
  80. model.add(tf.layers.dense({ units: 32, activation: 'selu' }));
  81. model.add(tf.layers.dense({ units: 1, activation: 'linear' }));
  82. model.compile({loss: 'meanSquaredError', optimizer: 'adam'});
  83. model.fit(wakeUpTimeArray, sleepingTimeArray, {epochs: 50, batchSize: 32, optimizer: tf.train.adam(0.001), callbacks: {onEpochEnd: async(epoch, logs) => { let lossStr = logs.loss ? logs.loss.toFixed(4) : 'N/A'; console.log(`Epoch: ${epoch} - loss: ${lossStr}`);}}});
  84. // const modelJSON = model.toJSON(); const modelString = JSON.stringify(modelJSON); GM_setValue('model', modelString); // Save the model
  85. } // <train | predict>
  86. // const modelString = GM_getValue('model'); const modelJSON = JSON.parse(modelString); const loadedModel = tf.loadLayersModel(modelJSON); // Load the model
  87.  
  88. const wakeTimer = GM_getValue("wakeTimer", 0) / maxSleep;
  89. let wake = [wakeTimer];
  90. wake = tf.tensor2d(wake, [wake.length, 1]);
  91. const predictionTensor = model.predict(wake);
  92. const prediction = predictionTensor.dataSync()[0] * maxSleep;
  93. tf.dispose(wake); // clean up: Memory management
  94. const predictionSleep = convertHours(prediction);
  95. return predictionSleep;
  96. }
  97.  
  98. function predictSleepAvg() {
  99. SleepingTimeArray = GM_getValue("SleepingTimeArray", null); WakeUpTimeArray = GM_getValue("WakeUpTimeArray", null); //for read persistent storage
  100. let index = SleepingTimeArray.length - 1; let sum = 0; const nsleep = SleepingTimeArray.length; counter++
  101. while (index > -1) { sum += SleepingTimeArray[index]; index--; }
  102. const sleepAverage = sum / nsleep; sum = 0; index = WakeUpTimeArray.length - 1; const nwake = WakeUpTimeArray.length;
  103. while (index > -1) { sum += WakeUpTimeArray[index]; index--; }
  104. const wakeAverage = sum / nwake; const ratio = sleepAverage / wakeAverage; const wakeTimer = GM_getValue("wakeTimer", 0); const predict = ratio * wakeTimer;
  105. return convertHours(predict);
  106. }
  107.  
  108. function convertHours(predict)
  109. {
  110. const hours = Math.floor(predict);
  111. let remainder = predict - hours;
  112. remainder = remainder * 60;
  113. const minutes = Math.floor(remainder);
  114. remainder = remainder - minutes;
  115. remainder = remainder * 60;
  116. const seconds = Math.floor(remainder);
  117. const predictionText = `${hours} hours, ${minutes} minutes and ${seconds} seconds.(${counter})`;
  118. return predictionText;
  119. }
  120.  
  121. function displaySleepTime() {
  122. sleepTimeDisplay = true; GM_setValue("sleepTimeDisplay", sleepTimeDisplay);
  123. predictionSleep = predictSleep();
  124. let pos = GM_getValue("sleepTimeDivPos", { x: "50%", y: "50%" }); if (pos.x == "NaN" || pos.y == "NaN") pos = { x: "50%", y: "50%" };
  125. sleepTimeDiv.style.cssText = `left: ${pos.x}; top: ${pos.y}; background-color: rgba(0,0,0,0.5); color: white; position: fixed; transform: translate(-50%, -50%); font-size: 100%; border-radius: 5px; padding: 10px; text-align: center; z-index: 9999;`;
  126. sleepTimeDiv.innerHTML = `If you sleep now, you will WakeUp in: <span id='sleepTimeSpan'>${predictionSleep}</span>`;
  127.  
  128. document.body.appendChild(sleepTimeDiv);
  129. let sleepTimeSpan = document.getElementById("sleepTimeSpan");
  130. sleepTimeSpan.style.marginRight = "30px";
  131. let closeButton = document.createElement("button");
  132. closeButton.style.cssText = `position: absolute; top: 5px; right: 5px; background-color: rgba(0,0,0,0.5); color: white; font-size: 100%; padding: 5px 10px; border-radius: 3px; box-shadow: 0px 0px 8px rgba(0,0,0,0.1); transition: all 0.2s ease-in-out;`;
  133. closeButton.innerHTML = "X";
  134.  
  135.  
  136. sleepTimeDiv.addEventListener("dragover", (event) => { event.preventDefault(); });
  137. sleepTimeDiv.addEventListener("drop", handleFileDrop);
  138.  
  139. closeButton.addEventListener("click", function() { removeSleepTimeDisplay(); });
  140.  
  141. closeButton.addEventListener("mouseover", function() {
  142. closeButton.style.backgroundColor = "rgba(0,0,0,0.2)";
  143. closeButton.style.color = "white";
  144. });
  145.  
  146. closeButton.addEventListener("mouseout", function() {
  147. closeButton.style.backgroundColor = "rgba(0,0,0,0.5)";
  148. closeButton.style.color = "white";
  149. });
  150. sleepTimeDiv.addEventListener("mousedown", function(event) {
  151. let currentX = event.clientX - sleepTimeDiv.offsetLeft; let currentY = event.clientY - sleepTimeDiv.offsetTop;
  152. document.addEventListener("mouseup", function() {
  153. document.removeEventListener("mousemove", moveDiv);
  154. let pos = { x: sleepTimeDiv.style.left, y: sleepTimeDiv.style.top }; GM_setValue("sleepTimeDivPos", pos);
  155. });
  156. document.addEventListener("mousemove", moveDiv);
  157. function moveDiv(event) {
  158. sleepTimeDiv.style.left = event.clientX - currentX + "px";
  159. sleepTimeDiv.style.top = event.clientY - currentY + "px";
  160. }
  161. });
  162.  
  163. sleepTimeDiv.appendChild(closeButton);
  164.  
  165. setInterval(function() {
  166. document.querySelector("#sleepTimeSpan") && (document.querySelector("#sleepTimeSpan").innerHTML = `${predictSleep()}`);
  167. }, 1000);
  168. }
  169.  
  170. function removeSleepTimeDisplay() {
  171. if (sleepTimeDisplay) {
  172. sleepTimeDisplay = false; GM_setValue("sleepTimeDisplay", sleepTimeDisplay);
  173. const pos = { x: "50%", y: "50%" }; GM_setValue("sleepTimeDivPos", pos);
  174. sleepTimeDiv.remove();
  175. }
  176. }
  177.  
  178. function handleFileDrop(event) { // get "BrowserHistory.json" browser history from https://takeout.google.com/
  179. event.preventDefault(); event.stopPropagation(); const reader = new FileReader(); reader.readAsArrayBuffer(event.dataTransfer.files[0]); reader.onload = () => { const data = JSON.parse(new TextDecoder().decode(reader.result)); MaxIndex_lastTime_usec = data['Browser History'].length;
  180. SleepingTimeArray = GM_getValue("SleepingTimeArray", null); WakeUpTimeArray = GM_getValue("WakeUpTimeArray", null); let lastTime_usec = 0; let wake = 0; let diff = 0; let hours = 0; let minValidSleep = 8; let maxValidSleep = 8; const minValidWakeUp = 10; const maxValidWakeUp = 30;
  181. data['Browser History'].forEach(item => {
  182. if (lastTime_usec == 0) { lastTime_usec = item.time_usec; }
  183. else { diff = lastTime_usec - item.time_usec; hours = diff / (1000 * 60 * 60);
  184. if (hours <= maxSleep && hours >= minSleep && wake >= minValidWakeUp && wake <= maxValidWakeUp) {
  185. if (hours > maxValidSleep) { maxValidSleep = hours; }
  186. else if (hours < minValidSleep) { minValidSleep = hours; }
  187. if (SleepingTimeArray == null) { SleepingTimeArray = [hours]; WakeUpTimeArray = [wake]; }
  188. else { SleepingTimeArray.push(hours); WakeUpTimeArray.push(wake); }
  189. wake = 0; Index_lastTime_usec++;
  190. }
  191. else if (hours < 6) { wake += hours; }
  192. else { wake = 0; }
  193. lastTime_usec = item.time_usec;
  194. }
  195. console.log(item.time_usec + " - " + Index_lastTime_usec + " \ " + MaxIndex_lastTime_usec); counter++;
  196. });
  197. console.log(SleepingTimeArray); console.log(WakeUpTimeArray);
  198. GM_setValue("SleepingTimeArray", SleepingTimeArray); GM_setValue("WakeUpTimeArray", WakeUpTimeArray);
  199. }; }
  200.  
  201. if (window.onurlchange === null) { console.log("URL CHANGE");
  202. let sleepTimeDisplay = GM_getValue("sleepTimeDisplay", false);
  203. if (sleepTimeDisplay) { displaySleepTime(); } else { removeSleepTimeDisplay();}
  204. //window.addEventListener('urlchange', (info) => { console.log("newly created"); });
  205. }
  206.  
  207. GM_registerMenuCommand("Sleep Time", () => { if (sleepTimeDisplay) { removeSleepTimeDisplay(); } else { displaySleepTime(); }});
  208. GM_registerMenuCommand("switchAlgorithm", () => { typeAlgorithme = GM_getValue("typeAlgorithme", "ML"); if (typeAlgorithme == "ML") { typeAlgorithme = "Avg"; } else { typeAlgorithme = "ML"; } GM_setValue("typeAlgorithme", typeAlgorithme); console.log("Apply: typeAlgorithme = " + typeAlgorithme); });
  209. GM_registerMenuCommand("showDelKey", () => { const keys = GM_listValues(); const data = keys.map(key => { const value = GM_getValue(key); return { key, value }; }); console.table(data); const confirmation = confirm(`Do you want to delete all ${keys.length} values show in console?`);
  210. if (confirmation) { keys.forEach(key => { GM_deleteValue(key); }); console.log(`${keys.length} values have been deleted.`); } else { console.log(`No values have been deleted.`); } });
  211.  
  212. })();