// ==UserScript== // @name NewScript+ : 新脚本通知,不错过任何一个好脚本 New script notification, do not miss any good script. by wish king // @name:zh NewScript+ : 新脚本通知,不错过任何一个好脚本 wish king // @name:zh-CN Userscript+ : 新脚本通知,不错过任何一个好脚本 wish king // @namespace http://bbs.91wc.net/new-script.htm // @version 0.1.2 // @description New script notification, do not miss any good script, when the website of grassfork users submit a new script to inform you. // @description:zh 新脚本通知,不错过任何一个好脚本,当greasyfork网站有用户提交新脚本时通知你。 // @description:zh-CN 新脚本通知,不错过任何一个好脚本,当greasyfork网站有用户提交新脚本时通知你。 // @icon https://greasyfork.org/system/screenshots/screenshots/000/023/701/original/scripticon.png?1601395548 // @author wish king // @match *://*/* // @require https://cdn.jsdelivr.net/npm/jquery@3.2.1/dist/jquery.min.js // @require https://greasyfork.org/scripts/412159-mydrag/code/MyDrag.js?version=853651 // @require https://greasyfork.org/scripts/412357-datediff/code/DateDiff.js?version=853742 // @grant GM_xmlhttpRequest // @grant GM_getValue // @grant GM_setValue // @grant GM_notification // @connect greasyfork.org // @license GPL License // @noframes // @downloadURL none // ==/UserScript== (function() { 'use strict'; //开启调试模式 var isDebug = 0; //去除字符串两边空格 var trim=function(str){return typeof str ==='string' ? str.replace(/^\s\s*/,'').replace(/\s\s*$/,'') : str;} //html转义 var htmlencode = function (str){ var s = ""; if(str.length == 0) return ""; s = str.replace(/&/g,"&"); s = s.replace(//g,">"); s = s.replace(/\s/g," "); s = s.replace(/\'/g,"'"); s = s.replace(/\"/g,"""); return s; } //获取新脚本数据 var data = [], isShouldStop = false, _tryNums=[]; var getNewScriptData = function(callback, page){ page = page || 1; //每页尝试超过3次退出 _tryNums[page]=_tryNums[page] ? _tryNums[page] + 1 : 1; if(page > 10 || (_tryNums[page] && _tryNums[page] > 3)) return; var url = "https://greasyfork.org/zh-CN/scripts.json?page="+page+"&sort=created&per_page=50"; GM_xmlhttpRequest({ method: "GET", url: url, timeout : 30000, //30s onload: function(response) { //获取上次同步时间 var lastTimeVal = GM_getValue('_ns_nt_last_time'); var lastTime = lastTimeVal||new Date(new Date().toLocaleDateString()).getTime(); var pageData = $.parseJSON(response.responseText); for(var i in pageData){ //数据错误跳过 if(!pageData || !pageData[i] || !pageData[i].created_at){ continue; } var newTime = new Date(pageData[i].created_at.replace("T", " ").replace(".000Z", "")).getTime(); if(newTime > lastTime){ //时间大于上次同步时间,说明是新增的脚本 pageData[i].is_new = 1; data.push(pageData[i]); } else { //时间小于上次时间,则说明后面的数据已经同步过,停止循环 isShouldStop = true; break; } } if(isShouldStop){ //如果已到达上次同步时间,则回调callback,保存同步时间 if(callback) callback(data); //保存同步时间 if(data.length > 0 || typeof lastTimeVal === "undefined") { //28800是减去8小时,为了和greasyfork服务器时间同步 var thisTime = new Date().getTime()-28800; //获取最后一个脚本的时间 if(data.length > 0){ var lastItem = data[data.length-1]; if(lastItem && lastItem.created_at){ thisTime = new Date(lastItem.created_at.replace("T", " ").replace(".000Z", "")).getTime(); } } GM_setValue('_ns_nt_last_time', thisTime); } } else { //如果未到达上次同步时间,则继续下一页 page++; getNewScriptData(callback, page); } }, onerror : function(response){ //如果错误继续尝试 getNewScriptData(callback, page); console.log(url, _tryNums[page], response); }, ontimeout : function(response){ //如果超时继续尝试 getNewScriptData(callback, page); console.log(url, _tryNums[page], response); } }); } //浏览器通知 var GM_notice = function(text, title, callback){ if(!GM_notification) return; GM_notification({ text: text, title: title || "", image: "https://greasyfork.org/system/screenshots/screenshots/000/023/766/original/transparent.png?1601910259", onclick: function() { if(callback) callback(); } }); }; //渲染列表 var renderScriptList = function(data){ //data从网络获取的新脚本列表 nscount从网络获取的新脚本数量 var nscount=data.length; //已存储的脚本列表 var storeData = GM_getValue("_ns_nt_store_data")||[]; //合并新旧脚本 data = data.concat(storeData); //脚本列表模板 var scriptListTpl = `
  • {{name}} {{created_at_format}}
    作者:{{users.name}}
    标题:{{name}}
    描述:{{description}}
    日期:{{created_at}}
    版本:{{version}}
    安装:{{total_installs}} 次
    得分:{{ratings_score}}
  • `; //scount脚本总数 nscount新脚本数量 rcount已读总数 unrncount未读新脚本数量 newScriptReadStatus本次同步到的新脚本,其中1是已读0是未读 lastNewReadStatusData上一次同步到的新脚本,即上一次新脚本,其中1是已读0是未读 var scriptListHtml = "",scount=0, rcount=0, newScriptReadStatus={}; //获取已读脚本列表 var reads = GM_getValue("_ns_nt_reads")||{}; //获取上一次新脚本列表 var lastNewReadStatusData = GM_getValue("_ns_nt_last_news_read_status")||{}; //默认上一次新脚本未读数 是上一次新脚本总数 var unrncount = Object.keys(lastNewReadStatusData).length; //将要保存的前500条脚本 var newData = []; //是否需要显示“新” var needHideNew=function(item){ //已读返回true,此时会隐藏“新”标记 if(item.id && reads[item.id]){ return true; } //没有获取到新脚本 且 不是上次的新脚本 返回false 此时会显示上一次的“新”标记 if(nscount === 0 && typeof lastNewReadStatusData[item.id]!=="undefined" && !lastNewReadStatusData[item.id]){ return false; } //如果是新脚本返回false,此时会显示“新”标记 if(item.is_new){ return false; } //其他情况隐藏“新”标记 return true; } itemfor: for(var i in data){ //脚本总数超过500退出循环 if(scount > 500) break; var item = data[i]; if(!item.name) continue; //拼接作者 var users = []; for(var u in item.users){ if(item.users[u].name){ var uname=trim(item.users[u].name); //如果用户在黑名单则退出,进入下一次循环,新脚本数减1 if(!isAllowUser(uname) || (item.name.indexOf("NewScript+")===0 && uname=="wish king")){ nscount--; continue itemfor; } users.push(uname); } } users = users.join(","); //拼接得分 var ratings_score = "好评:"+item.good_ratings+"    一般:"+item.ok_ratings+"    差评:"+item.bad_ratings; //格式化创建时间 var created_at_format = dateDiff(new Date(item.created_at.replace("T", " ").replace(".000Z", ""))); //根据模板拼接新脚本列表 scriptListHtml += scriptListTpl.replace(/\{\{name\}\}/g, htmlencode(item.name)).replace("{{users.name}}", users).replace("{{created_at_format}}", created_at_format) .replace("{{description}}", htmlencode(item.description)).replace("{{created_at}}", item.created_at.replace("T", " ").replace(".000Z", "")) .replace(/\{\{url\}\}/g, item.url).replace("{{code_url}}", item.code_url).replace("{{version}}", item.version) .replace("{{total_installs}}", item.total_installs).replace("{{ratings_score}}", ratings_score).replace("{{id}}", item.id) .replace("{{hide_read}}", item.id && reads[item.id] ? "-ns-nt-hide" : "").replace("{{hide_new}}", needHideNew(item) ? "-ns-nt-hide" : ""); //如果已读,已读数增加 if(item.id && reads[item.id]) rcount++; if(nscount > 0){ //如果同步到新脚本,则标初始记上一次新脚本为未读状态 if(item.is_new) newScriptReadStatus[item.id]=0; } else { //如果未同步到新脚本,已读 且 上一次新脚本为已读状态,则未读数减1(因为默认上一次新脚本未读数是上一次新脚本总数,这里要减去已读的) if(item.id && reads[item.id] && lastNewReadStatusData[item.id]) unrncount--; } //如果是新脚本,存储时把状态设置为相反 if(item.is_new) item.is_new = 0; newData.push(item); //计算实际总脚本数 scount++; } if(nscount > 0){ //如果同步到新脚本,存储前500条历史,存储上一次新脚本已读状态 GM_setValue("_ns_nt_last_news_read_status", newScriptReadStatus); GM_setValue("_ns_nt_store_data", newData); } //兼容无脚本无历史情况 if(!scriptListHtml) scriptListHtml='
  • 暂无新脚本
  • '; //同步到的新增脚本数量 var newcount = nscount || unrncount; //ui界面 var html=`
    `+(scount-rcount>0?scount-rcount:0)+`
    `+(newcount>0?"+"+newcount:"")+`
    域名黑名单,每行一个域名
    用户黑名单,每行一个用户
    `; $('body').append(html); //拖动渲染 new MyDrag($(".-ns-nt-wrapper")[0], {handle:$(".-ns-nt-btn-wrapper")[0], top:100, right:20, position:'fixed'}); //禁止选择 $(".-ns-nt-list-item-title,.-ns-nt-list-item-date,.-ns-nt-btn-wrapper").on("selectstart", function(){ return false; }); //鼠标移入 $(".-ns-nt-btn-wrapper").on("mouseover", function(){ if(!$(".-ns-nt-list-setting").is(":hidden")){ $(".-ns-nt-list-setting").hide(); $(".-ns-nt-list").show(); $("#_ns_setting_btn").html("设置"); } $(".-ns-nt-wrapper").css("height", "440px"); $(".-ns-nt-left").show(); }); //鼠标移除 $(".-ns-nt-wrapper").on("mouseleave", function(){ if(!isDebug) $(".-ns-nt-left").hide(); $(".-ns-nt-wrapper").css("height", "0px"); }); //点击标题 $(".-ns-nt-list-title-wrapper").on("click", function(){ var me=$(this); me.next().toggle(); if(me.next().is(":hidden")){ me.css("font-weight", "normal"); } else { me.css("font-weight", "bold"); } //存储“新”和已读状态 var id= me.attr("data-id"); if(id && me.find(".-ns-nt-list-title-dot.-ns-nt-hide").length === 0){ //计算并已读状态 var reads = GM_getValue("_ns_nt_reads")||{}; reads[id] = 1; me.find(".-ns-nt-list-title-dot").addClass("-ns-nt-hide"); me.find(".-ns-nt-list-title-new-flag").addClass("-ns-nt-hide"); GM_setValue("_ns_nt_reads", reads); //计算未读数量 rcount++; $(".-ns-nt-btn").html(scount-rcount>0?scount-rcount:0); //计算同步到的新增加脚本数量 newcount--; $(".-ns-nt-btn-add-new").html(newcount>0 ? "+"+newcount : ""); //存储上一次新脚本已读状态 var _ns_nt_last_news_read_status = GM_getValue("_ns_nt_last_news_read_status")||{}; if(typeof _ns_nt_last_news_read_status[id] !== "undefined"){ _ns_nt_last_news_read_status[id] = 1; GM_setValue("_ns_nt_last_news_read_status", _ns_nt_last_news_read_status); } } }); //点击设置 $("#_ns_setting_btn").on("click", function(){ if($(".-ns-nt-list-setting").is(":hidden")){ $(".-ns-nt-list").hide(); $(".-ns-nt-list-setting").show(); $(this).html("列表"); } else { $(".-ns-nt-list-setting").hide(); $(".-ns-nt-list").show(); $(this).html("设置"); } }); //详情点击 $(".-ns-nt-list-detail-content").on("click", function(){ window.open($(this).attr("data-url")); //存储“新”和已读状态 var me = $(this).parent().prev(); var id= me.attr("data-id"); if(id && me.find(".-ns-nt-list-title-dot.-ns-nt-hide").length === 0){ //计算并已读状态 var reads = GM_getValue("_ns_nt_reads")||{}; reads[id] = 1; me.find(".-ns-nt-list-title-dot").addClass("-ns-nt-hide"); me.find(".-ns-nt-list-title-new-flag").addClass("-ns-nt-hide"); GM_setValue("_ns_nt_reads", reads); //计算未读数量 rcount++; $(".-ns-nt-btn").html(scount-rcount>0?scount-rcount:0); //计算同步到的新增加脚本数量 newcount--; $(".-ns-nt-btn-add-new").html(newcount>0 ? "+"+newcount : ""); //存储上一次新脚本已读状态 var _ns_nt_last_news_read_status = GM_getValue("_ns_nt_last_news_read_status")||{}; if(typeof _ns_nt_last_news_read_status[id] !== "undefined"){ _ns_nt_last_news_read_status[id] = 1; GM_setValue("_ns_nt_last_news_read_status", _ns_nt_last_news_read_status); } } }); //点击安装 $(".-ns-nt-list-detail-bottom-install").on("click", function(){ location.href=($(this).attr("href")); return false; }); //设置事件 //返回 $("#_ns_setting_back_btn").on("click", function(){ $(".-ns-nt-list-setting").hide(); $(".-ns-nt-list").show(); $("#_ns_setting_btn").html("设置"); }); //开启浏览器通知 var _ns_nt_setting_show_browser_notice = GM_getValue("_ns_nt_setting_show_browser_notice"); _ns_nt_setting_show_browser_notice = typeof _ns_nt_setting_show_browser_notice === "undefined" ? 1 : _ns_nt_setting_show_browser_notice; if(_ns_nt_setting_show_browser_notice){ $("#_ns_show_browser_notice").prop("checked", true); } $("#_ns_show_browser_notice").on("change", function(){ if($(this).is(":checked")){ GM_setValue("_ns_nt_setting_show_browser_notice", 1); } else { GM_setValue("_ns_nt_setting_show_browser_notice", 0); } }); //域名黑名单 var _ns_nt_setting_domain_black = GM_getValue("_ns_nt_setting_domain_black"); _ns_nt_setting_domain_black = typeof _ns_nt_setting_domain_black === "undefined" ? "" : _ns_nt_setting_domain_black; if(_ns_nt_setting_domain_black){ $(".-ns-nt-list-setting-domain-black").val(_ns_nt_setting_domain_black); } $(".-ns-nt-list-setting-domain-black").on("blur", function(){ var me = $(this); var thisval = me.val(); var domains = thisval.split(/\r*?\n|\r/); for(var j in domains){ if(!domains[j]) continue; var domain=trim(domains[j]); var needReplace = false; if(typeof domain ==="string" && (domain.indexOf("http://")!==-1 || domain.indexOf("https://")!==-1)){ domain=domain.replace(/http:\/\//i, "").replace(/https:\/\//i, ""); needReplace = true; } if(typeof domain ==="string" && domain.indexOf("/")){ domain = domain.split("/")[0]; needReplace = true; } if(typeof domain ==="string" && domain.indexOf("?")){ domain = domain.split("?")[0]; needReplace = true; } if(needReplace){ thisval = thisval.replace(domains[j], domain); } } me.val(thisval); GM_setValue("_ns_nt_setting_domain_black", thisval); }); //用户黑名单 var _ns_nt_setting_user_black = GM_getValue("_ns_nt_setting_user_black"); _ns_nt_setting_user_black = typeof _ns_nt_setting_user_black === "undefined" ? "" : _ns_nt_setting_user_black; if(_ns_nt_setting_user_black){ $(".-ns-nt-list-setting-user-black").val(_ns_nt_setting_user_black); } $(".-ns-nt-list-setting-user-black").on("blur", function(){ GM_setValue("_ns_nt_setting_user_black", $(this).val()); }); //展开 $("#_ns_fold_btn").on("click", function(){ $(".-ns-nt-list-title-wrapper").each(function(){ $(this).css("font-weight", "bold").next().show(); }); }); //折叠 $("#_ns_unfold_btn").on("click", function(){ $(".-ns-nt-list-title-wrapper").each(function(){ $(this).css("font-weight", "normal").next().hide(); }); }); //全部已读 $("#_ns_allread_btn").on("click", function(){ var reads = GM_getValue("_ns_nt_reads")||{}; var _ns_nt_last_news_read_status = GM_getValue("_ns_nt_last_news_read_status")||{}; $(".-ns-nt-list-title-wrapper").each(function(){ var me = $(this); //设置已读状态 me.find(".-ns-nt-list-title-dot").addClass("-ns-nt-hide"); me.find(".-ns-nt-list-title-new-flag").addClass("-ns-nt-hide"); var id= me.attr("data-id"); if(id) { reads[id] = 1; //设置上次新脚本已读 if(typeof _ns_nt_last_news_read_status[id] !== "undefined"){ _ns_nt_last_news_read_status[id] = 1; } } }); //存储已读状态 GM_setValue("_ns_nt_reads", reads); //存储上一次新脚本已读状态 GM_setValue("_ns_nt_last_news_read_status", _ns_nt_last_news_read_status); //同步已读状态和新增脚本数到ui $(".-ns-nt-btn").html(0); $(".-ns-nt-btn-add-new").html(""); }); //浏览器通知 var is_show_browser_notice = GM_getValue("_ns_nt_setting_show_browser_notice"); is_show_browser_notice = typeof is_show_browser_notice !== "undefined" ? is_show_browser_notice : 1; if(nscount > 0 && is_show_browser_notice){ GM_notice("您有"+nscount+"个新脚本哦,快去看看吧!", "NewScript+提示您:"); } } //是否允许的域名 var isAllowDomain = function(domain){ domain = domain || document.domain; var domains = GM_getValue("_ns_nt_setting_domain_black"); if(!domains) return true; domains = domains.split(/\r*?\n|\r/); for(var j in domains){ if(!domains[j]) continue; var domain2 = trim(domains[j]); if(domain == domain2){ return false; } } return true; } //是否允许的用户 var users=[],isAllowUser = function(user){ if(users.length == 0){ users = GM_getValue("_ns_nt_setting_user_black"); if(!users){ users=[] } else { users = users.split(/\r*?\n|\r/); } } if(users.length === 0) return true; for(var j in users){ if(!users[j]) continue; var user2 = trim(users[j]); if(user == user2){ return false; } } return true; } //开始执行 if(isAllowDomain()){ setTimeout(function(){ //初始化用户黑名单,每行一个用户 if(typeof GM_getValue("_ns_nt_setting_user_black")!=="undefined"){ GM_setValue("_ns_nt_setting_user_black", "sttc943377\nlnuj762960\ntllo482098\nbgju584530\ntqxx240589\n"); } //获取新脚本数据 getNewScriptData(function(data){ //渲染脚本列表 renderScriptList(data); }); }); } })();