123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- import req from '../../util/req.js';
- import { formatPlayUrl, randDeviceWithId, jsonParse, randUUID } from '../../util/misc.js';
- import dayjs from 'dayjs';
- import NodeRSA from 'node-rsa';
- import CryptoJS from 'crypto-js';
- let url = 'https://api.tyun77.cn';
- let device = {};
- let timeOffset = 0;
- const appVer = '2.2.9';
- const rsa = NodeRSA(
- `-----BEGIN PUBLIC KEY-----
- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7QHUVAUM7yghB0/3qz5C
- bWX5YYD0ss+uDtbDz5VkTclop6YnCY+1U4aw4z134ljkp/jL0mWnYioZHTTqxXMf
- R5q15FcMZnnn/gMZNj1ZR67/c9ti6WTG0VEr9IdcJgwHwwGak/xQK1Z9htl7TR3Q
- WA45MmpCSSgjVvX4bbV43IjdjSZNm8s5efdlLl1Z+7uJTR024xizhK5NH0/uPmR4
- O8QEtxO9ha3LMmTYTfERzfNmpfDVdV3Rok4eoTzhHmxgqQ0/S0S+FgjHiwrCTFlv
- NCiDhSemnJT+NIzAnMQX4acL5AYNb5PiDD06ZMrtklTua+USY0gSIrG9LctaYvHR
- swIDAQAB
- -----END PUBLIC KEY-----`,
- 'pkcs8-public-pem',
- {
- encryptionScheme: 'pkcs1',
- }
- );
- async function request(reqUrl, ua) {
- let sj = dayjs().unix() - timeOffset;
- let uri = new URL(reqUrl);
- uri.searchParams.append('pcode', '010110010');
- uri.searchParams.append('version', appVer);
- uri.searchParams.append('devid', device.id);
- uri.searchParams.append('package', 'com.sevenVideo.app.android'); // com.xiaoxiaoVideo.app.android
- uri.searchParams.append('sys', 'android');
- uri.searchParams.append('sysver', device.release);
- uri.searchParams.append('brand', device.brand);
- uri.searchParams.append('state', 'on');
- uri.searchParams.append('model', device.model.replaceAll(' ', '_'));
- uri.searchParams.append('sj', sj);
- let keys = [];
- for (const k of uri.searchParams.keys()) {
- keys.push(k);
- }
- keys.sort();
- let tkSrc = uri.pathname;
- for (let k of keys) {
- let v = uri.searchParams.get(k);
- v = encodeURIComponent(v);
- tkSrc += v;
- }
- tkSrc += sj;
- tkSrc += 'XSpeUFjJ';
- console.log(tkSrc);
- let tk = CryptoJS.enc.Hex.stringify(CryptoJS.MD5(tkSrc)).toString().toLowerCase();
- console.log(tk);
- let header = {
- 'User-Agent': ua || 'okhttp/3.12.0',
- T: sj,
- TK: tk,
- };
- if (reqUrl.indexOf('getVideoPlayAuth') > 0) {
- header['TK-VToken'] = rsa.encrypt(`{"videoId":"${uri.searchParams.get('videoId')}","timestamp":"${sj}"}`, 'base64');
- } else if (reqUrl.indexOf('parserUrl') > 0) {
- header['TK-VToken'] = rsa.encrypt(`{"url":"${uri.searchParams.get('url')}","timestamp":"${sj}"}`, 'base64');
- }
- let resp = await req.get(uri.toString(), {
- headers: header,
- });
- let serverTime = resp.headers.date; // dart all response header key is lowercase
- let serverTimeS = dayjs(serverTime).unix();
- timeOffset = dayjs().unix() - serverTimeS;
- return resp.data;
- }
- async function init(inReq, _outResp) {
- console.log(inReq.server.config.kunyu77.testcfg);
- const deviceKey = inReq.server.prefix + '/device';
- device = await inReq.server.db.getObjectDefault(deviceKey, {});
- if (!device.id) {
- device = randDeviceWithId(32);
- device.id = device.id.toLowerCase();
- device.ua = 'Dalvik/2.1.0 (Linux; U; Android ' + device.release + '; ' + device.model + ' Build/' + device.buildId + ')';
- await inReq.server.db.push(deviceKey, device);
- }
- await request(url + '/api.php/provide/getDomain');
- await request(url + '/api.php/provide/config');
- await request(url + '/api.php/provide/checkUpgrade');
- await request(url + '/api.php/provide/channel');
- return {};
- }
- async function home(_inReq, _outResp) {
- let data = (await request(url + '/api.php/provide/filter')).data;
- let classes = [];
- let filterObj = {};
- let filterAll = [];
- for (const key in data) {
- classes.push({
- type_id: key,
- type_name: data[key][0].cat,
- });
- try {
- let typeId = key.toString();
- if (filterAll.length === 0) {
- let filterData = (await request(url + '/api.php/provide/searchFilter?type_id=0&pagenum=1&pagesize=24')).data.conditions;
- // 年份
- let year = {
- key: 'year',
- name: '年份',
- init: '',
- };
- let yearValues = [];
- yearValues.push({ n: '全部', v: '' });
- // yearValues.push({ n: '2022', v: '2022' });
- // yearValues.push({ n: '2021', v: '2021' });
- filterData.y.forEach((e) => {
- yearValues.push({ n: e.name, v: e.value });
- });
- year['value'] = yearValues;
- // 地区
- let area = {
- key: 'area',
- name: '地区',
- init: '',
- };
- let areaValues = [];
- areaValues.push({ n: '全部', v: '' });
- filterData.a.forEach((e) => {
- areaValues.push({ n: e.name, v: e.value });
- });
- area['value'] = areaValues;
- // 类型
- let type = {
- key: 'category',
- name: '类型',
- init: '',
- };
- let typeValues = [];
- typeValues.push({ n: '全部', v: '' });
- filterData.scat.forEach((e) => {
- typeValues.push({ n: e.name, v: e.value });
- });
- type['value'] = typeValues;
- filterAll.push(year, area, type);
- }
- if (filterAll.length !== 0) {
- filterObj[typeId] = filterAll;
- }
- } catch (e) {
- console.log(e);
- }
- }
- return {
- class: classes,
- filters: filterObj,
- };
- }
- async function category(inReq, _outResp) {
- const tid = inReq.body.id;
- const pg = inReq.body.page;
- const extend = inReq.body.filters;
- let reqUrl = url + '/api.php/provide/searchFilter?type_id=' + tid + '&pagenum=' + pg + '&pagesize=24&';
- reqUrl += `year=${extend.year || ''}&category=${extend.category || ''}&area=${extend.area || ''}`;
- let data = (await request(reqUrl)).data;
- let videos = [];
- for (const vod of data.result) {
- videos.push({
- vod_id: vod.id,
- vod_name: vod.title,
- vod_pic: vod.videoCover,
- vod_remarks: vod.msg,
- });
- }
- return {
- page: parseInt(data.page),
- pagecount: data.pagesize,
- limit: 24,
- total: data.total,
- list: videos,
- };
- }
- async function detail(inReq, _outResp) {
- const ids = !Array.isArray(inReq.body.id) ? [inReq.body.id] : inReq.body.id;
- const videos = [];
- for (const id of ids) {
- let data = (await request(url + '/api.php/provide/videoDetail?ids=' + id)).data;
- console.log(data);
- let vod = {
- vod_id: data.id,
- vod_name: data.videoName,
- vod_pic: data.videoCover,
- type_name: data.subCategory,
- vod_year: data.year,
- vod_area: data.area,
- vod_remarks: data.msg,
- vod_actor: data.actor,
- vod_director: data.director,
- vod_content: data.brief.trim(),
- };
- let episodes = (await request(url + '/api.php/provide/videoPlaylist?ids=' + id)).data.episodes;
- let playlist = {};
- for (const episode of episodes) {
- let playurls = episode.playurls;
- for (const playurl of playurls) {
- let from = playurl.playfrom;
- let t = formatPlayUrl(vod.vod_name, playurl.title);
- if (t.length == 0) t = playurl.title.trim();
- if (!playlist.hasOwnProperty(from)) {
- playlist[from] = [];
- }
- playlist[from].push(t + '$' + playurl.playurl);
- }
- }
- vod.vod_play_from = Object.keys(playlist).join('$$$');
- let urls = Object.values(playlist);
- let vod_play_url = [];
- for (const urlist of urls) {
- vod_play_url.push(urlist.join('#'));
- }
- vod.vod_play_url = vod_play_url.join('$$$');
- videos.push(vod);
- }
- return {
- list: videos,
- };
- }
- async function play(inReq, _outResp) {
- const flag = inReq.body.flag;
- const id = inReq.body.id;
- if (flag == 'alivc') {
- const ua = `Dalvik/2.1.0(sevenVideo android)${device.release} ${appVer} ${device.brand}`;
- let data = (await request(url + '/api.php/provide/getVideoPlayAuth?videoId=' + id)).data;
- var s = CryptoJS.enc.Utf8.stringify(CryptoJS.enc.Base64.parse(data.playAuth));
- s = JSON.parse(s);
- const e = {
- AccessKeyId: s.AccessKeyId,
- Action: 'GetPlayInfo',
- AuthInfo: s.AuthInfo,
- AuthTimeout: 3600,
- Channel: 'Android',
- Format: 'JSON',
- Formats: '',
- PlayerVersion: '',
- Rand: randUUID(),
- SecurityToken: s.SecurityToken,
- SignatureMethod: 'HMAC-SHA1',
- SignatureNonce: randUUID(),
- SignatureVersion: '1.0',
- Version: '2017-03-21',
- VideoId: id,
- };
- let keys = Object.keys(e);
- keys.sort();
- let param = keys.map((k) => k + '=' + encodeURIComponent(e[k])).join('&');
- let signSrc = 'GET&%2F&' + encodeURIComponent(param);
- let sign = CryptoJS.enc.Base64.stringify(CryptoJS.HmacSHA1(signSrc, s.AccessKeySecret + '&'));
- param += '&Signature=' + encodeURIComponent(sign);
- const aliurl = 'https://vod.cn-shanghai.aliyuncs.com/?' + param;
- const res = await req.get(aliurl, {
- header: {
- 'User-Agent': ua,
- },
- });
- if (res.status == 200) {
- const p = res.data;
- return {
- parse: 0,
- url: p.PlayInfoList.PlayInfo[0].PlayURL,
- header: {
- 'User-Agent': ua,
- },
- };
- } else {
- return {
- parse: 0,
- url: id,
- };
- }
- }
- let data = (await request(url + '/api.php/provide/parserUrl?url=' + id + '&retryNum=0')).data;
- let playHeader = data.playHeader;
- let jxUrl = data.url;
- if (jxUrl.indexOf(url) >= 0) {
- let result = jsonParse(id, await request(jxUrl));
- result['parse'] = 0;
- if (playHeader) {
- result.header = Object.assign(result.header, playHeader);
- }
- return result;
- } else {
- let res = await req.get(jxUrl, {
- headers: {
- 'user-agent': 'okhttp/3.12.0',
- },
- });
- let result = jsonParse(id, res.data);
- result['parse'] = 0;
- if (playHeader) {
- result.header = Object.assign(result.header, playHeader);
- }
- return result;
- }
- }
- async function search(inReq, _outResp) {
- const pg = inReq.body.page;
- const wd = inReq.body.wd;
- let page = pg || 1;
- if (page == 0) page = 1;
- let data = await request(url + '/api.php/provide/searchVideo?searchName=' + wd + '&pg=' + page, 'okhttp/3.12.0');
- let videos = [];
- for (const vod of data.data) {
- videos.push({
- vod_id: vod.id,
- vod_name: vod.videoName,
- vod_pic: vod.videoCover,
- vod_remarks: vod.msg,
- });
- }
- return {
- page: page,
- pagecount: data.pages,
- list: videos,
- };
- }
- async function test(inReq, outResp) {
- try {
- const prefix = inReq.server.prefix;
- const dataResult = {};
- let resp = await inReq.server.inject().post(`${prefix}/init`);
- dataResult.init = resp.json();
- resp = await inReq.server.inject().post(`${prefix}/home`);
- dataResult.home = resp.json();
- if (dataResult.home.class.length > 0) {
- resp = await inReq.server.inject().post(`${prefix}/category`).payload({
- id: dataResult.home.class[0].type_id,
- page: 1,
- filter: true,
- filters: {},
- });
- dataResult.category = resp.json();
- if (dataResult.category.list.length > 0) {
- resp = await inReq.server.inject().post(`${prefix}/detail`).payload({
- id: dataResult.category.list[0].vod_id, // dataResult.category.list.map((v) => v.vod_id),
- });
- dataResult.detail = resp.json();
- if (dataResult.detail.list.length > 0) {
- dataResult.play = [];
- for (const vod of dataResult.detail.list) {
- const flags = vod.vod_play_from.split('$$$');
- const ids = vod.vod_play_url.split('$$$');
- for (let j = 0; j < flags.length; j++) {
- const flag = flags[j];
- const urls = ids[j].split('#');
- for (let i = 0; i < urls.length && i < 2; i++) {
- resp = await inReq.server
- .inject()
- .post(`${prefix}/play`)
- .payload({
- flag: flag,
- id: urls[i].split('$')[1],
- });
- dataResult.play.push(resp.json());
- }
- }
- }
- }
- }
- }
- resp = await inReq.server.inject().post(`${prefix}/search`).payload({
- wd: '爱',
- page: 1,
- });
- dataResult.search = resp.json();
- return dataResult;
- } catch (err) {
- console.error(err);
- outResp.code(500);
- return { err: err.message, tip: 'check debug console output' };
- }
- }
- export default {
- meta: {
- key: 'kunyu77',
- name: '琨娱七七',
- type: 3,
- },
- api: async (fastify) => {
- fastify.post('/init', init);
- fastify.post('/home', home);
- fastify.post('/category', category);
- fastify.post('/detail', detail);
- fastify.post('/play', play);
- fastify.post('/search', search);
- fastify.get('/test', test);
- },
- };
|