EhTagSyringe

Build EhTagTranslater from Wiki.

Verzia zo dňa 12.09.2017. Pozri najnovšiu verziu.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name        EhTagSyringe
// @name:zh-CN	E绅士翻译注射器?
// @namespace   http://www.mapaler.com/
// @description Build EhTagTranslater from Wiki.
// @description:zh-CN	从Wiki获取EhTagTranslater数据库,将E绅士TAG翻译为中文,并注射到E站
// @include     *://github.com/Mapaler/EhTagTranslator*
// @include     *://exhentai.org/*
// @include     *://e-hentai.org/*
// @connect     raw.githubusercontent.com
// @connect     github.com
// @icon        http://exhentai.org/favicon.ico
// @require     https://cdn.bootcss.com/angular.js/1.4.6/angular.min.js
// @resource    template         https://raw.githubusercontent.com/Mapaler/EhTagTranslator/master/template/ets-builder-menu.html?v=10
// @resource    ets-prompt       https://raw.githubusercontent.com/Mapaler/EhTagTranslator/master/template/ets-prompt.html?v=15
// @version     1.0.0
// @run-at      document-start
// @grant       unsafeWindow
// @grant       GM_xmlhttpRequest
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_addStyle
// @grant       GM_deleteValue
// @grant       GM_listValues
// @grant       GM_info
// @grant       GM_getResourceText
// @grant       GM_addValueChangeListener
// @grant       GM_setClipboard
// @copyright	2017+, Mapaler <[email protected]> , xioxin <[email protected]>
// ==/UserScript==



