// ==UserScript== // @name 控制网页使用限制 单独域名版 // @namespace http://tampermonkey.net/ // @version 0.8 // @description 可以记录在不同的网站的使用时间,设置每个网站的可用时间,如果到达了指定的时间,页面会被遮挡而无法正常 // @author lavaf // @match https://*/* // @match http://*/* // @grant GM.setValue // @grant GM.getValue // @grant GM.deleteValue // @grant GM.listValues // @grant window.close // @noframes // @require https://cdn.bootcss.com/jquery/3.4.1/jquery.js // @require https://cdn.bootcss.com/jqueryui/1.12.1/jquery-ui.js // @downloadURL none // ==/UserScript== (async function () { 'use strict'; //region load css addStyle("@import 'https://cdn.bootcss.com/jqueryui/1.12.1/jquery-ui.css'"); function addStyle(style) { const head = document.getElementsByTagName("HEAD")[0]; const ele = head.appendChild(window.document.createElement('style')); ele.innerHTML = style; return ele; } //endregion load css //region function data let usage; /** * * @return {Promise} */ async function deleteData() { try { // noinspection JSUnresolvedVariable if (GM !== undefined && GM.deleteValue !== undefined && typeof GM.deleteValue == 'function') { // noinspection JSUnresolvedVariable,JSUnresolvedFunction await GM.deleteValue(key); } } catch (e) { // console.log(log_key, 'error', e) } } /** * * @returns {Promise} */ async function getData() { try { // noinspection JSUnresolvedVariable if (GM !== undefined && GM.getValue !== undefined) { // noinspection JSUnresolvedVariable,JSCheckFunctionSignatures return await GM.getValue(key).catch((reason => { console.log(log_key, 'error in promise catch', reason); })); } } catch (e) { console.log(log_key, 'error in try-catch getData', e) } return null; } /** * * @param key * @returns {Promise} */ async function getOtherData(key) { // console.log(log_key, 'getOtherData called:key:', key); try { // noinspection JSUnresolvedVariable if (GM !== undefined && GM.getValue !== undefined) { // noinspection JSUnresolvedVariable let t = await GM.getValue(key).catch((reason => { console.log(log_key, 'error in promise catch', reason); })); if (t != null) { return JSON.parse(t); } } } catch (e) { console.log(log_key, 'error in try-catch getOtherData', e) } return null; } /** * * @returns {Promise} */ async function saveData(remedy = true) { // console.log(log_key, "savedData called") if (remedy) await remedyTimeDiff(); let value = JSON.stringify(usage); try { // noinspection JSUnresolvedVariable if (GM !== undefined && GM.setValue !== undefined && typeof GM.setValue == 'function') { // noinspection JSUnresolvedVariable,JSUnresolvedFunction await GM.setValue(key, value); } } catch (e) { // console.log(log_key, 'error', e) } } /** * * @returns {Promise} */ async function getList() { try { // noinspection JSUnresolvedVariable if (GM !== undefined && GM.listValues !== undefined && typeof GM.listValues == 'function') { // noinspection JSUnresolvedVariable,JSUnresolvedFunction return await GM.listValues(); } } catch (e) { // console.log(log_key, 'error', e) } return null; } /** * 新建一个对象 * @return {{restrict: {single: undefined, domain, limit: undefined, interval: undefined}, statistics: {single: {date: undefined, time: number}|null, data: [], domain}}} */ function newObject() { return { 'restrict': {'domain': current_domain, 'limit': undefined, single: undefined, "interval": undefined}, 'statistics': { 'domain': current_domain, 'data': [], "single": {'time': 0, "date": undefined} } }; } /** * 获取数据,解析成json对象 * @return {{'restrict':{'domain':String,'limit':Number,'single':Number},statistics:{'domain':String,'data':[{year:Number,month:Number,day:Number,time:Number}]}}} */ async function getUsage(save = false) { let data = await getData(); // console.log(log_key, 'data:', data); if (data == null) { // console.log(log_key, "initUsage", "getData return null"); let usage = newObject(); if (save) await saveData(); return usage; } else { let parse = JSON.parse(data); if (parse.restrict === undefined || parse.statistics === undefined) { console.log(log_key, 'script data is null'); let usage = newObject(); if (save) await saveData(); return usage; } return parse; } } async function initUsage() { usage = await getUsage(); //console.log(log_key, 'after initUsage usage:', usage); } //endregion function data //let message = "web_page_usage_init"; if (window.top !== window.self) { //console.log(message,"Current environment is frame") return; } let webPageUsage = "web_page_usage"; console.log(webPageUsage,'start'); //region init key-url let current_h_href = location.href; //console.log(message, "current_h_href", current_h_href); let reg = new RegExp(/^(?:(?:ftp|http[s]?)?:\/\/)?(?:[\dA-Za-z-]+\.)+[\dA-Za-z-]+(?::[\d]{1,4})*/); let reg_localhost = new RegExp(/^(?:(?:ftp|http[s]?)?:\/\/)?localhost(?::[\d]{1,4})*/); let result = reg.exec(current_h_href); if (result == null) { //console.log(message, 'reg 不匹配'); result = reg_localhost.exec(current_h_href); if (result == null) { //console.log(message, "result is null"); return } } // console.log(log_key, "result:", result); let current_domain = result[0]; // let url_part = current_domain.split("."); // current_domain=url_part[url_part.length-2]+"."+url_part[url_part.length-1] // console.log(log_key,current_domain); let log_key = webPageUsage + "->" + current_domain; let key_base = "f-usage-data-"; let key = key_base + current_domain; //endregion key-url await initUsage(); if (usage === undefined) { //console.log(log_key, "usage is null"); usage = {}; } let statistics_data = usage.statistics; let restrict_data = usage.restrict; let current_statistics = getDomainStatisticsTimeObject(statistics_data.data, current_domain); //console.log(log_key, 'current_statistics', current_statistics); let statisticsTimer; let checkTimer; let counter = 0; let printTimer; //region ui let manager_panel = $("
", {id: "web_page_usage_manager_panel_id", 'translate': 'no'}); manager_panel.appendTo('body'); let web_page_usage_z_index = 10000001; let dialog_z_index = '10000001'; let curtain_z_index = 10000000; manager_panel.css({ 'position': 'fixed', 'left': '0', 'top': '50%', 'z-index': web_page_usage_z_index, 'background-color': 'white', 'border': '1px solid black' }); //region statistics let statistics_panel = $('
'); let totalTimeWasteLabel = $("

