From 80c6bda33b5b8b78be888b1871a827bc314ea400 Mon Sep 17 00:00:00 2001 From: badasr <48412637+badasr@users.noreply.github.com> Date: Thu, 14 Dec 2023 15:00:05 +0800 Subject: [PATCH] add caiji r18 --- repo/vod.api.json.collection18.js | 376 ++++++++++++++++++++++++++++++ 1 file changed, 376 insertions(+) create mode 100644 repo/vod.api.json.collection18.js diff --git a/repo/vod.api.json.collection18.js b/repo/vod.api.json.collection18.js new file mode 100644 index 0000000..eccb73e --- /dev/null +++ b/repo/vod.api.json.collection18.js @@ -0,0 +1,376 @@ +// ==MiruExtension== +// @name 18影视集合 +// @version v0.0.1 +// @author Bad +// @lang zh-cn +// @license MIT +// @package vod.api.json.collection18 +// @type bangumi +// @webSite https:// +// @nsfw true +// ==/MiruExtension== + +export default class extends Extension { + apis = { + // '91av': 'https://91av.cyou/api.php/provide/vod/at/json', + '91md': 'https://91md.me/api.php/provide/vod/at/json', + 'madou': 'http://wuxu.cc/api.php/provide/vod/from/mdm3u8/', + 'tianmei': 'http://www.tianmei.pw/api.php/provide/vod/from/m3u8/', + 'madouse': 'http://madouse.cc/api.php/provide/vod/at/json', + 'chujia': 'http://chujia.cc/api.php/provide/vod/from/m3u8/', + 'qqcm': 'https://qqcm.sbs/api.php/provide/vod/at/json', + 'shayuapi': 'https://shayuapi.com/api.php/provide/vod/', + 'apilyzy': 'https://api.apilyzy.com/api.php/provide/vod/', + 'sewozy': 'https://sewozyapi.com/api.php/provide/vod', + 'lajiao': 'https://apilj.com/api.php/provide/vod/at/json/', + 'xiaocao': 'https://www.caoliuzyw.com/api.php/provide/vod', + 'apiyikanapi': 'https://api.yikanapi.com/api.php/provide/vod/at/json', + 'zy018': 'https://www.zy018.com/api.php/provide/vod/at/json', + // '9szy': 'https://9szy.net/api.php/provide/vod/at/json', + // 'apibukazyw': 'https://api.bukazyw.fun/api.php/provide/vod/at/json', + 'kuaiavzy': 'http://kuaiavzy.com/api.php/provide/vod/at/json', + // 'apivodkok2': 'https://api.vodkok2.com/api.php/provide/vod/at/json', + 'maozyapi': 'https://api.maozyapi.com/inc/apijson_vod.php', + 'siwazywtw': 'https://www.siwazyw.tv/api.php/provide/vod/at/json', + 'semao': 'https://caiji.semaozy.net/inc/apijson_vod.php', + 'putaozyw': 'https://caiji.putaozyw.net/inc/apijson_vod.php', + 'apiddapi': 'https://api.ddapi.cc/api.php/provide/vod/at/json', + 'apixbapi': 'https://api.xbapi.cc/api.php/provide/vod/at/json', + 'apiyirenziyuan': 'https://api.yirenziyuan.com/api.php/provide/vod/at/json', + 'seyavod': 'https://api.seyavod.com/api.php/provide/vod/at/json', + // 'jizhiapi': 'https://jizhiapi.com/api.php/provide/vod/at/json', + 'timizy10': 'https://timizy10.cc/api.php/provide/vod/at/json', + 'naixxzy': 'https://naixxzy.com/api.php/provide/vod/at/json', + 'aosikazy': 'https://aosikazy.com/api.php/provide/vod/?ac=list', + 'sexnguon': 'https://api.sexnguon.com/api.php/provide/vod/at/json', + '156249': 'http://156.249.29.8/inc/apijson_vod.php', + 'kkzy': 'https://kkzy.me/api.php/provide/vod/at/json', + // 'apig14o': 'https://api.g14o.cc/api.php/provide/vod/at/json', + 'bominzy': 'https://www.bominzy.com/api.php/provide/vod/at/json', + // '155api': 'https://155api.com/api.php/provide/vod/?ac=list', + // 'avre00': 'https://www.avre00.com/api.php/provide/vod/?ac=list', + 'mtav': 'https://mtav.art/api.php/provide/vod/at/json', + '888dav': 'https://www.888dav.com/api.php/provide/vod/', + 'apittzy': 'https://apittzy.com/api.php/provide/vod/at/json', + '8day': 'https://8day.icu/api.php/provide/vod/at/json', + '5bo1': 'https://5bo1.xyz/api.php/provide/vod/at/json', + '92free': 'http://92free.icu/api.php/provide/vod/at/json', + 'tmav': 'https://tmav.art/api.php/provide/vod/at/json', + 'sezy': 'https://sezy.website/api.php/provide/vod/at/json', + 'xxavs': 'https://xxavs.com/api.php/provide/vod/at/json', + 'auezy': 'https://a.uezy.pw/api.php/provide/vod/at/json', + 'hongxiuzy': 'https://hongxiuzy.com/api.php/provide/vod/', + 'apilsbzy1': 'https://apilsbzy1.com/api.php/provide/vod/at/json', + // 'toto': 'https://to.to-long.com/api.php/provide/vod/at/json', + 'huangpian': 'https://www.pgxdy.com/api/json.php', + 'apittzy': 'https://apittzy.com/api.php/provide/vod/at/json', + // 'huakuiapi': 'https://caiji.huakuiapi.com/inc/apijson_vod.php', + 'hghhh': 'https://hghhh.com/api.php/provide/vod/at/json', + // 'slapibf': 'https://slapibf.com/api.php/provide/vod/at/json', + 'apiyutu': 'https://apiyutu.com/api.php/provide/vod/at/json', + // 'hszy': 'http://hszy.me/api.php/provide/vod/at/json', + 'haopianapi': 'https://haopianapi.com/api.php/provide/vod/at/json', + 'ziyuan': 'https://ziyuan.skm3u8.com/api.php/provide/vod/at/json', + 'jkunzyapi': 'https://jkunzyapi.com/api.php/provide/vod/at/json', + '888dav': 'https://www.888dav.com/api.php/provide/vod/at/json', + 'msnii': 'https://www.msnii.com/api/json.php', + 'xrbsp': 'https://www.xrbsp.com/api/json.php', + 'gdlsp': 'https://www.gdlsp.com/api/json.php', + 'kxgav': 'https://www.kxgav.com/api/json.php', + 'afasu': 'https://www.afasu.com/api/json.php', + // 'lbapi9': 'https://lbapi9.com/api.php/provide/vod/at/json', + 'fhapi9': 'http://fhapi9.com/api.php/provide/vod/at/json' + } + + api = 'https://91md.me/api.php/provide/vod/at/json' + headers = { + 'User-Agent': + 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36' + } + videoInfoCache = {} + apiCategoryCache = {} + defaultApiKey = null + + async latest(page) { + let res + if (!this.defaultApiKey) { + for (const key of Object.keys(this.apis)) { + this.api = this.apis[key] + this.defaultApiKey = key + try { + res = await this.callApi({ page, action: 'videolist' }) + break + } catch (error) { + console.log(`源 ${key} 加载失败,自动切换到下一个源`) + } + } + } else { + res = await this.callApi({ page, action: 'videolist' }) + } + res.list.forEach(item => { + this.videoInfoCache[item.vod_id] = item + }) + return res.list.map(item => ({ + title: item.vod_name, + url: `${this.api}|${item.vod_id}`, + cover: item.vod_pic, + //desc: item.vod_content, + update: item.vod_remarks + })) + } + + async createFilter(filter) { + const api = { + title: '源', + min: 1, + max: 1, + default: this.defaultApiKey || '91av', + options: { + // '91av': '91视频', + '91md': '九麻', + 'madou': '麻豆', + 'tianmei': '天美', + 'madouse': '果冻', + 'chujia': '精东', + 'qqcm': '传媒', + 'shayuapi': '鲨鱼', + 'apilyzy': '老鸭', + 'sewozy': '涩窝', + 'lajiao': '辣椒', + 'xiaocao': '小草', + 'apiyikanapi': '易看', + 'zy018': '十八', + // '9szy': '九色', + // 'apibukazyw': '不卡', + 'kuaiavzy': '快爱', + // 'apivodkok2': 'KOK2', + 'maozyapi': '猫咪', + 'siwazywtw': '袜丝', + 'semao': '色猫', + 'putaozyw': '葡萄', + 'apiddapi': '滴滴', + 'apixbapi': '雪豹', + 'apiyirenziyuan': '依人', + 'seyavod': '色鸭', + // 'jizhiapi': '极致', + 'timizy10': '甜蜜', + 'naixxzy': '奶香', + 'aosikazy': '奥斯', + 'sexnguon': '色南', + '156249': '蛋蛋', + 'kkzy': '写真', + // 'apig14o': '萝莉', + 'bominzy': '博民', + // '155api': '十五', + // 'avre00': '黄瓜', + 'mtav': '桃桃', + '888dav': '八八', + 'apittzy': '天天', + '8day': '八天', + '5bo1': '五播', + '92free': '久爱', + 'tmav': '美亚', + 'sezy': '色网', + 'xxavs': '湿园', + 'auezy': '优异', + 'hongxiuzy': '红袖', + 'apilsbzy1': '色逼', + // 'toto': '橘猫', + 'huangpian': '黄片', + 'apittzy': '探探', + // 'huakuiapi': '花魁', + 'hghhh': '皇冠', + // 'slapibf': '森林', + 'apiyutu': '玉兔', + // 'hszy': '黄色', + 'haopianapi': '好片', + 'ziyuan': '湿裤', + 'jkunzyapi': '鸡坤', + '888dav': '抖阴', + 'msnii': '美女', + 'xrbsp': '淫水', + 'gdlsp': '香奶', + 'kxgav': '白嫖', + 'afasu': '湿妹', + // 'lbapi9': '乐播', + 'fhapi9': '番号' + } + } + + let apiKey = this.defaultApiKey || 'baidu' + + // 选择后切换 api + if (filter && filter.api) { + this.api = this.apis[filter.api[0]] + apiKey = filter.api[0] + } + + return { + api, + category: { + title: '分类', + max: 1, + min: 1, + default: 'all', + options: { + all: '全部', + ...(await this.category(apiKey)) + } + } + } + } + + async search(kw, page, filter) { + const apiKey = filter?.api?.[0] + const category = filter?.category?.[0] + if (kw === '' && (!category || category === 'all')) { + return this.latest(page) + } + let res + if (kw && apiKey === '91av') { + res = await this.callApi({ query: kw, page }) + kw = res.list.map(item => item.vod_id).join() + } + if (kw.split(',').every(s => isNumeric(s))) { + res = await this.callApi({ ids: kw, action: 'videolist' }) + } else if (category && category !== 'all') { + res = await this.callApi({ + type: category, + page, + action: 'videolist' + }) + } else { + res = await this.callApi({ query: kw, page, action: 'videolist' }) + } + res.list.forEach(item => { + this.videoInfoCache[item.vod_id] = item + }) + return res.list.map(item => ({ + title: item.vod_name, + url: `${this.api}|${item.vod_id}`, + cover: item.vod_pic, + //desc: item.vod_content, + update: item.vod_remarks + })) + } + + async detail(url) { + var [api, url] = url.split('|') + const item = + this.videoInfoCache[url] || + (await this.callApi({ ids: url, action: 'videolist', api })).list[0] + const servers = item.vod_play_from.split('$$$') + const episodes = [] + loop: for (const [index, playlist] of Object.entries( + item.vod_play_url.split('$$$') + )) { + const urls = [] + var episodeName, playUrl; + for (const info of rtrim(playlist, '#').split('#')) { + if (info.includes("$")) { + [episodeName, playUrl] = info.split('$') + }else if (info.includes("=")) { + [, playUrl] = info.split('=') + episodeName='play' + }else{ + playUrl=info + episodeName='play' + } + if (!playUrl.endsWith('.m3u8')) { + continue loop + } + urls.push({ + name: episodeName, + url: playUrl + }) + } + episodes.push({ + title: servers[index], + urls + }) + } + var desc = item.vod_blurb + if (!desc) { + desc = item.vod_content + } + + return { + title: item.vod_name, + cover: item.vod_pic, + desc, + episodes + } + } + + async watch(url) { + return { + type: 'hls', + url + } + } + + async category(apiKey) { + if (this.apiCategoryCache[apiKey]) { + return this.apiCategoryCache[apiKey] + } + try { + const res = await this.callApi() + const options = Object.fromEntries( + res.class.map(item => [item.type_id, item.type_name]) + ) + this.apiCategoryCache[apiKey] = options + return options + } catch (error) { + return {} + } + } + + async callApi({ + query, + page = 0, + ids, + type, + pageSize, + action = 'list', + api = this.api + } = {}) { + var params = `?ac=${action}` + if (query) { + params += `&wd=${encodeURIComponent(query)}` + } else if (ids) { + params += `&ids=${ids}` + } + if (page > 0) { + params += `&pg=${page}` + } + if (type) { + params += `&t=${type}` + } + if (pageSize) { + params += `&pagesize=${pageSize}` + } + const options = { + headers: { + ...this.headers, + Referer: api + params, + 'Miru-Url': api + }, + method: 'get' + } + return await this.request(params, options) + } +} + +function rtrim(str, ch) { + let i = str.length + while (i-- && str.charAt(i) === ch); + return str.substring(0, i + 1) +} + +function isNumeric(str) { + if (typeof str != 'string') return false // we only process strings! + return ( + !isNaN(str) && // use type coercion to parse the _entirety_ of the string (`parseFloat` alone does not do this)... + !isNaN(parseFloat(str)) // ...and ensure strings of whitespace fail + ) +}