antiDTF (Userscript)

Ограничь свое время на DTF. Userscript version. Автор: Dude

  1. // ==UserScript==
  2. // @name antiDTF (Userscript)
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.1
  5. // @description Ограничь свое время на DTF. Userscript version. Автор: Dude
  6. // @author Dude (converted)
  7. // @match *://dtf.ru/*
  8. // @grant GM_getValue
  9. // @grant GM_setValue
  10. // @grant GM_addStyle
  11. // @grant GM_registerMenuCommand
  12. // @run-at document-idle
  13. // @license MIT
  14. // ==/UserScript==
  15.  
  16. (async function() {
  17. 'use strict';
  18.  
  19. // --- Configuration Keys ---
  20. const KEY_DAILY_LIMIT = 'antiDTF_dailyLimit';
  21. const KEY_START_TIMESTAMP = 'antiDTF_startTimestamp';
  22. const KEY_LAST_RESET = 'antiDTF_lastReset';
  23.  
  24. // --- Helper Functions for Storage ---
  25. async function getConfig(key, defaultValue = null) {
  26. return await GM_getValue(key, defaultValue);
  27. }
  28.  
  29. async function setConfig(key, value) {
  30. await GM_setValue(key, value);
  31. }
  32.  
  33. // --- Blocked Page Styling and Content ---
  34. const blockedStyles = `
  35. body {
  36. background: #ff00ff !important;
  37. color: #ffff00 !important;
  38. font-family: 'Comic Sans MS', cursive, sans-serif !important;
  39. text-align: center !important;
  40. font-size: 32px !important;
  41. margin: 0 !important;
  42. padding: 0 !important;
  43. height: 100vh !important;
  44. display: flex !important;
  45. align-items: center !important;
  46. justify-content: center !important;
  47. overflow: hidden !important;
  48. }
  49. /* Hide everything else just in case */
  50. body > *:not(#antiDTF-blocked-message) {
  51. display: none !important;
  52. }
  53. `;
  54. const blockedHTML = `<div id="antiDTF-blocked-message">Лимит DTF на сегодня исчерпан. Пиздуй работать.</div>`;
  55.  
  56. // --- Core Time Limit Check Logic ---
  57. async function checkTimeLimit() {
  58. const dailyLimit = await getConfig(KEY_DAILY_LIMIT);
  59. let startTimestamp = await getConfig(KEY_START_TIMESTAMP);
  60. let lastReset = await getConfig(KEY_LAST_RESET);
  61.  
  62. // If limit is not set or invalid, do nothing
  63. if (dailyLimit === null || isNaN(dailyLimit) || dailyLimit <= 0) {
  64. console.log("antiDTF: Limit not set or invalid.");
  65. return false; // Not blocked
  66. }
  67.  
  68. const limitMinutes = parseInt(dailyLimit, 10);
  69. const nowDate = new Date().toDateString();
  70.  
  71. // Check if it's a new day
  72. if (lastReset !== nowDate) {
  73. console.log("antiDTF: New day detected. Resetting timer.");
  74. startTimestamp = Date.now();
  75. await setConfig(KEY_LAST_RESET, nowDate);
  76. await setConfig(KEY_START_TIMESTAMP, startTimestamp);
  77. console.log(`antiDTF: Timer reset. Limit: ${limitMinutes} minutes.`);
  78. return false; // Not blocked yet today
  79. }
  80.  
  81. // Check if startTimestamp is valid (necessary after first setting the limit)
  82. if (!startTimestamp) {
  83. console.log("antiDTF: Start timestamp missing for today. Initializing.");
  84. startTimestamp = Date.now();
  85. await setConfig(KEY_START_TIMESTAMP, startTimestamp);
  86. return false; // Not blocked yet
  87. }
  88.  
  89. // Calculate elapsed time
  90. const elapsedMs = Date.now() - startTimestamp;
  91. const elapsedMinutes = Math.floor(elapsedMs / 60000);
  92.  
  93. console.log(`antiDTF: Time check - Elapsed: ${elapsedMinutes} min / Limit: ${limitMinutes} min`);
  94.  
  95. // Check if limit is exceeded
  96. if (elapsedMinutes >= limitMinutes) {
  97. console.log("antiDTF: Daily limit exceeded. Blocking page.");
  98. blockPage();
  99. return true; // Blocked
  100. }
  101.  
  102. return false; // Not blocked
  103. }
  104.  
  105. // --- Function to Block the Page ---
  106. function blockPage() {
  107. // Stop further loading/scripts if possible
  108. try { window.stop(); } catch (e) { console.warn("antiDTF: Could not stop window loading.", e); }
  109.  
  110. // Apply styles first
  111. GM_addStyle(blockedStyles);
  112.  
  113. // Replace body content
  114. document.body.innerHTML = blockedHTML;
  115.  
  116. // Set title
  117. document.title = "antiDTF - Лимит исчерпан";
  118. }
  119.  
  120. // --- Settings via Menu Commands (Replaces Popup) ---
  121.  
  122. // 1. Set/Change Limit
  123. GM_registerMenuCommand("antiDTF: Установить/Изменить лимит", async () => {
  124. const currentLimit = await getConfig(KEY_DAILY_LIMIT, '');
  125. const newLimitStr = prompt(`Введите дневной лимит времени на DTF в минутах.\n(Текущий: ${currentLimit || 'не установлен'})\nВведите 0 или оставьте пустым для снятия лимита.`, currentLimit);
  126.  
  127. if (newLimitStr === null) return; // User cancelled
  128.  
  129. const newLimit = parseInt(newLimitStr.trim(), 10);
  130.  
  131. if (!isNaN(newLimit) && newLimit > 0) {
  132. await setConfig(KEY_DAILY_LIMIT, newLimit);
  133. // Reset timer immediately when limit is set/changed
  134. const today = new Date().toDateString();
  135. await setConfig(KEY_LAST_RESET, today);
  136. await setConfig(KEY_START_TIMESTAMP, Date.now());
  137. alert(`antiDTF: Лимит установлен на ${newLimit} минут в день.\nТаймер сброшен на сегодня.`);
  138. // Reload to apply immediately (especially important if currently blocked)
  139. location.reload();
  140. } else if (newLimitStr.trim() === '' || newLimit === 0) {
  141. await setConfig(KEY_DAILY_LIMIT, null); // Use null to indicate no limit
  142. await setConfig(KEY_START_TIMESTAMP, null);
  143. await setConfig(KEY_LAST_RESET, '');
  144. alert("antiDTF: Лимит снят.");
  145. // Reload to unblock if currently blocked
  146. location.reload();
  147. } else {
  148. alert("antiDTF: Ошибка. Введите положительное число минут или 0 для снятия лимита.");
  149. }
  150. });
  151.  
  152. // 2. Extend Limit ("Продлить как лох")
  153. GM_registerMenuCommand("antiDTF: Продлить как лох", async () => {
  154. const currentLimit = await getConfig(KEY_DAILY_LIMIT);
  155. if (currentLimit === null) {
  156. alert("antiDTF: Сначала установите основной лимит.");
  157. return;
  158. }
  159.  
  160. const addMinutesStr = prompt(`На сколько минут продлить сегодняшний лимит? (Текущий: ${currentLimit} минут)`);
  161. if (addMinutesStr === null) return; // User cancelled
  162.  
  163. const addMinutes = parseInt(addMinutesStr.trim(), 10);
  164.  
  165. if (!isNaN(addMinutes) && addMinutes > 0) {
  166. const newLimit = (parseInt(currentLimit, 10) || 0) + addMinutes;
  167. await setConfig(KEY_DAILY_LIMIT, newLimit);
  168. alert(`antiDTF: Лимит продлен на ${addMinutes} минут.\nНовый лимит на сегодня: ${newLimit} минут.\nСтраница будет перезагружена.`);
  169. // Don't reset startTimestamp here, just increase the ceiling for today
  170. location.reload(); // Reload to potentially unblock or continue browsing
  171. } else {
  172. alert("antiDTF: Ошибка. Введите положительное число минут.");
  173. }
  174. });
  175.  
  176. // 3. Check Status
  177. GM_registerMenuCommand("antiDTF: Проверить статус", async () => {
  178. const dailyLimit = await getConfig(KEY_DAILY_LIMIT);
  179. let startTimestamp = await getConfig(KEY_START_TIMESTAMP);
  180. let lastReset = await getConfig(KEY_LAST_RESET);
  181.  
  182. if (dailyLimit === null) {
  183. alert("antiDTF: Лимит времени не установлен.");
  184. return;
  185. }
  186.  
  187. const limitMinutes = parseInt(dailyLimit, 10);
  188. const nowDate = new Date().toDateString();
  189.  
  190. if (lastReset !== nowDate || !startTimestamp) {
  191. // Handles both new day and cases where start timestamp wasn't set yet
  192. alert(`antiDTF:\nЛимит: ${limitMinutes} минут в день.\nТаймер на сегодня еще не запущен (начнет отсчет при следующем взаимодействии с сайтом).`);
  193. return;
  194. }
  195.  
  196. const elapsedMs = Date.now() - startTimestamp;
  197. const elapsedMinutes = Math.floor(elapsedMs / 60000);
  198. const remainingMinutes = Math.max(0, limitMinutes - elapsedMinutes);
  199. const remainingSecondsTotal = Math.max(0, (limitMinutes * 60) - Math.floor(elapsedMs / 1000));
  200. const remainingSecs = remainingSecondsTotal % 60;
  201. const remainingMins = Math.floor(remainingSecondsTotal / 60);
  202.  
  203.  
  204. alert(`antiDTF Статус:\nЛимит: ${limitMinutes} минут.\nИспользовано сегодня: ${elapsedMinutes} минут.\nОсталось: ${remainingMins} мин ${remainingSecs < 10 ? '0' : ''}${remainingSecs} сек.`);
  205. });
  206.  
  207.  
  208. // --- Initial Execution ---
  209. console.log("antiDTF Userscript running on:", window.location.href);
  210. // Run the check when the script loads
  211. await checkTimeLimit();
  212.  
  213. // Note: The script runs on 'document-idle', so the page content might already be visible
  214. // for a moment before being blocked if the limit is exceeded. The check runs on every
  215. // matching page load/navigation.
  216.  
  217. })();