|
| 1 | +var mv_list = []; |
| 2 | +var authors = []; |
| 3 | +var authorsPy = {}; |
| 4 | +const hots = '周华健,周杰伦,张信哲,陈奕迅,队长,林俊杰,王靖雯,时代少年团,薛之谦,周深,邓寓君,叶泽浩,莫文蔚,小阿七,邓紫棋,郭顶,蓝心羽,李荣浩,程响,蔡健雅,任然,许嵩,张杰,汪苏泷,一颗狼星,王忻辰,王菲,李宇春,不是花火呀,毛不易,王小帅,半吨兄弟,刘至佳,苏星婕,徐佳莹,郁可唯,张碧晨,王力宏,杨丞琳,五月天,周星星,刘大壮,张学友,刘梦妤,旺仔小乔,戴羽彤,陈慧娴,张韶涵,王唯乐,黄龄,易烊千玺,来一碗老于,周传雄,告五人,白小白,李克勤,虎二,黄霄雲,曲肖冰,张靓颖,魏晗,刘德华,房东的猫,孙燕姿,张信哲,大籽,音阙诗听,刘若英,王贰浪,庄心妍,赵雷,小鬼,王以太,方大同,杨宗纬,蒋雪儿,单依纯,林宥嘉,梁静茹,阿肆,陈粒,朴树,许巍,谭咏麟,金志文,蔡依林,李玉刚,马嘉祺,张远,姚六一,王杰,宋亚轩,司南,杨千嬅'; |
| 5 | +const starAuthors = '周杰伦,汪苏泷,李荣浩,蔡依林,筷子兄弟,凤凰传奇,程响'; |
| 6 | +const alphabetList = Array.from({length: 26}, (_, index) => { |
| 7 | + const uppercase = String.fromCharCode(65 + index); // 大写字母 A-Z |
| 8 | + const lowercase = String.fromCharCode(97 + index); // 小写字母 a-z |
| 9 | + // return {n: uppercase, v: lowercase}; |
| 10 | + return {n: uppercase, v: uppercase}; |
| 11 | +}); |
| 12 | +alphabetList.unshift({n: '全部', v: ''}); |
| 13 | +var rule = { |
| 14 | + 类型: '搜索', |
| 15 | + title: '点歌欢唱[B]', |
| 16 | + alias: '点歌欢唱搜索引擎', |
| 17 | + desc: '仅搜索源纯js写法', |
| 18 | + logo: 'https://tva1.sinaimg.cn/crop.6.7.378.378.1024/a22d2331jw8f6hs4xrb4kj20ay0ayacy.jpg', |
| 19 | + host: 'hiker://empty', |
| 20 | + url: '', |
| 21 | + searchUrl: 'hiker://empty', |
| 22 | + headers: { |
| 23 | + 'User-Agent': 'PC_UA', |
| 24 | + }, |
| 25 | + searchable: 1, |
| 26 | + quickSearch: 0, |
| 27 | + filterable: 1, |
| 28 | + double: true, |
| 29 | + play_parse: true, |
| 30 | + limit: 100, |
| 31 | + // class_name: '歌手&歌名&全名', |
| 32 | + // class_url: 'author&name&all', |
| 33 | + filter: { |
| 34 | + author: [ |
| 35 | + {key: 'letters', name: '首字母', value: alphabetList} |
| 36 | + ] |
| 37 | + }, |
| 38 | + // 推荐样式 |
| 39 | + hikerListCol: 'icon_round_2', |
| 40 | + // 分类列表样式 |
| 41 | + hikerClassListCol: 'avatar', |
| 42 | + home_flag: '3-11-S', |
| 43 | + // class_flag: '[CFS][CFPY]1', |
| 44 | + 预处理: async function () { |
| 45 | + let t1 = (new Date()).getTime(); |
| 46 | + let _url = rule.params; |
| 47 | + log(`传入参数:${_url}`); |
| 48 | + let _init = getItem('init'); |
| 49 | + if (_init === '1') { |
| 50 | + mv_list = JSON.parse(pathLib.readFile('./mv/十六万歌曲.json')); |
| 51 | + authors = JSON.parse(pathLib.readFile('./mv/十六万歌曲作者.json')); |
| 52 | + authorsPy = JSON.parse(pathLib.readFile('./mv/十六万歌曲作者拼音.json')); |
| 53 | + } else { |
| 54 | + mv_list = (await request(_url)).split('\n').map((it) => { |
| 55 | + it = it.trim(); |
| 56 | + let _tt = it.split(',')[0]; |
| 57 | + let _uu = it.split(',')[1]; |
| 58 | + let _aa, _nn; |
| 59 | + if (/.+-.+/.test(_tt)) { |
| 60 | + _aa = _tt.split('-')[0].trim() || '未知'; |
| 61 | + _nn = _tt.split('-')[1].trim(); |
| 62 | + } else { |
| 63 | + _aa = '未知'; |
| 64 | + _nn = _tt.trim(); |
| 65 | + } |
| 66 | + return { |
| 67 | + title: _tt, |
| 68 | + url: _uu, |
| 69 | + author: _aa, |
| 70 | + name: _nn, |
| 71 | + title_py: getFirstLetter(_tt), |
| 72 | + author_py: getFirstLetter(_aa), |
| 73 | + name_py: getFirstLetter(_nn) |
| 74 | + } |
| 75 | + }); |
| 76 | + authors = [...new Set(mv_list.filter(it => /[\u4e00-\u9fa5]{2,}/.test(it.author)).map(it => { |
| 77 | + const author = it.author.trim(); |
| 78 | + authorsPy[author] = it.author_py; |
| 79 | + return author; |
| 80 | + }))]; |
| 81 | + authors = authors.sort((a, b) => a.localeCompare(b, 'zh-CN', {numeric: true, sensitivity: 'base'})); |
| 82 | + pathLib.writeFile('./mv/十六万歌曲.json', JSON.stringify(mv_list)); |
| 83 | + pathLib.writeFile('./mv/十六万歌曲作者.json', JSON.stringify(authors)); |
| 84 | + pathLib.writeFile('./mv/十六万歌曲作者拼音.json', JSON.stringify(authorsPy)); |
| 85 | + setItem('init', '1'); |
| 86 | + } |
| 87 | + let t2 = (new Date()).getTime(); |
| 88 | + log(`读取文件并转json耗时:${t2 - t1}毫秒`); |
| 89 | + }, |
| 90 | + lazy: async function () { |
| 91 | + }, |
| 92 | + proxy_rule: async function (params) { |
| 93 | + let {input, proxyPath, getProxyUrl} = this; |
| 94 | + let resp_not_found = [404, 'text/plain', 'not found']; |
| 95 | + return resp_not_found |
| 96 | + }, |
| 97 | + action: async function (action, value) { |
| 98 | + if (action === 'only_search') { |
| 99 | + return '此源为纯搜索源,你直接全局搜索这个源或者使用此页面的源内搜索就好了' |
| 100 | + } |
| 101 | + if (action === '源内搜索') { |
| 102 | + let content = JSON.parse(value); |
| 103 | + return JSON.stringify({ |
| 104 | + action: { |
| 105 | + actionId: '__self_search__', |
| 106 | + skey: '', //目标源key,可选,未设置或为空则使用当前源 |
| 107 | + name: '搜索: ' + content.wd, |
| 108 | + tid: content.wd, |
| 109 | + flag: '1', |
| 110 | + msg: '源内搜索' |
| 111 | + } |
| 112 | + }); |
| 113 | + } |
| 114 | + return `没有动作:${action}的可执行逻辑` |
| 115 | + }, |
| 116 | + class_parse: async () => { |
| 117 | + let classes = [{ |
| 118 | + type_id: 'hot', |
| 119 | + type_name: '热门', |
| 120 | + type_flag: '1' |
| 121 | + }, { |
| 122 | + type_id: 'author', |
| 123 | + type_name: '歌手', |
| 124 | + type_flag: '[CFS][CFPY]1' |
| 125 | + }, { |
| 126 | + type_id: 'name', |
| 127 | + type_name: '歌名', |
| 128 | + type_flag: '[CFS][CFPY]1-11' |
| 129 | + }, { |
| 130 | + type_id: 'all', |
| 131 | + type_name: '全名', |
| 132 | + type_flag: '[CFS][CFPY]1-11' |
| 133 | + }, { |
| 134 | + type_id: '华语歌手-1', |
| 135 | + type_name: '男歌手', |
| 136 | + type_flag: '[CFPY][PY1]2-00-S' |
| 137 | + }, { |
| 138 | + type_id: '华语歌手-2', |
| 139 | + type_name: '女歌手', |
| 140 | + type_flag: '[CFPY][PY1]2-00-S' |
| 141 | + }, { |
| 142 | + type_id: '华语歌手-3', |
| 143 | + type_name: '组合歌手', |
| 144 | + type_flag: '[CFPY][PY1]2-00-S' |
| 145 | + }]; |
| 146 | + return { |
| 147 | + class: classes |
| 148 | + }; |
| 149 | + }, |
| 150 | + 推荐: async function () { |
| 151 | + let {publicUrl} = this; |
| 152 | + let searchIcon = urljoin(publicUrl, './images/icon_cookie/搜索.jpg'); |
| 153 | + let selectData = starAuthors.split(',').map(it => `${it}:=${it}`).join(','); |
| 154 | + return [{ |
| 155 | + vod_id: 'only_search', |
| 156 | + vod_name: '这是个纯搜索源哦', |
| 157 | + vod_pic: 'https://t8.baidu.com/it/u=102347688,62200072&fm=193', |
| 158 | + vod_remarks: `歌手数量:${authors.length}`, |
| 159 | + vod_tag: 'action' |
| 160 | + }, |
| 161 | + { |
| 162 | + vod_id: JSON.stringify({ |
| 163 | + actionId: '源内搜索', |
| 164 | + id: 'wd', |
| 165 | + type: 'input', |
| 166 | + title: '源内搜索', |
| 167 | + tip: '请输入搜索内容', |
| 168 | + value: '', |
| 169 | + selectData: selectData |
| 170 | + }), |
| 171 | + vod_name: '源内搜索', |
| 172 | + vod_pic: searchIcon, |
| 173 | + vod_remarks: `歌曲数量:${mv_list.length}`, |
| 174 | + vod_tag: 'action', |
| 175 | + }]; |
| 176 | + }, |
| 177 | + 一级: async function (tid, pg, filter, extend) { |
| 178 | + let {MY_FL} = this; |
| 179 | + let d = []; |
| 180 | + let _f = rule.limit * (pg - 1); |
| 181 | + let _t = rule.limit * pg; |
| 182 | + let _d = []; |
| 183 | + if (tid === 'hot') { |
| 184 | + _d = hots.split(',').slice(_f, _t); |
| 185 | + _d.forEach(it => { |
| 186 | + d.push({ |
| 187 | + vod_name: it, |
| 188 | + vod_id: 'author#' + it, |
| 189 | + }); |
| 190 | + }); |
| 191 | + } else if (tid === 'author') { |
| 192 | + let _authors = authors; |
| 193 | + if (MY_FL.custom) { |
| 194 | + _authors = authors.filter(_author => _author.includes(MY_FL.custom)); |
| 195 | + } else if (MY_FL.custom_pinyin) { |
| 196 | + _authors = authors.filter(_author => authorsPy[_author].includes(MY_FL.custom_pinyin)); |
| 197 | + } else if (MY_FL.letters) { |
| 198 | + _authors = authors.filter(_author => authorsPy[_author].startsWith(MY_FL.letters)); |
| 199 | + } |
| 200 | + _d = _authors.slice(_f, _t); |
| 201 | + _d.forEach(it => { |
| 202 | + d.push({ |
| 203 | + vod_name: it, |
| 204 | + vod_id: 'author#' + it, |
| 205 | + }); |
| 206 | + }); |
| 207 | + } else if (tid === 'name') { |
| 208 | + let _data = mv_list; |
| 209 | + if (MY_FL.custom) { |
| 210 | + _data = mv_list.filter(it => it.name.includes(MY_FL.custom)); |
| 211 | + } else if (MY_FL.custom_pinyin) { |
| 212 | + _data = mv_list.filter(it => it.name_py.includes(MY_FL.custom_pinyin)); |
| 213 | + } |
| 214 | + _d = _data.slice(_f, _t); |
| 215 | + _d.forEach(it => { |
| 216 | + d.push({ |
| 217 | + vod_name: it.title, |
| 218 | + vod_id: it.url + '#' + it.title, |
| 219 | + }); |
| 220 | + }); |
| 221 | + } else if (tid === 'all') { |
| 222 | + let _data = mv_list; |
| 223 | + if (MY_FL.custom) { |
| 224 | + const words = MY_FL.custom.split('-'); |
| 225 | + if (words.length > 1) { |
| 226 | + _data = mv_list.filter(it => it.author.includes(words[0]) && it.name.includes(words[1])); |
| 227 | + } else { |
| 228 | + _data = mv_list.filter(it => it.title.includes(MY_FL.custom)); |
| 229 | + } |
| 230 | + } else if (MY_FL.custom_pinyin) { |
| 231 | + const words = MY_FL.custom_pinyin.split('-'); |
| 232 | + if (words.length > 1) { |
| 233 | + _data = mv_list.filter(it => it.author_py.includes(words[0]) && it.name_py.includes(words[1])); |
| 234 | + } else { |
| 235 | + _data = mv_list.filter(it => it.title_py.includes(MY_FL.custom_pinyin)); |
| 236 | + } |
| 237 | + } |
| 238 | + _d = _data.slice(_f, _t); |
| 239 | + _d.forEach(it => { |
| 240 | + d.push({ |
| 241 | + vod_name: it.title, |
| 242 | + vod_id: it.url + '#' + it.title, |
| 243 | + }); |
| 244 | + }); |
| 245 | + } else if (tid.startsWith('华语歌手-')) { |
| 246 | + const cate = tid.substring(5); |
| 247 | + const letter = MY_FL.custom_pinyin ? MY_FL.custom_pinyin.substring(0, 1) : ''; |
| 248 | + const url = `https://wapi.kuwo.cn/api/www/artist/artistInfo?category=${cate}&prefix=${letter}&pn=${pg}&rn=60`; |
| 249 | + const data = JSON.parse(await request(url)).data.artistList; |
| 250 | + data.forEach(it => { |
| 251 | + d.push({ |
| 252 | + vod_id: 'author#' + it.name, |
| 253 | + vod_name: it.name, |
| 254 | + vod_pic: it.pic |
| 255 | + }); |
| 256 | + }); |
| 257 | + } else { |
| 258 | + // 仅搜索作者允许翻页,其他情况只有3个固定按钮 |
| 259 | + if (Number(pg) > 1) { |
| 260 | + return [] |
| 261 | + } |
| 262 | + d.push({ |
| 263 | + vod_name: '按歌手搜索', |
| 264 | + vod_id: 'author#' + tid, |
| 265 | + vod_remarks: '', |
| 266 | + }); |
| 267 | + d.push({ |
| 268 | + vod_name: '按歌名搜索', |
| 269 | + vod_id: 'name#' + tid, |
| 270 | + vod_remarks: '', |
| 271 | + }); |
| 272 | + d.push({ |
| 273 | + vod_name: '全名模糊搜索', |
| 274 | + vod_id: 'all#' + tid, |
| 275 | + vod_remarks: '', |
| 276 | + }); |
| 277 | + } |
| 278 | + return d; |
| 279 | + }, |
| 280 | + 二级: async function () { |
| 281 | + let {orId} = this; |
| 282 | + |
| 283 | + let _sname = ''; |
| 284 | + let _vname = ''; |
| 285 | + let data = []; |
| 286 | + let _stype = orId.split('#')[0]; |
| 287 | + _sname = orId.split('#')[1]; |
| 288 | + _vname = ''; |
| 289 | + switch (_stype) { |
| 290 | + case 'author': |
| 291 | + // log('_sname:', _sname); |
| 292 | + _vname = '歌手搜索'; |
| 293 | + data = mv_list.filter(it => it.author.includes(_sname)); |
| 294 | + break; |
| 295 | + case 'name': |
| 296 | + _vname = '歌名搜索'; |
| 297 | + data = mv_list.filter(it => it.name.includes(_sname)); |
| 298 | + break; |
| 299 | + case 'all': |
| 300 | + _vname = '全名搜索'; |
| 301 | + data = mv_list.filter(it => it.title.includes(_sname)); |
| 302 | + break; |
| 303 | + default: |
| 304 | + _vname = '单曲'; |
| 305 | + data = [{title: _sname, url: _stype}]; |
| 306 | + break; |
| 307 | + } |
| 308 | + return { |
| 309 | + vod_id: orId, |
| 310 | + vod_name: `${_vname}:${_sname}`, |
| 311 | + vod_remarks: `共计${data.length}`, |
| 312 | + vod_play_from: '道长源内搜索', |
| 313 | + vod_play_url: data.map(it => it.title + '$' + it.url).join('#') |
| 314 | + } |
| 315 | + }, |
| 316 | + 搜索: async function (wd, quick, pg) { |
| 317 | + if (Number(pg) > 1) { |
| 318 | + return [] |
| 319 | + } |
| 320 | + let d = []; |
| 321 | + d.push({ |
| 322 | + vod_name: '按歌手搜索:' + wd, |
| 323 | + vod_id: 'author#' + wd, |
| 324 | + vod_remarks: '', |
| 325 | + }); |
| 326 | + d.push({ |
| 327 | + vod_name: '按歌名搜索:' + wd, |
| 328 | + vod_id: 'name#' + wd, |
| 329 | + vod_remarks: '', |
| 330 | + }); |
| 331 | + d.push({ |
| 332 | + vod_name: '全名模糊搜索:' + wd, |
| 333 | + vod_id: 'all#' + wd, |
| 334 | + vod_remarks: '', |
| 335 | + }); |
| 336 | + return d |
| 337 | + } |
| 338 | +} |
0 commit comments