Sleazy Fork is available in English.

根据番号快速搜索

标记网页上的所有番号, 在相关网站快速方便的进行搜索

// ==UserScript==
// @name         根据番号快速搜索
// @namespace    https://github.com/qxinGitHub/searchAV
// @version      0.23.1
// @description  标记网页上的所有番号, 在相关网站快速方便的进行搜索
// @author       iqxin
// @icon         data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAABLdJREFUWEftmG2IVGUUx3//O6MZapIftJTeKAqDiqiPGllZSdqHXsw3KmNnpm1LzYqgAleoMAJLw2xmdtsKqS3BkIy0QDSS6FNIkAgRilhUkPjGprtzTzx3d2fv3L0z986upB+6X+855/6e5znnf55zZWYTOY8fOUBJJ85HxoDtf8BRHM2odtAM0cF0fC6oMnicpoUjEjYKrqpr04DWxTjOsNQ8Chg3AWNiQHoR++RTZCybtYx/RgqbGtA6mej3sVziRaCZqj9h0O79xga109csaCpAK3KDiW7g+mY/ELL/WcZCFfipmRiJgFZinsFHwMXNBK5je1SwSHl2po3VENBKzDWjG3FRQkCXY8chsBvX0NY4LrFQeb5KA1kX0Dq5zip8DVweE8gHDkis5Qxb1cbJQRvbyASyLDHxPHBNLIRxQD53qpUjSZCxgE4+/BKfSDwSE+CU4FlydDSSEmsn61/KCok1wPhoHIP3vRwtSXIUD1jkbhNbYwIPy6FgMWWeE8wyY3emwFthGHuP+SY2x6TJUXnMVwt7G+3iMED3QSuzBXgw4tgjn6V6MgAfEtIOJpvPLgg0cZ887lALf9fYlGkzC8BrNNOgnMmTbw6wzFVuJ6K5V+9ILA1g/ZQ5pF5mqY3D9SCH72CRxSY+BLJD28RxwX0q8N2wXEoB6HysyEyDLyNHfXpAdj5PDVgp8aYIKjD8/KBe7gpXa7Vq0wLW2g2t3ViTKdCeGtAv8xnGwzU5BB9k8iwLLgdF5iGuGHzve1won2cQl2EcNo93PJ+e0O4fosB2V61+iS+AeTWxjY2ZAk+nByyxA7gnArg+k2elFbnaFFTd1CT9Cr2vFk6lxNuCFRHfnV6ee88OYH8BuTycdhYBt3t55qcGrJToEjxe4yC2eDkWBMnewWQqNX15UqBzMAPYL2MpcKzqn+HooOz4DU4nPWCRdonVEYdYfRsETtLBwG4jl9gY9gDXhmML2pTn3dSAFt9FegQLlGf7iGWmzKNmdNbIF5yS8YAKQc+PfYbr4CamWCYQandk4We3xjA3ejtOJdT9EuMgbonE3K8Kt6uVP1MDOsNKkdckXoo4+WZs8PKsCjf4GkDjR8FsFYZycODisU5iOeBFJOb1TIGXGxVc/GWhzAwzvgGmR5x7DVZ7OdbWQJaZis8EQgUR5F1/i3tV4oWY2eWgKsxWKwebBgx2scQawSvRVQPuLrhNWQp6gr/qHs0mplsmyLk5MTH6XLdSnvVJclX/wtrFOOvlU+D+OkF6gV2CbjJ8Tx99ZMnSxywTi4GZdSa+wXB7VGFBo/zrP4UGfxbMFYzHDsTNSSsd4ftEyOShqZNp5rMN49YRQiS5NYRMBAy22c3EleCWk4vJpyQA994NVa4YnEjXVPKAc13IVICDBFbmRrMgsW9LCeoK6lsZrfzOL/401rnO0QxkU4BV0E1M8bM8Jp9FiCuBSQMfdUDHMA66mcar0BWe3IJBqknIEQGmOdP6nSHQxljhjjvu/xwwJOB1IcPD1DkBTAG5VyeZo1X0nDPARpAmPs7kWJIo1KPJtbS+A/36DYmVQedxF44KD+kpfj0vAKvK4P7pjGW8cvxRe+MZaHVpV3wu7P4FjSUI5qMsu14AAAAASUVORK5CYII=
// @license      MIT
// @match        *://**/*
// @require     https://update.greasyfork.org/scripts/447533/1214813/findAndReplaceDOMText%20v%20046.js
// @require     https://update.greasyfork.org/scripts/452219/1099124/MD5%20%E5%87%BD%E6%95%B0.js
// @require     https://update.greasyfork.org/scripts/452792/1214814/av%E7%95%AA%E5%8F%B7%E7%89%B9%E5%BE%81%28tag%29%E5%AF%B9%E7%85%A7%E8%A1%A8.js
// @exclude	    *://meta.appinn.net/*
// @exclude	    *://v2ex.com/*
// @exclude	    *://www.v2ex.com/*
// @exclude	    *://greasyfork.org/*
// @exclude	    *://bilibili.com/*
// @exclude	    *.bilibili.com/*
// @exclude	    *://www.douyin.com/*
// @exclude	    *.1688.com/*
// @exclude	    *.taobao.com/*
// @exclude	    *.tmall.com/*
// @exclude	    *.jd.com/*
// @exclude	    *.smzdm.com/*
// @exclude	    *.zhihu.com/*
// @exclude	    *://weibo.com/*
// @exclude	    *.qq.com/*
// @exclude	    *.live.com/*
// @exclude	    *.mi.com/*
// @exclude	    *docs.google.com/*
// @exclude	    *baike.baidu.com/*
// @exclude	    *.wikipedia.org/*
// @exclude     *://*.amazon.tld/*
// @exclude	    *.flightradar24.com/*
// @exclude	    *.obsidian.md/*
// @exclude	    *.runoob.com/*
// @exclude	    https://regex101.com/
// @exclude	    https://discord.com/*
// @exclude	    https://web.telegram.org/*
// @exclude	    https://www.flipkart.com/*
// @exclude	    *.themoviedb.org/*
// @exclude	    *.youku.com/*
// @exclude	    *.cn/*
// @exclude     *mall*
// @exclude     *shop*
// @exclude     /.*(?<!jav)store.*/
// @exclude     *buy*
// @exclude     *tools*
// @exclude     *translate*
// @exclude     */releases
// @exclude     */releases/*
// @exclude     *:5244*
// @exclude     *:8080*
// @connect     *
// @connect      javbus.com
// @connect      javdb.com
// @connect      fc2hub.com
// @connect      dmm.co.jp
// @connect      1pondo.tv
// @connect      caribbeancom.com
// @connect      tokyo-hot.com
// @connect      mgstage.com
// @connect      r18.com
// @connect      prestige-av.com
// @connect      javspyl.tk
// @connect      fc2.com
// @connect      heydouga.com
// @connect      heyzo.com
// @connect      translate.google.com.hk
// @connect      fanyi.baidu.com
// @connect      self
// @connect      localhost
// @grant       GM_addStyle
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_deleteValue
// @grant       GM_xmlhttpRequest
// @grant       GM_setClipboard
// @grant       GM_registerMenuCommand
// @grant       GM_openInTab
// @run-at      document-idle

// ==/UserScript==