(function() {
    'use strict';

    window.requestAnimationFrame = unsafeWindow.requestAnimationFrame;
    unsafeWindow.wikiUpdate = autoUpdate;

    var wiki_URL="https://github.com/Mapaler/EhTagTranslator/wiki"; //GitHub wiki 的地址
    var wiki_raw_URL="https://raw.githubusercontent.com/wiki/Mapaler/EhTagTranslator"; //GitHub wiki 的地址
    var rows_title="rows"; //行名的地址
    var pluginVersion = typeof(GM_info)!="undefined" ? GM_info.script.version.replace(/(^\s*)|(\s*$)/g, "") : "未获取到版本"; //本程序的版本
    var pluginName = typeof(GM_info)!="undefined" ? (GM_info.script.localizedName ? GM_info.script.localizedName : GM_info.script.name) : "EhTagSyringe"; //本程序的名称
    var rootScope = null;


    const headLoaded = new Promise(function (resolve, reject) {
        if(unsafeWindow.document.head && unsafeWindow.document.head.nodeName == "HEAD"){
            resolve(unsafeWindow.document.head);
        }else{
            //监听DOM变化
            MutationObserver = window.MutationObserver;
            var observer = new MutationObserver(function(mutations) {
                for(let i in mutations){
                    let mutation = mutations[i];
                    //监听到HEAD 结束
                    if(mutation.target.nodeName == "HEAD"){
                        observer.disconnect();
                        resolve(mutation.target);
                        break;
                    }
                }
            });
            observer.observe(document, {childList: true, subtree: true, attributes: true});
        }
    });

    function AddGlobalStyle(css) {
        //等待head加载完毕
        headLoaded.then(function (head) {
            GM_addStyle(css);
        })
    }

    AddGlobalStyle(`<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}.ng-animate-shim{visibility:hidden;}.ng-anchor{position:absolute;}</style>`);

    var defaultConfig = {
        'showDescription':true,
        'imageLimit':3,
        'showIcon':true,
        'syringe':true,
        'style':{
            'public':`div#taglist {
    overflow: visible;
    min-height: 295px;
    height: auto;
}
div#gmid {
    min-height: 330px;
    height:auto;
    position: static;
}
#taglist a{
  background:inherit;
}
#taglist a::before{
    font-size:12px;
    overflow: hidden;
    line-height: 20px;
    height: 20px;
}
#taglist a::after{
    display: block;
    color:#FF8E8E;
    font-size:14px;
    background: inherit;
    border: 1px solid #000;
    border-radius:5px;
    position:absolute;
    float: left;
    z-index:999;
    padding:8px;
    box-shadow: 3px 3px 10px #000;
    min-width:150px;
    max-width:500px;
    white-space:pre-wrap;
    opacity: 0;
    transition: opacity 0.2s;
    transform: translate(-50%,20px);
    top:0;
    left: 50%;
    pointer-events:none;
    padding-top: 8px;
    font-weight: 400;
    line-height: 20px;
}
#taglist a:hover::after,#taglist a:focus::after{
    opacity: 1;
    pointer-events:auto;
}
#taglist a:focus::before,
#taglist a:hover::before {
    font-size: 12px;
    position: relative;
    background-color: inherit;
    border: 1px solid #000;
    border-width: 1px 1px 0 1px;
    margin: -4px -5px;
    padding: 3px 4px;
    color:inherit;
    border-radius: 5px 5px 0 0;
}
div.gt,
div.gtw,
div.gtl{
    line-height: 20px;
    height: 20px;
}

#taglist a:hover::after{ z-index: 9999998; }
#taglist a:focus::after { z-index: 9999996; }
#taglist a:hover::before{ z-index: 9999999; }
#taglist a:focus::before { z-index: 9999997; }`,
            'ex':`#taglist a::after{ color:#fff; }`,
            'eh':`#taglist a::after{ color:#000; }`,
        }
    };

    var etbConfig = GM_getValue('config');

    if(!etbConfig){
        /*默认配置 json转换是用来深拷贝 切断关联 */
        etbConfig = JSON.parse(JSON.stringify(defaultConfig));
        // 不用存储 反正是默认的
        // GM_setValue('config',etbConfig);
    }

    // 配置自动升级
    for(var i in defaultConfig){
        if(typeof etbConfig[i] === "undefined"){
            etbConfig[i] = JSON.parse(JSON.stringify(defaultConfig[i]));
        }
    }


    console.log('ets config:',etbConfig);

    //UI控制方法等等
    function EhTagBuilder(){
        console.log('EhTagBuilder');
        console.log('angular',window.angular,unsafeWindow.angular);

        var buttonInserPlace = document.querySelector(".pagehead-actions");//按钮插入位置
        var li = document.createElement("li");
        li.id = 'etb';
        li.setAttribute('ng-csp','ng-csp');
        li.innerHTML = GM_getResourceText('template');
        var app = angular.module("etb",[]);
        app.controller("etb",function($rootScope,$scope,$location,$anchorScroll){
            // console.log();
            $scope.pluginVersion = pluginVersion;
            $scope.pluginName = pluginName;

            $scope.config = etbConfig;

            $scope.nowPage = "menu";
            $scope.menuShow = false;
            rootScope = $rootScope;
            $scope.dataset = false;
            $scope.wikiVersion = false;

            var backdrop = document.querySelector(".modal-backdrop");
            if(backdrop)backdrop.addEventListener('click',function(){
                $scope.closeMenu();
                $scope.$apply();
            });


            //xx时间前转换方法
            $scope.timetime = function (time) {
                if(!time){
                    return '';
                }
                var now = (new Date).valueOf();
                now = Math.floor(now/1000);
                time = Math.floor(time/1000);
                var t =  now-time;

                if(!t){
                    return '刚刚';
                }
                var f = [
                    [31536000,'年'],
                    [2592000,'个月'],
                    [604800,'星期'],
                    [86400,'天'],
                    [3600,'小时'],
                    [60,'分钟'],
                    [1,'秒']
                ];
                var c = 0;
                for(var i in f){
                    var k = f[i][0];
                    var v = f[i][1];
                    c = Math.floor(t/k);
                    if (0 != c) {
                        return c+v+'前';
                    }
                }
            };
            //打开菜单按钮
            $scope.openMenu = function () {
                $scope.nowPage = "menu";
                $scope.menuShow = true;
            };
            //关闭菜单按钮
            $scope.closeMenu = function () {
                $scope.menuShow = false;
            };
            //开始获取
            $scope.startProgram = async function () {
                $scope.nowPage = "getData";
                await startProgram($scope);
                //增加一个延迟 因为处理css时候会卡住 导致加载完毕的ui无法显示
                setTimeout(function(){
                    var css = buildCSS($scope.dataset,$scope.wikiVersion);
                    // 存储
                    $scope.css     = css;
                    $scope.cssStylish = buildStylishCSS(css,$scope.config);
                    $scope.nowPage = 'css';
                    $scope.$apply();
                },0);
            };
            //存储css样式
            $scope.saveCss = function () {
                GM_setValue('tags',{
                    css:$scope.css,
                    data:$scope.dataset,
                    version:$scope.wikiVersion,
                    update_time:new Date().getTime()
                });
                myNotification('保存完毕');
            };

            $scope.copyStylishCss = function () {
                GM_setClipboard($scope.cssStylish)
                myNotification('复制完毕');
            };
            $scope.copyCss = function () {
                GM_setClipboard($scope.css)
                myNotification('复制完毕');
            };

            //打开设置界面
            $scope.openOption = function () {
                $scope.nowPage = "option";
            };
            //保存设置
            $scope.optionSave = function () {
                GM_setValue('config',etbConfig);
                myNotification('保存成功');

            };
            //重置设置
            $scope.optionReset = function () {
                if(confirm('确定要重置配置吗?')){
                    $scope.config = etbConfig = JSON.parse(JSON.stringify(defaultConfig));
                    GM_setValue('config',etbConfig);
                    myNotification('已重置');
                }
            };

            $rootScope.$on('$locationChangeSuccess', function(event){
                if( $location.path() == "/ets-open-option" ){
                    $scope.openMenu();
                    $scope.openOption();
                    $anchorScroll('etb')
                    $location.path("/");
                }
                if( $location.path() == "/ets-open-menu" ){
                    $scope.openMenu();
                    $anchorScroll('etb')
                    $location.path("/");
                }
                if( $location.path() == "/ets-auto-update" ){
                    $scope.openMenu();
                    $scope.startProgram().then(function () {
                        $scope.saveCss();
                    })
                    $anchorScroll('etb');
                    $location.path("/");
                }
                if( $location.path() == "/ets-set-config" ){
                    let s = $location.search();
                    for(var i in s){
                        var v = s[i];
                        if(v === 'true'){
                            v = true;
                        }
                        if(v === 'false'){
                            v = false;
                        }
                        etbConfig[i] = v;
                    }
                    GM_setValue('config',etbConfig);
                    myNotification('配置已修改',{body:JSON.stringify(s)});
                    $location.path("/").search({});
                }

                if( $location.path() == "/ets-reset-config" ){
                    $scope.optionReset();
                    $location.path("/");
                }
            });

        });
        angular.bootstrap(li,['etb']);
        // unsafeWindow.etbApp = app;
        buttonInserPlace.insertBefore(li,buttonInserPlace.querySelector("li"));
        console.log('EhTagBuilder loaded')
    }

    //样式写入方法 enema syringe
    function EhTagSyringe(){
        console.time('EhTagSyringe Load Enema');
        let tags = GM_getValue('tags');
        console.timeEnd('EhTagSyringe Load Enema');
        if(!tags)return;

        console.time('EhTagSyringe Infusion');
        unsafeWindow.tags = tags;
        AddGlobalStyle(tags.css);
        AddGlobalStyle(etbConfig.style.public);

        if((/(exhentai\.org)/).test(unsafeWindow.location.href)){
            AddGlobalStyle(etbConfig.style.ex);
        }
        if((/(e-hentai\.org)/).test(unsafeWindow.location.href)){
            AddGlobalStyle(etbConfig.style.eh);
        }

        //临时隐藏翻译用的样式
        AddGlobalStyle(`
        .hideTranslate #taglist a{font-size:12px !important;}
        .hideTranslate #taglist a::before{display:none !important;}
        .hideTranslate #taglist a::after{display:none !important;}
        `);
        console.timeEnd('EhTagSyringe Infusion');
    }

    //EH站更新提示
    function EhTagVersion() {
        console.log('EhTagVersion');
        var buttonInserPlace = document.querySelector("#nb"); //按钮插入位置

        var span = document.createElement("span");
        var iconImg  = "https://exhentai.org/img/mr.gif";


        if((/(exhentai\.org)/).test(unsafeWindow.location.href)){
            iconImg="https://ehgt.org/g/mr.gif";
            span.className=span.className+" isEX";
        }
        var etsPrompt = GM_getResourceText('ets-prompt');
        // etsPrompt = ``;

        span.innerHTML = `${etsPrompt}`;

        var app = angular.module("etb",[]);
        app.controller("etb",function($rootScope,$scope){
            $scope.pluginVersion = pluginVersion;
            $scope.pluginName = pluginName;
            $scope.iconImg = iconImg;
            $scope.config = etbConfig;
            $scope.noData = false;
            let tags = GM_getValue('tags');
            if(!tags){
                $scope.noData =true;
            }
            $scope.update_time = tags.update_time;
            $scope.nowPage = "";
            $scope.menuShow = false;
            rootScope = $rootScope;
            $scope.dataset = false;
            $scope.wikiVersion = {};
            if(tags){
                $scope.wikiVersion = tags.version;
            }

            $scope.hide = false;
            //xx时间前转换方法
            $scope.timetime = function (time) {
                if(!time){
                    return '';
                }
                var now = (new Date).valueOf();
                now = Math.floor(now/1000);
                time = Math.floor(time/1000);
                var t =  now-time;

                if(!t){
                    return '刚刚';
                }
                var f = [
                    [31536000,'年'],
                    [2592000,'个月'],
                    [604800,'星期'],
                    [86400,'天'],
                    [3600,'小时'],
                    [60,'分钟'],
                    [1,'秒']
                ];
                var c = 0;
                for(var i in f){
                    var k = f[i][0];
                    var v = f[i][1];
                    c = Math.floor(t/k);
                    if (0 != c) {
                        return c+v+'前';
                    }
                }
            };
            //打开菜单按钮
            $scope.openMenu = function () {
                console.log('openMenu');
                $scope.nowPage = "menu";
                $scope.menuShow = !$scope.menuShow;
            };
            $scope.showRow = {};
            $scope.showRow.value = false;
            $scope.showRow.change = function(value){
                if(value){
                    document.body.className = "hideTranslate"
                }else{
                    document.body.className = "";
                }
            };

            $scope.VersionCheck = function () {
                getWikiVersion().then(function (Version) {
                    $scope.lastVersionCheck = {
                        time:new Date().getTime(),
                        version:Version,
                    };
                    GM_setValue('lastVersionCheck',$scope.lastVersionCheck);
                    $scope.newVersion = Version;
                    $scope.$apply();

                    //这是个秘密
                    if(etbConfig.autoUpdate){
                        if($scope.newVersion.code != $scope.wikiVersion.code){
                            autoUpdate().then(function () {
                                myNotification('更新完毕,刷新页面生效');
                            });
                        }
                    }
                    console.log(Version);
                });
            };

            let lastVersionCheck = GM_getValue('lastVersionCheck');
            $scope.lastVersionCheck = lastVersionCheck;
            if(!lastVersionCheck){
                console.log('auto VersionCheck1');
                $scope.VersionCheck();
            }else{
                $scope.newVersion = lastVersionCheck.version;
                //限制20分钟检查一次版本
                if(new Date().getTime() - lastVersionCheck.time > 20*60*1000 ){
                    console.log('auto VersionCheck');
                    $scope.VersionCheck();
                }
            }
            unsafeWindow.r = function () {
                $scope.$apply();
            };
        });
        angular.bootstrap(span,['etb']);
        unsafeWindow.etsApp = app;

        buttonInserPlace.appendChild(span);
    }
    
    //搜索输入框助手
    function EhTagInputHelper() {
        let tags = GM_getValue('tags');
        console.log(tags);
        if(!tags)return;

        console.time('add datalist');
        let stdinput = document.querySelector('.stdinput');
        if(!stdinput){return}
        stdinput.setAttribute("list", "tbs-tags");

        var datalist = document.createElement("datalist");
        datalist.setAttribute("id", "tbs-tags");
        stdinput.parentNode.insertBefore(datalist,stdinput.nextSibling);


        //调整加载顺序 作家在前面影响搜索
        let loadOrder = [
            'female',
            'male',
            'language',
            'character',
            'reclass',
            'misc',
            'parody',
            'artist'
        ];
        var tagsk = {};
        tags.data.forEach(function (row) {
            tagsk[row.name] = row;
        });
        loadOrder.forEach(function (key) {
            let row = tagsk[key];
            let type = row.name;
            let typeName = row.cname;
            row.tags.forEach(function (tag) {
                if(tag.name){
                    let z = document.createElement("OPTION");
                    z.setAttribute("value", `${type}:"${tag.name}$"`);
                    z.setAttribute("label", `${typeName}:${mdImg2cssImg(tag.cname,0)}`);
                    datalist.appendChild(z);
                }
            });
        })


        console.timeEnd('add datalist');


    }



    //获取数据
    async function startProgram($scope) {
        console.log('startProgram');

        //存放承诺
        var pp = {
            wikiVersion:getWikiVersion(),
            rows:getRows(),
            tags:[]
        };

        //获取 版本与row
        var [wikiVersion,rows] = await Promise.all([pp.wikiVersion,pp.rows]);

        $scope.dataset = rows;
        $scope.wikiVersion = wikiVersion;
        $scope.$apply();

        //构建获取tag任务 并执行

        rows.forEach(function (row) {
            var temp = getTags(row.name);
            temp.then(function (mdText) {
                row.tags = parseTable(mdText,row.name);
                $scope.$apply();
            });
            pp.tags.push(temp);
        });

        //等待获取完毕
        await Promise.all(pp.tags);
        console.log(rows);

        return rows;
    }

    //构建css
    function buildCSS(dataset,wikiVersion) {
        console.time('生成css样式');
        var css = "";

        css+=`
/* update_time:${wikiVersion.update_time} */
/* hash:${wikiVersion.code} */
        `;

        dataset.forEach(function (row) {
            css+= `\n/* ${row.name} ${row.cname} */\n`;
            // console.log(row.tags);
            row.tags.forEach(function (tag) {
                if(tag.name){
                    var tagid = (row.name=="misc"?"":row.name + ":") + tag.name.replace(/\s/ig,"_");
                    var cname = mdImg2cssImg(specialCharToCss(tag.cname),etbConfig.imageLimit<0?Infinity:etbConfig.imageLimit);
                    if(!tag.info)tag.info="";
                    var content = mdImg2cssImg(htmlBr2cssBr(specialCharToCss(tag.info)),etbConfig.imageLimit<0?Infinity:etbConfig.imageLimit);
                    css += `
a[id="ta_${tagid}"]{
font-size:0px;
}
a[id="ta_${tagid}"]::before{
content:"${cname}";
}
`;
                    if(content)css+=`a[id="ta_${tagid}"]::after{
content:"${content}";
}`;

                }else{
                    css += `\n/* ${row.cname} */\n`;
                }
            });
        });
        console.timeEnd('生成css样式');
        return css;

    }

    //Stylish css
    function buildStylishCSS(css,config) {
        var cssStylish = "@namespace url(http://www.w3.org/1999/xhtml);\n";

        cssStylish+=`@-moz-document
    domain('exhentai.org'),
    domain('e-hentai.org')
{
/* 通用样式 */
${config.style.public}
}
`;
        cssStylish+=`@-moz-document
    domain('e-hentai.org')
{
/* 表站样式 */
${config.style.eh}
}
`;
        cssStylish+=`@-moz-document
    domain('exhentai.org')
{
/* 里站样式 */
${config.style.ex}
}
`;

        cssStylish+=`@-moz-document
    domain('exhentai.org'),
    domain('e-hentai.org')
{
body{ }
/* 翻译样式 */
${css}
}`;
        return cssStylish;
    }


    //转换换行
    function htmlBr2cssBr(mdText){
        return mdText.replace(/<br[ \t]*(\/)?>/igm,"\\A ");
    }

    //转换图片
    function mdImg2cssImg(mdText,max=Infinity){
        var n = 0;
        return mdText.replace(/\!\[(.*?)\]\((.*?)\)/igm,function (text,alt,href,index) {
            n++;
            if( max >= n){
                var h = trim(href);
                if(h.slice(0,1) == "#"){
                    h = h.replace(/# +\\?['"](.*?)\\?['"]/igm,"$1");
                }else if(h.slice(h.length-1,h.length).toLowerCase() == 'h'){
                    h = h.slice(0,-1);
                }
                return `"url("${h}")"`;
            }else{
                return "";
            }
        });
    }

    function specialCharToCss(str)
    {
        var strn = str;
        strn = strn.replace("\\","\\\\");
        strn = strn.replace("\"","\\\"");
        strn = strn.replace("\r","");
        strn = strn.replace("\n","\\A ");
        return strn;
    }

    //获取版本
    function getWikiVersion(){
        return new Promise(function (resolve, reject) {

            PromiseRequest.get(wiki_URL+'/_history?t='+new Date().getTime()).then(function (response) {
                var parser = new DOMParser();
                var PageDOM = parser.parseFromString(response, "text/html");
                var lastDOM = PageDOM.querySelector('#version-form  table  tr:nth-child(1)');
                if(!lastDOM){
                    reject();
                    return;
                }
                var code = "";
                var time = 0;
                var commit = "";

                var timeDOM = lastDOM.querySelector(".date relative-time");
                if(timeDOM)time = Date.parse(new Date(timeDOM.getAttribute('datetime')));

                var codeDOM = lastDOM.querySelector(".commit-meta code");
                if(codeDOM)code = codeDOM.innerText.replace(/(^\s*)|(\s*$)/g, "");

                var commitDOM = lastDOM.querySelector(".commit code");
                if(commitDOM)commit = commitDOM.innerText.replace(/(^\s*)|(\s*$)/g, "");

                var v = {
                    update_time:time,
                    code:code,
                    commit:commit
                };
                resolve(v);
            },function () {
                reject();
            });
        });
    }

    //去除两端空白
    function trim(s){
        if(typeof s == 'string'){
            return s.replace(/(^\s*)|(\s*$)/g, "");
        }else{
            return s;
        }
    }

    //获取行 并解析
    function getRows() {
        return new Promise(async function (resolve, reject) {
            var url = `${wiki_raw_URL}/${rows_title}.md`+"?t="+new Date().getTime();
            console.log(url);
            var data = await PromiseRequest.get(url);
            /*剔除表格以外的内容*/
            var re = (/^\|.*\|$/gm);
            var table = "";
            resolve( parseTable(data) );
        });
    }

    //获取标签 并解析
    function getTags(row) {
        return new Promise(async function (resolve, reject) {

            var url = `${wiki_raw_URL}/tags/${row}.md`+"?t="+new Date().getTime();
            console.log(url);
            console.time(`加载 ${row}`);
            var data = await PromiseRequest.get(url);
            console.timeEnd(`加载 ${row}`);
            resolve(data);
        });
    }

    function parseTable(data,name) {
        /*剔除表格以外的内容*/
        var re = (/^\s*(\|.*\|)\s*$/gm);
        var table = "";
        var temp = "";
        while( temp = re.exec(data) ){
            if(table)table+="\n";
            table+=temp[1];
        }
        table = table.replace(/\\\|/igm,"{~Line~}");
        let tableArr = table.split("\n").map(
            (row)=>row.split("|").map(
                (t)=>t.replace("{~Line~}","|")
            )
        );
        let tags = [];
        var count = [];
        tableArr.forEach(function (tr,index) {
            if(index>1){
                let t = {
                    name  : trim(tr[1]||""),
                    cname : trim(tr[2]||""),
                    info  : trim(tr[3]||"")
                };
                tags.push(t);
                if(t.name){count++};
            }
        });
        console.log(name,count);
        return tags;
    }

    async function autoUpdate() {
        var $scope = {};
        $scope.$apply = function(){};
        await startProgram($scope);
        var css = buildCSS($scope.dataset,$scope.wikiVersion);
        GM_setValue('tags',{
            css:css,
            data:$scope.dataset,
            version:$scope.wikiVersion,
            update_time:new Date().getTime()
        });
        return true;
    }



    async function myNotification(title,options)
    {
        let permission = await Notification.requestPermission();
        if(permission == 'granted'){
            return new Notification(title, options);
        }else{
            return false;
        }
    }

    //承诺封装的异步请求
    function PromiseRequest(option) {
        return new Promise(function (resolve, reject) {
            option.onload = function (response) {
                resolve(response.responseText);
            };
            option.onerror = function (response) {
                reject(response);
            };
            // if(rootScope && rootScope.$broadcast){
            //
            // }
            // option.onprogress = function (response,response2) {
            //     // var info = {
            //     //     loaded:response.loaded,
            //     //     position:response.position,
            //     //     total:response.total,
            //     //     totalSize:response.totalSize,
            //     // };
            //     // console.info('onprogress',info,response,response2);
            // };
            GM_xmlhttpRequest(option);
        });
    }
    //助手 快速get post
    PromiseRequest.get = function (url) {
        return PromiseRequest({
            method: "GET",
            url: url,
        });
    };
    PromiseRequest.post = function (url,data) {
        var post = "";
        for(var i in data){
            if(post)post+="&";
            post+= encodeURIComponent(i)+"="+encodeURIComponent(data[i]);
        }
        return PromiseRequest({
            method: "POST",
            url: url,
            data: post
        });
    };

    var bootstrap = function(){
        //在github页面下添加生成工具
        if((/github\.com/).test(unsafeWindow.location.href)){
            EhTagBuilder();
        }
        if(etbConfig.syringe) {
            //在EH站点下添加版本提示功能
            if ((/(exhentai\.org|e-hentai\.org)/).test(unsafeWindow.location.href)) {
                EhTagVersion();
                EhTagInputHelper();
            }
        }
    };

    if (/loaded|complete/.test(document.readyState)){
        bootstrap();
    }else{
        document.addEventListener('DOMContentLoaded',bootstrap,false);
    }

    //注射器总开关
    if(etbConfig.syringe){
        //注入css 不需要等待页面
        if((/(exhentai\.org|e-hentai\.org)/).test(unsafeWindow.location.href)){
            EhTagSyringe();
        }
    }

})();