UNPKG

rsshub

Version:
131 lines (119 loc) 4.36 kB
import { Route } from '@/types'; import { load } from 'cheerio'; import ofetch from '@/utils/ofetch'; import { decodeCipherText, composeMagnetUrl, getUrlType, ensureDomain } from './utils'; // 兼容没有 script 标签的情况,直接解析 dom function getDomList($, detailUrl) { const list = $('.down-list li') .toArray() .map((item) => { item = $(item); const title = item.find('a').attr('title'); const downurl = item.find('a').attr('href'); const urlType = getUrlType(downurl); const enclosureUrl = urlType === 'magnet' ? composeMagnetUrl(downurl) : downurl; return { enclosure_url: enclosureUrl, enclosure_length: '', enclosure_type: 'application/x-bittorrent', title, link: detailUrl, guid: `${title}-${urlType}`, }; }); return list; } export function getItemList($, detailUrl, second) { const encoded = $('.article script[type]') .text() .match(/return p}\('(.*)',(\d+),(\d+),'(.*)'.split\(/); // 若 script 标签没有内容,直接解析 dom if (!encoded) { return getDomList($, detailUrl); } const data = JSON.parse( decodeCipherText(encoded[1], encoded[2], encoded[3], encoded[4].split('|'), 0, {}) .match(/var down_urls=\\'(.*)\\'/)[1] .replaceAll(String.raw`\\"`, '"') .replaceAll(/\\{3}/g, '') ); // support secondary download address const { downurls } = second && data.Data.length > 1 ? data.Data[1] : data.Data[0]; return downurls.map((item) => { const [title, downurl] = item.split('$'); const urlType = getUrlType(downurl); // only magnet need compose trackers const enclosureUrl = urlType === 'magnet' ? composeMagnetUrl(downurl) : downurl; return { enclosure_url: enclosureUrl, enclosure_length: '', enclosure_type: 'application/x-bittorrent', title, link: detailUrl, guid: `${title}-${urlType}`, }; }); } function getMetaInfo($) { const title = $('.article-header .text p').first().find('span').text(); const cover = $('.article-header .pic img').attr('src'); const description = $('.article-related.info p').text(); return { title, cover, description, }; } export const route: Route = { path: '/detail/:id', categories: ['multimedia'], example: '/domp4/detail/LBTANI22222I', parameters: { id: '从剧集详情页 URL 处获取,如:`https://www.xlmp4.com/html/LBTANI22222I.html`,取 `.html` 前面部分' }, features: { requireConfig: false, requirePuppeteer: false, antiCrawler: false, supportBT: true, supportPodcast: false, supportScihub: false, }, radar: [ { source: ['www.xlmp4.com/detail/:id'], }, ], name: '剧集订阅', maintainers: ['savokiss', 'pseudoyu'], handler, description: `::: tip 由于大部分详情页是 \`/html/xxx.html\`,还有部分是 \`/detail/123.html\`,所以此处做了兼容,id 取 \`xxx\` 或者 \`123\` 都可以。 新增 \`second\` 参数,用于选择下载地址二(地址二不可用或者不填都默认地址一),用法: \`/domp4/detail/LBTANI22222I?second=1\`。 域名频繁更换,目前使用 www.xlmp4.com :::`, }; async function handler(ctx) { const id = ctx.req.param('id'); const { domain, second } = ctx.req.query(); let pureId = id; let detailType = 'html'; // compatible for .html suffix in radar if (id.endsWith('.html')) { pureId = id.replace('.html', ''); } // compatible for /detail/123.html && /html/xxx.html if (/^\d+$/.test(pureId)) { detailType = 'detail'; } const detailUrl = `${ensureDomain(ctx, domain)}/${detailType}/${pureId}.html`; const res = await ofetch(detailUrl); const $ = load(res); const list = getItemList($, detailUrl, second); const meta = getMetaInfo($); return { link: detailUrl, title: meta.title || 'domp4电影 - 详情', image: meta.cover, description: meta.description, item: list, }; }