Greasy Fork

Greasy Fork is available in English.

NewScript+ : 新脚本通知,不错过任何一个好脚本 New script notification, do not miss any good script. by wish king

新脚本通知,不错过任何一个好脚本,当greasyfork网站有用户提交新脚本时通知你。 New script notification, do not miss any good script, when the website of greasyfork users submit a new script to inform you.

当前为 2020-10-09 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         NewScript+ : 新脚本通知,不错过任何一个好脚本 New script notification, do not miss any good script. by wish king
// @namespace    http://bbs.91wc.net/new-script.htm
// @version      0.1.13
// @description  新脚本通知,不错过任何一个好脚本,当greasyfork网站有用户提交新脚本时通知你。 New script notification, do not miss any good script, when the website of greasyfork users submit a new script to inform you.
// @icon         http://greasyfork.icu/system/screenshots/screenshots/000/023/701/original/scripticon.png?1601395548
// @author       wish king
// @match        *://*/*
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js
// @require      http://greasyfork.icu/scripts/412159-mydrag/code/MyDrag.js?version=853651
// @require      http://greasyfork.icu/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
// ==/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,"&lt;");
        s = s.replace(/>/g,"&gt;");
        s = s.replace(/\s/g,"&nbsp;");
        s = s.replace(/\'/g,"&#39;");
        s = s.replace(/\"/g,"&quot;");
        return s;
    }

    //获取新脚本数据
    var data = [], isShouldStop = false, _tryNums=[];
    var getNewScriptData = function(callback, page){
        var lastTimeVal = GM_getValue('_ns_nt_last_time');
        //当停止获取数据时回调
        var onStop = function(){
            //如果已到达上次同步时间,则回调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[0];
                    if(lastItem && lastItem.created_at){
                        thisTime = new Date(lastItem.created_at.replace("T", " ").replace(".000Z", "")).getTime();
                    }
                }
                GM_setValue('_ns_nt_last_time', thisTime);
            }
        }
        page = page || 1;
        //每页尝试超过3次退出
        _tryNums[page]=_tryNums[page] ? _tryNums[page] + 1 : 1;
        if(page > 10 || (_tryNums[page] && _tryNums[page] > 3)){onStop(); return;}
        var url = "http://greasyfork.icu/zh-CN/scripts.json?page="+page+"&sort=created&per_page=50";
        GM_xmlhttpRequest({
            method: "GET",
            url: url,
            timeout : 30000, //30s
            onload: function(response) {
                //获取上次同步时间
                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){
                    onStop();
                } else {
                    //如果未到达上次同步时间,则继续下一页
                    page++;
                    getNewScriptData(callback, page);
                }
            },
            onerror : function(response){
                //如果错误继续尝试
                getNewScriptData(callback, page);
                if(console && console.log) console.log('getNewScriptData.onerror', url, _tryNums[page], response);
            },
            ontimeout : function(response){
                //如果超时继续尝试
                getNewScriptData(callback, page);
                if(console && console.log) console.log('getNewScriptData.ontimeout', url, _tryNums[page], response);
            }
        });
    }

    //浏览器通知
    var GM_notice = function(text, title, callback){
        if(!GM_notification) return;
        GM_notification({
            text: text,
            title: title || "",
            image: "http://greasyfork.icu/system/screenshots/screenshots/000/023/766/original/transparent.png?1601910259",
            onclick: function() {
                if(callback) callback();
            }
        });
    };

    //渲染列表
    var renderScriptList = function(data){
        //脚本列表模板
        var scriptListTpl = `
<li>
  <div class="-ns-nt-list-title-wrapper" data-id="{{id}}">
     <span class="-ns-nt-list-item-title"><span class="-ns-nt-list-title-new-flag {{hide_new}}">新</span><span class="-ns-nt-list-title-dot {{hide_read}}"></span>{{name}}</span>
     <span class="-ns-nt-list-item-date">{{created_at_format}}</span>
  </div>
  <div class="-ns-nt-list-detail-wrapper">
      <div class="-ns-nt-list-detail-content" data-url="{{url}}">
      <table width="100%" border="0">
      <tr><td width="38" valign="top">作者:</td><td>{{users.name}}</td></tr>
      <tr><td valign="top">标题:</td><td style="word-break: break-all;">{{name}}</td></tr>
      <tr><td valign="top">描述:</td><td style="word-break: break-all;">{{description}}</td></tr>
      <tr><td valign="top">日期:</td><td>{{created_at}}</td></tr>
      <tr><td valign="top">版本:</td><td>{{version}}</td></tr>
      <tr><td valign="top">安装:</td><td>{{total_installs}} 次</td></tr>
      <tr><td valign="top">得分:</td><td>{{ratings_score}}</td></tr>
      </table>
      <div>
      <div class="-ns-nt-list-detail-bottom">
          <a href="{{url}}" target="_blank">查看</a>
          <a href="{{code_url}}" class="-ns-nt-list-detail-bottom-install">安装</a>
      </div>
  </div>
</li>
`;
        //已存储的脚本列表
        var storeData = GM_getValue("_ns_nt_store_data")||[];
        //data从网络获取的新脚本列表 nscount从网络获取的新脚本数量
        var nscount=data.length;
        //新脚本对象映射表
        var dataMap = {}
        for(var d in data){
            dataMap[data[d].id] = 1;
        }
        //重复数据映射表
        var repeats = {};
        for(var s in storeData){
            if(dataMap[storeData[s].id]){
                repeats[storeData[s].id] = 1;
            }
        }
        //合并新旧脚本
        data = data.concat(storeData);

        //scount脚本总数 nscount新脚本数量 readCount已读总数 lastNewCount上一次新脚本总数 lastNewReadCount上一次新脚本已读总数 lastNewReadNewData本次新脚本已读数据
        var scriptListHtml="", scount=0, readCount=0, lastNewCount=0, lastNewReadCount=0, lastNewReadNewData={};
        //获取已读脚本列表
        var reads = GM_getValue("_ns_nt_reads")||{};
        //获取上一次新脚本已读列表
        var lastNewReads = GM_getValue("_ns_nt_last_news_reads")||{};
        lastNewCount=Object.keys(lastNewReads).length;
        //将要保存的前500条脚本
        var newData = [];
        //是否需要显示“新”
        var needNew=function(item){
            //已读隐藏“新”标记
            if(item.id && reads[item.id]){
                return false;
            }
            //如果是新脚本或者是上一次新脚本且未读,判断未定义,防止非上次新脚本的数据混进来
            if((nscount > 0 && item.is_new)||(nscount === 0 && typeof lastNewReads[item.id] !=="undefined" && !lastNewReads[item.id])){
                return true;
            }
            //其他情况隐藏“新”标记
            return false;
        }

        //根据模板拼接脚本列表
        itemfor:
        for(var i in data){
            //脚本总数超过500退出循环
            if(scount > 500) break;
            var item = data[i];
            if(!item.name) continue;
            //重复处理
            if(repeats[item.id]){
                if(item.is_new){
                    //一般重复是新老数据重复,这里老数据优先,把新数据标记为老数据
                    item.is_new=0;
                } else {
                    //老数据跳过,这样保证新数据在前
                    nscount--;
                    continue itemfor;
                }
            }
            //判断是否垃圾脚本
            var is_filter_spam = GM_getValue("_ns_nt_filter_spam");
            is_filter_spam = typeof is_filter_spam ==="undefined" ? 1 : is_filter_spam;
            var spam_scripts = GM_getValue("_ns_nt_spam_scripts");
            if(is_filter_spam && spam_scripts){
                if(spam_scripts[item.name]){
                    if(item.is_new){nscount--;}
                    continue itemfor;
                }
            }
            //获取作者并判断是否是黑名单用户
            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")){
                        if(item.is_new){nscount--;}
                        continue itemfor;
                    }
                    users.push(uname);
                }
            }
            //拼接作者
            users = users.join(",");
            //拼接得分
            var ratings_score = "好评:"+item.good_ratings+"&nbsp;&nbsp;&nbsp;&nbsp;一般:"+item.ok_ratings+"&nbsp;&nbsp;&nbsp;&nbsp;差评:"+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}}", !needNew(item) ? "-ns-nt-hide" : "");

            //如果已读,已读数增加
            if(item.id && reads[item.id]) readCount++;
            //如果上次新脚本已读,已读数增加
            if(item.id && lastNewReads[item.id]) lastNewReadCount++;

            if(nscount > 0 && item.is_new){
                //如果同步到新脚本,则保存上一次新脚本已读状态
                lastNewReadNewData[item.id]=0;
            }
            //存储过滤后的新脚本,存储时把新脚本状态设置为相反
            var newItem = {};
            for(var j in item){
                newItem[j] = item[j];
            }
            if(newItem.is_new) newItem.is_new = 0;
            newData.push(newItem);
            //计算实际总脚本数
            scount++;
        }
        if(nscount > 0){
            //如果同步到新脚本,存储前500条历史,存储上一次新脚本已读状态
            if(Object.keys(lastNewReadNewData).length>0) GM_setValue("_ns_nt_last_news_reads", lastNewReadNewData);
            if(newData.length>0) GM_setValue("_ns_nt_store_data", newData);
        }
        //兼容无脚本无历史情况
        if(!scriptListHtml) scriptListHtml='<li><div class="-ns-nt-list-title-wrapper">暂无新脚本</div></li>';

        //同步到的新增脚本数量
        var newcount = nscount || lastNewCount - lastNewReadCount;
        //ui界面
        var html=`
<style>
.-ns-nt-wrapper *{margin:0;padding:0;outline:0 none;text-align:left;}
.-ns-nt-wrapper{width:414px;height:0;position:fixed;right:20px;top:100px;z-index:999999999;}
.-ns-nt-wrapper a{text-decoration: none;color:#2440b3;}
.-ns-nt-wrapper a:hover{text-decoration: underline;color: #315efb;}
.-ns-nt-wrapper a:visited{color:#2440b3;}
.-ns-nt-btn-wrapper{padding:2px;border:1px solid #aaa;border-radius:21px;float:right;background:#fff;position: relative;}
.-ns-nt-btn{width:36px;height:36px;line-height:36px;border-radius:21px;background:red;color:#fff;text-align:center;font-size:16px;}
.-ns-nt-left{display:none;width:400px;float: left;margin-right:-30px;margin-top:12px;background:#fff;border:1px solid #aaa;border-radius:5px;padding:0;box-shadow: 1px 1px 6px rgba(0,0,0,.2);}
.-ns-nt-list{max-height:400px;overflow-y:auto;}
.-ns-nt-list li{list-style: none;border-top:1px solid #ccc;cursor:pointer;}
.-ns-nt-list li:first-child{border-top:none;}
.-ns-nt-list-title-wrapper{height:36px;line-height:36px;padding:0 8px;}
.-ns-nt-list-detail-wrapper{display:none;padding:0 8px;}
.-ns-nt-list-toolbar{padding:4px 8px;font-size:12px;border-bottom:1px solid #ccc;}
.-ns-nt-list-setting{padding:8px;display:none;}
.-ns-nt-list-item-date{float:right;color:#999;font-size:14px;}
.-ns-nt-list-title-dot{width: 8px;height: 8px;padding: 0;border-radius: 50%;background-color: #FF5722;display: inline-block;margin-right:2px;}
.-ns-nt-list-title-new{width: 20px;position: absolute;top: -10px;left:2px;}
.-ns-nt-btn-add-new{
    position: absolute;width:36px;text-align:center;top: -21px;left: 0px;color: red;font-weight: bold;font-size: 16px;
    text-shadow: #fff 1px 0 0, #fff 0 1px 0, #fff -1px 0 0, #fff 0 -1px 0;
}
.-ns-nt-list-toolbar a{margin-right:2px;}
.-ns-nt-list-setting-item{line-height:26px;font-size:14px;}
.-ns-nt-list-detail-content{cursor:pointer;padding-bottom: 8px;}
.-ns-nt-list-detail-content td{line-height: 22px;color: #444;font-size:9pt;}
.-ns-nt-list-detail-bottom a{margin-right:2px;color:#2440b3;font-size:14px;}
.-ns-nt-list-item-title{width:293px;overflow: hidden; text-overflow:ellipsis; white-space: nowrap;display: inline-block;font-size: 14px;}
.-ns-nt-list-item-title,.-ns-nt-list-item-date,.-ns-nt-btn-wrapper{user-select:none;}
.-ns-nt-list-title-new-span{position:relative}
.-ns-nt-list-title-new-flag{background-color: #FF455B;margin-right:2px;display: inline-block;padding: 0 2px;text-align: center;vertical-align: middle;font-style: normal;color: #fff;overflow: hidden;line-height: 16px;height: 16px;font-size: 12px;border-radius: 4px;font-weight: 200;}
.-ns-nt-list-setting-domain-black,.-ns-nt-list-setting-user-black{width:90%;height:76px;border: 1px solid #999;}
#_ns_nt_remember_drag_pos_tips{color:green;margin-left:10px;}
.-ns-nt-list-title-wrapper:hover{background-color: #f8f8f8;}
.-ns-nt-hide{display:none}
</style>
<div class="-ns-nt-wrapper">
    <div class="-ns-nt-btn-wrapper">
       <div class="-ns-nt-btn">`+(scount-readCount>0?scount-readCount:0)+`</div>
       <div class="-ns-nt-btn-add-new">`+(newcount>0?"+"+newcount:"")+`</div>
    </div>
    <div class="-ns-nt-left">
    <div class="-ns-nt-list-toolbar">
        <a href="javascript:;" id="_ns_fold_btn">全部展开</a>
        <a href="javascript:;" id="_ns_unfold_btn">全部折叠</a>
        <a href="javascript:;" id="_ns_allread_btn">全部已读</a>
        <a href="javascript:;" id="_ns_setting_btn">设置</a>
        <a href="http://bbs.91wc.net/new-script.htm" target="_blank" id="_ns_help_btn">帮助</a>
    </div>
    <div class="-ns-nt-list-setting">
        <div class="-ns-nt-list-setting-item" style="line-height: normal;margin-bottom: 10px;"><a href="javascript:;" id="_ns_setting_back_btn" style="text-decoration: underline;">返回</a></div>
        <div class="-ns-nt-list-setting-item"><label><input id="_ns_nt_show_browser_notice" type="checkbox">开启浏览器通知</label></div>
        <div class="-ns-nt-list-setting-item"><label><input id="_ns_nt_filter_spam" type="checkbox">过滤垃圾脚本</label></div>
        <div class="-ns-nt-list-setting-item"><label><input id="_ns_nt_remember_drag_pos" type="checkbox">记住拖动位置</label><span id="_ns_nt_remember_drag_pos_tips"></span></div>
        <div class="-ns-nt-list-setting-item">域名黑名单,每行一个域名</div>
        <div class="-ns-nt-list-setting-item"><textarea class="-ns-nt-list-setting-domain-black"></textarea></div>
        <div class="-ns-nt-list-setting-item">用户黑名单,每行一个用户</div>
        <div class="-ns-nt-list-setting-item"><textarea class="-ns-nt-list-setting-user-black"></textarea></div>
    </div>
    <div class="-ns-nt-list">
        <ul>
           `+ scriptListHtml +`
           <li>
              <div class="-ns-nt-list-title-wrapper"><a id="_ns_nt_list_more" href="http://greasyfork.icu/zh-CN/scripts?sort=created&fr=newscript" target="_blank">更多</a></div>
           </li>
        </ul>
    </div>
    </div>
</div>
`;
        $('body').append(html);
        //拖动渲染
        var _ns_nt_wrapper = $(".-ns-nt-wrapper"), _ns_nt_btn_wrapper = $(".-ns-nt-btn-wrapper");
        var _dragStop = function(){GM_setValue("_ns_nt_drag_posion", [parseFloat(_ns_nt_wrapper.css("left")), parseFloat(_ns_nt_wrapper.css("top"))]);}
        var _dragInitConfg = {handle:_ns_nt_btn_wrapper[0], top:100, right:20, position:'fixed', onStop: _dragStop};
        if(GM_getValue("_ns_nt_remember_drag_pos")){
            var _ns_nt_drag_posion = GM_getValue("_ns_nt_drag_posion");
            if(_ns_nt_drag_posion && _ns_nt_drag_posion.length >= 2){
                _dragInitConfg = {handle:_ns_nt_btn_wrapper[0], left:_ns_nt_drag_posion[0], top:_ns_nt_drag_posion[1], position:'fixed', onStop: _dragStop};
            }
        }
        new MyDrag(_ns_nt_wrapper[0], _dragInitConfg);
        //禁止选择
        $(".-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", ($(".-ns-nt-left").height()+10)+"px");
            $(".-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);
            if(me.text() ==="更多") return;
            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);
                //计算未读数量
                readCount++;
                $(".-ns-nt-btn").html(scount-readCount>0?scount-readCount:0);
                //计算同步到的新增加脚本数量
                newcount--;
                $(".-ns-nt-btn-add-new").html(newcount>0 ? "+"+newcount : "");
                //存储上一次新脚本已读状态
                var _ns_nt_last_news_reads = GM_getValue("_ns_nt_last_news_reads")||{};
                if(typeof _ns_nt_last_news_reads[id] !== "undefined"){
                    _ns_nt_last_news_reads[id] = 1;
                    GM_setValue("_ns_nt_last_news_reads", _ns_nt_last_news_reads);
                }
            }
        });
        //点击设置
        $("#_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);
                //计算未读数量
                readCount++;
                $(".-ns-nt-btn").html(scount-readCount>0?scount-readCount:0);
                //计算同步到的新增加脚本数量
                newcount--;
                $(".-ns-nt-btn-add-new").html(newcount>0 ? "+"+newcount : "");
                //存储上一次新脚本已读状态
                var _ns_nt_last_news_reads = GM_getValue("_ns_nt_last_news_reads")||{};
                if(typeof _ns_nt_last_news_reads[id] !== "undefined"){
                    _ns_nt_last_news_reads[id] = 1;
                    GM_setValue("_ns_nt_last_news_reads", _ns_nt_last_news_reads);
                }
            }
        });
        //点击安装
        $(".-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_nt_show_browser_notice").prop("checked", true);
        }
        $("#_ns_nt_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_filter_spam = GM_getValue("_ns_nt_filter_spam");
        _ns_nt_filter_spam = typeof _ns_nt_filter_spam === "undefined" ? 1 : _ns_nt_filter_spam;
        if(_ns_nt_filter_spam){
            $("#_ns_nt_filter_spam").prop("checked", true);
        }
        $("#_ns_nt_filter_spam").on("change", function(){
            if($(this).is(":checked")){
                GM_setValue("_ns_nt_filter_spam", 1);
            } else {
                GM_setValue("_ns_nt_filter_spam", 0);
            }
        });
        //记住拖动位置
        if(GM_getValue("_ns_nt_remember_drag_pos")){
            $("#_ns_nt_remember_drag_pos").prop("checked", true);
        }
        $("#_ns_nt_remember_drag_pos").on("change", function(){
            if($(this).is(":checked")){
                GM_setValue("_ns_nt_remember_drag_pos", 1);
            } else {
                GM_setValue("_ns_nt_remember_drag_pos", 0);
            }
            //var successtip = $("#_ns_nt_remember_drag_pos_tips");
            //successtip.html("设置成功!");
            //setTimeout(function(){successtip.html("");}, 2000);
        });

        //域名黑名单
        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_nt_list_more").css("font-weight", "normal");
        });
        //折叠
        $("#_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_reads = GM_getValue("_ns_nt_last_news_reads")||{};
            $(".-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_reads[id] !== "undefined"){
                        _ns_nt_last_news_reads[id] = 1;
                    }
                }
            });
            //存储已读状态
            GM_setValue("_ns_nt_reads", reads);
            //存储上一次新脚本已读状态
            GM_setValue("_ns_nt_last_news_reads", _ns_nt_last_news_reads);
            //同步已读状态和新增脚本数到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;
    }

    //获取垃圾脚本列表,每天抓取一次
    var spamScripts = {};
    var getSpamScripts = function(callback, maxpage, page, trys){
        maxpage = maxpage || 2;
        page = page || 1;
        if(page > maxpage){
            //设定每天抓取一次
            GM_setValue("_ns_nt_last_get_spam_time", new Date().setHours(23, 59, 59, 0));
            //存储垃圾脚本
            GM_setValue("_ns_nt_spam_scripts", spamScripts);
            //开始抓取新脚本
            if(callback) callback();
            return;
        }
        //获取是否开启垃圾脚本过滤
        var _ns_nt_filter_spam = GM_getValue("_ns_nt_filter_spam");
        _ns_nt_filter_spam = typeof _ns_nt_filter_spam ==="undefined" ? 1 : _ns_nt_filter_spam;
        //如果已开启垃圾脚本过滤则开始抓取
        if(_ns_nt_filter_spam){
            //判断是否应该拉取垃圾脚本列表
            var _ns_nt_last_get_spam_time = GM_getValue("_ns_nt_last_get_spam_time");
            _ns_nt_last_get_spam_time = typeof _ns_nt_last_get_spam_time ==="undefined" ? 0 : _ns_nt_last_get_spam_time;
            var inTime = new Date().getTime() > _ns_nt_last_get_spam_time;
            if(callback || inTime){
                trys = trys || 1;
                //尝试3次后仍失败,则放弃,开始获取新脚本
                if(trys > 3){
                    //存储垃圾脚本
                    GM_setValue("_ns_nt_spam_scripts", spamScripts);
                    //回调
                    if(callback) callback();
                    return;
                }
                GM_xmlhttpRequest({
                    method: "GET",
                    url: "http://greasyfork.icu/zh-CN/moderator_actions?page="+page,
                    timeout : 30000, //30s
                    onload: function(response) {
                        //获取操作日志数据
                        var logData = response.responseText;

                        ////过滤关键词 empty script, ad, ads, spam
                        logData = logData.split('<table class="text-content log-table">');
                        logData = logData[logData.length-1].split('<div role="navigation" aria-label="Pagination" class="pagination">')[0];
                        logData = "<table>" + logData;
                        logData = $(logData);
                        logData.find("td:contains('脚本:')").each(function(){
                            var me = $(this);
                            var projectName = trim(me.text());
                            //把垃圾脚本存储到垃圾脚本黑名单
                            if(projectName.indexOf("脚本:")!==-1){
                                spamScripts[projectName.replace("脚本:", "")] = 1;
                            }
                        });

                        //抓取下一页
                        getSpamScripts(callback, maxpage, ++page);
                    },
                    onerror : function(response){
                        //如果错误继续尝试
                        getSpamScripts(callback, maxpage, page, ++trys);
                        if(console && console.log) console.log('getSpamScripts.onerror', response, trys);
                    },
                    ontimeout : function(response){
                        //如果超时继续尝试
                        getSpamScripts(callback, maxpage, page, ++trys);
                        if(console && console.log) console.log('getSpamScripts.ontimeout', response, trys);
                    }
                });
            }
        } else {
            //如果未开启垃圾脚本过滤,则直接获取新脚本
            if(callback) callback();
        }
    }

    //垃圾清理,清除一些无效的存储,每天清理一次
    var clearGarbage = function(){
        var lastClearTime = GM_getValue("_ns_nt_last_clear_time") || 0;
        if(new Date().getTime() < lastClearTime){
           return;
        }
        try{
            //设定清理时间,每天清理一次
            GM_setValue("_ns_nt_last_clear_time", new Date().setHours(11, 59, 59, 0));

            //读取当前的脚本列表
            var storeData = GM_getValue("_ns_nt_store_data")||[];
            var storeScriptIds = {};
            for(var i in storeData){
                var item = storeData[i];
                if(item && item.id){
                    storeScriptIds[item.id]=1;
                }
            }
            //清理已读列表
            var reads = GM_getValue("_ns_nt_reads")||{};
            for(var j in reads){
                if(!storeScriptIds[j]){
                    delete reads[j];
                }
            }
            GM_setValue("_ns_nt_reads", reads);
        }catch(e){
            if(console && console.log) console.log('clearGarbage', e);
        }
    }

    //开始执行
    if(isAllowDomain()){
        if(GM_getValue("_ns_nt_spam_scripts")){
            //如果已存储过垃圾脚本列表则直接获取新脚本,每天会自动更新一次垃圾脚本列表
            setTimeout(function(){
                //获取新脚本数据
                getNewScriptData(function(data){
                    //渲染脚本列表
                    renderScriptList(data);
                });
            });
            //后台获取并存储垃圾脚本列表
            setTimeout(function(){
                getSpamScripts();
            });
        } else {
            //如果没有存储过垃圾脚本列表(通常是第一次执行时),则先查找垃圾脚本列表并存储
            setTimeout(function(){
                getSpamScripts(function(){
                    //获取新脚本数据
                    getNewScriptData(function(data){
                        //渲染脚本列表
                        renderScriptList(data);
                    });
                });
            });
        }
        //垃圾清理
        setTimeout(function(){
            clearGarbage();
        });
    }
})();