(function() {
    'use strict';

    if(window.location.href.search(/detail|product/gi)>0
        && window.location.href.search(/attackers\.net|www\.dmm\.co\.jp|www\.mgstage\.com/i)<0){
        console.log("sav: 当前网址不匹配: " + window.location.href);
        return;
    }

    window.qxin = {};   // 给引用脚本传参
    var timerGetInfo;   // 延时获取信息
    var timerMouseLeave;    // 鼠标离开番号。鼠标进入菜单时的定时器, 超时不进入, 菜单消失
    var timerMouseLeaveMenu;    // 鼠标离开菜单
    // var timerImgLoading;    // 图片加载后 重新定位的定时器。 加载成功后, 清除该定时器
    var avInfo = {};    // 临时存储相关信息
    var avInfoID = "";    // 临时存储avID
    var localInfo = {}; // 从本地获取到的番号信息, 只在判断是否本地存在和存储信息时使用
    var Imgscall = 1.0; // 图片默认放大倍数, 在图片上滚动鼠标滚轮使用。
    var javdbTime = []; // 记录访问javdb的时间, 如果短时间内多次访问就限制访问, 默认是5分钟内限制为10次访问。
    var divTarget;  // 鼠标当前经过的番号节点
    var imgErrorSVG = "data:image/svg+xml,%3Csvg class='icon' viewBox='0 0 1024 1024' xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cpath d='M304.128 456.192c48.64 0 88.064-39.424 88.064-88.064s-39.424-88.064-88.064-88.064-88.064 39.424-88.064 88.064 39.424 88.064 88.064 88.064zm0-116.224c15.36 0 28.16 12.288 28.16 28.16s-12.288 28.16-28.16 28.16-28.16-12.288-28.16-28.16 12.288-28.16 28.16-28.16z' fill='%23999'/%3E%3Cpath d='M887.296 159.744H136.704C96.768 159.744 64 192 64 232.448v559.104c0 39.936 32.256 72.704 72.704 72.704h198.144L500.224 688.64l-36.352-222.72 162.304-130.56-61.44 143.872 92.672 214.016-105.472 171.008h335.36C927.232 864.256 960 832 960 791.552V232.448c0-39.936-32.256-72.704-72.704-72.704zm-138.752 71.68v.512H857.6c16.384 0 30.208 13.312 30.208 30.208v399.872L673.28 408.064l75.264-176.64zM304.64 792.064H165.888c-16.384 0-30.208-13.312-30.208-30.208v-9.728l138.752-164.352 104.96 124.416-74.752 79.872zm81.92-355.84l37.376 228.864-.512.512-142.848-169.984c-3.072-3.584-9.216-3.584-12.288 0L135.68 652.8V262.144c0-16.384 13.312-30.208 30.208-30.208h474.624L386.56 436.224zm501.248 325.632c0 16.896-13.312 30.208-29.696 30.208H680.96l57.344-93.184-87.552-202.24 7.168-7.68 229.888 272.896z' fill='%23999'/%3E%3C/svg%3E";
    var cid = {};  // 用于预告视频的链接转换 
    var localVideoList = [];    // 获取本地 jellyfin/emby 中所有的视频名称

    var allHTML = document.querySelector("body");   // 获取网页
    
    // 取出本地的信息 
    localInfo = GM_getValue("avInfo2");
    if(!localInfo){
        GM_setValue("avInfo2",{});
        localInfo = {};
    }
    
    // 初始化 setting
    // setting: 相关设置选项
    var setting = GM_getValue("_setting");  
    if(!setting || JSON.stringify(setting) == "{}"){
        setting = {
            "list":[
                ["JavDB 搜索","https://javdb.com/search?q=%s&f=all"],
                ["JavLib 搜索","http://www.javlibrary.com/cn/vl_searchbyid.php?keyword=%s"],
                ["JavMenu 搜索","https://javmenu.com/search?wd=%s"],
                ["missav 在线","https://missav.com/search/%s"]
            ],
            "list_wuma":[
                ["JavMenu 搜索","https://javmenu.com/search?wd=%s"],
                ["btsow 下载","https://btsow.com/search/%s"]
            ]
        }
        GM_setValue("_setting",setting);
    }
    // 更新
    if(setting.version && setting.version != 2){
        setting.version = 2;
        setting.selectLength = 0;
        setting.list_wuma = [
            ["JavMenu 搜索","https://javmenu.com/search?wd=%s"],
            ["btsow 下载","https://btsow.com/search/%s"]
        ];
        GM_setValue("_setting",setting);
    }
    // setting2 放一些隐藏的变量, 本身这些变量就不允许用户修改, 例: version, javdbTime
    var setting2 = GM_getValue("_setting2");  
    if(!setting2){
        setting2 = {
            "version":2,
            "javdbTime":[]
        }
        if(setting.javdbTime){
            setting2.javdbTime = setting.javdbTime;
        }
        GM_setValue("_setting2",setting2);
    }
    if(setting2.javdbTime && Array.isArray(setting2.javdbTime)){
        javdbTime = setting2.javdbTime
    }

    // 自定义获取信息的地址, 避免网络不通顺 
    var javbusLink = setting.javbus? setting.javbus: "https://www.javbus.com/"
    var javDBLink = setting.javdb? setting.javdb: "https://javdb.com/"
    
    // 磁链复制功能在引用脚本中还有一部分
    window.qxin.CopyMagnet = setting.magnetCopy? true:false;
    window.qxin.includeIDinLinks = setting.includeIDinLinks ?? false;

    // 测试用
    var debug = setting.debug?setting.debug:false
    // debug = true;   // 打开一些console.log提示
    if (debug) { 
        console.clear(); 
        console.log("sav已开启debug模式:"); 
        console.log("老司机共浏览了" + Object.keys(localInfo).length + "个番号!");
    }
    if(debug) {var searchTimes = 0; var avIDTimes=0};    // 计数, 查看有多少番号。searchTimes: 通过正则搜索到的次数。 avIDTimes:最后的实际匹配的番号数量

    // 一般发行番号: 从javbus获取信息
    // var oRegExp = /[a-zA-Z]{2,6}[-\s]?\d{2,5}/gi; 
    //             ; --------------------------------------------------------普通番号,带横杠-----------------------------------------------------------------  |--------------------------------------------------------------普通番号, 不带横杠-------------------------------------------------------------------------------------------------                       |-------------字母特别的番号-------------------------|---------字母超长的番号----------------------       |     东京热 n k                |加勒比(-)、一本道(_)、 MuraMura(_):   月日年        |       带前缀 carib|1pondo 的加勒比, 一本道        |       带后缀的 -1pon|-carib|-paco 加勒比 一本道 paco    |Mesubuta メス豚 (也可能是一本道的变种)        ||       HEYZO             
    var oRegExp = /(?<!\w|\/|www\.|=|col-|\d-|>|Jukujo-)(?!heyzo|SHINKI|JPNXXX|carib|vps)[a-zA-Z]{2,6}-\d{2,5}(?:-c|_c|-4k)?(?!\d|[A-Za-z]{2,}|-\d|\.com|\.\d)|(?<!\w|\/|\\|\.|【|-|#|@|=|www\.)(?!heyzo|SHINKI|JPNXXX|carib|and|vps|dvd)[a-zA-Z]{2,6}\s{0,2}\d{3,4}(?:-c|_c)?(?!\w|-|\.|\/|×|%|%|@|\s?天| 发表| 發表|歳| 歲|小时|分|系列| Min| day|ml| time|cm| ppi|\.com)|(?<!\w)(?:PARATHD|3DSVR|STARSBD)[-\s]?\d{3,4}(?!\w)|(?<!\w)(?:HIMEMIX|CASMANI|MGSSLND)[-\s]?\d{3}(?!\w)|(?<!\w)(?:k|n)[01]\d{3}(?!\w|-)|(?<!\w|\d-|\/)[01]\d{5}[-_](?:1)?\d{2,3}(?!\w|-\d)|(?<!\w)(?:carib|1pondo)[-_]\d{6}[-_]\d{2,3}(?!\w)|(?<!\w|\d-)\d{6}[-_]\d{2,3}(?:-1pon|-carib|-paco)(?!\w)|(?<!\w|\d-)\d{6}_(?:1)?\d{3}_0[12](?!\w|-\d)|HEYZO[_-\s]?(?:hd_)?\d{4}/gi; 
    // 省略字母, 连续数字的番号 例: abc-001、002、003
    var oRegExp2 = /(?<=(?<!\w|\d-)([a-zA-Z]{2,6})(?:[\s,,、-]?(?!2022|2021|2020|2019)\d{3,4})+(?!\d)[\s,、,和跟]?)\d{3,4}(?!\w|%|%|人|年|歳|万|の|発)/gmi
    // 一些素人、无码番号: 从javdb获取信息
    //                  ;--------- mgstage 字母 + 数字 + 字母 -----------------------|--------- FC2 ----------------|     HEYDOUGA                |      T28       | TMA 5位,6位,3位(没匹配)   |         1000girl   数字 + 字母             |MUGEN Entertainmen: MKD-S  MKBD-S |    素人 | 北池袋盗撮倶楽部            | japornXXX: JPNXXX       | xxx-av                   |    crazyasia               | PEWORLD                   |   10Musume  6位数字_01          |熟女俱乐部
    var oRegExp_wuma = /(?<!\w|-|\/)\d{3}[a-zA-Z]{2,5}[-\s]?\d{3,4}(?!\w|-|.torrent|年)|(?<!\w|\/)FC2[^\d]{0,5}\d{6,7}|HEYDOUGA[_-\s]?\d{4}-\d{3,5}|(?<!\w)T28-\d{3}|(?<!\w)T-2\d{4,5}(?!\w|-)|(?<!\w|-|\/)[01]\d{5}-[a-zA-Z]{2,7}(?!\w|-)|(?<!\w)MK(?:B)?D-S\d{2,3}(?!\w|-)|(?:SHINKI|KITAIKE)[-\s]?\d{3}(?!\w|-)|JPNXXX[-\s]?\d{5}(?!\w|-)|xxx-av[-\s]\d{4,5}(?!\w|-)|(?<!\w)crazyasia\d{5}(?!\w|-)|(?<!\w)PEWORLD\d{5}(?!\w|-)|(?<!\w)[01]\d{5}[-_]?_01(?=-10mu)?|Jukujo-Club-\d{3}/gi;
    // 省略写的fc2番号 例: fc2-123456 567890
    var oRegExp_wuma2 = /(?<=(FC2[^\d]{0,5})(?:[\s,、-]?\d{6,7})+[\s,、]?)\d{6,7}/gmi
    // 排除在此的番号, 与下面的 Exclude 不同的是: 这个还会判断后面跟的数字, 能够精确排除。
    //                         | 排除非 fx-0xx          | 数字部分全是0     |                                                                          | 一些国家简称 + 两位数字 sr是黑鸟侦察机               |卡西欧         |细胞相关        |csgo皮肤        |致钛硬盘              | 瑞昱芯片      | soc          | ns530刀片
    var oRegExp_Exclude_ID = /^(?:fx-?([^0]\d{2}|\d{4})|[a-zA-Z]+-?0{2,6}$|pg-13|crc-32|ea211|fs[\s-]?140|trc-20|erc-20|rs[\s-]?(232|422|485)|(sg|ae|kr|tw|ph|vn|kh|ru|uk|ua|tr|th|fr|in|de|sr)[\s-]\d{2}|(gm|ga)-\d{4}|cd[\s-]?\d{2,4}|seed[\s-]?\d{3}$|pc005|moc-\d{5}|wd-40|rtd[\s-]?\d{4}|cm\d{4}|rk\d{4})|ns[\s-]?\d{3,4}/i
    // 排除在此的关键词。 个别与番号同名的也被排除, 例如 Top-10 这种
    var oRegExp_Exclude_en = /^(?:about|ac|actg|aes|again|agm|ah|aim|all|ak|akko|apex|aptx|au|ax|avhd|avx|bej|bgm|chrome|bd|bm|build|(?:fc|p)?[blp]ga|by|bzk|cc|ccie|cctv|cea|ckg|class|cny|covid|cpu|code|debian|df|ds|dw|dx|ea|er|ecma|eia|emui|eof|ep|error|ez|fc|file|flash|flyme|fps|for|fork|from|fuck|fx|gbx|get|glm|gnz|gp|groupr|gt|gts|gtx|guest|hao|hd|her|hk|https?|hp|IEEE|il|ilc|ilce|imx|index|intel|inteli|ip|ipad|is|ISBN|iso|issue|issues|it|jav|javdb|joy|jp|jr|jsr|jt|jukujo|kc|keccak|kv[bd]|Kirin|lancet|line|linux|lk|lolrng|lpl|lt|lumia|lg|macos|md|mh|miui|mipc|mnvr|mm|mnvr|model|mv|mvp|ms|nas|nature|nc|next|ngff|note|number|ok|only|os|osx|pa|page|pch|phl|ppv|pmw|png|qbz|qsz|raid|rfc|ripemd|rmb|rng|rog|row|rtx|rush|rx|sale|scp|scte|sdm|sdr|server|sha|shp|spent|sql|sn|snh|Socket|ssd|status|steam|su|swipe|tcp|the|to|top|than|thread|ts|type|uh|uhd|us|usa|usc|utf|utc|via|video|vkffsc|vol|vr|vs|vv|win|with|width|wikis|wta|xdr|xfx|xiaomi|yah)$/i
    // 在没有横杠的情况下, 会排除在此的关键词 例: 识别 tv-001  但是会排除 tv001
    var oRegExp_Special_en = /^(?:ace|akb|api|am|anime|at|be|best|bt|bl|cp|crc|exynos|dl|dp|dq|gb|girl|jd|ha|has|hc|hours|iq|in|mk|mini|mhz|mx|no|open|of|over|part|pd|pdd|porn|pt|sb|sex|tv|tb|ty|ver|vip|zd|zip)$/i
    // 在没有横杠的情况下, 会排除在此的数字 
    var oRegExp_Special_num = /^(?:007|101|110|115|123|128|256|360|365|370|404|512|520|911|996|\d{1,2}00|19[789]\d|20[012]\d|720|1080|1024|2048|[056789]\d{3}|(\d)\1{2,3})$/
    // 排除符合条件的无码番号
    var oRegExp_Exclude_wuma = /^(?:512gb)/i
    // 可能是素人、无码番号, 如果在javbus获取不到信息, 会继续从javdb中查找. 2022-10-23 v0.19.3注: 可能会被弃用
    var oRegExp_SuRen = /ANAN|ARA|BEAF|BKKJ|BSKC|BSKJ|CCDV|CUTE|DAVC|DCV|DDH|ECSN|ENE|ERKR|EROFC|FKNP|FLC|FTHT|GANA|GESB|GRQR|GRMO|GRMR|HABJ|HHL|HMDN|HMDNC|HMT|HOMEV|IMGN|IND|INSF|INSTC|JAC|JNT|JPNXXX|KING|KNB|LBJ|LOG|LUXU|MAAN|MCHT|MFC|MIUM|MKGF|MONA|NAEN|NMCH|NTK|NTR|OPCYN|OREC|ORECO|PAK|POK|pow|PPZ|PRGO|REIW|RKD|SCOH|SGK|SHE|SHINKI|SIRO|SIROR|SIMM|SQB|SROM|SSDV|SSK|STCV|STH|SUKE|TEN|TKOL|TKPR|WITH|\d{6}|(?:k|n)\d{4}/i
    // 磁力链接
    var oRegExp_Magnet = /magnet:\?xt=urn:btih:[0-9a-fA-F]{40}|(?<!\w|\/|\||=)[0-9a-fA-F]{40}(?!\w|-)/ig
    // 特别的className,在这些class中不识别番号。 /name|auth|user|code/i; pstatus:javbus修改帖子的用户名; TbwUpd:谷歌搜索页面链接
    window.qxin.RE_Exclude_className = /(?<!file)name|auth|user|(?<!home)code|^pstatus$|(?<!_tl_|ql-)editor|time|sav-id|sidebar|menu|TbwUpd/gi;

    // 相关网站匹配规则
    switch(window.location.hostname){
        case "www.dmm.co.jp":
            console.log("当前匹配网站: www.dmm.co.jp");
            oRegExp = /[a-zA-Z]{2,6}\d{3,4}/gi;
            break;
        case "attackers.net":
            console.log("当前匹配网站: attackers.net");
            oRegExp = /(?<=dvd)[a-zA-Z]{2,5}\d{3,4}/gi;
            break;
        case "www.mgstage.com":
            window.qxin.RE_Exclude_className = /(?<!file)name|auth|user|(?<!home)code|^pstatus$|(?<!_tl_|ql-)editor|time|sav-id|sidebar|TbwUpd/gi;
            break;
        case "www.javlibrary.com":
        case "www.d67b.com":
            window.qxin.javlibrary = true;
            break;

    }

    // 用于预告视频的链接转换 
    if(!setting.dontGetVideo){
        cid = {
            abp: ["118abp"],
            abw:["118abw"],
            aczd:["h_019aczd"],
            aed: ["aed"],
            aege:["1aege"],
            akdl: ["1akdl"],
            ako: ["ako"],
            ambi:["h_237ambi"],
            anb: ["anb"],
            apaa: ["apaa"],
            apns: ["apns"],
            aran: ["aran"],
            arbb:["h_092arbb"],
            atid:["atid"],
            avop:["avop","h_455avop00"],
            awd: ["awd"],
            bank: ["h_1495bank"],
            bdsr:["57bdsr"],
            bfd: ["24bfd00"],
            bfkb: ["h_1285bfkb"],
            bkynb: ["1bkynb"],
            clot: ["h_237clot"],
            dandy: ["1dandy"],
            davk:["55davk"],
            dldss: ["1dldss"],
            docp:["118docp"],
            dori:["h_491dori"],
            drpt: ["1drpt"],
            dtvr: ["24dtvr"],
            dv: ["53dv"],
            dvaj: ["53dvaj"],
            dvdes: ["1dvdes"],
            ekdv: ["ekdv"],
            emth:["h_1638emth"],
            erofc:["erofc"],
            fbos:["fbos"],
            fera: ["h_086fera"],
            fgan: ["h_1440fgan"],
            fir:["118fir"],
            fneo: ["h_491fneo"],
            fone: ["h_491fone"],
            fsdss: ["1fsdss"],
            fset: ["1fset"],
            fsre:["h_491fsre"],
            fsvr: ["h_955fsvr"],
            ftht: ["1ftht"],
            fuga: ["h_086fuga"],
            gar:["1gar"],
            gas: ["71gas"],
            gets:["118gets"],
            gnab:["118gnab"],
            gnax:["gnax","h_1345gnax"],
            gone: ["h_1133gone"],
            gs:["140gs"],
            gvg: ["13gvg"],
            haru: ["h_687haru"],
            havd: ["1havd"],
            hbad:["1hbad"],
            hez:["59hez"],
            hgot:["84hgot"],
            hkd: ["hkd"],
            hmnf:["h_172hmnf"],
            hnd:["hnd00"],
            hoks: ["hoks"],
            honb:["h_1133honb"],
            hz: ["h_113hz"],
            hzgb: ["h_1100hzgb"],
            hzgd:["h_1100hzgd"],
            ienf:["1ienf"],
            instc:["instc"],
            jbs:["118jbs"],
            jrze: ["h_086jrze"],
            jsop:["jsop"],
            jukf: ["h_227jukf"],
            keed:["h_086keed"],
            kmhr:["1kmhr"],
            kmhrs:["1kmhrs"],
            kri:["h_286kri"],
            ktra: ["h_094ktra"],
            lbdd:["n_1515lbdd"],
            lol: ["12lol"],
            macb:["h_687macb"],
            mas:["118mas"],
            mct: ["118mct"],
            mds: ["84mds"],
            meko: ["h_1160meko"],
            mesu: ["h_086mesu"],
            mist:["1mist"],
            mogi: ["1mogi"],
            moko: ["h_254moko"],
            mond:["18mond"],
            mtall: ["1mtall"],
            mxgs:["h_068mxgs"],
            natr:["h_067natr00"],
            neo:["433neo"],
            nhdta:["1nhdta"],
            nhdtb: ["1nhdtb"],
            npv:["118npv"],
            nxgs: ["h_254nxgs"],
            nyh:["1nyh"],
            ofku: ["h_254ofku"],
            omhd: ["omhd"],
            onez:["h_1674onez"],
            pako:["h_1133pako"],
            piyo: ["1piyo"],
            ppt: ["118ppt"],
            pydvr: ["h_1321pydvr00"],
            pym: ["h_283pym"],
            rct: ["1rct"],
            rctd: ["1rctd"],
            rdt:["118rdt"],
            rebd: ["h_346rebd"],
            sait:["55sait"],
            san:["h_796san00"],
            scpx: ["84scpx"],
            scr:["12scr"],
            sdab: ["1sdab"],
            sdam:["1sdam"],
            sdde: ["1sdde"],
            sdjs: ["1sdjs"],
            sdmf: ["1sdmf"],
            sdmm: ["1sdmm"],
            sdmu: ["1sdmu"],
            sdmua: ["1sdmua"],
            sdnm: ["1sdnm"],
            sdnt:["1sdnt"],
            sdth: ["1sdth"],
            sga:["118sga"],
            shh: ["1shh"],
            shic:["h_839shic"],
            shind: ["h_1560shind"],
            shn: ["1shn"],
            silkc: ["1silkc"],
            skmj: ["h_1324skmj"],
            sprd:["18sprd"],
            spro: ["h_1594spro"],
            spz: ["h_254spz"],
            star: ["1star"],
            stars: ["1stars"],
            stcv: ["h_1616stcv"],
            stko:["1stko"],
            sun: ["1sun"],
            svdvd: ["1svdvd"],
            svmgm:["1svmgm"],
            sw: ["1sw"],
            t28: ["55t28"],
            tmhp: ["h_452tmhp"],
            tmvi: ["h_452tmvi"],
            udak: ["h_254udak"],
            umd: ["125umd"],
            vrtm:["h_910vrtm"],
            wo: ["1wo"],
            wps:["118wps"],
            xrw:["84xrw"],
            yst:["540yst"],
            zeaa: ["h_086zeaa"],
            zex: ["h_720zex"],
            // 未验证
            // 多个
            // h_139doks571   36doks00567
            doks:["h_139doks","36doks"],
            arso: ["h_1378arso","1arso"],
            // gvh-476, gvh-017
            gvh:["gvh","13gvh"],
            // 末尾补零
            bf:["bf00"],
            // 末尾截断
            // n_1445thni088
            thnib:["n_1445thni"],
        };
    }

    // 对动态添加的dom进行检测
    var observerTarget = document.querySelector('body');    // 选择目标节点
    var observerConfig = {childList: true, characterData: true ,subtree:true,}; // 配置观察选项
    var observer = new window.MutationObserver(function(mutations) {    // 创建观察者对象  
        // console.log("观察者数量");
        // console.log(mutations.length);
        mutations.forEach(function(mutation) {
            if(mutation.target.innerText.length<5){
                // console.log(mutation.target.innerText);
                if(debug)console.log("内容为空");
            }
            else if(checkParentClass(mutation.target)){
                if(debug){console.log("存在不合适的父元素")}
            }else{
                observer.disconnect();  // 关闭对 dom 的监听
                // if(debug){console.log("开始判断正则")}
                if(mutation.target.innerText?.search(oRegExp)>-1){
                    // console.log("普通番号");
                    findAndReplaceDOMTextFun(mutation.target)
                }
                if(mutation.target.innerText.search(oRegExp2)>-1){
                    // console.log("连续番号");
                    findAndReplaceDOMTextFun2(mutation.target)
                }
                if(mutation.target.innerText.search(oRegExp_wuma)>-1){
                    // console.log("无码番号");
                    findAndReplaceDOMTextFun_Wuma(mutation.target)
                }
                if(mutation.target.innerText.search(oRegExp_wuma2)>-1){
                    // console.log("连续无码番号");
                    findAndReplaceDOMTextFun_Wuma2(mutation.target)
                }
                observer.observe(observerTarget, observerConfig);   // 开启对 dom 的监听
            } 
        })
    }); 
    
    addStyle()

    // 比对本地 jellyfin/emby 视频, 
    if(setting.jellyfinHost && setting.jellyfinApiKey && setting.LocalVideoSearch){
        setTimeout(() => {
            localVideo_search();
        }, 500);
    }

    // 延时执行, 解决javbus论坛通过搜索进入的帖子无发弹出工具栏的问题
    setTimeout(findAVID,300);

    // 磁链
    // 如果设置中有qbit的网址和下载地址, 则认为启用了下载功能
    if(!(setting.dontMagnetDiscern || setting.dontCopyMagnet )&& setting.qBitHost && setting.qBitDownload){
        window.qxin.QBit = qBit;
    }

    // 滑词搜索 
    if(setting.selectLength && setting.selectLength>0){
        document.onmouseup = selectSearch
    }

    // 切换页面 暂停预览视频播放
    if(setting.dontClearMenu){
        document.addEventListener("visibilitychange",visibilitychangeFun);  // 切换页面 暂停预览视频播放
    }

    // 
    function findAVID(){
        if(debug){console.time("正则查询用时");}
        observer.disconnect();  // 关闭对 dom 的监听
        findAndReplaceDOMTextFun_Wuma2(allHTML);    //// 查找连续的 fc2 番号。 例: fc2-123456 567890
        findAndReplaceDOMTextFun_Wuma(allHTML);  // 查找fc2、素人、无码等番号 (无菜单,点击后会跳转到javdb进行搜索)
        findAndReplaceDOMTextFun2(allHTML);    // 省略字母, 连续数字的番号 例: abc-001、002、003
        findAndReplaceDOMTextFun(allHTML);     // 查找普通番号  (与上面的顺序不能变,否则会导致 2函数 失效)
        observer.observe(observerTarget, observerConfig);   // 开启对 dom 的监听
        if(debug) {console.timeEnd("正则查询用时"); console.log("本页面通过正则匹配的有: " + searchTimes + " . 实际的番号数量: " + avIDTimes);}
        if(!(setting.dontMagnetDiscern || setting.dontCopyMagnet )){    // 磁链
            findAndReplaceDOMTextFunMagnet();
        }
    }

    // 查找番号, 匹配最基础的番号
    function findAndReplaceDOMTextFun(element){
        findAndReplaceDOMText(element, {
            find:oRegExp,
            preset: 'prose', // 仅搜索文本元素(不搜索样式、脚本、对象等),开启会会默认启用下面(NON_INLINE_PROSE)的这个功能, 强制隔断上下文。
            forceContext: findAndReplaceDOMText.NON_INLINE_PROSE,    //调用内置的元素判断, 强制隔断上下文
            replace: function(portion,match) {
                // 当番号介于两个HTML元素之中, 只作用最后一个
                if(portion.isEnd){
                    var otext = match[0];
                }else{
                    return "";
                }
                if(debug) {searchTimes++;};
                
                // 检查番号, 如果存在特殊英文或者数字,则退出
                if(IDcheck(otext)){return otext};
                
                // 添加事件和样式
                var avID = formatAVID(otext)
                
                // 判断3位数字写成2位的
                if(avID.match(/-\d{2}$/) && localInfo[avID] && localInfo[avID].noInfo){
                    let avID2 = avID.replace("-","-0");
                    if(localInfo[avID2]){
                        avID = avID2;
                    }
                }
                
                var odiv = addEventAndStyle(localInfo[avID],avID)   // 添加事件和样式
                if(debug){avIDTimes++; console.log(avIDTimes + "番号: " + avID,otext);otext = "["+avIDTimes +"]" + otext;}

                return displayMode(odiv,otext);
            }
        });
    }
    // 省略字母, 连续数字的番号 例: abc-001、002、003
    function findAndReplaceDOMTextFun2(element){
        findAndReplaceDOMText(element,{
            find: oRegExp2,
            preset: "prose",
            forceContext:findAndReplaceDOMText.NON_INLINE_PROSE, 
            replace: function(portion,match){
                var avID = match[1] + " " +match[0] // 视为无横杠番号
                
                // 检查番号, 如果存在特殊英文或者数字,则退出
                if(IDcheck(avID)){return match[0]};
                if(debug) {searchTimes++;}
                
                // 添加事件和样式
                avID = formatAVID(avID)
                var odiv = addEventAndStyle(localInfo[avID],avID)   // 添加事件和样式

                if(debug){avIDTimes++; console.log(avIDTimes + "省略字母,连续数字的番号: " + avID, portion.text);portion.text = "[*"+avIDTimes +"]" + portion.text}
 
                return displayMode(odiv,portion.text);     
            }
        })
    }
    // 查找番号, 匹配fc2、MGSTAGE(259LUXU等)、一本道、东京热、HEYZO等
        // 只有一个功能就是跳转到 javdb 进行搜索, 没有菜单, 也没有其他任何功能
        // 关于heyzo, 如果是后面跟横杠会触发上面的基础查找, 只有中间没有横杠或者有下划线的情况才会匹配这个。
    function findAndReplaceDOMTextFun_Wuma(element){
        findAndReplaceDOMText(element, {
            find:oRegExp_wuma,
            preset: 'prose', // 仅搜索文本元素(不搜索样式、脚本、对象等),开启会会默认启用下面(NON_INLINE_PROSE)的这个功能, 强制隔断上下文。
            forceContext: findAndReplaceDOMText.NON_INLINE_PROSE,    //调用内置的元素判断, 强制隔断上下文
            replace: function(portion,match) {
                // 当番号介于两个HTML元素之中, 只作用最后一个
                if(portion.isEnd){
                    var otext = match[0];
                }else{
                    return "";
                }

                // 检查番号是否合法
                if(IDcheckWuma(otext)){return otext};
                // 添加事件和样式
                var avID = formatWuma(otext);    // 格式化番号
                // 123abc-456 数字字母-数字
                if(avID.match(/\d{3}[a-zA-Z]{2,5}[-\s]?\d{3,4}/)){
                    avID = avID.slice(3);
                    avID = formatAVID(avID)
                }

                var odiv = addEventAndStyle(localInfo[avID],avID)   // 添加事件和样式

                if(debug) {searchTimes++;avIDTimes++; console.log(avIDTimes + "无码番号: " + avID, otext); otext = "[!"+avIDTimes +"]" + otext;}

                odiv.dataset.av_wuma = avID;
                return displayMode(odiv,otext);
            }
        });
    }
    // 查找番号, 连续的 fc2 番号。 例: fc2-123456 567890
    function findAndReplaceDOMTextFun_Wuma2(element){
        findAndReplaceDOMText(element, {
            find:oRegExp_wuma2,
            preset: 'prose', // 仅搜索文本元素(不搜索样式、脚本、对象等),开启会会默认启用下面(NON_INLINE_PROSE)的这个功能, 强制隔断上下文。
            forceContext: findAndReplaceDOMText.NON_INLINE_PROSE,    //调用内置的元素判断, 强制隔断上下文
            replace: function(portion,match) {
                // 当番号介于两个HTML元素之中, 只作用最后一个
                if(portion.isEnd){
                    var otext = match[0];
                }else{
                    return "";
                }
                var avID = match[1] + otext;

                avID = formatWuma(avID); // 格式化 fc2 番号

                // 复制上方的。 fc2 番号是否合法: FC2-012345 和 FC2PPV-012345 搜索结果不一样 
                if(avID.match(/fc2/i) && localInfo[avID] && localInfo[avID].noInfo ){
                    let avID2;
                    if(avID.match(/ppv/i)){
                        avID2 = avID.replace("FC2PPV","FC2");
                    }else{
                        avID2 = avID.replace("FC2","FC2PPV");
                    }
                    if(localInfo[avID2] && !localInfo[avID2].noInfo){
                        avID = avID2;
                    }
                }

                var odiv = addEventAndStyle(localInfo[avID],avID)   // 添加事件和样式
                
                if(debug) {searchTimes++;avIDTimes++; console.log(avIDTimes + "连续Fc2番号: " + avID,otext); otext = "[**"+avIDTimes +"]" + otext;}

                odiv.dataset.av_wuma = avID;
                return displayMode(odiv,otext);
            }
        });
    }

    // 点击磁力链接, 可以复制到剪贴板
    function findAndReplaceDOMTextFunMagnet(){
        if(debug){console.log("开始查找磁力链接");};
        observer.disconnect();  // 关闭对 dom 的监听
        findAndReplaceDOMText(allHTML, {
            find:oRegExp_Magnet,
            preset: 'prose', // 仅搜索文本元素(不搜索样式、脚本、对象等),开启会会默认启用下面(NON_INLINE_PROSE)的这个功能, 强制隔断上下文。
            forceContext: findAndReplaceDOMText.NON_INLINE_PROSE,    //调用内置的元素判断, 强制隔断上下文
            replace: function(portion,match) {
                // 当番号介于两个HTML元素之中, 只作用最后一个
                if(portion.isEnd){
                    var otext = match[0];
                }else{
                    return "";
                }
                if(debug){console.log("发现磁力链接: " + otext);};
                var magnet = otext
                if(magnet.indexOf("magnet")<0){
                    magnet = "magnet:?xt=urn:btih:" + magnet;
                }

                var odiv = document.createElement('savmagnet');

                if(setting.magnetCopy){
                    odiv.addEventListener("click",function(){
                        GM_setClipboard(magnet);
                        if(setting.qBitHost && setting.qBitDownload){
                            qBit(magnet);
                        }
                    });
                    odiv.title = "点击复制磁力链接";
                } else {
                    otext = "<a href='" +magnet+  "' style='text-decoration:underline;'>" +otext+  "</a>";
                }
                
                odiv.innerHTML = otext;
                odiv.style.textDecoration = "underline #D9B412"
                return odiv;
            }
        });
        observer.observe(observerTarget, observerConfig);   // 开启对 dom 的监听
    }
        
    // 添加页面番号样式 , 传入的参数是番号, 用来判断番号是否在本地存在
    function addEventAndStyle(isExist,avID){
        // 添加事件
        var odiv = document.createElement('savdiv');
        odiv.addEventListener("click",savIDClick);  // 点击番号复制
        if(setting.clickToMenu){
            odiv.addEventListener("click",savIDMouseEnter);    // 点击鼠标 开启菜单
        }else{
            odiv.addEventListener("mouseenter",savIDMouseEnter);    // 鼠标滑过 开启菜单
        }
        odiv.addEventListener("mouseleave",savIDMouseLeave);    // 鼠标离开 关闭菜单

        if(isExist){
            // 添加浏览次数
            if(isExist.visited){
                odiv.dataset.visited = isExist.visited;
            } else {
                odiv.dataset.visited = 1;
            }
            // 添加class 在本地是否存在, (通过添加 class 来改变颜色)
            if(isExist.noInfo){
                odiv.classList.add("sav-id", "infoNonExistent");
            }else{
                odiv.classList.add("sav-id", "infoExistent");
            }
        }else {
            odiv.dataset.visited = 0;
            odiv.classList.add("sav-id", "infoFirst");
        }

        odiv.dataset.av = avID;    

        return odiv;
    }
    // 番号后面添加图标, 不作用于番号 
    function displayMode(odiv,otext){
        if(setting.addSearchButton){
            odiv.innerHTML = setting.searchButtonIcon?setting.searchButtonIcon:"✈";
            var divWrap = document.createElement("savdiv");
            divWrap.innerHTML = otext;
            divWrap.appendChild(odiv);
            return divWrap;
        }else{
            odiv.innerHTML = otext;
            return odiv;
        }
    }

    // 创建搜索基本菜单(搜索按钮)
    function createPattenr(id,id_wuma){
        let aPattern = `<avdivbutton>`
        // 添加 相关页面 按钮
        if(!setting.close_Related_Page){
            aPattern +=  `<avdiv class='savlink relatedPage RPdisabled'><a href='' target='_blank' referrerpolicy='same-origin'>JavBus 页面</a></avdiv>`;
        }
        // 添加特定搜索
        if(id.match(/fc2/i)){
            var basiceSearch = `https://fc2hub.com/search?kw=${id_wuma}`;
            aPattern +=  `<avdiv class='savlink'><a href='${basiceSearch}' target='_blank' referrerpolicy='same-origin'>fc2hub 搜索</a></avdiv><avdiv class='savlink'><a href='${javDBLink}search?q=${id_wuma}&f=all' target='_blank' referrerpolicy='same-origin'>JavDB 搜索</a></avdiv>`;
            var savList = setting.list_wuma;
        }else if(id_wuma){
            var basiceSearch = `${javDBLink}search?q=${id_wuma}&f=all`;
             aPattern +=  `<avdiv class='savlink'><a href='${basiceSearch}' target='_blank' referrerpolicy='same-origin'>JavDB 搜索</a></avdiv>` ;
            var savList = setting.list_wuma;
        } else{
            var basiceSearch = javbusLink + "search/" + id;
             aPattern +=  "<avdiv class='savlink'>" + "<a href='" + basiceSearch +"' target='_blank' referrerpolicy='same-origin'>JavBus 搜索</a>" +"</avdiv>" ;
            var savList = setting.list;
        }
        if(savList){
            for(let i=0; i<savList.length;i++){
                aPattern += "<avdiv class='savlink'>" + "<a href='" + savList[i][1].replace("%s", id) +" 'target='_blank' referrerpolicy='same-origin'>" + savList[i][0] + "</a>" + "</avdiv>"
            }
        }

        // 添加通用搜索按钮
        if(setting.list_all && setting.list_all.length>0){
            var savListAll = setting.list_all;
            for(let i=0; i<savListAll.length;i++){
                aPattern += "<avdiv class='savlink'>" + "<a href='" + savListAll[i][1].replace("%s", id) +" 'target='_blank' referrerpolicy='same-origin'>" + savListAll[i][0] + "</a>" + "</avdiv>"
            }
        }

        // 添加色花堂搜索
        if(setting.sehuatang){
            aPattern += `<avdiv class='savlink savsehuatang'  data-avid=${id}> 色花堂 </avdiv>`
            sehuatang_getFormHash();
        }

        // 添加jellyfin按钮
        if(setting.jellyfinHost && setting.jellyfinApiKey){
            if(setting.emby){
                aPattern += "<avdiv class='savlink jellyfin'> Emby </avdiv>"
            }else{
                aPattern += "<avdiv class='savlink jellyfin'> Jellyfin </avdiv>"
            }
        }
        // 添加额外按钮
        if(debug){
            let debugSearchList = [
                [
                    "dmm",
                    "https://www.dmm.co.jp/search/?redirect=1&enc=UTF-8&category=&searchstr=%s&commit.x=11&commit.y=14"
                ],
                [
                    "google",
                    "https://www.google.com/search?q=%s&ie=utf-8&oe=utf-8"
                ]
            ];
            for(let i=0; i<debugSearchList.length;i++){
                aPattern += "<avdiv class='savlink'>" + "<a href='" + debugSearchList[i][1].replace("%s", id) +" 'target='_blank' referrerpolicy='same-origin'>" + debugSearchList[i][0] + "</a>" + "</avdiv>"
            }
        }
        if(debug || setting.addOtherButton){aPattern += "<avdiv class='savlink savSetting'>设置</avdiv><avdiv class='savlink savCopyID' data-av='"+ id +"'>" + id + "</avdiv>"};
        if(setting.dontClearMenu || setting.addOtherButton){aPattern += "<avdiv class='savlink savCloseMenu'> 关闭 </avdiv>"};
        
        aPattern += `</avdivbutton>`
    
        var odiv = document.createElement("avdiv")
        if(localInfo[id]){
            odiv.classList.add("sav-menu","idExistent");
            odiv.dataset.visited = localInfo[id].visited?localInfo[id].visited:1;
        }else{
            odiv.classList.add("sav-menu","idNonExistent");
            odiv.dataset.visited = 0;
        }
        odiv.addEventListener("mouseenter",savMenuMouseEnter)
        odiv.addEventListener("mouseleave",savMenuMouseLeave)
        // 鼠标在图片上点击和滚轮放大缩小图片
        if(!setting.dontImgBig){ 
            odiv.addEventListener("click",savMenuClick)
            odiv.addEventListener("wheel",savImgWheel)
        };
        odiv.dataset.av = id; 
        odiv.innerHTML=aPattern;
        return odiv;
    }

    // 点击番号复制
    function savIDClick(e){
        if(!document.querySelector(".sav-menu")){
            e.preventDefault();
            return false;
        }

        var avid = e.target.dataset.av
        if(avid){
            GM_setClipboard(avid);
            if(debug) console.log("粘贴成功: ", avid);
        }
        e.preventDefault();
        return false;
    }

    // 鼠标经过番号
    function savIDMouseEnter(e){ 
        // 进入番号, 如果之前存在菜单, 就判断是否是现在番号的菜单, 如果是, 退出; 否则删掉菜单, 重新获取
        if(divTarget && e.target.dataset.av==divTarget.dataset.av){
            clearTimeout(timerMouseLeaveMenu)
            return
        }else if (divTarget){
            clearTimeout(timerMouseLeaveMenu)

            let odiv = document.querySelector(".sav-menu");
            odiv.parentNode.removeChild(odiv);
        }

        // 
        observer.disconnect();
        if(e.buttons != 0) return;  // 如果是按键的情况下划过番号, 则不触发
        divTarget = e.target;
        clearTimeout(timerMouseLeave);   
        clearTimeout(timerGetInfo);
        avmouseenter(e);
    }
    // 鼠标离开番号
    function savIDMouseLeave(e){ 
        observer.observe(observerTarget, observerConfig);    
        timerMouseLeave = setTimeout(function(){
            avInfo = {};
            avInfoID = "";
            savMenuMouseLeave();
            removeLoading();
            clearTimeout(timerGetInfo);
        },50)

    }
    // 鼠标进入菜单
    function savMenuMouseEnter(e){  
        observer.disconnect();  
        clearTimeout(timerMouseLeave);
    }
    // 鼠标离开菜单
    function savMenuMouseLeave(e){
        timerMouseLeaveMenu = setTimeout(function(){

            var odiv = document.querySelector(".sav-menu");
            if(odiv){
                if(setting.dontClearMenu){
                    console.log("移除");
                } else {
                    // odiv.parentNode.removeChild(odiv);
                    odiv.classList.add("savCloseAnim")
                    setTimeout(function(){
                        if(odiv){
                            odiv.parentNode.removeChild(odiv);
                        }
                    },100)
                }
                Imgscall = 1.0;
                divTarget = null;
            }
            avInfo = {};
            avInfoID = "";
            clearTimeout(timerGetInfo);
            // clearInterval(timerImgLoading); // 重置位置的定时器
            observer.observe(observerTarget, observerConfig);     
        },10);
    }

    // 鼠标滑过 显示菜单
    function avmouseenter(e){
        if(document.querySelector(".sav-menu")){
            return; // 防止出现菜单后重复触发, 尤其是margin上移两像素后
        } 
        var wuma = e.target.dataset.av_wuma;
        var avid = e.target.dataset.av;

        if(e.target.classList.contains("infoFirst")){
            // e.target.classList.remove("infoFirst");
            // e.target.classList.add("infoExistent");
            let allDoms = document.querySelectorAll(`savdiv.infoFirst[data-av='${avid}']`)
            for( let i=0; i<allDoms.length; i++){
                allDoms[i].classList.remove("infoFirst");
                allDoms[i].classList.add("infoExistent");
            }
        }

        var avdiv = document.querySelector(".sav-menu")
        if(avdiv){
            avdiv.parentNode.removeChild(avdiv)
        }
        var oPosition = e.target.getBoundingClientRect()
        var odiv = createPattenr(avid,wuma);
        // e.target.appendChild(odiv);

        // 信息加载时的动画
        if(!setting.closeLoadingAnimation && (setting.infoReload || !localInfo[avid])){
            addLoading(odiv)
        }

        var posRight =630 - (document.documentElement.clientWidth-divTarget.getBoundingClientRect().x);
        if(posRight<15){
            posRight = 15
        }
        odiv.style.transformOrigin = posRight + "px 5px";

        document.body.appendChild(odiv);
        odiv.style.left = oPosition.x + "px";
        odiv.style.top = oPosition.y + oPosition.height - 2 + "px";

        // return;  // 停止一切信息获取

        if(localInfo[avid]){
            avInfo = localInfo[avid];
            avInfoID = avid;
            timerGetInfo = setTimeout(() => {  
                if(wuma){
                    if(setting.infoReload){
                        getInfo_wuma(avid);
                    }else{
                        getInfo_local(avid)
                    }
                }else{
                    if(setting.infoReload){
                        getInfo(avid);
                    }else{
                        getInfo_local(avid)
                    }
                }
            }, 100);
        } else{
            timerGetInfo = setTimeout(() => {
                if(wuma){
                    getInfo_wuma(avid);
                }else{
                    getInfo(avid);
                }
            }, 300);
        }
        
        var otherInfo = document.createElement('avdivsInfo');
        otherInfo.innerHTML=addOtherInfo(avid);
        odiv.appendChild(otherInfo);
        
        e.target.parentNode.title = "";
        e.target.parentNode.parentNode.title = "";
        settingPostion();  //重置位置
        if(setting.emby){
            getEmby(avid);
        }else{
            getJellyfin(avid);
        }
    }

    // 点击事件, 图片放大缩小, debug中复制番号
    function savMenuClick(e){
        // 测试使用
        if(e.target.classList.contains("savCopyID")){
            GM_setClipboard(e.target.dataset.av)
        } else if(e.target.classList.contains("savCloseMenu")){
            var odiv = document.querySelector(".sav-menu");
            
            odiv.classList.add("savCloseAnim")
            setTimeout(function(){
                odiv.parentNode.removeChild(odiv);

            },100)

            Imgscall = 1.0;
            avInfo = {};
            avInfoID = "";
            divTarget = null;
            clearTimeout(timerGetInfo);
            return;
        } else if(e.target.classList.contains("savSetting")){
            savBoxEdit();
            return;
        } else if(e.target.classList.contains("jellyfin")){
            if(e.target.classList.contains("noJellyfin")){
                console.log(e.target.dataset.avid);
                GM_setClipboard(e.target.dataset.avid);
            }
            // console.log(e.target.dataset.url);
            if(debug)console.log(e.target.dataset.url);
            GM_openInTab(e.target.dataset.url,{active: true, insert: true,setParent:true});
            return;
        } else if(e.target.classList.contains("savsehuatang")){
            // 防止多次点击导致重复发送请求
            e.target.classList.remove("savsehuatang");
            sehuatang(e.target.dataset.avid);
            return;
        }  else if(e.target.classList.contains("savVideoClose")){
            let videoDiv = document.querySelector("avdivVideo");
            if(videoDiv){
                videoDiv.classList.add("savCloseAnim2");
                setTimeout(()=>{
                    videoDiv.parentNode.removeChild(videoDiv);
                },200)
            }
            return;
        }


        // 图片放大缩小
        if(e.target.tagName == "IMG"){
            if( e.target.classList.contains("imageBig")){    
                e.target.classList.remove("imageBig");
                Imgscall = 1.0
                e.target.style = "";
            } else {
                Imgscall = 1.3  // 重置大小
                e.target.classList.add("imageBig");
            }
        } else {
            var oImg = document.querySelector(".sav-menu").querySelector("img");
            if(oImg){
                oImg.classList.remove("imageBig");
                Imgscall = 1.0
                oImg.style = "";
            }
        } 
    }
    // 滚动图片放大缩小
    function savImgWheel(e){
        if(e.target.tagName == "IMG"){
            if(e.wheelDelta>0){
                e.target.classList.add("imageBig"); // 点击后可以恢复
                Imgscall += 0.15
                e.target.style.transform = "scale(" + Imgscall +")"
            } else if(e.wheelDelta<0){
                if(Imgscall>1){
                    Imgscall -= 0.15;
                    if(Imgscall<1){Imgscall=1}; // 偶尔会继续减小, 明明已经小于1还是会执行到这
                    e.target.style.transform = "scale(" + Imgscall +")";
                    if(Imgscall==1){ // 缩放到1就去掉class, 之前是缩放到1后继续滚动一次才会去掉class
                        e.target.classList.remove("imageBig");
                        e.target.style = "";
                    };
                }else{
                    e.target.classList.remove("imageBig");
                    e.target.style = "";
                }
            }
        }
        e.preventDefault();
        return false;
    }

    // 鼠标选中 划词搜索
    function selectSearch(e){
        if(e.button !=0) return;    // 排除非左键点击
        if(document.activeElement.tagName.toUpperCase() == "INPUT" || document.activeElement.tagName.toUpperCase() == "TEXTAREA") return;   // 排除inpu和textarea内的文本
        if(document.querySelector(".sav-menu")) return; //如果已经存在菜单, 退出
        
        var selectText = window.getSelection().toString().trim();
        if (selectText.length > setting.selectLength) return; //如果复制的文字过长,退出。避免复制网址时自己弹出。
        selectText = selectText.replace(/[^a-zA-Z0-9-]/g,"");  //去掉一些莫名其妙的符号。网友分享的番号总是各种各样
        var avid = selectText.match(/[a-z|A-Z]{2,8}-?\d{2,6}/i);
        if(!avid) return;  //如果没搜索到,退出
        
        observer.disconnect();  // 关闭dom变动的监听

        avid = formatAVID(avid[0]);
        var odiv = createPattenr(avid);
        
        var divClientRect = odiv.getBoundingClientRect()
        var divWidth = divClientRect.right - divClientRect.left;
        odiv.style.left = e.pageX - divWidth/2 + "px";
        odiv.style.top = e.pageY + "px";
        odiv.style.position = "absolute";
        
        if(localInfo[avid]){
            avInfo = {};
            avInfo = localInfo[avid];
            avInfoID = avid;
            timerGetInfo = setTimeout(() => {
                if(setting.infoReload){
                    getInfo(avid);
                }else{
                    getInfo_local(avid)
                }
            }, 500);
        } else{
            timerGetInfo = setTimeout(() => {
                getInfo(avid,true);
            }, 300);
        }
        
        document.body.appendChild(odiv);
    }

    // 调整距离底部的距离,以防越界
    function settingPostion(image){
        if(debug){console.log("正在重置位置");};
        // if(image && image.complete){
        //     if(debug){console.log("图片加载情况: " + image.complete)};
        //     clearInterval(timerImgLoading);
        // }
        var odiv = document.querySelector(".sav-menu");
        if(!odiv)  return;
        var oClient = odiv.getBoundingClientRect()
        var oTop = oClient.top; // 距离顶部举例
        var oHeight = oClient.height;   //自身高度
        // var oWidth = oClient.Width;  // 自身宽度
        var winHeight = document.documentElement.clientHeight;  //可视窗口高度
        var winWidth = document.documentElement.clientWidth;    //可视窗口宽度
        let loadingContainerHeight = document.querySelector(".savLoadingContainer")?8:0;
        if(oTop + oHeight - loadingContainerHeight > winHeight){ // 越出了屏幕底边
            odiv.style.position = "fixed";
            odiv.style.top = winHeight-oHeight + 2*loadingContainerHeight - 16 +"px";
            var posBottom =oHeight - (document.documentElement.clientHeight-divTarget.getBoundingClientRect().y) +30;
            if(posBottom<5){
                posBottom = 5
            }
            odiv.style.transformOrigin = odiv.style.transformOrigin.replace(/\s.+px/,` ${posBottom}px`)
        }
        if(oClient.x<0){   //左边
            odiv.style.position = "fixed";
            odiv.style.left = 0;
        }else if(winWidth-oClient.x<600){  // 越出了屏幕右边
            odiv.style.position = "fixed";
            odiv.style.right = "4px";
            odiv.style.left = "";
        }
    }

    // 获取番号相关的信息, 添加图片,调用其他函数添加信息
    function getInfo(avID,oFirstBrowse){
        if(debug){console.log("从javbus获取信息中 getInfo: " + avID);}
        if(setting.dontGetInfo){
            getInfo_end_error(`<avdiv>已经设置为禁止获取番号信息</avdiv>`,avID);
            return;
        };

        GM_xmlhttpRequest({
            method: 'get',
            url: javbusLink + avID,
            headers: {
                "Content-Type": "application/x-www-form-urlencoded"
            },
            data: "",
            timeout: 3000,  // 应对2023-12月 出现的javbus 无法访问的问题
            onload: function (data) {
                noReferrer();   // 针对防盗链问题
                javbusloading();
                if(data.status==403 || data.status==522){
                    if(setting.getInfoFailToJavDB??true){
                        getInfo_wuma_javdb1(avID);
                    } else{
                        getInfo_end(avID,data);
                    }
                    return;
                }else if(data.status==404){
                    // javbus 对于番号中002简写成02的会识别错误, 只认准确的番号。 一些网友分享的番号会简写, 此处做个判断。不能全部补全, 因为以前的番号确实有两位数字的, 补全后javbus不识别。
                    if( avID.length - avID.indexOf("-") ==3){
                        // 将错误番号存储到本地
                        localInfo[avID] = {};   
                        localInfo[avID].title = "番号可能存在问题";
                        localInfo[avID].noInfo = true;
                        GM_setValue("avInfo2",localInfo);
                        setTimeout(() => {
                            var avdivinfo = document.querySelector("avdivsinfo");
                            avdivinfo.parentNode.removeChild(avdivinfo);
                        }, 300);
                        // 重新获取信息
                        getInfo(avID.replace("-","-0"),true);
                        let relatedPage = document.querySelector(".relatedPage a");
                        if(relatedPage){
                            relatedPage.href = relatedPage.href.replace("-","-0");
                        }
                    } else if(avID.match(oRegExp_SuRen) || (setting.getInfoFailToJavDB??true) ){
                        getInfo_wuma_javdb1(avID);
                    } else {
                        getInfo_end(avID,data);
                    }
                    return;
                }

                var parser=new DOMParser();
                var htmlDoc=parser.parseFromString(data.responseText, "text/html");

                // 标题
                avInfo.title = htmlDoc.title.replace(avID,"").replace(" - JavBus","");
                // 获取演员名字
                var starNameList = htmlDoc.querySelectorAll(".star-name");
                var starName = [];
                for(let i=0;i<starNameList.length;i++){
                    starName.push(starNameList[i].querySelector("a").innerHTML);
                }
                avInfo.starName = starName;
                // 获取标签
                var tagList = htmlDoc.querySelectorAll("input[name='gr_sel']");
                var tags = "";
                for(let i=0;i<tagList.length;i++){
                    tags += tagList[i].nextSibling.innerHTML + " ";
                }
                avInfo.tags = tags;
                // 其他: 发行日期和系列  此处的“发行日期”必须是繁体, 因为是匹配的具体的字。
                var other = htmlDoc.querySelectorAll(".header");
                for(let i=0;i<other.length;i++){
                    if(other[i].innerHTML=="發行日期:"){
                        avInfo.date = other[i].parentNode.innerText.replace("發行日期","日期");
                    }
                    if(other[i].innerHTML=="系列:"){
                        avInfo.series = other[i].parentNode.innerText;
                        avInfo.seriesLink = other[i].nextElementSibling.href;
                    }
                }
                // 封面
                var image = htmlDoc.querySelector(".bigImage img");
                if(image){ 
                    changeRelatedPage(javbusLink + avID, "JavBus 页面");

                    var imgSrc = image.src;
                    if(imgSrc.search("pics.dmm.co.jp")<0){
                        // var imgNum = imgSrc.search(/(imgs|pics)/i);
                        imgSrc = imgSrc.slice(imgSrc.search(/(imgs|pics)/i));
                        image.src = javbusLink + imgSrc;
                    }
                    image.removeAttribute("title");     //鼠标经过的时候会触发离开事件,所以删掉
                }
                // 链接
                avInfo.link = javbusLink + avID;

                // 视频链接部分
                let avIDsplit = avID.toLowerCase().split("-");
                if(debug){
                    console.log(avIDsplit)
                    console.log(cid[avIDsplit[0]])
                }
                if(!setting.dontGetVideo && !cid[avIDsplit[0]]){
                    let videoURL = htmlDoc.querySelector("#sample-waterfall a")?.href;
                    if(videoURL?.includes("dmm.co.jp")){
                        videoURL = videoURL.match(/(?<=.*video\/).*?(?=\/)/)
                        // 1bkynb00008
                        let corp_finish = videoURL[0].slice(0,-avIDsplit[1].length);
                        corp_finish = corp_finish.replace("00","");
                        if(corp_finish.length != avIDsplit[0].length){
                            // 只作用2015年以后的番号, 防止污染cid
                            if(avInfo.date && new Date(avInfo.date)>new Date("1/1/2015")){
                                let setting2 = GM_getValue("_setting2");
                                setting2.cid_user = setting2.cid_user ?? {};
                                setting2.cid_user[avIDsplit[0]] = [corp_finish,avID];
                                //       cid_user[bkynb]        = 1bkynb00
                                if(debug) console.log("更新用户规则 cid: ",corp_finish,avID );
                                GM_setValue("_setting2",setting2);
                            }
                        }
                    }
                }
                
                getInfo_end(avID,data,image);
            },
            // 2023-12-20左右, javbus无法访问, 临时使用javdb
            ontimeout(data){
                if(setting.getInfoFailToJavDB??true){
                    getInfo_wuma_javdb1(avID);
                } else{
                    getInfo_end(avID,data);
                }
            }
        });
    }

    // 无码信息获取
    function getInfo_wuma(avID){
        if(debug){console.log("从网络获取信息中 getInfo_wuma: " + avID);}
        if(avID.match(/fc2/i)){
            if(setting.dontGetInfoFc2){
                getInfo_end_error(`<avdiv>已经设置为禁止获取 FC2 信息</avdiv>`,avID);
                return
            };
            getInfo_fc2(avID);
            // getInfo_fc2_market(avID);
        }else{
            getInfo_wuma_javdb1(avID);
        }
    }
    // 无码信息获取 - fc2
    function getInfo_fc2_market(avID){
        if(debug){console.log("从fc2hub获取信息中 getInfo_fc2_market: " + avID);}
        
        let IDnum = avID.slice(4)
        let link = `https://adult.contents.fc2.com/article/${IDnum}/`
        console.log(link)

        GM_xmlhttpRequest({
            method: 'get',
            // https://contents.fc2.com/article/3107706/
            url: link,
            headers: {
                "Content-Type": "application/x-www-form-urlencoded"
            },
            data: "",
            onload: function (data) {
                console.log(data);
                let parser=new DOMParser();
                let htmlDoc=parser.parseFromString(data.responseText, "text/html");
                console.log(htmlDoc)
                let info = htmlDoc.querySelector(".items_article_headerInfo");

                // 标题
                let title = htmlDoc.title.replace("PPV-","").replace(avID,"").trim();
                // 番号的链接
                // let link = link;
                // 获取名字
                // 获取标签
                let tags = info.querySelector(".items_article_TagArea div").innerText
                // 获取日期
                let d = info.querySelector(".items_article_Releasedate").innerText.slice(7).replaceAll("/","-");
                
                // 获取图片
                let img = htmlDoc.querySelector(".items_article_SampleImages a").href;
                // 获取视频
                let video = htmlDoc.querySelector(".fc2-video-container video");
                console.log(video);
                if(video){
                    console.log(video);
                    var videoURL = video.src;
                    var img2 = video.poster;
                }

                console.log(link)
                console.log(title)
                console.log(tags)
                console.log(d)
                console.log(img)
                console.log(img2)
                console.log(videoURL)
            }
        });
    }
    function getInfo_fc2(avID){
        if(debug){console.log("从fc2hub获取信息中 getInfo_fc2: " + avID);}

        let url = 'https://fc2hub.com/search?kw=' + avID;
        GM_xmlhttpRequest({
            method: 'get',
            url: url,
            headers: {
                "Content-Type": "application/x-www-form-urlencoded"
            },
            data: "",
            onload: function (data) {
                console.log(data);
                if(data.status == 500){
                    data.status = 404
                    getInfo_end(avID,data,false)
                    return
                }
                if(data.finalUrl && data.finalUrl != url){
                    getInfo_fc2_openPage(avID,data.finalUrl)
                } else {
                    data.status = 404
                    getInfo_end(avID,data,false)
                    return
                }
            }
        });
    }
    function getInfo_fc2_openPage(avID,link){
        if(debug){console.log("从fc2hub获取信息中 getInfo_fc2_openPage: " + link);}
        fc2loading();
        GM_xmlhttpRequest({
            method: 'get',
            url: link,
            headers: {
                "Content-Type": "application/x-www-form-urlencoded"
            },
            data: "",
            onload: function (data) {
                let parser=new DOMParser();
                let htmlDoc=parser.parseFromString(data.responseText, "text/html");

                var iframe = htmlDoc.querySelector("iframe.lazy")
                // 视频
                avInfo.fc2Video = iframe.dataset.src
                // return

                 // 番号的链接
                avInfo.link = link.match(/http.*id\d{5,7}/)[0];
                // 标题
                avInfo.title = htmlDoc.querySelector(".fc2-title");
                if(!avInfo.title){
                    data.status = 404
                    getInfo_end(avID,data,false)
                    return
                }
                avInfo.title = avInfo.title.innerText
                //标签
                avInfo.tags = htmlDoc.body.querySelector("meta[name~='keywords']")?.content.replaceAll(", "," ");
                // 日期
                avInfo.date = "日期: " + htmlDoc.body.querySelector("meta[property~='videos:published_time']")?.content.slice(0,10);
                // 图片
                let imgSrc;
                let img = htmlDoc.querySelector(".col-xl-4 .card-body .row a")
                if(img){
                    imgSrc = img.href;
                    avInfo.imgSrc2 = htmlDoc.querySelector(".des img")?.src;
                }
                // 加载缩略图
                if(setting.fc2Thumbnail){
                    imgSrc = imgSrc.replace("https://","https://contents-thumbnail2.fc2.com/w500/");
                }
                let image = document.createElement("img");
                image.src = imgSrc;
                
                changeRelatedPage(link, "fc2hub 页面");

                getInfo_end(avID,data,image);
            }
        });
    }
    // 无码信息获取 - 获取链接
    function getInfo_wuma_javdb1(avID){
        if(debug){console.log("从javdb获取信息中 getInfo_wuma_javdb1: " + avID);}

        if(setting.dontGetInfoWuma){
            getInfo_end_error(`<avdiv>已经设置为禁止从 JavDB 获取信息</avdiv><avdiv>提示: 如果该选项自动出现, 说明IP地址已被禁止访问。(存在误触发的可能) </avdiv><avdiv>javdb会在两个星期内禁止你的访问,在此期间不要开启自动获取无码信息</avdiv>`,avID);
            return
        };

        // 从javdb加一些限制, 防止ip被禁用。 目前是5分钟内限制10个。
        if(setting.closeJavdbLimit){
            console.log("已经关闭对javdb的访问限制, 有封IP的风险");
        }else{
            var oTime = new Date().getTime();
            if(javdbTime.length<10){
                javdbTime.push(oTime);
                setting2.javdbTime = javdbTime;
                GM_setValue("_setting2",setting2);
            }else{
                javdbTime = GM_getValue("_setting2").javdbTime;
                if(oTime-javdbTime[0]>300000){
                    if(debug){console.log("javdb时间保护机制: 正在更新");};
                    javdbTime.shift();
                    javdbTime.push(oTime)
                    setting2.javdbTime = javdbTime;
                    GM_setValue("_setting2",setting2);
                } else {
                    if(debug){console.log("触发保护机制, 停止获取信息")};
                    getInfo_end_error(`<avdiv>提示: <br>由于短时间内过多访问 JavDB, 触发了脚本的自动保护机制 <br>目前已经限制脚本从 JavDB 获取信息, 稍后会自动恢复<br>该消息仅供参考,依旧有被封IP的风险</avdiv>`,avID);
                    return;
                }
            }
        }

        GM_xmlhttpRequest({
            method: 'get',
            url: javDBLink + 'search?q=' + avID ,
            headers: {
                "Content-Type": "application/x-www-form-urlencoded"
            },
            data: "",
            onload: function (data) {
                noReferrer();   // 针对防盗链问题

                var parser=new DOMParser();
                var htmlDoc=parser.parseFromString(data.responseText, "text/html");
                // console.log("data.status:");
                var searchResult = htmlDoc.querySelectorAll(".movie-list .item")

                var REavID = new RegExp(avID.replace(/-|_/,"[_-]"),"i")

                // 没有搜索结果
                if(!searchResult.length){
                    // console.log(htmlDoc);
                    //  测试了一上午, ip被禁止访问了。。。
                    if(!htmlDoc.querySelector("title")){
                        console.log("ip被ban")
                        
                        if(htmlDoc.body.innerText.indexOf("copyright")>-1){
                            getInfo_end_error(`疑似使用的是日本代理,导致javdb拒绝了您的访问。 网站返回信息:</br></br> ${htmlDoc.querySelector("body").innerHTML}`,avID);
                        }else{
                            setting.dontGetInfoWuma = true;
                            GM_setValue("_setting",setting);
                            getInfo_end_error(`疑似IP地址被封。 网站返回信息:</br></br> ${htmlDoc.querySelector("body").innerHTML}`,avID);
                        }
                        return;
                    }
                    data.status = 404
                    getInfo_end(avID,data,false)
                    return
                }
                // 有搜索结果, 但是没有该番号
                var fuzzyID = false;
                if(searchResult[0].innerText.search(REavID)<0){
                    fuzzyID = fuzzyMatch(avID,searchResult[0].innerText);
                    if(!fuzzyID){
                        data.status = 404
                        getInfo_end(avID,data,false)
                        return
                    }
                }

                var avLink = searchResult[0].querySelector("a").href;
                avLink = javDBLink.slice(0,-1) + avLink.slice(avLink.search(/\/v\//i));

                changeRelatedPage(avLink, "JavDB 页面")

                getInfo_wuma_javdb2(avID,avLink)
            }
        });
    }
    // 无码信息获取 - 具体内容
    function getInfo_wuma_javdb2(avID,link){
        if(debug){console.log("从javdb获取信息中 getInfo_wuma_javdb2: " + avID);}
        javdbloading()
        GM_xmlhttpRequest({
            method: 'get',
            url: link,
            headers: {
                "Content-Type": "application/x-www-form-urlencoded"
            },
            data: "",
            onload: function (data) {
                noReferrer();   // 针对防盗链问题

                var parser=new DOMParser();
                var htmlDoc=parser.parseFromString(data.responseText, "text/html");
                // console.log("真实番号地址");
                // console.log(htmlDoc);
                
                // 标题
                avInfo.title = htmlDoc.title.replace(avID,"").slice(0,-16).trim();
                // 番号的链接
                avInfo.link = link;
                
                // 获取相关信息, 匹配的具体的字。
                var other = htmlDoc.querySelectorAll(".panel-block");
                for(let i=0;i<other.length;i++){
                    if(other[i].innerHTML.search("日期:")>-1){
                        avInfo.date = other[i].innerText.trim();
                    }
                    if(other[i].innerHTML.search("系列")>-1){
                        avInfo.series = other[i].innerText.trim();
                        avInfo.seriesLink = other[i].querySelector("a").href; 
                        avInfo.seriesLink = avInfo.seriesLink.replace(/https:\/\/.*?\//,setting.javDBLink??"https://javdb.com/");
                    }
                    if(other[i].innerHTML.search("類別")>-1){
                        avInfo.tags = other[i].lastElementChild.innerText.trim().replaceAll(", "," ");
                    }
                    if(other[i].innerHTML.search("演員")>-1){
                        var starNameList = other[i].querySelectorAll("a")
                        var starName = [];
                        for(let i=0;i<starNameList.length;i++){
                            if(starNameList[i].nextElementSibling.classList.contains("female")){
                                starName.push(starNameList[i].innerText);
                            }
                        }
                    }
                }
                avInfo.starName = starName;

                // 封面
                var image = htmlDoc.querySelector(".video-meta-panel img");
                image.removeAttribute("title");     //鼠标经过的时候会触发离开事件,所以删掉

                // 预览视频相关
                if(!setting.dontGetVideo){
                    let videoURL = htmlDoc.querySelector("video source")?.src;
                    if(videoURL?.includes("mp4")){
                        avInfo.video = videoURL;
                        javdbVideoTest(videoURL,avID);
                    }
                }
                
                getInfo_end(avID,data,image);
            }
        });
    }
    // javdb网页中自带的视频链接判断是否有效
    async function javdbVideoTest(link,avID){
        await GetMess(link)
            .then((res) =>{
                if(res.status == 200){
                    if(debug)console.log("javdb中的链接正常")
                    return link;
                }else{
                    if(debug)console.error("javdb中的链接有误 X")
                    let videoButton = document.querySelector(".avimg-preview-button");
                    if(videoButton){
                        videoButton.parentNode.removeChild(videoButton);
                        localInfo[avID].video = false;
                        GM_setValue("avInfo2",localInfo);
                    }
                    return false
                }
            })
    }

    // 将获取到的信息进行展示和保存
    function getInfo_end(avID,data,image){
        // removeLoading()
        if(debug){console.log("从网络获取信息结束 end: " + avID, avInfo);}
        let errorDiv = document.querySelector("avdiverror");
        if(errorDiv){
            errorDiv.parentNode.removeChild(errorDiv);
        }

        // 标题翻译
        if(data.status==403){
            avInfo.title = "403错误, javBus 拒绝了您的访问!";
        }else if(data.status==404){
                getInfo_end_error(`脚本没有匹配到 ${avID} 相关页面, 请使用上方搜索进行查找`,avID)
                avInfo.noInfo = true;

                if(divTarget){
                    divTarget.classList.remove("infoExistent");
                    divTarget.classList.add("infoNonExistent");
                }
                
        }else if(setting.dontTransTitle){
            if(debug){console.log("禁止翻译标题 ✖  ✖  ✖ : ", avInfo.title);}
        }else if(!avInfo.titleTrans || avInfo.titleTrans.search("没有找到")>-1){   // 如果本地存在翻译, 就不再重复翻译
            // 删除标题之后的演员名字
            let title = avInfo.title;
            let starName = avInfo.starName;
            if(starName && starName.length ==1 && title.indexOf(starName[0])>-1){
                let oLength = title.length-title.indexOf(starName[0]);
                if( oLength == starName[0].length){
                    title = title.slice(0,(oLength+1)*-1)
                }
            }
            // 删除标题中的番号(这是第二次删除, getInfo中还有一次)
            title = title.replace(avID,"");
            // 删除奇奇怪怪的标点
            let biaodian = /[\※\☆\★\♥️\●\▲\♡]|[\s\……\——\-\】\』\}\、\|\;\‘\’\:\“\”\》\,\。\、\_\]\;\'\'\:\"\"\,\.\/\~]*$/g
            title = title.replace(biaodian,"")
            
            avInfo.title = title;

            if(setting.baiduAppid && setting.baiduKey){
                baiduTrans(avID,title);
            } else{
                googleTrans(avID,title);
            }
        }

        if(avInfo.tags && !setting.dontTransTags){
            avInfo.tags= translateTag(avInfo.tags)
        }
        
        localInfo[avID] = {};   // 重置,防止在一个页面重复划过番号导致系列、发行日期等重复显示。
        if(avInfo.noInfo){
            localInfo[avID].noInfo = true;
        }else{
            localInfo[avID].title = avInfo.title
            localInfo[avID].titleTrans = avInfo.titleTrans;
            localInfo[avID].starName = avInfo.starName;
            
            localInfo[avID].date = avInfo.date?.replace(/\n\s*/g," ")
            localInfo[avID].series = avInfo.series?.replace(/\n\s*/g," ").replace("系列: ","");
            localInfo[avID].seriesLink = avInfo.seriesLink;
            localInfo[avID].tags = avInfo.tags
            if(image){
                localInfo[avID].image = image.src;
            }
            localInfo[avID].link = avInfo.link
            localInfo[avID].visited = localInfo[avID].visited? localInfo[avID].visited+1:1;
            localInfo[avID].tips = avInfo.tips;
            localInfo[avID].correctID = avInfo.correctID;
            localInfo[avID].video = avInfo.video;
            localInfo[avID].fc2Video = avInfo.fc2Video;
        }
        localInfo[avID].getInfo_Time = new Date().getTime();

        if(debug) console.log("保存相关信息: localInfo[avID] : ", localInfo[avID]);
        GM_setValue("avInfo2",localInfo);

        if(!document.querySelector(".sav-menu")){return};
        // 判断是否重复加载图片
        // if(document.querySelector(".avimg")){return};

        // console.log("获取到的所有信息: ");
        // console.log(avInfo);
        // console.log("------------------");
        var otherInfo = document.querySelector("avdivsInfo");
        if(!otherInfo){
            otherInfo = document.createElement('avdivsInfo');
        }
        otherInfo.innerHTML = addOtherInfo(avID);

        if(image){
            let imageDiv = document.createElement('avdivimg');
            image.classList.add("avimg");
            image.setAttribute("referrerpolicy","no-referrer");
            imageDiv.appendChild(image)
            otherInfo.appendChild(imageDiv);
            image.onload = function(){
                if(debug)console.log("getInfo_end: 图片加载完成");
                removeLoading();
                settingPostion();
            }
            image.onerror = ()=>{
                if(avInfo.imgSrc2){
                    image.src = avInfo.imgSrc2;
                    localInfo[avID].image = avInfo.imgSrc2;
                    GM_setValue("avInfo2",localInfo);
                }else{
                    image.classList.add('savImgError');
                    image.src = imgErrorSVG;
                }
            }
            settingPostion()
        }else{
            removeLoading();
        }
        document.querySelector(".sav-menu").appendChild(otherInfo);

        if(localInfo[avID].fc2Video){
            getVideoURLFC2();
        }else{
            getVideo(avID);
        }
    }
    function getInfo_end_error(errorText,avID){
        if(debug){console.log("getInfo_end_error : ", errorText);}
        let errorInfo = document.createElement('avdivError');
        errorInfo.innerHTML = errorText ;
        document.querySelector(".sav-menu").appendChild(errorInfo);
        removeLoading();
        // 如果获取错误, 会不进入end函数; 错误会导致重新获取, 获取不到会继续保持错误, 然后不断循环
        localInfo[avID].getInfo_Time = new Date().getTime();
        GM_setValue("avInfo2",localInfo);
    }

    // 从本地加载信息
    function getInfo_local(avID){
        if(debug){console.log("从本地加载信息 local: " ,avID, localInfo[avID]);}
        if(!document.querySelector(".sav-menu")){return};
        // 判断是否重复加载图片
        if(document.querySelector(".avimg")){return};
        
        noReferrer();

        if(localInfo[avID].noInfo){
            getInfo_end_error(`脚本没有匹配到 ${avID} 相关页面, 请使用上方搜索进行查找`)
            localInfo[avID].visited = localInfo[avID].visited? localInfo[avID].visited+1:1;
            GM_setValue("avInfo2",localInfo);
            
            reloadGetInfo(avID);
            
            return;
        }

        // 浏览过的番号,从本地加载链接。 信息只获取一次, 避免被网站拉黑IP
        if(localInfo[avID].link){
            if(localInfo[avID].link.indexOf(javDBLink)>-1){
                changeRelatedPage(localInfo[avID].link,"JavDB 页面",avID);
            }else if(localInfo[avID].link.indexOf(javbusLink)>-1){
                changeRelatedPage(localInfo[avID].link,"JavBus 页面",avID);
            }else if(localInfo[avID].link.indexOf("fc2hub")>-1){
                changeRelatedPage(localInfo[avID].link,"fc2Hub 页面",avID);
            }
        }

        let imgDiv = document.createElement("avdivimg");
        let image = document.createElement("img");
        if(localInfo[avID].image){
            // 2022-10-12 0.18.0 之后将只保存网址, 之前的版本是保存的img节点
            image.src = localInfo[avID].image.match(/https.*\.(jpg|jpeg|gif|png)/)[0];
            image.classList.add("avimg");
            image.setAttribute("referrerpolicy","no-referrer");
            imgDiv.appendChild(image);
        } else {
            // image.innerHTML = "没有在本地找到图片信息"
            if(debug){console.log("由于本地没有图片, 重新从网络中获取信息: ", avID)}
            reloadGetInfo(avID)
            return;
        }

        var otherInfo = document.querySelector('avdivsInfo');
        otherInfo.appendChild(imgDiv);
        document.querySelector(".sav-menu").appendChild(otherInfo);

        localInfo[avID].visited = localInfo[avID].visited? localInfo[avID].visited+1:1;
        GM_setValue("avInfo2",localInfo);

        image.onload = function(){
            if(debug){console.log("getInfo_local: 图片加载完成")}
            settingPostion()
        }
        image.onerror = ()=>{
            image.classList.add('savImgError');
            image.src = imgErrorSVG;
            // 图片无法加载, 视为网站更换了网址, 重新获取
            reloadGetInfo(avID)
        }
        
        if(localInfo[avID].fc2Video){
            getVideoURLFC2();
        }else{
            getVideo(avID);
        }
    }

    function changeRelatedPage(link,txt,avID){
        // if(avInfo.correctID || localInfo[avID]?.correctID){
        //     return;
        // }
        let relatedPageButton = document.querySelector(".relatedPage");
        let relatedPage = relatedPageButton?.querySelector("a");
        if(relatedPage){
            relatedPage.href = link;
            relatedPage.innerHTML = txt;
        }
        relatedPageButton?.classList.remove("RPdisabled")
    }

    // 重新获取信息, 通常是在本地信息不完整的情况下会调用该函数。例:noInfo为true, 或者缺少图片
    function reloadGetInfo(avID){
        if(debug){console.log("重新获取信息 reloadGetInfo: ",avID)};
        avInfo = {};
        let nowTime = new Date().getTime();
        if(!localInfo[avID].getInfo_Time || nowTime-localInfo[avID].getInfo_Time > 43200000){
            if(avID.match(oRegExp)){
                getInfo(avID)
            }else if(avID.match(/fc2/i)){
                getInfo_fc2(avID)
            } else {
                getInfo_wuma_javdb1(avID)
            }
        }else{
            if(debug){console.log("重新获取信息 reloadGetInfo: 距离上次更新信息时间不足12小时, 将不会重新获取信息。")};
        }
    }
    // 在菜单中添加番号相关的信息(标题,演员等)
    function addOtherInfo(avID){
        if(localInfo[avID] && localInfo[avID].noInfo){return ""};   // 如果没有信息就直接返回
        var actors = ""
        var str = "";
        if(avInfo.titleTrans){
            str += "<avdiv class='sav-title' id='searchAVMenuTitle'>标题: " + avInfo.titleTrans + "</avdiv>"
        }else if(avInfo.title){
            str += "<avdiv class='sav-title' id='searchAVMenuTitle'>标题: " + avInfo.title + "</avdiv>"
        }
        if(avInfo.starName && avInfo.starName.length>0){
            for(var i=0;i<avInfo.starName.length;i++){
                actors += "<a class='sav-actors-"+ i + "' target='_blank' title='' href='https://db.msin.jp/jp.search/actress?str=" + avInfo.starName[i] + "'>"+ avInfo.starName[i] + "</a>, ";
                getJellyfin_Actor(avInfo.starName[i],i)
            }
            actors = actors.slice(0,actors.length-2);
            str += "<avdiv class='sav-actors'>演员: " + actors + "</avdiv>"
        }
        if(avInfo.tags && avInfo.tags.length>0){
            str += "<avdiv class='avInfoTags'>标签: " + avInfo.tags + "</avdiv>"
        }
        if(avInfo.seriesLink){
            str += `<avdiv class='avInfoSeries'>系列: <a target='_blank' href='${avInfo.seriesLink}' >${localInfo[avID].series}</a></avdiv>`
        }else if(avInfo.series){
            // 2022-10-15 0.18.2  存储的series中, 不再含有汉字 “系列: ”, 此处的replace是与之前的版本兼容
            str += "<avdiv class='avInfoSeries'>系列: " + avInfo.series.replace("系列: ","") + "</avdiv>"
        }
        if(avInfo.date){
            str += "<avdiv>" + avInfo.date + "</avdiv>"
        }
        if(avInfo.tips){
            str += "<avdiv>提示: " + avInfo.tips + "</avdiv>"
        }
        str += ""
        return str;
    }

    // 添加信息加载时的动画
    function addLoading(odiv){
        var savLoading = document.createElement('avdiv');
        savLoading.classList.add("savLoadingContainer");
        var savhr = '<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" version="1.1">' +
                        '<linearGradient xmlns="http://www.w3.org/2000/svg" id="grad4" x1="0%" y1="50%" x2="100%" y2="50%">' +
                            '<stop class="stop1" offset="30%" />' +
                            '<stop class="stop2" offset="50%" />' +
                            '<stop class="stop3" offset="70%" />' +
                        '</linearGradient>' +
                        '<rect xmlns="http://www.w3.org/2000/svg" width="600" height="5" style="fill:url(#grad4)"/> ' +
                    '</svg>'
        savLoading.innerHTML='<avdiv class="savLoading">' + savhr +savhr + '</avdiv>';
        odiv.appendChild(savLoading);
    }
    function javbusloading(){
        var stop2 = document.querySelector(".stop2");
        if(stop2){
            stop2.classList.toggle("javbusloading")
        }
    }
    function javdbloading(){
        var stop2 = document.querySelector(".stop2");
        if(stop2){
            stop2.classList.remove("javbusloading")
            stop2.classList.toggle("javdbloading")
        }
    }
    function fc2loading(){
        var stop2 = document.querySelector(".stop2");
        if(stop2){
            stop2.classList.toggle("fc2loading")
        }
    }
    // 移除信息加载时的动画
    function removeLoading(){
        // return;
        var loading = document.querySelector(".savLoadingContainer");
        if(loading){
            loading.style.height = "0px";
            loading.style.marginTop = "0px";
            setTimeout(()=>{
                loading.parentNode?.removeChild(loading);
            },200)
        }
    }

    // 格式化番号, 添加中间的横杠
    function formatAVID(otext){
        otext = otext.replace(/\s+|-c|_c|-4k|carib[-_]|1pondo[-_]|-1pon|-paco|-carib|hd_/ig,"");
        if(otext.match((/^[a-z|A-Z]{2,8}\d{2,5}$/i))){
            var oindex = otext.search(/\d/);
            if(oindex>0){
                otext = otext.slice(0,oindex) + "-" + otext.slice(oindex)
            }
        }
        return otext.toUpperCase();
    }
    // 格式化无码番号
    function formatWuma(otext){
        otext = otext.replace(/\s+|carib[-_]|1pondo[-_]|-1pon|-paco|-carib|hd_/ig,"");
        // 不再分 "FC2PPV-" 和 "FC2-" 统一为 "FC2-"
        if(otext.match(/fc2/i)){
            var oindex = otext.search(/(?<!fc)\d/i);
            // if(otext.match(/ppv/i)){
            //     otext = "FC2PPV-" + otext.slice(oindex)
            // }else{
                otext = "FC2-" + otext.slice(oindex)
            // }
            return otext.toUpperCase();
        }
        // heyzo
        if(otext.match(/heyzo/i)){  
            var oindex = otext.search(/\d/i);
            return "HEYZO-" + otext.slice(oindex)
        }
        //  东京热 n1234  返回小写
        if(otext.match(/(?:k|n)\d{4}/i)){
            return otext.toLowerCase();
        }

        // 返回大写  MKD-S\d{2,3}(?!\w|-)|(?:SHINKI|KITAIKE)[-\s]?\d{3}(?!\w|-)|JPNXXX[-\s]?\d{5}(?!\w|-)|xxx-av[-\s]\d{4,5}(?!\w|-)|(?<!\w)crazyasia\d{5}(?!\w|-)|(?<!\w)PEWORLD\d{5}(?!\w|-)|(?<!\w)MKBD-S\d{2,3}|(?<!\w)\d{6}[-_]?_01(?=-10mu)/gi;
        if(otext.match(/t28|t-|MKD-S|SHINKI|KITAIKE|JPNXXX|xxx-av|crazyasia|PEWORLD|MKBD-S/i)){
            return otext.toUpperCase();
        }
        // heydouga
        if(otext.match(/HEYDOUGA/i)){
            return "heydouga-" + otext.slice(otext.search(/\d/i))
        }
        
        return otext;
    }

    // 检查番号是否需要排除
    function IDcheck(otext){
        var oOnlyText = otext.replace(/[^a-zA-Z]/gi,"");    // 番号中的英文
        var oOnlyNum = otext.replace(/[^0-9]/ig,"");    // 番号中的数字
        // if(debug) console.table([{name:"完整番号",value:otext},{name:"英文",value:oOnlyText},{name:"数字",value:oOnlyNum},{name:"是否有横杠",value:oNoHyphen},{name:"是否排除",value:oExclude},{name:"占位",value:"占位"}]);

        // 排除 特别的番号
        if(otext.match(oRegExp_Exclude_ID)){
            if(debug) {console.log(searchTimes-avIDTimes,` 特别的番号,略过:  ${otext} `);}
            return true;
        }
        // 包含关键词的情况下
        if(oOnlyText.match(oRegExp_Exclude_en)){    
            if(debug) {console.log(searchTimes-avIDTimes,` 存在排除词 ${oOnlyText} ,略过 ${otext} `);}
            return true;
        }
        if(otext.match((/^[a-z|A-Z]{2,8}\s?\d{2,5}$/i))){
            // 没有横杠的情况下, 含有需要排除的数字
            if(oOnlyNum.match(oRegExp_Special_num)){
                if(debug) {console.log(searchTimes-avIDTimes,` 无横杠,且存在需要排除的数字 ${oOnlyNum},略过 ${otext} `)};
                return true;
            }
            // 没有横杠的情况下, 并且含有关键词
            if(oOnlyText.match(oRegExp_Special_en)){
                if(debug) {console.log(searchTimes-avIDTimes,` 无横杠,且有关键词 ${oOnlyText},略过 ${otext} `)} ;
                return true;
            }
        }
        return false;
    }
    // 检查番号是否需要排除 无码
    function IDcheckWuma(otext){
        if(otext.match(/\d{3}[a-zA-Z]{2,5}[-\s]?\d{3,4}/i)){
            if(otext.replace(/[^a-zA-Z]/gi,"").match(/^cm$/i)){
                return true;
            }
        }
        if(otext.match(oRegExp_Exclude_wuma)){
            if(debug) {console.log(searchTimes-avIDTimes,` 存在无码排除词,略过:  ${otext} `);}
            return true;
        }
        return false;
    }

    // 动态添加的元素, 检查所有父元素的class是否是排除项
    function checkParentClass(startDom){
        if(startDom.classList && startDom.classList.length && startDom.className.match(window.qxin.RE_Exclude_className)){
            if(debug)console.log("checkParentClass: 父元素存在相关class, 已排除: ",startDom.className);
            return true;
        }
        if(startDom.parentElement && "body" !== startDom.parentElement.nodeName){
            return checkParentClass(startDom.parentElement)
        } else {
            return false
        }
    }
    
    // 模糊匹配
    function fuzzyMatch(avID,title){
        if(debug){console.log("进入模糊匹配, 标题: ",title)}
        let onlyText = avID.replace(/[^a-zA-Z]/gi,"");    // 番号中的英文
        let onlyNum = avID.replace(/[^0-9]/ig,"");    // 番号中的数字

        // 数字都是错误的情况下, 直接返回
        if(title.indexOf(onlyNum)<0){
            console.log("数字错误");
            return false;
        }

        let searchIDLength = onlyText.length;
        // 紧邻两个字符错位的情况
        for(let i =1;i<onlyText.length-1; i++ ){
            let newID = onlyText.slice(0,i) + onlyText.charAt(i+1) + onlyText.charAt(i)
            if(i+2<onlyText.length){
                newID += onlyText.slice(i+2)
            }
            if(title.indexOf(newID)>-1){
                let wrongId1 = newID.slice(0,i) +"<b><u>" + newID.slice(i,i+2) +"</u></b>"+ newID.slice(i+2);
                let wrongId2 = avID.slice(0,i) +"<b><u>" + avID.slice(i,i+2) +"</u></b>"+ avID.slice(i+2);
                avInfo.tips = `这是 ${wrongId1}-${onlyNum} 的搜索结果, 如果继续搜索 ${wrongId2}, 请使用上方按钮`
                avInfo.correctID = `${newID}-${onlyNum}`
                return true
            }
        }
        // 单个字符错误的情况
        let titleID = title.match(/\w{2,6}(?=-)/);
        if(!titleID || searchIDLength<3 || titleID[0].length != searchIDLength){
            return
        }
        let title_ID = titleID[0];

        let rightNum = 1;   // 共同的次数
        let wrongNum ;
        if(title_ID.length == searchIDLength){
            // 第一个字符就错的情况, 直接返回
            if(onlyText.charAt(0)!=title_ID.charAt(0)){
                // console.log("第 1 个字符出现错误");
                return false
            }
            for(let i =1;i<searchIDLength; i++ ){
                if(onlyText.charAt(i)==title_ID.charAt(i)){
                    rightNum++;
                } else {
                    wrongNum = i
                    // console.log(`第 ${i} 个字符出现错误。`)
                }
            }
            if(rightNum==searchIDLength-1){
                let wrongId1 = title_ID.slice(0,wrongNum) +"<b><u>" + title_ID.charAt(wrongNum) +"</u></b>"+ title_ID.slice(wrongNum+1);
                let wrongId2 = avID.slice(0,wrongNum) +"<b><u>" + avID.charAt(wrongNum) +"</u></b>"+ avID.slice(wrongNum+1);
                avInfo.tips = `这是 ${wrongId1}-${onlyNum} 的搜索结果, 如果继续搜索 ${wrongId2}, 请使用上方按钮`
                avInfo.correctID = `${title_ID}-${onlyNum}`;
                return true
            }
        }
        return false;
    }

    // 谷歌翻译
    function googleTrans(avID,transText) {
        if(debug){console.log("谷歌翻译 googleTrans: ",transText);}

        var translate_url = "";
        var googleTransApi = "https://translate.google.com.hk/translate_a/single?client=gtx&dt=t&dj=1&sl=auto&tl=zh-CN&hl=zh-CN&q=";
        translate_url = googleTransApi + encodeURIComponent(transText);

        GM_xmlhttpRequest({
            method: "GET",
            url: translate_url,
            onload: function (r) {
                setTimeout(function () {
                    // 如果返回结果不对
                    if(r.responseText.indexOf("sentences")<0){
                        console.log("谷歌翻译失败: ",r.responseText);
                        return;
                    } 
                    var data = JSON.parse(r.responseText);
                    var trans = "";
                    for (var i = 0; i < data.sentences.length; i++) {
                        var getransCont = data.sentences[i];
                        trans += getransCont.trans;
                    }
                    trans_end(avID,trans)
                }, 100);
            },
            onerror: function (e) {
                console.error(e);
                console.log("谷歌翻译失败");
            }
        });
    }
    // 百度翻译
    function baiduTrans(avID,transText) {
        if(debug){console.log("百度翻译 baiduTrans: ",transText);}
        var appid = setting.baiduAppid;
        var key = setting.baiduKey;
        var salt = (new Date).getTime();
        // var query = 'apple';
        // 多个query可以用\n连接  如 query='apple\norange\nbanana\npear'
        // var from = 'jp';
        // var to = 'zh';
        var str1 = appid + transText + salt +key;
        var sign = MD5(str1);
        var translate_url = "http://api.fanyi.baidu.com/api/trans/vip/translate?q="+ encodeURIComponent(transText) +"&from=jp&to=zh&appid="+appid+"&salt="+salt+"&sign="+sign;
        GM_xmlhttpRequest({
            method: "GET",
            url: translate_url,
            onload: function (r) {
                console.log(r)
                if(r.responseText.indexOf("error_code")>0){
                    console.log("百度翻译失败:",r.responseText)
                    return;
                } 
                var data = JSON.parse(r.responseText);
                trans_end(avID,data.trans_result[0].dst)
            },
            onerror: function (e) {
                console.error(e);
                console.log("百度翻译失败");
            }
        });
    }
    // 翻译结束
    function trans_end(avID,result){
        if(debug){console.log("翻译结束 trans_end: ",result)}
        localInfo[avID].titleTrans = result;
        GM_setValue("avInfo2",localInfo);
        if(document.querySelector("#searchAVMenuTitle")){
            document.querySelector("#searchAVMenuTitle").innerHTML = "标题: (译)" + result;
        }
    }

    // 防盗链
    function noReferrer(){
        // 相关代码地址 https://greasyfork.org/zh-CN/scripts/376884
        // 名称: 显示防盗链图片 for Inoreader
        // 作者: maboloshi
        var meta = document.createElement('meta');
        meta.name = "referrer";
        meta.content = "no-referrer";
        document.getElementsByTagName('head')[0].appendChild(meta);
    }
        
    // 预览视频 项目名称: "JAVBUS影片预告" 作者:"bigwolf99"  相关代码: https://sleazyfork.org/zh-CN/scripts/450740
    async function getVideo(avID) {
        if(setting.dontGetVideo) return;
        if(avInfo.noInfo) return;
        if(debug) console.log("getVideo  开始");
        
        let videoURL;
        if(!localInfo[avID].video){
            videoURL = await queryVideoURL(avID);
            
            if(debug)console.log("最终url: ", videoURL);

            if(videoURL){
                localInfo = GM_getValue("avInfo2")
                localInfo[avID].video = videoURL;
                GM_setValue("avInfo2",localInfo);
            }else{
                if(debug)console.log("未获取到视频链接: ", videoURL);
                return;
            }
        }else{
            videoURL = localInfo[avID].video;
            if(debug)console.log("本地存在视频链接: ", videoURL)
        }
        
        let avimg = document.querySelector(".avimg")
        if(avimg){
            let videoButton = document.createElement("savdiv");
            videoButton.classList.add("avimg-preview-button");
            avimg.parentNode.insertBefore(videoButton,avimg);
            videoButton.addEventListener("click",addVideoDiv(videoURL, avID));
        }

        return videoURL;
    }

    // 获取播放地址
    async function queryDMMVideoURL(avID, host = "cc3001.dmm.co.jp") {
        // if (movieInfo.isUncensored)
        //   return Promise.reject("DMM server not support uncensored movie.");
        //see https://www.javbus.com/forum/forum.php?mod=viewthread&tid=63374
        //see https://bit.ly/3wXLj6T
        let infix = "litevideo/freepv";
        //1500kbps = _dmb_w || 3000kbps = _mhb_w || vrlite
        // 1080p:hhb 720p:hmb  576p:mhb
        let quality ={
            "p1080":"hhb",
            "p720":"hmb",
            "p576":"mhb",
            "old720":"_dmb_w",
        }
        // vr 影片
        // if (avID.search("VR-")) {
        //   postfix = "vrlite";
        //   infix = "vrsample";
        //   url =  `https://${host}/${infix}/${urlPart[0]}/${urlPart.substring(0,3)}/${urlPartAdd00}/${urlPartAdd00}${postfix}.mp4`
        // }
    
        // 提取番号中的英文和数字
        const movieIdSplit = avID.toLowerCase().split("-");
        const corp = movieIdSplit[0];  // 番号中的英文
        const idNum = movieIdSplit[1];    // 返回中的数字
        let urlPart;
    
        let cid_user = GM_getValue("_setting2").cid_user ?? {};
        var urls = [];

        // 是否需要特殊处理
        if (cid[corp]) {
            if(debug) console.log("视频加载: 在默认URL规则中: ",cid[corp])
            if (cid[corp].length>1){
                console.log("多个")
                // 此处只会处理第2个及之后的, 第一个依旧会判断是否含0, 请求两遍
                for(let i=1;i<=cid_user.length;i++){
                    urlPart = cid[corp][i] + idNum;
                    urls.push(`https://${host}/${infix}/${urlPart[0]}/${urlPart.substring(0,3)}/${urlPart}/${urlPart}${quality.p576}.mp4`);
                    urls.push(`https://${host}/${infix}/${urlPart[0]}/${urlPart.substring(0,3)}/${urlPart}/${urlPart}${quality.old720}.mp4`);
                }
            }
            urlPart = cid[corp][0] + idNum;
            // corp = cid[corp][0]
        } else if (cid_user[corp]){
            if(debug) console.log("视频加载: 在用户学习URL规则中: ",cid_user[corp]);
            urlPart = cid_user[corp][0] + idNum;
            // corp = cid_user[corp][0]
        } else {
            if(debug) console.log("视频加载: URL规则,默认添加00");
            urlPart = corp + "00" + idNum;
        }

        //  https:// cc3001.dmm.co.jp / litevideo/freepv /  s            / ssn                       / ssni00378       / ssni00378       _dmb_w    .mp4    
        // `https:// ${host}          / ${infix}         / ${urlPart[0]} / ${urlPart.substring(0,3)} / ${urlPart}      / ${urlPart}      ${postfix}.mp4`;
        // var videoURL = `https://${host}/${infix}/${urlPart[0]}/${urlPart.substring(0,3)}/${urlPart}/${urlPart}${postfix}.mp4`;

        let urlPartAdd00 = replace00(urlPart);
        // 根据番号发布时间 访问不同的网址
        // if(avInfo.date && new Date(avInfo.date)>new Date("1/1/2024")){
            // urls.push(`https://${host}/${infix}/${urlPart[0]}/${urlPart.substring(0,3)}/${urlPart}/${urlPart}${quality.p576}.mp4`);
            // urls.push(`https://${host}/${infix}/${urlPart[0]}/${urlPart.substring(0,3)}/${urlPartAdd00}/${urlPartAdd00}${quality.p576}.mp4`);
        // }else 
        if(avInfo.date && new Date(avInfo.date)>new Date("8/29/2023")){
            urls.push(`https://${host}/${infix}/${urlPart[0]}/${urlPart.substring(0,3)}/${urlPart}/${urlPart}${quality.p576}.mp4`);
            urls.push(`https://${host}/${infix}/${urlPart[0]}/${urlPart.substring(0,3)}/${urlPartAdd00}/${urlPartAdd00}${quality.p576}.mp4`);
            // urls.push(`https://${host}/${infix}/${urlPart[0]}/${urlPart.substring(0,3)}/${urlPart}/${urlPart}${quality.old720}.mp4`);
            // urls.push(`https://${host}/${infix}/${urlPart[0]}/${urlPart.substring(0,3)}/${urlPartAdd00}/${urlPartAdd00}${quality.old720}.mp4`);
        }else{
            urls.push(`https://${host}/${infix}/${urlPart[0]}/${urlPart.substring(0,3)}/${urlPart}/${urlPart}${quality.old720}.mp4`);
            urls.push(`https://${host}/${infix}/${urlPart[0]}/${urlPart.substring(0,3)}/${urlPartAdd00}/${urlPartAdd00}${quality.old720}.mp4`);
        }

        var urlListGetMess = [];
        for(let i=0;i<urls.length;i++){
            let p = GetMess(urls[i])
            urlListGetMess.push(p)
        }

        return Promise.any(urlListGetMess)
            .then(res=>{
                if(debug)console.log(res);
                return res.finalUrl;
            })
            .catch(e=>{
                if(debug)console.log(e);
                return queryJavSpylVideoURL(avID)
                            .then(res=>{
                                let resJSON = JSON.parse(res.response)
                                if(resJSON?.info?.url){
                                    return "https://" + resJSON.info.url
                                }
                                return false
                            })
                            .catch(()=>{return false})
            })
    }

    async function queryJavSpylVideoURL(avID) {
        if(debug)console.log("通过javspyl获取链接中:");
        let javspylURL = "https://api.javspyl.eu.org/api/";
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                url:javspylURL,
                method :"POST",
                headers: {
                    origin: "https://api.javspyl.eu.org",
                    "Content-Type": "application/x-www-form-urlencoded",
                },
                data: `ID=${avID}`,
                onload:function(xhr){
                    resolve(xhr);
                },
                onerror:function(xhr){
                    resolve(xhr);
                }
            });
        })}

    // 用来替换番号中的 00 , 预览视频使用
    function replace00(urlPart){
        if(urlPart.search(/00\d{3,4}/)>0){
            return urlPart.replace("00","");
        } else {
            let oindex = urlPart.search(/[a-z]\d/i) +1;
            return urlPart.slice(0,oindex) + "00" + urlPart.slice(oindex)
        }
    }

    // 其他番号的播放地址
    async function queryVideoURL(avID){
        let link = "";
        if(avID.match(/[01]\d{5}\-(?:1)?\d{2,3}/i)){ 
            if(debug) {console.log("加勒比: ", avID);}
            link = `http://smovie.caribbeancom.com/sample/movies/${avID}/480p.mp4`
        }else if(avID.match(/[01]\d{5}\_(?:1)?\d{2,3}/i)){ 
            if(debug) {console.log("一本道: ", avID);}
            link = `http://smovie.1pondo.tv/sample/movies/${avID}/480p.mp4`
        }else if(avID.match(/HEYZO/i)){  
            if(debug) {console.log("HEYZO: ", avID);}

            link = `https://www.heyzo.com/contents/3000/${avID.slice(6)}/heyzo_hd_${avID.slice(6)}_sample.mp4`
        }else if(avID.match(/HEYDOUGA/i)){
            if(debug) {console.log("HEYDOUGA视频无法解析: ",avID)}
            return false;
            // heydouga-4037-445
            let avIDSplit = avID.split("-");
            link = `https://hls-mediaac.heydouga.com/sample/${avIDSplit[1]}/${avIDSplit[2]}/mb.m3u8`;
        }else if(avID.match(/(?:k|n)\d{4}/i)){
            //  东京热 n1234 
            link = `https://my.cdn.tokyo-hot.com/media/samples/${avID}.mp4`;
        }else if(avID.search(/^[A-Z]{2,7}-\d{2,6}$/i>-1)){
            return await queryDMMVideoURL(avID)
        }else{
            if(debug) {console.log("该视频目前无法解析视频: ",avID);}
            return false;
        }

        return await GetMess(link)
            .then((res) =>{
                if(res.status == 200){
                    return link;
                }else{
                    return false
                }
            })
            .catch((e) =>{
                return false;
            })
    }

    function GetMess(link){
        if(debug)console.log("GetMess请求: ", link);
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                url:link,
                method :"HEAD",
                headers: {
                },
                fetch:link,
                onload:function(xhr){
                    if(xhr.status ==200){
                        resolve(xhr);
                    } else{
                        reject(xhr)
                    }
                },
                onerror:function(xhr){
                    resolve(xhr);
                }
            });
        })
    }

    // 添加视频
    function addVideoDiv(videoURL, avID){
        return function(){
            let videoDiv = document.createElement("avdivVideo");
            videoDiv.innerHTML = `
                <video class="avVideo" poster="${localInfo[avID].image}" controls autoplay loop >
                    <source src="${videoURL}" type="video/mp4">
                </video>
                <avidv class="savVideoClose"> X </avdiv>
                `
            let imgDiv = document.querySelector("avdivimg");
            imgDiv.appendChild(videoDiv)

            let videoSelect = document.querySelector(".avVideo");
            if(videoSelect){
                videoSelect.volume = setting.videoVolume??0.2;
            }
        }
    }
    // fc2 预览视频
    function getVideoURLFC2(avID) {
        if(setting.dontGetVideo) return;
        if(debug) console.log("getVideoURLFC2  开始");

        let videoButton = document.createElement("savdiv");
        videoButton.classList.add("avimg-preview-button");

        let avimg = document.querySelector(".avimg")
        avimg.parentNode.insertBefore(videoButton,avimg);

        videoButton.addEventListener("click",addVideoDivFc2(avInfo.fc2Video));

        return 
    }
    // 添加fc2视频
    function addVideoDivFc2(videoURL){
        return function(){
            let videoDiv = document.createElement("avdivVideo");
            videoDiv.innerHTML = `
                <iframe src="${videoURL}"></iframe>
                <avidv class="savVideoClose"> X </avdiv>
                `
            let imgDiv = document.querySelector("avdivimg");

            imgDiv.appendChild(videoDiv)
        }
    }
    //  切换页面 暂停预览视频播放
    function visibilitychangeFun(e){
        if(e.target.hidden){
            document.querySelector("avdiv .avVideo")?.pause();
            document.querySelector(".main-video")?.pause(); // FC2
        }else{
            document.querySelector("avdiv .avVideo")?.play(); 
            // document.querySelector(".main-video")?.play();  // FC2 仅自动暂停, 不会自动播放
        }
    }

    // 获取色花堂的formhash
    function sehuatang_getFormHash(){
        let setting2 = GM_getValue("_setting2");
        let sehuatang_getTime = setting2.sehuatang_getTime;
        let nowTime = new Date().getTime();
        let sehuatangURL = setting.sehuatangURL?setting.sehuatangURL.replace(/\/$/,""):"https://www.sehuatang.org";

        // 不确定这个值会不会变动, 12小时获取一次
        if(!sehuatang_getTime || nowTime-sehuatang_getTime > 43200000 || setting2.sehuatang_url != sehuatangURL){
            GM_xmlhttpRequest({
            method:"get",
            url:sehuatangURL,
            onload:function(data){
                // console.log(data);
                var parser=new DOMParser();
                let htmlDoc=parser.parseFromString(data.responseText, "text/html");
                let odom = htmlDoc.querySelector('input[name="formhash"]');
                // console.log(odom);
                let formhash_value = odom.value;
                // console.log(formhash_value);
    
                let setting2 = GM_getValue("_setting2");
                setting2.sehuatang_formhash = formhash_value;
                setting2.sehuatang_getTime = nowTime;
                setting2.sehuatang_url = sehuatangURL;
                GM_setValue("_setting2",setting2);
                }
            })
            if(debug){console.log(`重新获取色花堂的formhash`)};
        }else{
            if(debug){console.log(`没有重新获取色花堂的formhash`)}
        }
    }
    // 色花堂搜索
    function sehuatang(avID){
        let formhash = GM_getValue("_setting2").sehuatang_formhash;
        let sehuatangURL = setting.sehuatangURL?setting.sehuatangURL.replace(/\/$/,""):"https://www.sehuatang.org";

        if(formhash){
            GM_xmlhttpRequest({
                method: "post",
                url: sehuatangURL+"/search.php?mod=forum",
                data: `formhash=${formhash}&srchtxt=${avID}&searchsubmit=yes`,
                headers:  {
                    "Content-Type": "application/x-www-form-urlencoded",
                    "Origin":sehuatangURL,
                    "Referer":sehuatangURL
                },
                onload: function(data){
                    // console.log(data);
                    // console.log(data.finalUrl);
                    if(data.finalUrl){
                        window.open(data.finalUrl);
                    }else{
                        GM_setClipboard(avID)
                        window.open(`${sehuatangURL}/search.php`);
                    }
                },
                onerror : function(err){
                    console.log('error')
                    console.log(err)
                }
            });
        }else{
            GM_setClipboard(avID)
            window.open(`${sehuatangURL}/search.php`);
        }
    }

    // 查看本地 jellyfin 中是否存在
    function getJellyfin(avID){
        if(setting.jellyfinHost && setting.jellyfinApiKey){
            if(debug){console.log("查询本地jellyfin: getJellyfin");};
        } else {
            if(debug){console.log("退出jellfin函数, 其中host和apiKey: ", setting.jellyfinHost , setting.jellyfinApiKey)}
            return;
        }

        GM_xmlhttpRequest({
            method: 'get',
            url: setting.jellyfinHost + "emby/Search/Hints?searchTerm=" + avID,
            headers: {
                "Content-Type": "application/x-www-form-urlencoded",
                "X-Emby-Token":setting.jellyfinApiKey
            },
            data: "",
            timeout: 1000, 
            onload: function (r) {
                var div_jellyfin = document.querySelector(".jellyfin");
                if(!div_jellyfin){return};

                // ApiKey输入错误的情况下, 会出现401错误, 身份验证错误
                if(r.status == 401){
                    console.log("jellyfin: 身份验证错误, 请检查设置中的 ApiKey 是否设置正确");
                    div_jellyfin.classList.add("errJellyfin")
                    return;
                }
                var data = JSON.parse(r.responseText);
                if(data.SearchHints[0]){
                    if(debug){console.log("jellyfin中的标题: ", data.SearchHints[0].Name)};
                    div_jellyfin.dataset.url = setting.jellyfinHost + "web/index.html#!/details?id=" + data.SearchHints[0].Id;
                    div_jellyfin.classList.add("yesJellyfin");
                } else {
                    div_jellyfin.dataset.url = setting.jellyfinHost + "web/index.html#!/search.html";
                    div_jellyfin.dataset.avid = avID;
                    div_jellyfin.classList.add("noJellyfin");
                }
            },
            ontimeout(data){
                console.log("jellyfin访问超时")
                console.log(data)
                document.querySelector(".jellyfin")?.classList.add("errJellyfin")
            }
        });
    }

    function getEmby(avID){
        if(setting.jellyfinHost && setting.jellyfinApiKey){
            if(debug){console.log("查询本地 Emby : getEmby");};
        } else {
            if(debug){console.log("退出 Emby 函数, 其中host和apiKey: ", setting.jellyfinHost , setting.jellyfinApiKey)}
            return;
        }

        GM_xmlhttpRequest({
            method: "GET",
            url:
                setting.jellyfinHost+"emby/Users/"+setting.jellyfinApiKey+"/Items?api_key="+setting.jellyfinApiKey+
                "&Recursive=true&IncludeItemTypes=Movie&SearchTerm="+avID,
            // url: setting.jellyfinHost+"emby/Items?api_key="+setting.jellyfinApiKey+"&Recursive=true&IncludeItemTypes=Movie&SearchTerm="+avID,
            headers: {
              accept: "application/json",
            },
            onload: function (r) {
                var data = JSON.parse(r.responseText);
                var div_jellyfin = document.querySelector(".jellyfin");
                if(!div_jellyfin){return};
                if(data.Items[0]){
                    div_jellyfin.dataset.url = ` ${setting.jellyfinHost}web/index.html#!/item?id=${data.Items[0].Id}&serverId=${data.Items[0].ServerId} `;
                    div_jellyfin.classList.add("yesJellyfin");
                } else {
                    div_jellyfin.dataset.url = setting.jellyfinHost + "web/index.html#!/list/list.html?type=search";
                    div_jellyfin.dataset.avid = avID;
                    div_jellyfin.classList.add("noJellyfin");
                }
            }
        });
    }

    // 查看本地 jellyfin 演员
    function getJellyfin_Actor(name,index){
        if(debug){console.log("jellyfin/emby 演员查询: ", index, name);};
        GM_xmlhttpRequest({
            method: 'get',
            url: setting.jellyfinHost + "Persons?searchTerm=" + name,
            headers: {
                "Content-Type": "application/x-www-form-urlencoded",
                "X-Emby-Token":setting.jellyfinApiKey
            },
            data: '',
            onload: function (r) {
                if(!r || r?.status != 200){return};
                var data = JSON.parse(r.responseText);
                // TotalRecordCount 查询到的数量
                if(data.TotalRecordCount){
                    var div_actor = document.querySelector(".sav-actors-"+ index)
                    if(div_actor){
                        var div_jellyfin = document.createElement("avspan");
                        if(setting.emby){
                            var jellyfin_ico =  '<svg  role="img" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" ><path d="M469.333333 85.333333L256 298.666667l42.666667 42.666666-213.333334 213.333334 213.333334 213.333333 42.666666-42.666667 213.333334 213.333334 213.333333-213.333334-42.666667-42.666666 213.333334-213.333334-213.333334-213.333333-42.666666 42.666667-213.333334-213.333334m-42.666666 277.333334l256 149.333333-256 149.333333v-298.666666z" fill="#05b010" p-id="1934"></path></svg>'
                            div_jellyfin.innerHTML = "<a class='actor-jellyfin' target='_blank' title='' href= '"+ setting.jellyfinHost + "web/index.html#!/item?id=" + data.Items[0].Id  + "&serverId="+ data.Items[0].ServerId +"'>"+ jellyfin_ico + "</a>";
                        }else{
                            var jellyfin_ico =  '<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> <linearGradient id="grad3" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="30%" style="stop-color:#AA5CC3;stop-opacity:1" /><stop offset="100%" style="stop-color:#00A4DC;stop-opacity:1" /></linearGradient><path style="fill:url(#grad3)" d="M12 .002C8.826.002-1.398 18.537.16 21.666c1.56 3.129 22.14 3.094 23.682 0C25.384 18.573 15.177 0 12 0zm7.76 18.949c-1.008 2.028-14.493 2.05-15.514 0C3.224 16.9 9.92 4.755 12.003 4.755c2.081 0 8.77 12.166 7.759 14.196zM12 9.198c-1.054 0-4.446 6.15-3.93 7.189.518 1.04 7.348 1.027 7.86 0 .511-1.027-2.874-7.19-3.93-7.19z"/></svg>'
                            div_jellyfin.innerHTML = "<a class='actor-jellyfin' target='_blank' title='' href= '"+ setting.jellyfinHost + "web/index.html#!/details?id=" + data.Items[0].Id  + "&serverId="+ data.Items[0].ServerId +"'>"+ jellyfin_ico + "</a>";
                        }
                        // 插入到演员dom的后面
                        var div_parent = div_actor.parentNode;
                        if(div_parent.lastChild == div_actor){
                            div_parent.appendChild(div_jellyfin);
                        }else{
                            div_parent.insertBefore(div_jellyfin,div_actor.nextSibling);
                        }
                    }
                }else{
                    if(debug){console.log("jellyfin 中没搜到相关演员: ",name)}
                }
            }
        });
    }

    // 搜索本地 jellyf/emby 视频, 返回所有所有的 movie 分类视频的名称列表
    function localVideo_search(){
        // console.log("localVideo_search")
        let url;
        if(setting.emby){
            url = setting.jellyfinHost+"emby/Items?Recursive=true&IsMovie=true&IsFolder=false&api_key=" + setting.jellyfinApiKey;
        }else{
            url = setting.jellyfinHost + "Items?recursive=true&filters=IsNotFolder&includeItemTypes=Movie&api_key=" + setting.jellyfinApiKey;
        }
        GM_xmlhttpRequest({
            method: "GET",
            url: url,
            headers: {
              accept: "application/json"
            },
            onload: (r) => {
                // console.log(r)
                var data = JSON.parse(r.responseText);
                // console.log(data);
                if(r.status == 200 && data.Items?.length>0){
                    localVideoList = data.Items;
                    localVideo_addStyle();
                }
            },
          });
    }
    function localVideo_comparison(avID){
        let reg = new RegExp(avID,"i")
        return localVideoList.find(value=>{
            return value.Name?.search(reg)>-1
        })
    }
    // 对本地视频(jellyfin/emby)已有的番号添加额外样式
    function localVideo_addStyle(){
        let avdivs = document.querySelectorAll('.sav-id');
        for(let i=0;i<avdivs.length;i++){
            // 判断本地有没有相关视频
            let localVideoExist = localVideo_comparison(avdivs[i].dataset.av);
            if(localVideoExist){
                if(setting.LocalVideoSearchExtraButton){
                    let exDiv = document.createElement("savdiv");
                    let url;
                    if(setting.emby){
                        exDiv.innerHTML =  '<svg  role="img" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" ><path d="M469.333333 85.333333L256 298.666667l42.666667 42.666666-213.333334 213.333334 213.333334 213.333333 42.666666-42.666667 213.333334 213.333334 213.333333-213.333334-42.666667-42.666666 213.333334-213.333334-213.333334-213.333333-42.666666 42.666667-213.333334-213.333334m-42.666666 277.333334l256 149.333333-256 149.333333v-298.666666z" fill="#05b010" p-id="1934"></path></svg>'
                        url = ` ${setting.jellyfinHost}web/index.html#!/item?id=${localVideoExist.Id}&serverId=${localVideoExist.ServerId} `
                    }else{
                        exDiv.innerHTML =  '<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> <linearGradient id="grad3" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="30%" style="stop-color:#AA5CC3;stop-opacity:1" /><stop offset="100%" style="stop-color:#00A4DC;stop-opacity:1" /></linearGradient><path style="fill:url(#grad3)" d="M12 .002C8.826.002-1.398 18.537.16 21.666c1.56 3.129 22.14 3.094 23.682 0C25.384 18.573 15.177 0 12 0zm7.76 18.949c-1.008 2.028-14.493 2.05-15.514 0C3.224 16.9 9.92 4.755 12.003 4.755c2.081 0 8.77 12.166 7.759 14.196zM12 9.198c-1.054 0-4.446 6.15-3.93 7.189.518 1.04 7.348 1.027 7.86 0 .511-1.027-2.874-7.19-3.93-7.19z"/></svg>'
                        url = setting.jellyfinHost + "web/index.html#!/details?id=" + localVideoExist.Id;;
                    }
                    exDiv.classList.add("jellyfin_openPage");
                    exDiv.addEventListener("click",function(e){
                        GM_openInTab(url,{active: true, insert: true,setParent:true});
                        e.preventDefault();
                        return;
                    })
                    appendChild_Afterend(exDiv,avdivs[i]);
                }
                // 番号上添加相关标识
                avdivs[i].classList.remove("infoFirst","infoExistent","infoNonExistent");
                avdivs[i].classList.add("infoLocalVideoExistent");   
            }
            avdivs[i].classList.add("infoLocalVideoSearched");
        }
    }

    // 插入到给定元素的后面
    function appendChild_Afterend(obj,oTarget){
        if (oTarget.nextSibling) {
           oTarget.parentNode.insertBefore(obj, oTarget.nextSibling);
        } else {
            oTarget.parentNode.appendChild(obj);
        };
    }

    // 调用qbit下载
    function qBit(torrent){
        if(debug){console.log("正在调用磁力下载, ",torrent);};
        // 弹窗询问是否下载
        let download_check = setting.qBitNoPopup ? setting.qBitNoPopup : window.confirm ("是否调用 qBittorrent 下载磁链: \n" + torrent);
        if (!download_check){
            if(debug){console.log("取消qbit 下载",download_check, setting.qBitNoPopup)}
            return
        }

        var qbi_host = setting.qBitHost
        var download = setting.qBitDownload;
        GM_xmlhttpRequest({
            method: 'POST',
            url: qbi_host + 'api/v2/torrents/add', 
            headers: {
                "Content-Type": "application/x-www-form-urlencoded"
            },
            timeout:1000,
            data:"urls=" + torrent + "&autoTMM=false&savepath=" + download + "&cookie=&rename=&category=&paused=false&contentLayout=Original&dlLimit=NaN&upLimit=NaN" ,
            onload: function (response) {
                console.log("qBittorrent 返回消息: " ,response);
                if(response.statusText){
                    if(setting.qBitNoPopup && response.statusText.indexOf("OK")>-1){
                        return;
                    }
                    let confirm_r = window.confirm ("qBittorrent 返回消息: \n" + response.statusText + "\n 确定打开 qBit, 取消关闭弹窗");
                    if(confirm_r){
                        window.open(setting.qBitHost, "_blank")
                    }
                } else {
                    alert("网址可能存在问题,  网站返回消息: \n" + response.statusText);
                }
            },
            ontimeout: function (response) {
                console.log(response)
                alert("调用 qBittorrent 出现超时 \n请检查是否已经打开相关软件");
            },
            onerror: function (response) {
                console.log(response)
                alert("调用 qBittorrent 发生错误");
            },
        })
    }

    // 菜单
    // 菜单编辑
    function savBoxEdit(){
        var editbox = document.createElement("div");
        editbox.id = "sav-editCodeBox";
        editbox.style.cssText = "position:fixed;" +
        "z-index:99999;" +
        "top:50%;left:50%;" +
        "transform:translate(-50%,-50%);" +
        "background:#ccc;" +
        "border-radius:4px;" +
        "padding:10px 20px;" ;
        var innerH = " "+
        "<p>搜索词用 %s 代替 <br>格式是 JSON ,修改时注意中英文标点符号 尤其有无逗号 <br>点击“供测试使用”按钮后, 会增加额外选项, 能影响脚本功能 <br><u><a href='https://github.com/qxinGitHub/searchAV'>Github</a></u>上有具体使用说明, 也可以去<u><a href='https://greasyfork.org/zh-CN/scripts/423350/feedback'>greasyfork论坛求助</a></u> </p>" +
        "<textarea wrap='off' cols='66' rows='20' style='overflow:auto;border-radius:4px;'>" + JSON.stringify( GM_getValue("_setting"),false,4) + "</textarea>" +
        "<br>" +
        "<p>老司机共浏览了" + Object.keys(localInfo).length + "个番号!</p>" +
        "<button id='savDebug' >供测试使用</button> &nbsp;&nbsp;&nbsp;" +
        "<button id='savClearSetting' >清空设置</button> &nbsp;&nbsp;&nbsp;" +
        "<button id='savHistory' >清空浏览历史</button> &nbsp;&nbsp;&nbsp;" +
        "<button id='savEditBoxCloase' >关闭</button> &nbsp;&nbsp;&nbsp;" +
        "<button id='savEditBoxSave' >保存</button>" +
        "";
        editbox.innerHTML = innerH;
        editbox.querySelector("#savDebug").addEventListener("click",savDebug)
        editbox.querySelector("#savClearSetting").addEventListener("click",clearSetting)
        editbox.querySelector("#savHistory").addEventListener("click",clearHistory)
        editbox.querySelector("#savEditBoxCloase").addEventListener("click",savBoxClose)
        editbox.querySelector("#savEditBoxSave").addEventListener("click",savBoxSave)
        document.body.appendChild(editbox);
    }
    // 菜单保存
    function savBoxSave(){
        var codevalue = savBoxGetValue();
        if(codevalue){
            GM_setValue("_setting",codevalue);
            setTimeout(function(){
                window.location.reload();
            },300);
        }
    }
    // 关闭菜单
    function savBoxClose(){
        var box = document.querySelector("#sav-editCodeBox");
        if(box){
            box.parentNode.removeChild(box);
        }
    }
    // 开启debug, 会加入额外的信息  
    function savDebug(){
        // 如果是想自定义搜索列表和颜色, 去设置里点击“测试”,然后“保存”, 不要改动此处
        var debug_setting = {
            "debug":false,   // 会在番号上额外添加一些信息, 不建议开启
            "selectLength":0,  // 选中搜索的字符长度。超过该长度的会忽略掉, 设置0可以关闭划词搜索。 
                                // 设置更大的数字,例如16,可以应对一些超长的番号。实际使用中颇多的问题。
            "javbus":"https://www.javbus.com/", // 自定义javbus网站地址 "https://www.javsee.bid/"
            "javdb":"https://javdb.com/",    // 自定义javdb网站地址 "https://javdb004.com/"
            "sehuatangURL":"https://www.sehuatang.net", // 自定义色花堂网址
            "addSearchButton":false,    // 在番号后面添加一个图标, 鼠标滑过作用于图标, 而不是番号
            "searchButtonIcon":"✈",    // 番号后面的图标样式
            "clickToMenu":false,    // 鼠标点击番号才会出现菜单
            "dontClearMenu": false, // 鼠标移出后,菜单不会消失(测试时找问题使用, 开启会影响脚本使用)
            "includeIDinLinks":true,    // 番号本身是个链接的情况下是否识别
            "dontImgBig": false,    // 图片点击放大, 包括滚动放大
            "dontGetInfo":false,    // 获取番号的相关信息(从javbus获取)
            "dontGetInfoFc2":false, // 获取fc2的相关信息(从javmenu获取)
            "dontGetInfoWuma":false,    // 获取无码番号的信息, 大量访问会导致javdb禁止你的ip访问一到两个星期。
            "getInfoFailToJavDB":true,    // 从javbus获取不到信息时, 会从javdb尝试获取。有被javDB封IP的风险
            "dontMagnetDiscern":false,   // 将磁链转为链接
            "magnetCopy":false,     // 磁链不转化链接,点击磁链复制到剪贴板
            // "avLinkMagnet":false,       // 链接是磁链的番号是否添加复制功能
            "dontTransTitle":false, // 翻译标题
            "dontTransTags":false,  // 翻译标签
            "dontGetVideo":false,   // 关闭视频预览
            "videoVolume":0.2, // 视频播放音量,取值0-1, 对fc2的预览视频无效
            "fc2Thumbnail":false,   // fc2 的预览图是否用缩略图, 用低画质换取快速加载图片
            "infoReload": false,    // 浏览过的番号将不会重复获取信息, 避免IP地址被网站拉黑。
            "closeJavdbLimit":false,    // 禁止在短时间内多次访问javdb。 设为 true 可以关闭限制, 容易封IP
            "closeLoadingAnimation":false,  // 关闭信息加载时的动画
            "close_Related_Page":false, // 关闭相关页面的按钮(第一个按钮)
            "addOtherButton":false, // 添加3个额外的按钮: 1,设置按钮; 2,番号按钮,点击复制; 3,关闭按钮
            "sehuatang":false,  // 添加色花堂的搜索按钮
            "emby":false,   // 将 Jellyfin 替换成 Emby, 如果使用 emby, 必须改为true
            "jellyfinHost":"http://localhost:8096/",    // 本地的jellyfin/emby的地址
            "jellyfinApiKey":"",    // 外部程序需要密钥才能和jellyfin/emby通信。  “设置 - 控制台 - API密钥” 点击加号生成一个
            "LocalVideoSearch":false,    // 如果在本地有相关视频, 显示样式为 “infoLocalVideoStyle”, 该样式的优先级最高
            "LocalVideoSearchExtraButton": false,   // 如果在本地有相关视频, 会直接在番号后面显示跳转按钮
            "qBitHost":"http://localhost:8080/", //本地 qbit 的地址
            "qBitDownload":"",    // 在qbit中才下载地址,注意双斜杠: D:\\_下载\\qBittorrent
            "qBitNoPopup":false,   // qbit 弹窗询问是否调用qbit下载
            "baiduAppid":"",    // 百度翻译的 APP ID
            "baiduKey":"",    // 百度翻译的 密钥
            "linkStyle":{   // 没浏览的番号
                "color":"green",  // 颜色  名称:green  十六进制:#00FF00  RGB:rgb(0,255,0) 
                "text-decoration":"underline green",  //下划线
                "font-weight":"normal",   // 加粗: normal、bold、lighter 
                "text-shadow":"rgb(177 177 177 / 70%) 1px 1px",    // 字体阴影
            },
            "visitStyle":{  // 已经浏览过的番号
                "color":"chocolate",  // 颜色
                "text-decoration":"underline dotted chocolate",   // 下划线
                "font-weight":"normal", // 加粗
                "text-shadow":"rgb(177 177 177 / 65%) 1px 1px", // 字体阴影
            },
            "noExistStyle":{  // 已经浏览过, 但是没有获取到信息的番号
                "color":"red",    // 颜色
                "text-decoration":"underline dotted red",   // 下划线
            },
            "infoLocalVideoStyle":{ //本地视频(jellyfin/emby)已有的番号
                "color":"#598987",    // 颜色
                "text-decoration":"underline dotted #598987",   // 下划线
            },
            "list":[],  // 普通番号的搜索列表, 建议直接将搜索加在 "list_all"
            "list_wuma":[], // 素人番号的搜索列表, 建议直接将搜索加在 "list_all"
            "list_all":[]   // 它俩共同的搜索, 会同时加在上面两个列表的后面, 建议使用这个。
        }
        Object.assign(debug_setting,savBoxGetValue());
        document.querySelector("#sav-editCodeBox textarea").value = JSON.stringify(debug_setting,false,4)
    }
    // 返回设置选择的json格式
    function savBoxGetValue(){
        var codevalue = document.querySelector("#sav-editCodeBox textarea").value;
        if(codevalue.length ==0){
            codevalue = "{}"
        }
        var return_value ;
        try{
            return_value = JSON.parse(codevalue)
        }catch(err){
            alert("保存失败,请按照下方提示修改后重新保存\n"+err);
        }
        return return_value;
    }
    // 清空设置
    function clearSetting(){
        GM_deleteValue("_setting");
        GM_deleteValue("_setting2");
        localInfo = {};
        savBoxClose();
        location.reload();
    }
    // 清除浏览历史
    function clearHistory(){
        GM_setValue("avInfo2",{});
        localInfo = {}
        savBoxClose()
        location.reload();
    }
    GM_registerMenuCommand("自定义搜索", savBoxEdit)
    // 添加样式
    function addStyle(){
        var styleText = "";
        var styleAVID = "";
        if(setting.linkStyle){
            styleAVID += ".infoFirst{"
            for(let key in setting.linkStyle){
                styleAVID += key + ":" + setting.linkStyle[key] + ";"
            }
            styleAVID += "}"
        }else {
            styleAVID += ".infoFirst{text-decoration:underline green;}"
        }
        if(setting.visitStyle){
            styleAVID += ".infoExistent{"
            for(let key in setting.visitStyle){
                styleAVID += key + ":" + setting.visitStyle[key] + ";"
            }
            styleAVID += "}"
        }else {
            styleAVID += ".infoExistent{text-decoration:underline dotted #66ccff;}"
        }    
        if(setting.noExistStyle){
            styleAVID += ".infoNonExistent{"
            for(let key in setting.noExistStyle){
                styleAVID += key + ":" + setting.noExistStyle[key] + ";"
            }
            styleAVID += "}"
        }else {
            styleAVID += ".infoNonExistent{text-decoration:underline dotted red;}"
        }
        if(setting.infoLocalVideoStyle){
            styleAVID += ".infoLocalVideoExistent{"
            for(let key in setting.infoLocalVideoStyle){
                styleAVID += key + ":" + setting.infoLocalVideoStyle[key] + ";"
            }
            styleAVID += "}"
        }else {
            styleAVID += ".infoLocalVideoExistent{text-decoration:underline dotted #598987;}"
        }

        styleText = `
            .sav-menu{
                font-family: Microsoft YaHei,sans-serif;
                position:fixed;
                display: block;
                text-align: left;
                color: #000;
                background:rgba(255,255,255,.8);
                backdrop-filter: blur(5px);
                border-radius: 4px;
                padding:6px 12px 10px 9px;
                /* margin-top: -2px; */
                z-index: 99999; 
                font-size: 14px;
                max-width: 600px;
                box-shadow: 4px 4px 12px #ccc, -1px -1px 5px #eee;
                border-top: 2px solid #fff;
                border-left: 2px solid #fff;
                transform:scale(1);
                transition:0.2s;
                transition-timing-function: ease-out;
                animation: savOpenAnim 0.15s;
            }
            .savCloseAnim{
                animation: savCloseAnim 0.15s;
            }
            @keyframes savOpenAnim {
                0% {
                    transform:scale(0.5);
                    background:rgba(255,255,255,.1);
                }
                100% {
                    transform:scale(1);
                    background:rgba(255,255,255,.8);
                }
            }
            @keyframes savCloseAnim {
                0% {
                    opacity: 1;
                    transform:scale(1);
                }
                100% {
                    opacity: 0;
                    transform:scale(0.5);
                }
            }
            /* 链接相关 */
            .savlink{
                margin: 4px 4px 4px 4px;
                border-radius: 4px;
                padding: 3px 5px;
                background: #fff;
                display: inline-block;
                transition: 0.2s;
                transition-timing-function: ease-out;
                box-shadow: -2px -2px 4px rgb(240 240 240), 2px 2px 4px rgb(70 70 70 / 50%);
                cursor: pointer;
                user-select: none;
            }
            .savlink:not(.RPdisabled):hover{
                background: aliceblue;
                box-shadow: -2px -2px 6px rgb(255 255 255 / 50%), 1px 1px 2px rgb(70 70 70 / 50%), inset -2px -2px 6px rgb(255 255 255 / 50%),inset 2px 2px 6px rgb(100 100 100 / 50%);
            }
            .sav-menu .savlink a{
                color:#459df5;
                text-decoration:none;
                transition:0.4s;
            }
            .sav-menu .savlink:not(.RPdisabled):hover a {
                color: #039cff;
                text-shadow: 0 0 #7cfb80;
            }
            avdivsinfo a,
            avdivsinfo a:visited,
            avdivsinfo a:link{
                color: #000;
                transition:0.2s;
            }
            avdivsinfo a:hover{
                color: #850000; 
            }
            /* 相关页面按钮 */
            .relatedPage.RPdisabled{
                cursor:default;
            }
            .relatedPage.RPdisabled a{
                cursor:default;
                pointer-events:none;
                text-decoration:line-through;
                color:#333;
            }

            avdivsinfo{
                text-indent: -2.5em;
                line-height: normal;
            }
            avdivsinfo avdiv{
                display:block;
                margin-bottom: 5px;
                text-shadow: 0 0 #d9d9d9;
                transition: 0.2s;
                padding-left: 2.5em;
            }
            avdivsinfo .avInfoTags,
            avdivsinfo .avInfoSeries{
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
            }
            avdiverror{
                display:block;
                margin-top: 10px;
                padding-left: 10px;
            }
            avdiverror avdiv{
                display:block;
                margin-bottom: 5px;
                transition: 0.2s;
            }
            avdiv .avimg{
                height: 400px;
                max-width: 100%;
                max-height: 500px;
                cursor: pointer;
                box-shadow: -2px -2px 4px rgb(230 230 230), 2px 2px 2px rgb(70 70 70 / 50%);
                border-top: 1px solid #fff;
                border-left: 1px solid #fff;
                border-radius: 4px;
                transform-origin: center 80%;
                transition:0.2s;
                transition-timing-function: ease-out;
            }
            /* .avimg-preview-button:hover + .avimg,
            avdiv .avimg:hover{
                scale:1.01;
                box-shadow: -2px -2px 4px rgb(160 160 160), 4px 4px 4px rgb(70 70 70 / 60%);
            } */
            avdiv .imageBig{
                max-height: 600px;
                transform: scale(1.3);
                border-radius: 10px;
                border-top: 2px solid #fff;
                border-left: 2px solid #fff;
                box-shadow: -2px -2px 4px rgb(160 160 160), 4px 4px 4px rgb(70 70 70 / 60%);
            }
            avdiv .imageBig:hover{
                box-shadow: -4px -4px 8px rgb(160 160 160), 6px 6px 8px rgb(70 70 70 / 60%);
            }

            savdiv.sav-id{
                transition: 0.5s;
            }
            savdiv.sav-id,
            savmagnet {
                cursor: pointer;
            }
            .jellyfin_openPage svg{
                cursor:pointer;
                width:1em;
                scale:0.9;
                vertical-align:text-bottom;
            }
            u:has(savdiv){
                text-decoration: none;
            }
            .yesJellyfin{
                color:#459df5
            }
            .noJellyfin{
                text-decoration:line-through;
            }
            .errJellyfin{
                cursor:default;
                pointer-events:none;
                text-decoration:line-through;
                color:#333;
            }
            avspan svg {
                height: 14px;
                position: relative;
                top: 0.1em;
                opacity:0.8;
                transition:0.2s;
                display: inline-block;
                vertical-align: baseline;
            }
            avspan svg:hover {
                opacity:1;
            }
            avdiv.sav-menu .avimg.savImgError{
                height:200px;
            }
            /* 动画: 横线加载时的动画 */
            @keyframes sav-loading-animation {
                from{ transform: translate(0, 0); }
                to{ transform: translate(50%, 0); }
            }
            .savLoadingContainer {
                display:block;
                overflow: hidden;
                width: 100%;
                transition:0.1s;
                height: 3px;
                margin-top: 5px;
            }
            .savLoading {
                display: block;
                font-size: 0;
                height: 100%;
                width: 200%;
                position: relative;
                transition:0.2s;
                animation: sav-loading-animation 3s linear infinite;
            }
            .savLoading svg {
                border: none;
                height: 100%;
                width: 50%;
                position: absolute;
            }
            .savLoading svg:last-child {
                left: -50%;
            }
            .stop1,
            .stop3{
                stop-color:#fff0;
            }
            .stop2{
                stop-color:#6dc4ed;
                transition: 1s;
            }
            .stop2.javbusloading{
                stop-color:#71d99b;
            }
            .stop2.javdbloading{
                stop-color:#cccc00;
            }
            .stop2.fc2loading{
                stop-color:#F8A01C;
            }
            /* 预览视频 */
            avdivimg{
                position: relative;
                display: block;
                text-indent: initial;
                user-select: none;

            }
            .avimg-preview-button{
                width: 40px;
                height: 40px;
                border-radius: 40px;
                background:#00e7ff00;
                opacity: 0.8;
                position: absolute;
                top: 0;
                bottom: 0;
                left: 0;
                right: 0;
                margin: auto;
                z-index:1;
                transition:0.4s;
                animation: savOpenAnim2 0.15s;
                
            }
            @keyframes huerotate{
                0%{
                    filter:hue-rotate(0deg);
                }
                100%{
                    filter:hue-rotate(360deg);
                }
            }
            .avimg-preview-button:hover{
                opacity: 1;
                background:#00e7ff;
            }
            .avimg-preview-button:after {
                background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'  viewBox='0 0 512 512'%3E%3Cpath d='M448 255c0-106-86-192-192-192S64 150 64 256s86 192 192 192 192-86 192-192z' fill=''  fill-opacity='0.8' stroke='none'/%3E%3Cpath fill='white' d='M216.32  334.44l114.45-69.14a10.89 10.89 0 000-18.6l-114.45-69.14a10.78 10.78 0 00-16.32 9.31v138.26a10.78 10.78 0 0016.32 9.31z'/%3E%3C/svg%3E");
                background-repeat: no-repeat;
                background-position: 50%;
                background-size: 48px 48px;
                content: "";
                display: block;
                position: absolute;
                top: 0;
                bottom: 0;
                left: 0;
                right: 0;
                /* border: 2px solid;
                border-image:linear-gradient(45deg,gold,deeppink)1; */
            }
            .savCloseAnim2,
            avdivimg:has(avdivVideo) .avimg-preview-button,
            avdivimg:has(.imageBig) .avimg-preview-button{
                animation: savCloseAnim2 0.15s;
                animation-fill-mode: forwards;
            }
            avdivVideo{
                position: absolute;
                top: 0;
                bottom: 0;
                left: 0;
                right: 0;
                animation: savOpenAnim2 0.15s;
            }
            avdivimg video{
                width: 100%;
                height: 100%;
                object-fit: contain;
                background: #fff9;
                backdrop-filter: blur(5px);
                border-radius:4px;
            }
            .savVideoClose {
                position: absolute;
                right: 0;
                top: 0;
                padding: 7px 10px 7px 97%;
                border-radius: 4px;
                cursor: pointer;
                transition:0.4s;
            }
            iframe + .savVideoClose{
                color:#fff;
            }
            .savVideoClose:hover {
                color:red;
                background: #fff8;
            }
            avdivvideo iframe{
                width:100%;
                height:100%;
                border: none;
            }
            @keyframes savOpenAnim2 {
                0% {
                    opacity: 0;
                    transform:scale(0);
                }
                100% {
                    opacity: 1;
                    transform:scale(1);
                }
            }
            @keyframes savCloseAnim2 {
                0% {
                    opacity: 1;
                    transform:scale(1);
                }
                100% {
                    opacity: 0;
                    transform:scale(0);
                }
            }

            /* 对其他网站的一些更改 */
            .fc2-embed-video-player.opt_logo .fc2-video-player .fc2-video-metadata{
                display:none !important;
            }
            .fc2-video-player-logo{
                display:none !important;
            }
            `;
        styleText += styleAVID;
        GM_addStyle(styleText);
    }

})();