code:
(function () {
    "use strict";

    var drT = {
        name: "drT",
        version: "1.0.0",
        templateSettings: {
            evaluate:    /\{\{([\s\S]+?(\}?)+)\}\}/g,
            interpolate: /\{\{([\s\S]+?)\}\}/g, // 变量渲染
            encode:      /\{\{@([\s\S]+?)\}\}/g, // 变量自动url编码
            use:         /\{\{#([\s\S]+?)\}\}/g,
            useParams:   /(^|[^\w$])def(?:\.|\[[\'\"])([\w$\.]+)(?:[\'\"]\])?\s*\:\s*([\w$\.]+|\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})/g,
            define:      /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,
            defineParams:/^\s*([\w$]+):([\s\S]+)/,
            conditional: /\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g, // ? if ?? else if ?? else
            iterate:     /\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,
            varname:	"fl",
            strip:		true,
            append:		true,
            selfcontained: false,
            doNotSkipEncoded: false
        },
        template: undefined, //fn, compile template
        compile:  undefined, //fn, for express
        log: true
    }, _globals;

    drT.encodeHTMLSource = function(doNotSkipEncoded) {
        var encodeHTMLRules = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'", "/": "/" },
            matchHTML = doNotSkipEncoded ? /[&<>"'\/]/g : /&(?!#?\w+;)|<|>|"|'|\//g;
        return function(code) {
            return code ? code.toString().replace(matchHTML, function(m) {return encodeHTMLRules[m] || m;}) : "";
        };
    };

    _globals = (function(){ return this || (0,eval)("this"); }());

    /* istanbul ignore else */
    if (typeof module !== "undefined" && module.exports) {
        module.exports = drT;
    } else if (typeof define === "function" && define.amd) {
        define(function(){return drT;});
    } else {
        _globals.drT = drT;
    }

    var startend = {
        append: { start: "'+(",      end: ")+'",      startencode: "'+encodeHTML(" },
        split:  { start: "';out+=(", end: ");out+='", startencode: "';out+=encodeHTML(" }
    }, skip = /$^/;

    function resolveDefs(c, block, def) {
        return ((typeof block === "string") ? block : block.toString())
            .replace(c.define || skip, function(m, code, assign, value) {
                if (code.indexOf("def.") === 0) {
                    code = code.substring(4);
                }
                if (!(code in def)) {
                    if (assign === ":") {
                        if (c.defineParams) value.replace(c.defineParams, function(m, param, v) {
                            def[code] = {arg: param, text: v};
                        });
                        if (!(code in def)) def[code]= value;
                    } else {
                        new Function("def", "def['"+code+"']=" + value)(def);
                    }
                }
                return "";
            })
            .replace(c.use || skip, function(m, code) {
                if (c.useParams) code = code.replace(c.useParams, function(m, s, d, param) {
                    if (def[d] && def[d].arg && param) {
                        var rw = (d+":"+param).replace(/'|\\/g, "_");
                        def.__exp = def.__exp || {};
                        def.__exp[rw] = def[d].text.replace(new RegExp("(^|[^\\w$])" + def[d].arg + "([^\\w$])", "g"), "$1" + param + "$2");
                        return s + "def.__exp['"+rw+"']";
                    }
                });
                var v = new Function("def", "return " + code)(def);
                return v ? resolveDefs(c, v, def) : v;
            });
    }

    function unescape(code) {
        return code.replace(/\\('|\\)/g, "$1").replace(/[\r\t\n]/g, " ");
    }

    drT.template = function(tmpl, c, def) {
        c = c || drT.templateSettings;
        var cse = c.append ? startend.append : startend.split, needhtmlencode, sid = 0, indv,
            str  = (c.use || c.define) ? resolveDefs(c, tmpl, def || {}) : tmpl;

        // console.log(str);
        let beforeCode = '';
        if(str.match(c.interpolate || skip)){
            let inter_codes = str.match(c.interpolate || skip);
            let inter_dict = {};
            inter_codes.forEach(item=>{
                item.replace(c.interpolate || skip,function (m,code) {
                    let varname = code.split('.')[0];
                    if(!inter_dict.hasOwnProperty(varname)){
                        let beginCode = `if(typeof(${varname})==='undefined'){${varname}={}}`;
                        inter_dict[varname] = beginCode;
                    }if(!inter_dict.hasOwnProperty(code)){
                        let beginCode = `if(typeof(${code})==='undefined'){${code}=''};`;
                        inter_dict[code] = beginCode;
                    }
                });
            });
            let beginCode = Object.values(inter_dict).join('\n');
            // console.log(beginCode);
            beforeCode += beginCode;
        }
        str = beforeCode+("var out='" + (c.strip ? str.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g," ")
                .replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,""): str)
                .replace(/'|\\/g, "\\$&")
                .replace(c.encode || skip, function(m, code) {
                    needhtmlencode = true;
                    return cse.startencode + unescape(code) + cse.end;
                })
                .replace(c.interpolate || skip, function(m, code) {
                    let varname = code.split('.')[0];
                    // console.log(varname === code);
                    // console.log(`varname:${varname},code:${code}`);
                    if(varname === code){
                        let res = cse.start + `JSON.stringify(${unescape(code)})` + cse.end;
                        // console.log(res);
                        return res
                    }
                    return cse.start + unescape(code) + cse.end;
                })
                .replace(c.conditional || skip, function(m, elsecase, code) {
                    return elsecase ?
                        (code ? "';}else if(" + unescape(code) + "){out+='" : "';}else{out+='") :
                        (code ? "';if(" + unescape(code) + "){out+='" : "';}out+='");
                })
                .replace(c.iterate || skip, function(m, iterate, vname, iname) {
                    if (!iterate) return "';} } out+='";
                    sid+=1; indv=iname || "i"+sid; iterate=unescape(iterate);
                    return "';var arr"+sid+"="+iterate+";if(arr"+sid+"){var "+vname+","+indv+"=-1,l"+sid+"=arr"+sid+".length-1;while("+indv+"<l"+sid+"){"
                        +vname+"=arr"+sid+"["+indv+"+=1];out+='";
                })
                .replace(c.evaluate || skip, function(m, code) {
                    return "';" + unescape(code) + "out+='";
                })
            + "';return out;")
            .replace(/\n/g, "\\n").replace(/\t/g, '\\t').replace(/\r/g, "\\r")
            .replace(/(\s|;|\}|^|\{)out\+='';/g, '$1').replace(/\+''/g, "");
        //.replace(/(\s|;|\}|^|\{)out\+=''\+/g,'$1out+=');

        if (needhtmlencode) {
            // console.log('需要编码');
            // console.log(c.doNotSkipEncoded);
            if (!c.selfcontained && _globals && !_globals._encodeHTML) _globals._encodeHTML = drT.encodeHTMLSource(c.doNotSkipEncoded);
            str = "var encodeHTML = typeof _encodeHTML !== 'undefined' ? _encodeHTML : ("
                + drT.encodeHTMLSource.toString() + "(" + (c.doNotSkipEncoded || '') + "));"
                + str;
            // console.log(str);
        }else{
            // console.log('不需要编码');
        }
        // console.log(c.varname);
        // console.log(str);
        try {
            return new Function(c.varname, str);
        } catch (e) {
            /* istanbul ignore else */
            // console.log(e.message);
            if (typeof console !== "undefined") console.log("Could not create a template function: " + str);
            throw e;
        }
    };

    drT.compile = function(tmpl, def) {
        return drT.template(tmpl, null, def);
    };
    drT.renderText = function (tmpl,dict,varname){
        varname = varname||'';
        if(varname){
            drT.templateSettings.varname = varname;
        }
        dict = dict||{};
        return drT.compile(tmpl)(dict);
    };
}());

license: unknown


code:
if (typeof Object.assign != 'function') {
    Object.assign = function () {
	var target = arguments[0];
    for (var i = 1; i < arguments.length; i++) {
        var source = arguments[i];
        for (var key in source) {
            if (Object.prototype.hasOwnProperty.call(source, key)) {
                target[key] = source[key];
            }
        }
    }
    return target;
};
}
function getMubans() {
    var mubanDict = { // 模板字典
        mxpro: {
            title: '',
            host: '',
            // homeUrl:'/',
            url: '/vodshow/fyclass--------fypage---.html',
            searchUrl: '/vodsearch/**----------fypage---.html',
            searchable: 2,//是否启用全局搜索,
            quickSearch: 0,//是否启用快速搜索,
            filterable: 0,//是否启用分类筛选,
            headers: {//网站的请求头,完整支持所有的,常带ua和cookies
                'User-Agent': 'MOBILE_UA',
                // "Cookie": "searchneed=ok"
            },
            class_parse: '.navbar-items li:gt(2):lt(8);a&&Text;a&&href;/(\\d+).html',
            play_parse: true,
            lazy: '',
            limit: 6,
            推荐: '.tab-list.active;a.module-poster-item.module-item;.module-poster-item-title&&Text;.lazyload&&data-original;.module-item-note&&Text;a&&href',
            double: true, // 推荐内容是否双层定位
            一级: 'body a.module-poster-item.module-item;a&&title;.lazyload&&data-original;.module-item-note&&Text;a&&href',
            二级: {
                "title": "h1&&Text;.module-info-tag&&Text",
                "img": ".lazyload&&data-original",
                "desc": ".module-info-item:eq(1)&&Text;.module-info-item:eq(2)&&Text;.module-info-item:eq(3)&&Text",
                "content": ".module-info-introduction&&Text",
                "tabs": ".module-tab-item",
                "lists": ".module-play-list:eq(#id) a"
            },
            搜索: 'body .module-item;.module-card-item-title&&Text;.lazyload&&data-original;.module-item-note&&Text;a&&href;.module-info-item-content&&Text',
        },
        mxone5: {
            title: '',
            host: '',
            url: '/show/fyclass--------fypage---.html',
            searchUrl: '/search/**----------fypage---.html',
            searchable: 2,//是否启用全局搜索,
            quickSearch: 0,//是否启用快速搜索,
            filterable: 0,//是否启用分类筛选,
            class_parse: '.nav-menu-items&&li;a&&Text;a&&href;.*/(.*?).html',
            play_parse: true,
            lazy: '',
            limit: 6,
            推荐: '.module-list;.module-items&&.module-item;a&&title;img&&data-src;.module-item-text&&Text;a&&href',
            double: true, // 推荐内容是否双层定位
            一级: '.module-items .module-item;a&&title;img&&data-src;.module-item-text&&Text;a&&href',
            二级: {
                "title": "h1&&Text;.tag-link&&Text",
                "img": ".module-item-pic&&img&&data-src",
                "desc": ".video-info-items:eq(0)&&Text;.video-info-items:eq(1)&&Text;.video-info-items:eq(2)&&Text;.video-info-items:eq(3)&&Text",
                "content": ".vod_content&&Text",
                "tabs": ".module-tab-item",
                "lists": ".module-player-list:eq(#id)&&.scroll-content&&a"
            },
            搜索: '.module-items .module-search-item;a&&title;img&&data-src;.video-serial&&Text;a&&href',
        },
        首图: {
            title: '',
            host: '',
            url: '/vodshow/fyclass--------fypage---/',
            searchUrl: '/vodsearch/**----------fypage---.html',
            searchable: 2,//是否启用全局搜索,
            quickSearch: 0,//是否启用快速搜索,
            filterable: 0,//是否启用分类筛选,
            headers: {//网站的请求头,完整支持所有的,常带ua和cookies
                'User-Agent': 'MOBILE_UA',
                // "Cookie": "searchneed=ok"
            },
            class_parse: '.myui-header__menu li.hidden-sm:gt(0):lt(5);a&&Text;a&&href;/(\\d+).html',
            play_parse: true,
            lazy: '',
            limit: 6,
            推荐: 'ul.myui-vodlist.clearfix;li;a&&title;a&&data-original;.pic-text&&Text;a&&href',
            double: true, // 推荐内容是否双层定位
            一级: '.myui-vodlist li;a&&title;a&&data-original;.pic-text&&Text;a&&href',
            二级: {
                "title": ".myui-content__detail .title&&Text;.myui-content__detail p:eq(-2)&&Text",
                "img": ".myui-content__thumb .lazyload&&data-original",
                "desc": ".myui-content__detail p:eq(0)&&Text;.myui-content__detail p:eq(1)&&Text;.myui-content__detail p:eq(2)&&Text",
                "content": ".content&&Text",
                "tabs": ".nav-tabs:eq(0) li",
                "lists": ".myui-content__list:eq(#id) li"
            },
            搜索: '#searchList li;a&&title;.lazyload&&data-original;.text-muted&&Text;a&&href;.text-muted:eq(-1)&&Text',
        },
        首图2: {
            title: '',
            host: '',
            url: '/list/fyclass-fypage.html',
            searchUrl: '/vodsearch/**----------fypage---.html',
            searchable: 2,//是否启用全局搜索,
            quickSearch: 0,//是否启用快速搜索,
            filterable: 0,//是否启用分类筛选,
            headers: {
                'User-Agent': 'UC_UA',
                // "Cookie": ""
            },
            // class_parse:'.stui-header__menu li:gt(0):lt(7);a&&Text;a&&href;/(\\d+).html',
            class_parse: '.stui-header__menu li:gt(0):lt(7);a&&Text;a&&href;.*/(.*?).html',
            play_parse: true,
            lazy: '',
            limit: 6,
            推荐: 'ul.stui-vodlist.clearfix;li;a&&title;.lazyload&&data-original;.pic-text&&Text;a&&href',
            double: true, // 推荐内容是否双层定位
            一级: '.stui-vodlist li;a&&title;a&&data-original;.pic-text&&Text;a&&href',
            二级: {
                "title": ".stui-content__detail .title&&Text;.stui-content__detail p:eq(-2)&&Text",
                "img": ".stui-content__thumb .lazyload&&data-original",
                "desc": ".stui-content__detail p:eq(0)&&Text;.stui-content__detail p:eq(1)&&Text;.stui-content__detail p:eq(2)&&Text",
                "content": ".detail&&Text",
                "tabs": ".stui-vodlist__head h3",
                "lists": ".stui-content__playlist:eq(#id) li"
            },
            搜索: 'ul.stui-vodlist__media:eq(0) li,ul.stui-vodlist:eq(0) li,#searchList li;a&&title;.lazyload&&data-original;.text-muted&&Text;a&&href;.text-muted:eq(-1)&&Text',
            搜索1: 'ul.stui-vodlist&&li;a&&title;.lazyload&&data-original;.text-muted&&Text;a&&href;.text-muted:eq(-1)&&Text',
            搜索2: 'ul.stui-vodlist__media&&li;a&&title;.lazyload&&data-original;.text-muted&&Text;a&&href;.text-muted:eq(-1)&&Text',
        },
        默认: {
            title: '',
            host: '',
            url: '/vodshow/fyclass--------fypage---.html',
            searchUrl: '/vodsearch/-------------.html?wd=**',
            searchable: 2,//是否启用全局搜索,
            quickSearch: 0,//是否启用快速搜索,
            filterable: 0,//是否启用分类筛选,
            headers: {
                'User-Agent': 'MOBILE_UA',
            },
            play_parse: true,
            lazy: '',
            limit: 6,
            double: true, // 推荐内容是否双层定位
        },
        vfed: {
            title: '',
            host: '',
            url: '/index.php/vod/show/id/fyclass/page/fypage.html',
            searchUrl: '/index.php/vod/search/page/fypage/wd/**.html',
            searchable: 2,//是否启用全局搜索,
            quickSearch: 0,//是否启用快速搜索,
            filterable: 0,//是否启用分类筛选,
            headers: {
                'User-Agent': 'UC_UA',
            },
            // class_parse:'.fed-pops-navbar&&ul.fed-part-rows&&a.fed-part-eone:gt(0):lt(5);a&&Text;a&&href;.*/(.*?).html',
            class_parse: '.fed-pops-navbar&&ul.fed-part-rows&&a;a&&Text;a&&href;.*/(.*?).html',
            play_parse: true,
            lazy: '',
            limit: 6,
            推荐: 'ul.fed-list-info.fed-part-rows;li;a.fed-list-title&&Text;a&&data-original;.fed-list-remarks&&Text;a&&href',
            double: true, // 推荐内容是否双层定位
            一级: '.fed-list-info&&li;a.fed-list-title&&Text;a&&data-original;.fed-list-remarks&&Text;a&&href',
            二级: {
                "title": "h1.fed-part-eone&&Text;.fed-deta-content&&.fed-part-rows&&li&&Text",
                "img": ".fed-list-info&&a&&data-original",
                "desc": ".fed-deta-content&&.fed-part-rows&&li:eq(1)&&Text;.fed-deta-content&&.fed-part-rows&&li:eq(2)&&Text;.fed-deta-content&&.fed-part-rows&&li:eq(3)&&Text",
                "content": ".fed-part-esan&&Text",
                "tabs": ".fed-drop-boxs&&.fed-part-rows&&li",
                "lists": ".fed-play-item:eq(#id)&&ul:eq(1)&&li"
            },
            搜索: '.fed-deta-info;h1&&Text;.lazyload&&data-original;.fed-list-remarks&&Text;a&&href;.fed-deta-content&&Text',
        },
        海螺3: {
            title: '',
            host: '',
            searchUrl: '/v_search/**----------fypage---.html',
            url: '/vod_____show/fyclass--------fypage---.html',
            headers: {
                'User-Agent': 'MOBILE_UA'
            },
            timeout: 5000,
            class_parse: 'body&&.hl-nav li:gt(0);a&&Text;a&&href;.*/(.*?).html',
            cate_exclude: '明星|专题|最新|排行',
            limit: 40,
            play_parse: true,
            lazy: '',
            推荐: '.hl-vod-list;li;a&&title;a&&data-original;.remarks&&Text;a&&href',
            double: true,
            一级: '.hl-vod-list&&.hl-list-item;a&&title;a&&data-original;.remarks&&Text;a&&href',
            二级: {
                "title": ".hl-infos-title&&Text;.hl-text-conch&&Text",
                "img": ".hl-lazy&&data-original",
                "desc": ".hl-infos-content&&.hl-text-conch&&Text",
                "content": ".hl-content-text&&Text",
                "tabs": ".hl-tabs&&a",
                "lists": ".hl-plays-list:eq(#id)&&li"
            },
            搜索: '.hl-list-item;a&&title;a&&data-original;.remarks&&Text;a&&href',
            searchable: 2,//是否启用全局搜索,
            quickSearch: 0,//是否启用快速搜索,
            filterable: 0,//是否启用分类筛选,
        },
        海螺2: {
            title: '',
            host: '',
            searchUrl: '/index.php/vod/search/page/fypage/wd/**/',
            url: '/index.php/vod/show/id/fyclass/page/fypage/',
            headers: {
                'User-Agent': 'MOBILE_UA'
            },
            timeout: 5000,
            class_parse: '#nav-bar li;a&&Text;a&&href;id/(.*?)/',
            limit: 40,
            play_parse: true,
            lazy: '',
            推荐: '.list-a.size;li;a&&title;.lazy&&data-original;.bt&&Text;a&&href',
            double: true,
            一级: '.list-a&&li;a&&title;.lazy&&data-original;.list-remarks&&Text;a&&href',
            二级: {
                "title": "h2&&Text;.deployment&&Text",
                "img": ".lazy&&data-original",
                "desc": ".deployment&&Text",
                "content": ".ec-show&&Text",
                "tabs": "#tag&&a",
                "lists": ".play_list_box:eq(#id)&&li"
            },
            搜索: '.search-list;a&&title;.lazy&&data-original;.deployment&&Text;a&&href',
            searchable: 2,//是否启用全局搜索,
            quickSearch: 0,//是否启用快速搜索,
            filterable: 0,//是否启用分类筛选,
        },
        短视: {
            title: '',
            host: '',
            // homeUrl:'/',
            url: '/channel/fyclass-fypage.html',
            searchUrl: '/search.html?wd=**',
            searchable: 2,//是否启用全局搜索,
            quickSearch: 0,//是否启用快速搜索,
            filterable: 0,//是否启用分类筛选,
            headers: {//网站的请求头,完整支持所有的,常带ua和cookies
                'User-Agent': 'MOBILE_UA',
                // "Cookie": "searchneed=ok"
            },
            class_parse: '.menu_bottom ul li;a&&Text;a&&href;.*/(.*?).html',
            cate_exclude: '解析|动态',
            play_parse: true,
            lazy: '',
            limit: 6,
            推荐: '.indexShowBox;ul&&li;a&&title;img&&data-src;.s1&&Text;a&&href',
            double: true, // 推荐内容是否双层定位
            一级: '.pic-list&&li;a&&title;img&&data-src;.s1&&Text;a&&href',
            二级: {
                "title": "h1&&Text;.content-rt&&p:eq(0)&&Text",
                "img": ".img&&img&&data-src",
                "desc": ".content-rt&&p:eq(1)&&Text;.content-rt&&p:eq(2)&&Text;.content-rt&&p:eq(3)&&Text;.content-rt&&p:eq(4)&&Text;.content-rt&&p:eq(5)&&Text",
                "content": ".zkjj_a&&Text",
                "tabs": ".py-tabs&&option",
                "lists": ".player:eq(#id) li"
            },
            搜索: '.sr_lists&&ul&&li;h3&&Text;img&&data-src;.int&&p:eq(0)&&Text;a&&href',
        }

    };
    return JSON.parse(JSON.stringify(mubanDict));
}
var mubanDict = getMubans();
var muban = getMubans();
export default {muban,getMubans};


path: js/libs


code:
var rule = {
    title:'omofun动漫',
    host:'https://www.omofun.tv',
    // homeUrl:'/',
    url:'/vod/show/id/fyclass/page/fypage.html',
    searchUrl:'/vod/search.html?wd=**',
    searchable:2,//是否启用全局搜索,
    quickSearch:0,//是否启用快速搜索,
    filterable:0,//是否启用分类筛选,
    headers:{//网站的请求头,完整支持所有的,常带ua和cookies
        'User-Agent':'MOBILE_UA',
        // "Cookie": "searchneed=ok"
    },
    class_parse:'.navbar-items li;a&&Text;a&&href;.*/(.*?).html',
    play_parse:true,
    lazy:'',
    limit:6,
    推荐:'.module-item;.lazyload&&alt;.lazyload&&data-original;.module-item-note&&Text;a&&href',
    double:true, // 推荐内容是否双层定位
    一级:'.module-item;.lazyload&&alt;.lazyload&&data-original;.module-item-note&&Text;a&&href',
    二级:{"title":"h1&&Text;.module-info-tag&&Text","img":".lazyload&&data-original","desc":".module-info-item:eq(1)&&Text;.module-info-item:eq(2)&&Text;.module-info-item:eq(3)&&Text","content":".module-info-introduction&&Text","tabs":".module-tab-item","lists":".module-play-list-content:eq(#id) a"},
    搜索:'body .module-item;.module-card-item-title&&Text;.lazyload&&data-original;.module-item-note&&Text;a&&href;.module-info-item-content&&Text',
}


code:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# File  : rules.py.py
# Author: DaShenHan&道长-----先苦后甜，任凭晚风拂柳颜------
# Date  : 2022/8/25
import json
import os
from time import time
import js2py
from utils.log import logger
# from utils.web import get_interval,UA
from utils.ua import UA,get_interval
from flask import render_template_string

def getRuleLists():
    base_path = os.path.dirname(os.path.abspath(__file__)) # 当前文件所在目录
    # print(base_path)
    file_name = os.listdir(base_path)
    file_name = list(filter(lambda x:str(x).endswith('.js') and str(x).find('模板') < 0,file_name))
    # print(file_name)
    rule_list = [file.replace('.js','') for file in file_name]
    # print(rule_list)
    return rule_list

def getCacheCount():
    base_path = 'cache/'  # 当前缓存js所在目录
    os.makedirs(base_path, exist_ok=True)
    file_name = os.listdir(base_path)
    file_name = list(filter(lambda x: str(x).endswith('.js') and str(x).find('模板') < 0, file_name))
    return len(file_name)

def getRules(path='cache',js_mode=0):
    t1 = time()

    base_path = path+'/'  # 当前文件所在目录
    # print(base_path)
    os.makedirs(base_path,exist_ok=True)
    file_name = os.listdir(base_path)
    file_name = list(filter(lambda x: str(x).endswith('.js') and str(x).find('模板') < 0, file_name))
    # print(file_name)
    rule_list = [file.replace('.js', '') for file in file_name]
    js_path = [f'{path}/{rule}.js' for rule in rule_list]
    with open('js/模板.js', encoding='utf-8') as f:
        before = f.read().split('export')[0]
    rule_codes = []
    # for js in js_path:
    #     with open(js,encoding='utf-8') as f:
    #         code = f.read()
    #         rule_codes.append(js2py.eval_js(before+code))

    ctx = js2py.EvalJs()
    codes = []
    for i in range(len(js_path)):
        js = js_path[i]
        with open(js,encoding='utf-8') as f:
            code = f.read()
            new_code = 'var muban = JSON.parse(JSON.stringify(mubanDict));\n'+code.replace('rule',f'rule{i}',1)
            # new_code = ''+code.replace('rule',f'rule{i}',1)
            codes.append(new_code)
    newCodes = before + '\n'+ '\n'.join(codes)
    # print(newCodes)
    try:
        ctx.execute(newCodes)
        for i in range(len(js_path)):
            rule_codes.append(ctx.eval(f'rule{i}'))

        # print(rule_codes)
        # print(type(rule_codes[0]),rule_codes[0])
        # print(rule_codes[0].title)
        # print(rule_codes[0].searchable)
        # print(rule_codes[0].quickSearch)
        new_rule_list = []
        for i in range(len(rule_list)):
            if js_mode == 1 and rule_list[i] == 'drpy':
                continue
            sable = rule_codes[i].searchable or 0
            tmpObj = {
                'name':rule_list[i],
                # 'searchable':1 if (js_mode==1 and sable==2) else sable, # 对js模式1开放软件聚搜(还是算了，服务器遭不住)
                'searchable':sable,
                'quickSearch':rule_codes[i].quickSearch or 0,
                'filterable':rule_codes[i].filterable or 0,
            }
            if rule_codes[i].multi:
                tmpObj['multi'] = 1
            new_rule_list.append(tmpObj)
        # print(new_rule_list)
        rules = {'list': new_rule_list, 'count': len(rule_list)}
    except Exception as e:
        logger.info(f'装载js内置源列表失败,置空内置源')
        rules = []
    logger.info(f'自动配置装载耗时:{get_interval(t1)}毫秒')
    return rules

def jxTxt2Json(text:str,host:str):
    try:
        data = render_template_string(text,host=host).strip().split('\n')
    except Exception as e:
        logger.info(f'jxTxt2Json发生错误:{e}')
        data = []
    jxs = []
    for i in data:
        i = i.strip()
        dt = i.split(',')
        if not i.startswith('#') and len(i) > 10:
            try:
                jxs.append({
                    'name':dt[0],
                    'url':dt[1],
                    'type':dt[2] if len(dt) > 2 and dt[2] else 0,
                    'ua':dt[3] if len(dt) > 3 and dt[3] else UA,
                })
            except Exception as e:
                logger.info(f'解析行有错误:{e}')
    return jxs

def getJxs(path='js',host=None):
    custom_jx = 'base/解析.conf'
    if not os.path.exists(custom_jx):
        with open(custom_jx,'w+',encoding='utf-8') as f1:
            msg = """# 这是用户自定义解析列表,不会被系统升级覆盖
# 0123，对应，普通解析，json解析，并发多json解析，聚合解析,参数3不填默认0
# flags是线路名称标识,会自动拦截并走以下的解析
# 名称，链接，类型,ua (ua不填默认 Mozilla/5.0) 可以手动填 Dart/2.14 (dart:io)
虾米,https://dm.xmflv.com:4433/?url=
            """
            f1.write(msg)
    base_path = 'jiexi'  # 自建解析目录
    os.makedirs(base_path, exist_ok=True)
    file_name = os.listdir(base_path)
    file_name = list(filter(lambda x: str(x).endswith('.js') and str(x).find('模板') < 0, file_name))
    # print(file_name)
    jx_list = [file.replace('.js', '') for file in file_name]
    # print(file_name)
    # print(jx_list)
    jx_str = '\n'.join([jx+',{{host}}'+f'/parse/api/{jx}.js?url=,1' for jx in jx_list])
    # print(jx_str)

    with open(f'{path}/解析.conf',encoding='utf-8') as f:
        text = f.read()
    text = jx_str + '\n' + text
    jxs = jxTxt2Json(text,host)
    with open(custom_jx,encoding='utf-8') as f2:
        text = f2.read()
    jxs2 = jxTxt2Json(text,host)
    jxs.extend(jxs2)
    print(f'共计{len(jxs)}条解析')
    return jxs

def getPys(path='txt/py'):
    t1 = time()
    base_path = os.path.dirname(os.path.abspath(os.path.dirname(__file__)))  # 上级目录
    py_path = os.path.join(base_path, path)
    os.makedirs(py_path, exist_ok=True)
    file_name = os.listdir(py_path)
    file_name = list(filter(lambda x: str(x).endswith('.py'), file_name))
    # print(file_name)
    rule_list = [file.replace('.py', '') for file in file_name]
    py_path = [f'{path}/{rule}.py' for rule in rule_list]
    new_rule_list = []
    for i in range(len(rule_list)):
        new_rule_list.append({
            'name': rule_list[i],
            'searchable': 1,
            'quickSearch': 1,
            'filterable': 0,
        })
    logger.info(f'自动加载Pyramid耗时:{get_interval(t1)}毫秒')
    return new_rule_list

def gen_cache(path='txt/js/tg'):
    t1 = time()
    base_path = os.path.dirname(os.path.abspath(os.path.dirname(__file__)))  # 上级目录
    py_path = os.path.join(base_path, path)
    os.makedirs(py_path, exist_ok=True)
    file_name = os.listdir(py_path)
    file_name = list(filter(lambda x: str(x).endswith('.js'), file_name))
    # print(file_name)
    rule_list = [file.replace('.js', '') for file in file_name]
    js_path = [f'{path}/{rule}.js' for rule in rule_list]
    new_rule_list = []
    for i in range(len(rule_list)):
        # print(js_path[i])
        rname = rule_list[i]
        new_rule_list.append(
            {
                "key": f"dr_{rname}",
                "name": f"{rname}(道长)",
                "type": 1,
                # "api": "{{host}}"+f"/vod?rule={rname}&ext="+"{{host}}/"+js_path[i],
                "api": "{{host}}"+f"/vod?rule={rname}&ext="+js_path[i],
                "searchable": 2,
                "quickSearch": 0,
                "filterable": 0
            })
    logger.info(f'自动加载{len(new_rule_list)}个缓存JS耗时:{get_interval(t1)}毫秒')
    new_rules_texts = [json.dumps(new_rule,ensure_ascii=False) for new_rule in new_rule_list]
    # new_rules_text = json.dumps(new_rule_list,ensure_ascii=False)
    new_rules_text = ',\n'.join(new_rules_texts)+','
    return new_rules_text

if __name__ == '__main__':
    print(getRuleLists())
    # print(gen_cache())
    # print(gen_cache('txt/js/18'))

    custom_file = gen_cache() + '\n'+gen_cache('txt/js/18')
    print(custom_file)
    with open('custom.conf','w+',encoding='utf-8') as f:
        f.write(custom_file)


code:
muban.首图.二级.tabs = '.myui-panel__head.bottom-line h3';
var rule = Object.assign(muban.首图,{
title:'TV云播',
host:'http://www.tvyb03.com',
url:'/vod/type/id/fyclass/page/fypage.html',
class_parse:'.item.nav-list.clearfix li:gt(0):lt(5);a&&Text;a&&href;/(\\d+).html',
推荐:'.myui-panel_bd.clearfix;.myui-vodlist.clearfix&&li;a&&title;a&&data-original;.background-color&&Text;a&&href',
 一级:'.myui-vodlist li;a&&title;a&&data-original;.pic-tag-top&&Text;a&&href',
});


code:
muban.mxone5.二级.desc = ';;.video-info-items:eq(2);.video-info-items:eq(1);.video-info-items:eq(0)';
var rule = Object.assign(muban.mxone5,{
    title:'Vid影视',
    host:'https://vidhub.cc',
    url:'/vodshow/fyclass--------fypage---.html',
    searchUrl:'/vodsearch/**----------fypage---.html',
    cate_exclude:'网址+',
    tab_exclude:'主选一',
});


code:
var rule = Object.assign(muban.vfed,{
title:'VIP影院',
host:'http://360yy.cn',
url:'/index.php/vod/show/id/fyclass/page/fypage.html',
searchUrl:'/index.php/vod/search/page/fypage/wd/**.html',
});


code:
muban.首图.二级.重定向='js:let url = jsp.pd(html,".myui-content__operate&&a&&href");log("重定向到:"+url);html = request(url)';
muban.首图.二级.tabs='.myui-screens__list&&ul&&li';
muban.首图.二级.lists='.myui-content__list:eq(#id)&&li';

var rule = Object.assign(muban.首图,{
title:'七小时影院',
host:'https://www.qxsyy.com',
url:'/type/fyclass-fypage.html',
searchUrl:'/search/**----------fypage---.html',
class_parse:'.myui-header__menu&&li:gt(0):lt(6);a&&Text;a&&href;.*/(.*?).html',
搜索:'#searchList li;.myui-vodlist__thumb&&title;.lazyload&&data-original;;a&&href;.text-muted:eq(-1)&&Text',
});


code:
var rule = Object.assign(muban.首图,{
title:'万能影视',
host:'https://wnvod.net',
});


code:
function fiveSing(packages) {
    const { axios, cheerio } = packages;
    const pageSize = 10;

    function formatMusicItem(_) {
        return {
            id: _.songId,
            title: cheerio.load(_.songName).text(),
            artist: _.singer,
            singerId: _.singerId,
            album: _.typeName,
            type: _.type,
            typeName: _.typeName,
            typeEname: _.typeEname
        }
    }

    function formatAlbumItem(_) {
        return {
            id: _.songListId,
            artist: _.userName,
            title: cheerio.load(_.title).text(),
            artwork: _.pictureUrl,
            description: _.content,
            date: _.createTime,
        }
    }

    function formatArtistItem(_) {
        return ({
            id: _.id,
            name: cheerio.load(_.nickName).text(),
            fans: _.fans,
            avatar: _.pictureUrl,
            description: _.description,
            worksNum: _.totalSong

        })
    }

    const searchHeaders = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36',
        'Host': 'search.5sing.kugou.com',
        'Accept': 'application/json, text/javascript, */*; q=0.01',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'zh-CN,zh;q=0.9',
        'Referer': 'http://search.5sing.kugou.com/home/index'
    }

    async function searchMusic(query, page) {
        const res = (await axios.get('http://search.5sing.kugou.com/home/json', {
            headers: searchHeaders,
            params: {
                keyword: query,
                sort: 1,
                page,
                filter: 0,
                type: 0,
            }
        })).data;
        const songs = res.list.map(formatMusicItem);

        return {
            isEnd: res.pageInfo.cur >= res.pageInfo.totalPages,
            data: songs
        }
    }

    async function searchAlbum(query, page) {
        const res = (await axios.get('http://search.5sing.kugou.com/home/json', {
            headers: searchHeaders,
            params: {
                keyword: query,
                sort: 1,
                page,
                filter: 0,
                type: 1,
            }
        })).data;
        const songs = res.list.map(formatAlbumItem);

        return {
            isEnd: res.pageInfo.cur >= res.pageInfo.totalPages,
            data: songs
        }
    }

    async function searchArtist(query, page) {
        const res = (await axios.get('http://search.5sing.kugou.com/home/json', {
            headers: searchHeaders,
            params: {
                keyword: query,
                sort: 1,
                page,
                filter: 1,
                type: 2,
            }
        })).data;
        const songs = res.list.map(formatArtistItem);

        return {
            isEnd: res.pageInfo.cur >= res.pageInfo.totalPages,
            data: songs
        }
    }

    let fcEnd = false;
    let ycEnd = false;
    let bzEnd = false;
    async function getArtistMusicWorks(artistItem, page) {
        if(page === 1) {
            fcEnd = false;
            ycEnd = false;
            bzEnd = false;
        }
        const headers = {
            'Accept': 'application/json, text/plain, */*',
            'Accept-Encoding': 'gzip, deflate',
            'Accept-Language': 'zh-CN,zh;q=0.9',
            'Cache-Control': 'no-cache',
            'Connection': 'keep-alive',
            'Host': 'service.5sing.kugou.com',
            'Origin': 'http://5sing.kugou.com',
            'Pragma': 'no-cache',
            'Referer': 'http://5sing.kugou.com/',
            'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'
        }
        let data = [];
        if(!fcEnd) {
            const res = (await (axios.get('http://service.5sing.kugou.com/user/songlist', {
                headers,
                params: {
                    userId: artistItem.id,
                    type: 'fc',
                    pageSize,
                    page
                }
            }))).data;
            if(res.count <= page * pageSize) {
                fcEnd = true;
            }
            data = data.concat(res.data.map(_ => ({
                id: _.songId,
                artist: artistItem.name,
                title: _.songName,
                typeEname: 'fc',
                typeName: '翻唱',
                type: _.songType,
                album: '翻唱'
            })))
        }
        if(!ycEnd) {
            const res = (await (axios.get('http://service.5sing.kugou.com/user/songlist', {
                headers,
                params: {
                    userId: artistItem.id,
                    type: 'yc',
                    pageSize,
                    page
                }
            }))).data;
            if(res.count <= page * pageSize) {
                ycEnd = true;
            }
            data = data.concat(res.data.map(_ => ({
                id: _.songId,
                artist: artistItem.name,
                title: _.songName,
                typeEname: 'yc',
                typeName: '原唱',
                type: _.songType,
                album: '原唱'
            })));
        }
        if(!bzEnd) {
            const res = (await (axios.get('http://service.5sing.kugou.com/user/songlist', {
                headers,
                params: {
                    userId: artistItem.id,
                    type: 'bz',
                    pageSize,
                    page
                }
            }))).data;
            if(res.count <= page * pageSize) {
                bzEnd = true;
            }
            data = data.concat(res.data.map(_ => ({
                id: _.songId,
                artist: artistItem.name,
                title: _.songName,
                typeEname: 'bz',
                typeName: '伴奏',
                type: _.songType,
                album: '伴奏'
            })));
        }
        return {
            isEnd: fcEnd && ycEnd && bzEnd,
            data
        }

    }

    async function getArtistWorks(artistItem, page, type) {
        if (type === 'music') {
            return getArtistMusicWorks(artistItem, page);
        }
    }

    async function getLyric(musicItem) {
        const headers = {
            'Accept': '*/*',
            'Accept-Encoding': 'gzip, deflate',
            'Accept-Language': 'zh-CN,zh;q=0.9',
            'Host': 'service.5sing.kugou.com',
            'Referer': 'http://5sing.kugou.com/',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36'
        };
        const res = (await axios.get('http://5sing.kugou.com/fm/m/json/lrc', {
            headers,
            params: {
                songId: musicItem.id,
                songType: musicItem.typeEname
            }
        })).data;
        return {
            rawLrc: res.txt
        }
    }

    async function getAlbumInfo(albumItem) {
        const headers = {
            'Accept': 'application/json, text/plain, */*',
            'Accept-Encoding': 'gzip, deflate',
            'Accept-Language': 'zh-CN,zh;q=0.9',
            'Cache-Control': 'no-cache',
            'Host': 'service.5sing.kugou.com',
            'Origin': 'http://5sing.kugou.com',
            'Referer': 'http://5sing.kugou.com/',
            'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1'
        }
        const res = (await axios.get('http://service.5sing.kugou.com/song/getPlayListSong', {
            headers: headers,
            params: {
                id: albumItem.id,
            }
        })).data;

        return {
            ...albumItem,
            musicList: res.data.map(_ => ({
                id: _.ID,
                typeEname: _.SK,
                title: _.SN,
                artist: _.user.NN,
                singerId: _.user.ID,
                album: albumItem.title,
                artwork: albumItem.artwork,
            }))
        }

    }

    return {
        platform: '5sing',
        version: '0.0.0',
        srcUrl: 'https://gitee.com/maotoumao/MusicFreePlugins/raw/master/5sing.js',
        cacheControl: 'no-cache',
        async search(query, page, type) {
            if (type === 'music') {
                return await searchMusic(query, page);
            }
            if (type === 'album') {
                return await searchAlbum(query, page);
            }
            if (type === 'artist') {
                return await searchArtist(query, page);
            }
        },
        async getMediaSource(musicItem) {
            const headers = {
                'Accept': '*/*',
                'Accept-Encoding': 'gzip, deflate',
                'Accept-Language': 'zh-CN,zh;q=0.9',
                'Host': 'service.5sing.kugou.com',
                'Referer': 'http://5sing.kugou.com/',
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36'
            };
            const res = (await axios.get('http://service.5sing.kugou.com/song/getsongurl', {
                headers,
                params: {
                    songid: musicItem.id,
                    songtype: musicItem.typeEname,
                    from: 'web',
                    version: '6.6.72',
                    _: Date.now()
                }
            })).data;
            const data = JSON.parse(res.substring(1, res.length - 1)).data;

            return {
                url: data.hqurl || data.lqurl || data.squrl
            };
        },
        getAlbumInfo,
        getLyric,
        getArtistWorks

    }
}


code:
function qq(packages) {
    const { axios, CryptoJs } = packages;

    const pageSize = 20;

    function formatMusicItem(_) {
        const albumid = _.albumid || (_.album || {}).id;
        const albummid = _.albummid || (_.album || {}).mid;
        const albumname = _.albumname || (_.album || {}).title;
        return {
            id: _.id || _.songid,
            songmid: _.mid || _.songmid,
            title: _.title || _.songname,
            artist: _.singer.map(s => s.name).join(', '),
            artwork: albummid ? `https://y.gtimg.cn/music/photo_new/T002R300x300M000${albummid}.jpg` : undefined,
            album: albumname,
            lrc: _.lyric || undefined,
            albumid: albumid,
            albummid: albummid,
        }
    }

    function formatAlbumItem(_) {
        return {
            id: _.albumID || _.albumid,
            albumMID: _.albumMID || _.album_mid,
            title: _.albumName || _.album_name,
            artwork: _.albumPic || `https://y.gtimg.cn/music/photo_new/T002R300x300M000${_.albumMID || _.album_mid}.jpg`,
            date: _.publicTime || _.pub_time,
            singerID: _.singerID || _.singer_id,
            artist: _.singerName || _.singer_name,
            singerMID: _.singerMID || _.singer_mid,
            description: _.desc
        }
    }

    function formatArtistItem(_) {
        return {
            name: _.singerName,
            id: _.singerID,
            singerMID: _.singerMID,
            avatar: _.singerPic,
            worksNum: _.songNum
        }
    }

    const searchTypeMap = {
        0: 'song',
        2: 'album',
        1: 'singer',
        3: 'songlist',
        7: 'lyric',
        12: 'mv',
    };

    const headers = {
        referer: 'https://y.qq.com',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36',
        Cookie: 'uin='
    }

    const validSongFilter = (item) => {
        return item.pay.pay_play === 0 || item.pay.payplay === 0
    }

    async function searchBase(query, page, type) {

        const res = (await axios({
            "url": "https://u.y.qq.com/cgi-bin/musicu.fcg",
            "method": "POST",
            "data": {
                "req_1": {
                    "method": "DoSearchForQQMusicDesktop",
                    "module": "music.search.SearchCgiService",
                    "param": {
                        "num_per_page": pageSize,
                        "page_num": page,
                        "query": query,
                        "search_type": type
                    }
                }
            },
            "headers": headers,
            "xsrfCookieName": "XSRF-TOKEN",
            "withCredentials": true
        }
        )).data;

        return {
            isEnd: res.req_1.data.meta.sum <= page * pageSize,
            data: res.req_1.data.body[searchTypeMap[type]].list
        }
    }

    async function searchMusic(query, page) {
        const songs = await searchBase(query, page, 0);

        return {
            isEnd: songs.isEnd,
            data: songs.data.filter(validSongFilter).map(formatMusicItem)
        }
    }

    async function searchAlbum(query, page) {
        const albums = await searchBase(query, page, 2);

        return {
            isEnd: albums.isEnd,
            data: albums.data.map(formatAlbumItem)
        }
    }

    async function searchArtist(query, page) {
        const artists = await searchBase(query, page, 1);

        return {
            isEnd: artists.isEnd,
            data: artists.data.map(formatArtistItem)
        }
    }

    function getQueryFromUrl(key, search) {
        try {
            const sArr = search.split('?');
            let s = '';
            if (sArr.length > 1) {
                s = sArr[1];
            } else {
                return key ? undefined : {};
            }
            const querys = s.split('&');
            const result = {};
            querys.forEach((item) => {
                const temp = item.split('=');
                result[temp[0]] = decodeURIComponent(temp[1]);
            });
            return key ? result[key] : result;
        } catch (err) {
            // 除去search为空等异常
            return key ? '' : {};
        }
    }

    // geturl
    function changeUrlQuery(obj, baseUrl) {
        const query = getQueryFromUrl(null, baseUrl);
        let url = baseUrl.split('?')[0];

        const newQuery = { ...query, ...obj };
        let queryArr = [];
        Object.keys(newQuery).forEach((key) => {
            if (newQuery[key] !== undefined && newQuery[key] !== '') {
                queryArr.push(`${key}=${encodeURIComponent(newQuery[key])}`);
            }
        });
        return `${url}?${queryArr.join('&')}`.replace(/\?$/, '');
    }

    const typeMap = {
        m4a: {
            s: 'C400',
            e: '.m4a',
        },
        128: {
            s: 'M500',
            e: '.mp3',
        },
        320: {
            s: 'M800',
            e: '.mp3',
        },
        ape: {
            s: 'A000',
            e: '.ape',
        },
        flac: {
            s: 'F000',
            e: '.flac',
        },
    };

    async function getSourceUrl(id, type = '128') {
        const mediaId = id;
        let uin = ''
        const guid = (Math.random() * 10000000).toFixed(0);
        const typeObj = typeMap[type];
        const file = `${typeObj.s}${id}${mediaId}${typeObj.e}`;
        const url = changeUrlQuery({
            '-': 'getplaysongvkey',
            g_tk: 5381,
            loginUin: uin,
            hostUin: 0,
            format: 'json',
            inCharset: 'utf8',
            outCharset: 'utf-8¬ice=0',
            platform: 'yqq.json',
            needNewCode: 0,
            data: JSON.stringify({
                req_0: {
                    module: 'vkey.GetVkeyServer',
                    method: 'CgiGetVkey',
                    param: {
                        filename: [file],
                        guid: guid,
                        songmid: [id],
                        songtype: [0],
                        uin: uin,
                        loginflag: 1,
                        platform: '20',
                    },
                },
                comm: {
                    uin: uin,
                    format: 'json',
                    ct: 19,
                    cv: 0,
                    authst: '',
                },
            }),
        }, 'https://u.y.qq.com/cgi-bin/musicu.fcg')
        return (await axios({
            method: 'GET',
            url: url,
            xsrfCookieName: 'XSRF-TOKEN',
            withCredentials: true
        })).data
    }

    async function getAlbumInfo(albumItem) {
        const url = changeUrlQuery({
            data: JSON.stringify({
                comm: {
                    ct: 24,
                    cv: 10000
                },
                albumSonglist: {
                    method: "GetAlbumSongList",
                    param: {
                        albumMid: albumItem.albumMID,
                        albumID: 0,
                        begin: 0,
                        num: 999,
                        order: 2
                    },
                    module: "music.musichallAlbum.AlbumSongList"
                }
            })
        }, 'https://u.y.qq.com/cgi-bin/musicu.fcg?g_tk=5381&format=json&inCharset=utf8&outCharset=utf-8');
        const res = (await axios({
            "url": url,
            "headers": headers,
            "xsrfCookieName": "XSRF-TOKEN",
            "withCredentials": true
        }
        )).data;
        return {
            ...albumItem,
            musicList: res.albumSonglist.data.songList.filter(_ => validSongFilter(_.songInfo)).map((item) => {
                const _ = item.songInfo;
                return formatMusicItem(_)
            })
        }
    }

    async function getArtistSongs(artistItem, page) {
        const url = changeUrlQuery({
            data: JSON.stringify({
                comm: {
                    ct: 24,
                    cv: 0
                },
                singer: {
                    method: "get_singer_detail_info",
                    param: {
                        sort: 5,
                        singermid: artistItem.singerMID,
                        sin: (page - 1) * pageSize,
                        num: pageSize,
                    },
                    module: "music.web_singer_info_svr"
                }
            })
        }, 'http://u.y.qq.com/cgi-bin/musicu.fcg')

        const res = (await axios({
            "url": url,
            "method": "get",
            "headers": headers,
            "xsrfCookieName": "XSRF-TOKEN",
            "withCredentials": true
        }
        )).data;
        return {
            isEnd: res.singer.data.total_song <= page * pageSize,
            data: res.singer.data.songlist.filter(validSongFilter).map(formatMusicItem)
        }
    }

    async function getArtistAlbums(artistItem, page) {
        const url = changeUrlQuery({
            data: JSON.stringify({
                comm: {
                    ct: 24,
                    cv: 0
                },
                singerAlbum: {
                    method: "get_singer_album",
                    param: {
                        singermid: artistItem.singerMID,
                        order: "time",
                        begin: (page - 1) * pageSize,
                        num: pageSize / 1,
                        exstatus: 1
                    },
                    module: "music.web_singer_info_svr"
                }
            })
        }, 'http://u.y.qq.com/cgi-bin/musicu.fcg');
        const res = (await axios({
            url,
            "method": "get",
            "headers": headers,
            "xsrfCookieName": "XSRF-TOKEN",
            "withCredentials": true
        }
        )).data;
        return {
            isEnd: res.singerAlbum.data.total <= page * pageSize,
            data: res.singerAlbum.data.list.map(formatAlbumItem)
        }
    }

    async function getArtistWorks(artistItem, page, type) {
        if (type === 'music') {
            return getArtistSongs(artistItem, page);
        }
        if (type === 'album') {
            return getArtistAlbums(artistItem, page);
        }

    }

    async function getLyric(musicItem) {
        const result = (await axios({
            "url": `http://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg?songmid=${musicItem.songmid}&pcachetime=${new Date().getTime()}&g_tk=5381&loginUin=0&hostUin=0&inCharset=utf8&outCharset=utf-8&notice=0&platform=yqq&needNewCode=0`,
            "headers": { "Referer": "https://y.qq.com", "Cookie": "uin=" },
            "method": "get",
            "xsrfCookieName": "XSRF-TOKEN",
            "withCredentials": true
        }
        )).data;

        const res = JSON.parse(result.replace(/callback\(|MusicJsonCallback\(|jsonCallback\(|\)$/g, ''))

        return {
            rawLrc: CryptoJs.enc.Base64.parse(res.lyric).toString(CryptoJs.enc.Utf8)
        }
    }

    async function importMusicSheet(urlLike) {
        //
        let id;
        if (!id) {
            id = (urlLike.match(/https?:\/\/i\.y\.qq\.com\/n2\/m\/share\/details\/taoge\.html\?.*id=([0-9]+)/) || [])[1];
        }
        if (!id) {
            id = (urlLike.match(/https?:\/\/y\.qq\.com\/n\/ryqq\/playlist\/([0-9]+)/) || [])[1];
        }
        if (!id) {
            return;
        }

        const result = (await axios({
            "url": `http://c.y.qq.com/qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg?type=1&utf8=1&disstid=${id}&loginUin=0`,
            "headers": { "Referer": "https://y.qq.com/n/yqq/playlist", "Cookie": "uin=" },
            "method": "get",
            "xsrfCookieName": "XSRF-TOKEN",
            "withCredentials": true
        }
        )).data;
        const res = JSON.parse(result.replace(/callback\(|MusicJsonCallback\(|jsonCallback\(|\)$/g, ''))
        console.log(res);
        return res.cdlist[0].songlist.filter(validSongFilter).map(formatMusicItem);
    }

    // 接口参考：https://jsososo.github.io/QQMusicApi/#/
    return {
        platform: 'QQ音乐',
        version: '0.0.2',
        srcUrl: 'https://gitee.com/maotoumao/MusicFreePlugins/raw/master/qq.js',
        cacheControl: 'no-cache',
        async search(query, page, type) {
            if (type === 'music') {
                return await searchMusic(query, page);
            }
            if (type === 'album') {
                return await searchAlbum(query, page);
            }
            if (type === 'artist') {
                return await searchArtist(query, page);
            }
        },
        async getMediaSource(musicItem) {
            let purl = '';
            let domain = '';
            const result = await getSourceUrl(musicItem.songmid);
            if (result.req_0 && result.req_0.data && result.req_0.data.midurlinfo) {
                purl = result.req_0.data.midurlinfo[0].purl;
            }
            if (domain === '') {
                domain =
                    result.req_0.data.sip.find(i => !i.startsWith('http://ws')) ||
                    result.req_0.data.sip[0];
            }

            return {
                url: `${domain}${purl}`
            };
        },
        getLyric,
        getAlbumInfo,
        getArtistWorks,
        importMusicSheet
    }
}


code:
var rule={
title:'TVA云播',
host:'http://www.tvyb03.com',
url:'/vod/type/id/fyclass/page/fypage.html',
searchUrl:'/vod/search.html?wd=**&submit=',
searchable:2,//是否启用全局搜索,
quickSearch:0,//是否启用快速搜索,
filterable:0,//是否启用分类筛选,
class_name:'电影&电视剧&综艺&动漫&日韩剧&国产剧&欧美剧&港台剧',
class_url:'1&2&3&4&16&13&15&14',
play_parse:true,
lazy:'',
limit:6,
// 推荐:'ul.myui-vodlist;ul li;*;*;*;*',
推荐:'ul.myui-vodlist;li;*;*;*;*',
// 推荐:'ul.myui-vodlist;ul&&li;*;*;*;*', // 此写法本地js无效
double:true, // 推荐内容是否双层定位
一级:'.myui-vodlist__box;a&&title;.lazyload&&data-original;.tag&&Text;a&&href',
二级:{"title":"h1&&Text;.data:eq(0) a:eq(0)&&Text","img":".lazyload&&data-original","desc":";.data:eq(0) a:eq(2)&&Text;.data:eq(0) a:eq(1)&&Text;.data:eq(2)&&Text;.data:eq(3)&&Text","content":".text-collapse span&&Text","tabs":".myui-panel__head h3","lists":".myui-content__list:eq(#id) li"},
搜索:'ul.myui-vodlist__media li;*;*;*;*',
}


code:
var rule={
    title:'YOKE影视',
    host:'https://qnyoke.top',
    url:'/index.php/vod/show/id/fyclass/page/fypage.html',
    searchUrl:'/index.php/vod/search/page/fypage/wd/**.html',
    searchable:2,//是否启用全局搜索,
    quickSearch:0,//是否启用快速搜索,
    filterable:0,//是否启用分类筛选,
    //class_parse:'.nav-menu-items&&li;a&&Text;a&&href;.*/(.*?).html',
    //cate_exclude:'演员',
    class_name:'电影&电视剧&综艺&动漫&哔站&国产剧&港台剧&日韩剧&欧美剧&直播',
    class_url:'1&2&3&4&5&13&14&15&16&27',
    推荐:'.module-poster-item;a&&title;.lazyload&&data-original;.module-item-note&&Text;a&&href',
    一级:'.module-poster-item;a&&title;.lazyload&&data-original;.module-item-note&&Text;a&&href',
    //二级:{"title":"h1&&Text;","img":".lazyload&&data-original","desc":";;.module-info-item:eq(4) p&&Text;.module-info-item:eq(3) div&&Text;.module-info-item:eq(1) a&&Text","content":".show-desc&&Text","tabs":'#y-playList&&span',"lists":".module-play-list:eq(#id) a"},
    二级:{"title":"h1&&Text;.module-info-tag-link:eq(2)&&Text","img":".lazyload&&data-original","desc":".module-info-content&&.module-info-item:eq(-2)&&Text;.module-info-content&&.module-info-item:eq(-2)&&Text;.module-info-content&&.module-info-item:eq(-2)&&Text;.module-info-content&&.module-info-item:eq(2)&&.module-info-item-content&&Text;.module-info-content&&.module-info-item:eq(1)&&.module-info-item-content&&Text","content":".module-info-introduction-content&&Text","tabs":".module-tab-items-box:eq(0)&&.module-tab-item","lists":".module-list:eq(#id)&&.module-play-list-content a"},
    搜索:'.module-card-item;.module-card-item-title&&Text;.lazyload&&data-original;.module-item-note&&Text;a&&href',
}

path: js/不良帅/YOKE影视.


code:
function bilibili(packages) {
    const { axios, dayjs } = packages;
    const headers = {
        "user-agent":
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.63",
        accept: "*/*",
        "accept-encoding": "gzip, deflate, br",
        "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
    };
    let cookie;

    /** 获取cid */
    async function getCid(bvid, aid) {
        const params = bvid
            ? {
                bvid: bvid,
            }
            : {
                aid: aid,
            };
        const cidRes = (
            await axios.get("https://api.bilibili.com/x/web-interface/view?%s", {
                headers: headers,
                params: params,
            })
        ).data;
        return cidRes;
    }

    /** 格式化 */
    function durationToSec(duration) {
        if (typeof duration === "number") {
            return duration;
        }

        if (typeof duration === "string") {
            var dur = duration.split(":");
            return dur.reduce(function (prev, curr) {
                return 60 * prev + +curr;
            }, 0);
        }

        return 0;
    }

    const searchHeaders = {
        "user-agent":
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.63",
        accept: "application/json, text/plain, */*",
        "accept-encoding": "gzip, deflate, br",
        origin: "https://search.bilibili.com",
        "sec-fetch-site": "same-site",
        "sec-fetch-mode": "cors",
        "sec-fetch-dest": "empty",
        referer: "https://search.bilibili.com/",
        "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
    };
    async function getCookie() {
        if (!cookie) {
            cookie = await axios.get(
                "https://api.bilibili.com/x/frontend/finger/spi",
                { headers: searchHeaders }
            );
        }
    }
    const pageSize = 30;
    async function searchBase(keyword, page, searchType) {
        await getCookie();
        const params = {
            context: "",
            page: page,
            order: "",
            page_size: pageSize,
            keyword: keyword,
            duration: "",
            tids_1: "",
            tids_2: "",
            __refresh__: true,
            _extra: "",
            highlight: 1,
            single_column: 0,
            platform: 'pc',
            from_source: '',
            search_type: searchType,
            dynamic_offset: 0
        };
        const res = (
            await axios.get(
                "https://api.bilibili.com/x/web-interface/search/type",
                {
                    headers: {
                        ...searchHeaders,
                        cookie: `buvid3=${cookie.b_3};buvid4=${cookie.b_4}`,
                    },
                    params: params,
                }
            )
        ).data;
        return res.data;
    }

    async function searchAlbum(keyword, page) {
        const resultData = await searchBase(keyword, page, 'video');
        const albums = resultData.result.map(function (result) {
            return {
                id:
                    result["bvid"] !== null && result["bvid"] !== void 0
                        ? result["bvid"]
                        : result["aid"],
                aid: result.aid,
                bvid: result.bvid,
                artist: result.author,
                title:
                    result.title === null || result.title === void 0
                        ? void 0
                        : result.title.replace(/(\<em(.*?)\>)|(\<\/em\>)/g, ""),
                album:
                    result["bvid"] !== null && result["bvid"] !== void 0
                        ? result["bvid"]
                        : result["aid"],
                artwork: "http:".concat(result.pic),
                description: result.description,
                duration: durationToSec(result.duration),
                tags:
                    result.tag === null || result.tag === void 0
                        ? void 0
                        : result.tag.split(","),
                date: dayjs.unix(result.pubdate).format("YYYY-MM-DD"),
            };
        })
        return {
            isEnd: resultData.numResults <= page * pageSize,
            data: albums
        }

    }

    async function searchArtist(keyword, page) {
        const resultData = await searchBase(keyword, page, 'bili_user');
        const artists = resultData.result.map(result => ({
            name: result.uname,
            id: result.mid,
            fans: result.fans,
            description: result.usign,
            avatar: result.upic,
            worksNum: result.videos
        }));
        return {
            isEnd: resultData.numResults <= page * pageSize,
            data: artists
        }
    }

    async function getArtistWorks(artistItem, page, type) {
        if (type !== 'album') {
            return;
        }

        const queryHeaders = {
            "user-agent":
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.63",
            accept: "application/json, text/plain, */*",
            "accept-encoding": "gzip, deflate, br",
            origin: "https://space.bilibili.com",
            "sec-fetch-site": "same-site",
            "sec-fetch-mode": "cors",
            "sec-fetch-dest": "empty",
            referer: `https://space.bilibili.com/${artistItem.id}/video`,
            "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
        };

        await getCookie();
        const params = {
            mid: artistItem.id,
            ps: 30,
            tid: 0,
            pn: page,
            order: 'pubdate',
            jsonp: 'jsonp'
        };
        const res = (
            await axios.get(
                "https://api.bilibili.com/x/space/arc/search",
                {
                    headers: {
                        ...queryHeaders,
                        cookie: `buvid3=${cookie.b_3};buvid4=${cookie.b_4}`,
                    },
                    params: params,
                }
            )
        ).data;
        const resultData = res.data;
        const albums = resultData.list.vlist.map(function (result) {
            return {
                id:
                    result["bvid"] !== null && result["bvid"] !== void 0
                        ? result["bvid"]
                        : result["aid"],
                aid: result.aid,
                bvid: result.bvid,
                artist: result.author,
                title:
                    result.title === null || result.title === void 0
                        ? void 0
                        : result.title.replace(/(\<em(.*?)\>)|(\<\/em\>)/g, ""),
                album:
                    result["bvid"] !== null && result["bvid"] !== void 0
                        ? result["bvid"]
                        : result["aid"],
                artwork: result.pic,
                description: result.description,
                duration: durationToSec(result.length),
                tags:
                    result.tag === null || result.tag === void 0
                        ? void 0
                        : result.tag.split(","),
                date: dayjs.unix(result.created).format("YYYY-MM-DD"),
            }
        })

        return {
            isEnd: resultData.page.pn * resultData.page.ps >= resultData.page.count,
            data: albums
        }

    }

    return {
        platform: "bilibili",
        appVersion: ">=0.0",
        version: '0.0.1',
        defaultSearchType: 'album',
        cacheControl: 'no-cache',
        srcUrl: 'https://gitee.com/maotoumao/MusicFreePlugins/raw/master/bilibili.js',
        primaryKey: ['id', 'aid', 'bvid', 'cid'],
        async search(keyword, page, type) {
            if (type === 'album') {
                return await searchAlbum(keyword, page);
            }
            if (type === 'artist') {
                return await searchArtist(keyword, page);
            }
        },

        async getMediaSource(musicItem) {
            let cid = musicItem.cid;

            if (!cid) {
                cid = (await getCid(musicItem.bvid, musicItem.aid)).data.cid;
            }

            const _params = musicItem.bvid
                ? {
                    bvid: musicItem.bvid,
                }
                : {
                    aid: musicItem.aid,
                };

            const res = (
                await axios.get("https://api.bilibili.com/x/player/playurl", {
                    headers: headers,
                    params: { ..._params, cid: cid, fnval: 16 },
                })
            ).data;
            let url;

            if (res.data.dash) {
                url = res.data.dash.audio[0].baseUrl;
            } else {
                url = res.data.durl[0].url;
            }

            const hostUrl = url.substring(url.indexOf("/") + 2);
            const _headers = {
                "user-agent":
                    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36 Edg/89.0.774.63",
                accept: "*/*",
                host: hostUrl.substring(0, hostUrl.indexOf("/")),
                "accept-encoding": "gzip, deflate, br",
                connection: "keep-alive",
                referer: "https://www.bilibili.com/video/".concat(
                    (musicItem.bvid !== null && musicItem.bvid !== undefined
                        ? musicItem.bvid
                        : musicItem.aid) ?? ""
                ),
            };
            return {
                url: url,
                headers: _headers,
            };
        },

        async getAlbumInfo(albumItem) {
            const cidRes = await getCid(albumItem.bvid, albumItem.aid);

            const _ref2 =
                cidRes.data !== null && cidRes.data !== void 0 ? cidRes.data : {};
            const cid = _ref2.cid;
            const pages = _ref2.pages;

            let musicList;
            if (pages.length === 1) {
                musicList = [{ ...albumItem, cid: cid }];
            } else {
                musicList = pages.map(function (_) {
                    return {
                        ...albumItem,
                        cid: _.cid,
                        title: _.part,
                        duration: durationToSec(_.duration),
                        id: _.cid,
                    };
                });
            }
            return {
                ...albumItem,
                musicList
            };
        },

        getArtistWorks
    };

}