From ec1df0a7ba2384209abcba57b6cb8ac4935c9804 Mon Sep 17 00:00:00 2001 From: gyjune <14752+gyjune@noreply.example.org> Date: Wed, 5 Aug 2026 04:28:30 +0200 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6=E8=87=B3?= =?UTF-8?q?=E3=80=8Cjs=E3=80=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/茶杯狐.js | 207 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 js/茶杯狐.js diff --git a/js/茶杯狐.js b/js/茶杯狐.js new file mode 100644 index 0000000..7dbe334 --- /dev/null +++ b/js/茶杯狐.js @@ -0,0 +1,207 @@ +/* +@header({ + searchable: 1, + filterable: 1, + quickSearch: 1, + title: '茶杯狐', + lang: 'cat' +}) +*/ + +const API_HOST = 'http://www.bnjxjd.com'; + +const HEADERS = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', + 'Referer': 'http://www.bnjxjd.com/', +}; + +async function fetchHtml(url) { + try { + const res = await req(url, { headers: HEADERS }); + return res.content || ''; + } catch (e) { + return ''; + } +} + +function fixUrl(url) { + if (!url) return ''; + if (url.startsWith('//')) return 'https:' + url; + if (url.startsWith('http')) return url; + if (url.startsWith('/')) return API_HOST + url; + return API_HOST + '/' + url; +} + +// 直接抓 a 标签 +function parseVideoList(html) { + const videos = []; + if (!html) return videos; + + // 匹配 stui-vodlist__thumb 的 a 标签 + const regex = /]*class="[^"]*stui-vodlist__thumb[^"]*"[^>]*href="([^"]+)"[^>]*title="([^"]*)"[^>]*data-original="([^"]+)"[^>]*>/g; + + let match; + while ((match = regex.exec(html)) !== null) { + videos.push({ + vod_id: fixUrl(match[1]), + vod_name: match[2].trim(), + vod_pic: fixUrl(match[3]), + vod_remarks: '更新中' + }); + } + + return videos; +} + +const CLASSES = [ + { type_id: '1', type_name: '电影' }, + { type_id: '2', type_name: '电视剧' }, + { type_id: '3', type_name: '综艺' }, + { type_id: '4', type_name: '动漫' } +]; + +function init(cfg) { return true; } + +function home(filter) { + return JSON.stringify({ class: CLASSES, filters: {} }); +} + +async function homeVod() { + try { + const html = await fetchHtml(API_HOST + '/'); + const videos = parseVideoList(html); + return JSON.stringify({ list: videos.slice(0, 12) }); + } catch (e) { + return JSON.stringify({ list: [] }); + } +} + +async function category(tid, pg, filter, extend) { + try { + const page = parseInt(pg) || 1; + const url = `${API_HOST}/movie/fenlei${tid}---${page}.html`; + const html = await fetchHtml(url); + const videos = parseVideoList(html); + return JSON.stringify({ + list: videos, + page: page, + pagecount: 9999, + limit: 90, + total: 999999 + }); + } catch (e) { + return JSON.stringify({ list: [] }); + } +} + +async function detail(id) { + try { + let url = id.startsWith('http') ? id : API_HOST + id; + const html = await fetchHtml(url); + + // 提取标题 + let title = ''; + const titleMatch = html.match(/]*class="title"[^>]*>([^<]*)<\/h1>/); + if (titleMatch) title = titleMatch[1].trim(); + + // 提取图片 + let pic = ''; + const picMatch = html.match(/]*class="img-responsive"[^>]*src="([^"]+)"/); + if (picMatch) pic = fixUrl(picMatch[1]); + + // 提取简介 + let content = ''; + const contentMatch = html.match(/]*class="detail-content"[^>]*>([\s\S]*?)<\/span>/); + if (contentMatch) { + content = contentMatch[1].replace(/<[^>]+>/g, '').replace(/\s+/g, ' ').trim(); + } + + // 提取播放列表(剧集) + const playFrom = ['茶杯狐']; + const episodes = []; + + // 匹配播放列表中的链接 + const ulMatch = html.match(/]*class="stui-content__playlist[^"]*"[^>]*>([\s\S]*?)<\/ul>/); + if (ulMatch) { + const ulContent = ulMatch[1]; + const liRegex = /]*>.*?]*href="([^"]+)"[^>]*>([^<]*)<\/a>/g; + let liMatch; + while ((liMatch = liRegex.exec(ulContent)) !== null) { + let epLink = liMatch[1]; + const epName = liMatch[2].trim(); + if (epName && epLink) { + if (!epLink.startsWith('http')) epLink = fixUrl(epLink); + episodes.push(epName + '$' + epLink); + } + } + } + + const vod = { + vod_id: id, + vod_name: title || '未知', + vod_pic: pic || '', + vod_content: content || '', + vod_play_from: playFrom.join('$$$'), + vod_play_url: episodes.join('#') || '' + }; + + return JSON.stringify({ list: [vod] }); + } catch (e) { + return JSON.stringify({ list: [{ vod_id: id, vod_name: '加载失败' }] }); + } +} + +async function search(wd, quick, pg) { + try { + const page = parseInt(pg) || 1; + const url = `${API_HOST}/vodsearch/wd/${encodeURIComponent(wd)}.html?page=${page}`; + const html = await fetchHtml(url); + const videos = parseVideoList(html); + return JSON.stringify({ list: videos, page: page }); + } catch (e) { + return JSON.stringify({ list: [] }); + } +} + +async function play(flag, id, flags) { + let playUrl = id.startsWith('http') ? id : API_HOST + id; + + try { + const html = await fetchHtml(playUrl); + + // 提取真实视频地址 + let realUrl = null; + + // 匹配 m3u8 + const m3u8Match = html.match(/https?:\/\/[^"'\s<>]+\.m3u8[^"'\s<>]*/i); + if (m3u8Match) realUrl = m3u8Match[0]; + + // 匹配 json 中的 url + if (!realUrl) { + const jsonMatch = html.match(/"url"\s*:\s*"([^"]+\.m3u8[^"]*)"/); + if (jsonMatch) realUrl = jsonMatch[1].replace(/\\\//g, '/'); + } + + if (realUrl) { + if (realUrl.startsWith('//')) realUrl = 'https:' + realUrl; + return JSON.stringify({ parse: 0, url: realUrl, header: HEADERS }); + } + + return JSON.stringify({ parse: 1, url: playUrl, header: HEADERS }); + } catch (e) { + return JSON.stringify({ parse: 1, url: playUrl, header: HEADERS }); + } +} + +export function __jsEvalReturn() { + return { + init: init, + home: home, + homeVod: homeVod, + category: category, + detail: detail, + search: search, + play: play + }; +} \ No newline at end of file