"); totalTimeWasteLabel.appendTo(statistics_panel); let statistics_ol = $('

    ', {id: "web-page-usage-statistics-ol"}); statistics_ol.css({'height': "100px", 'overflow-y': 'scroll'}); statistics_ol.appendTo(statistics_panel); let currentSecond = $(""); currentSecond.appendTo(statistics_panel); currentSecond.title = "当前计算时间的秒数 当前页面从打开直到现在的秒数" let clear_data_button = $("
`; let restrictPanel = $($.parseHTML(restrictPanelString)); let dialog_string = `
到达单次使用限制了
`; let singleDialog = $($.parseHTML(dialog_string)); singleDialog.css('display', 'none'); singleDialog.appendTo('body'); restrictPanel.appendTo(manager_panel); let top = $('div#web-page-usage-top'); let input_string = `
`; let input_div = $($.parseHTML(input_string)); input_div.appendTo(top); let saveButton = $("#saveLimitButton"); let input_url = $("#add_input_data"); input_url.val(current_domain); let input_limit = $("#add_input_limit_time"); input_limit.val(restrict_data.limit); let inputSingleLimit = $("#add_input_single_limit"); inputSingleLimit.val(restrict_data.single); let interval = $("#add_input_time_interval") interval.val(restrict_data.interval) let saveSingleInterval = $("#save_single_interval") async function afterUpdateConfig() { await saveData(); curtain.hide(); startTimer(); printList(); } saveButton.click(async function () { stopTimer(); //获取input 中的内容 let url = input_url.val(); console.log(log_key,"添加限制", url, input_limit.val()); let limit = parseInt(input_limit.val()); if (limit === Number.NaN || limit === -1) { restrict_data.limit = undefined; } else { // noinspection JSValidateTypes restrict_data.limit = limit; console.log(log_key, "保存", limit, restrict_data); } await afterUpdateConfig(); }); let saveSingleButton = $("#save_single_limit"); saveSingleButton.click(async function () { stopTimer(); //获取input 中的内容 //let url = input_url.val(); // noinspection JSValidateTypes8 let single = parseInt(inputSingleLimit.val()); if (single === Number.NaN || single === -1) { restrict_data.single = undefined; } else { restrict_data.single = single; } await afterUpdateConfig(); }); saveSingleInterval.click(async function () { stopTimer(); let interval1 = parseInt(interval.val()); if (interval1 === Number.NaN || interval1 === -1) { restrict_data.interval = undefined; } else { restrict_data.interval = interval1; } await saveData(); startTimer(); printList(); }) // let center = $('div#center'); let viewStatisticsButton = $('button#web-page-usage-view'); viewStatisticsButton.click(async function () { dialog_ol.children().remove(); let list = await getList(); console.log(log_key, 'list', list, 'type', typeof list); let space = 0; for (let index = 0; index < list.length; index++) { let temp = await getOtherData(list[index]); space += JSON.stringify(temp).length; // console.log(log_key, 'temp', temp); let domain_item = temp.statistics.domain; let ol_div = $("
"); let ol_div_ol = $("
    "); let timeData = temp.statistics['data']; if (timeData == null) { continue; } let timeSum = 0; for (let day = 0; day < timeData.length; day++) { let ol_div_ol_p = $("

    "); let tt = timeData[day]; let t = tt['time']; timeSum += t; ol_div_ol_p.text(`${tt['year']}-${tt['month']}-${tt['day']}: ${format(t)}`); ol_div_ol_p.appendTo(ol_div_ol); } let ol_div_legend = $("

    ", {text: domain_item + " " + format(timeSum) + (temp.restrict.limit !== undefined ? " ⌛" + temp.restrict.limit : "")}); ol_div_legend.appendTo(ol_div); ol_div_ol.appendTo(ol_div); /** * * @type {Object} */ let position = null; for (let y = 0; y < dialog_ol.children().length; y++) { let $1 = $(dialog_ol.children().get(y)); if (parseInt($1.attr('data-timeData-sum')) < timeSum) { position = $1; break; } } if (position != null) { position.before(ol_div); } else ol_div.appendTo(dialog_ol); ol_div.attr('data-timeData-sum', timeSum); } if (dialog.dialog == null || typeof dialog.dialog !== "function") { dialog.dialog = function () { console.log(log_key, "启动对话框失败"); } } dialog.dialog({ title: '所有数据:数据占用空间' + space, modal: true, height: document.body.clientHeight / 2, width: document.body.clientWidth / 2, 'minWidth': '300', open: function (event, ui) { }, buttons: { 'close': function () { $(this).dialog("close"); } } }); let elementsByClassName = document.getElementsByClassName('ui-dialog'); for (let i = 0; i < elementsByClassName.length; i++) { if (elementsByClassName[i].innerText.indexOf("所有数据") >= 0) elementsByClassName[i].style.zIndex = dialog_z_index } }); viewStatisticsButton.dblclick(function () { clearInterval(statisticsTimer); }); let bottom = $('
    ', { "id": "web-page-usage-bottom" }); bottom.css({'height': "100px"}); let ol = $("
      ", { id: 'web-page-usage-restrictPanel-ol' }); ol.appendTo(bottom); bottom.appendTo(restrictPanel); printList(); //endregion restrictPanel function printList() { if (ol.children().length !== 0) ol.children().remove(); if (restrict_data.limit != null) { let li = $('
    1. '); li.text(restrict_data['domain'] + " limit:" + format(restrict_data.limit) + " " + restrict_data.limit + "s"); li.appendTo(ol) } if (restrict_data.single != null) { let li = $('
    2. '); li.text(restrict_data['domain'] + " single:" + format(restrict_data.single) + " " + restrict_data.single + "s"); li.appendTo(ol) } if (restrict_data.interval != null) { let li = $("
    3. ") li.text(restrict_data['domain'] + " interval:" + format(restrict_data.interval) + " " + restrict_data.interval + "s") li.appendTo(ol); } } //region button let button = $('