Add files via upload

This commit is contained in:
alantang 2025-02-01 20:48:46 +08:00 committed by GitHub
parent cea658c6b6
commit d57ad925e9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

384
js/littleapple_open.js Normal file
View file

@ -0,0 +1,384 @@
import { Crypto, Uri, _ } from 'assets://js/lib/cat.js';
let key = 'littleapple';
let HOST = ''
let siteKey = '';
let siteType = 0;
const APP_VER = '1.3.3';
const FULL_VER = 'XPGBOX com.phoenix.tv' + APP_VER;
const UA = 'okhttp/3.12.11';
let SIGN;
let TOKEN;
let TOKEN2;
async function request(reqUrl, method, data) {
const res = await req(reqUrl, {
method: method || 'get',
headers: getHeaders(),
data: data,
postType: method === 'post' ? 'form' : '',
});
return res.content;
}
function getHeaders() {
if (!SIGN || !TOKEN || !TOKEN2) {
SIGN = generateSignContent();
TOKEN = generateToken(SIGN);
TOKEN2 = generateToken('eT/G/wE7YQpBbk02LN1uGw8s2cOPPAj9jVVkjWjY6BQ=');
}
const timestamp = Math.floor(new Date().getTime() / 1000).toString();
const hash = getHash(SIGN, timestamp);
const headers = {
'token': TOKEN,
'token2': TOKEN2,
'user_id': 'XPGBOX',
'version': FULL_VER,
'timestamp': timestamp,
'hash': hash,
'screenx': 2331,
'screeny': 1121,
'User-Agent': UA,
};
return headers;
}
function getHash(signContent, timestamp) {
const signStr = signContent + FULL_VER + timestamp;
const md5 = Crypto.MD5(signStr).toString();
return md5.substring(8, 12);
}
function generateSignContent() {
const separator = '||';
const serial = 'unknown';
const fingerprint = 'HUAWEI/INE-LX2/HWINE:9/HUAWEIINE-LX2/9.1.0.318C636:user/release-keys';
const strArr = [];
strArr.push(randStr(16));
strArr.push(randStr(16));
const intCount = 6;
const int8Arr = new Int8Array(intCount);
for (let i = 0; i < intCount; i++) {
const random = _.random(0, 127);
int8Arr[i] = random;
}
const byte = int8Arr[0];
int8Arr[0] = (byte & (byte ^ 1));
const byteStr = _.map(int8Arr, (value) => value.toString(16).padStart(2, '0')).join('').toUpperCase();
strArr.push(byteStr);
strArr.push(randStr(16));
strArr.push(serial);
strArr.push(fingerprint);
return strArr.join(separator);
}
const charStr = 'abacdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789';
function randStr(len, withNum) {
var _str = '';
let containsNum = withNum === undefined ? true : withNum;
for (var i = 0; i < len; i++) {
let idx = _.random(0, containsNum ? charStr.length - 1 : charStr.length - 11);
_str += charStr[idx];
}
return _str;
}
function generateToken(text) {
const data = Crypto.enc.Utf8.parse(text);
const uint8Array = wordArrayToUint8Array(data);
const encoded = encodeBytes(uint8Array);
const words = uint8ArrayToWordArray(encoded);
return Crypto.enc.Base64.stringify(words);
}
function wordArrayToUint8Array(wordArray) {
let words = wordArray.words;
let sigBytes = wordArray.sigBytes;
let uint8Array = new Uint8Array(sigBytes);
for (let i = 0; i < sigBytes; i++) {
let byte = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
uint8Array[i] = byte;
}
return uint8Array;
}
function uint8ArrayToWordArray(uint8Array) {
let len = uint8Array.length;
let words = [];
for (let i = 0; i < len; i++) {
words[i >>> 2] |= (uint8Array[i] & 0xff) << (24 - (i % 4) * 8);
}
return Crypto.lib.WordArray.create(words, len);
}
function encodeBytes(byteArray) {
let result = null;
const key = Crypto.enc.Utf8.parse('XPINGGUO');
const keyBytes = wordArrayToUint8Array(key);
const table = new Int8Array(333);
for (let i = 0; i < 333; i++) {
table[i] = i;
}
let index1 = 0;
let index2 = 0;
const keyLength = keyBytes.length;
for (let i = 0; i < 333; i++) {
let keyByte = keyBytes[index2];
let tableByte = table[i];
index1 = ((index1 + (((((keyByte & (keyByte ^ (-256))) - 4) + (tableByte & (tableByte ^ (-256)))) + 4) + 17)) - 17) % 333;
let temp = table[i];
table[i] = table[index1];
table[index1] = temp;
index2 = (index2 + 1) % keyLength;
}
result = table;
const encryptedData = new Int8Array(byteArray.length);
index1 = 0;
index2 = 0;
for (let i = 0; i < byteArray.length; i++) {
let pos = (index1 + 1) % 333;
const tableByte = result[pos];
index2 = ((tableByte & (tableByte ^ -256)) + index2) % 333;
const temp = result[pos];
result[pos] = result[index2];
result[index2] = temp;
const b6 = result[pos];
const b7 = result[index2];
const b8 = result[(-((-(b6 & (b6 ^ (-256)))) - (b7 & (b7 ^ (-256))))) % 333];
const inputByte = byteArray[i];
encryptedData[i] = (b8 & ~inputByte) | (~b8 & inputByte);
index1 = pos;
}
return encryptedData;
}
// cfg = {skey: siteKey, ext: extend}
async function init(cfg) {
siteKey = cfg.skey;
siteType = cfg.stype;
await requestAppHost();
}
async function requestAppHost() {
const resp = await request('http://194.147.100.39/api.php/v3.user/tokenlogin?version=' + APP_VER + '&os=4', 'post', {});
try {
const encrypted = JSON.parse(resp).data;
const key = Crypto.enc.Utf8.parse('XPINGGUOXPINGGUO');
const decrypted = Crypto.AES.decrypt(encrypted, key, {
mode: Crypto.mode.ECB,
padding: Crypto.pad.Pkcs7
});
const json = Crypto.enc.Utf8.stringify(decrypted).substring(8);
const data = JSON.parse(json);
const uri = new Uri(data.apiurl);
uri.setPath('/api.php');
HOST = uri.toString();
} catch(e) {
HOST = 'http://tipu.xjqxz.top/api.php';
}
}
async function home(filter) {
const url = HOST + '/v2.vod/androidtypes';
const homeResult = await request(url);
const json = JSON.parse(homeResult);
const filters = {};
const classes = _.map(json.data, (item) => {
const filter = getFilters(item);
filters[item.type_id] = filter;
return {
type_id: item.type_id,
type_name: item.type_name,
};
});
return {
class: classes,
filters: filters,
};
}
function getFilters(data) {
const filterArray = [];
const clazz = convertTypeData(data, 'classes', '类型');
if (clazz) filterArray.push(clazz);
const area = convertTypeData(data, 'areas', '地区');
if (area) filterArray.push(area);
const year = convertTypeData(data, 'years', '年份');
if (year) filterArray.push(year);
const by = {
key: 'by',
name: '排序',
init: '',
value: [
{'n':'时间','v':'updatetime'},
{'n':'人气','v':'hits'},
{'n':'评分','v':'score'},
]
};
filterArray.push(by);
return filterArray;
}
function convertTypeData(typeData, typeKey, typeName) {
if (!typeData || !typeData[typeKey] || _.isEmpty(typeData[typeKey])) {
return null;
}
let valueList = typeData[typeKey];
const values = _.map(valueList, (item) => {
return {
n: item,
v: item,
};
});
values.unshift({
n: '全部',
v: '',
});
const typeClass = {
key: typeKey,
name: typeName,
init: '',
value: values,
};
return typeClass;
}
async function homeVod() {
const url = HOST + '/v2.main/androidhome';
const homeResult = await request(url);
const json = JSON.parse(homeResult);
const filters = {};
const videos = [];
videos.push({
vod_id: json.data.top.id,
vod_name: json.data.top.name,
vod_pic: json.data.top.pic,
vod_remarks: json.data.top.state,
});
for (const list of json.data.list) {
for (const item of list.list) {
videos.push({
vod_id: item.id,
vod_name: item.name,
vod_pic: item.pic,
vod_remarks: item.state,
});
}
}
return {
list: videos,
};
}
async function category(tid, pg, filter, extend) {
const limit = 20;
const areaPath = extend.areas ? ('&area=' + extend.areas) : '';
const classPath = extend.classes ? ('&class=' + extend.classes) : '';
const yearPath = extend.years ? ('&year=' + extend.years) : '';
const byPath = extend.by ? ('&sortby=' + extend.by) : '';
const url = HOST + '/v2.vod/androidfilter?page=' + pg + '&type=' + tid + areaPath + yearPath + byPath + classPath;
const cateResult = await request(url);
const json = JSON.parse(cateResult);
const videos = _.map(json.data, (vObj) => {
return {
vod_id: vObj.id,
vod_name: vObj.name,
vod_pic: vObj.pic,
vod_remarks: vObj.state,
};
});
const hasMore = !_.isEmpty(videos);
const page = parseInt(pg);
const pageCount = hasMore ? page + 1 :page;
return {
page: page,
pagecount: pageCount,
limit: limit,
total: pageCount * limit,
list: videos,
};
}
async function detail(id) {
const url = HOST + '/v3.vod/androiddetail2?vod_id=' + id;
const detailResult = await request(url);
const content = JSON.parse(detailResult);
const vObj = content.data;
const vodAtom = {
vod_id: id,
vod_name: vObj.name,
vod_pic: vObj.pic,
type_name: vObj.className,
vod_year: vObj.year,
vod_area: vObj.area,
vod_remarks: vObj.state,
vod_actor: vObj.actor,
vod_director: vObj.director,
vod_content: vObj.content,
}
const playInfo = vObj.urls;
const vodItems = _.map(playInfo, (epObj) => {
const epName = epObj.key;
const playUrl = epObj.url;
return epName + '$' + playUrl;
});
vodAtom.vod_play_from = '主力源';
vodAtom.vod_play_url = vodItems.join('#');
return {
list: [vodAtom],
};
}
async function play(flag, id, flags) {
let playUrl = id;
if (!playUrl.startsWith('http')) {
playUrl = 'http://c.xpgtv.net/m3u8/' + id + '.m3u8';
}
return {
parse: 0,
url: playUrl,
header: getHeaders(),
};
}
async function search(wd, quick, pg) {
const limit = 20;
const url = HOST + '/v2.vod/androidsearch10086?page=' + pg + '&wd=' + encodeURIComponent(wd);
const searchResult = await request(url);
const json = JSON.parse(searchResult);
const videos = _.map(json.data, (vObj) => {
return {
vod_id: vObj.id,
vod_name: vObj.name,
vod_pic: vObj.pic,
vod_remarks: vObj.state,
};
});
const page = parseInt(pg);
const hasMore = limit * page < json.totalcount;
const pageCount = hasMore ? page + 1 :page;
return {
page: page,
pagecount: pageCount,
limit: limit,
total: pageCount * limit,
list: videos,
};
}
export function __jsEvalReturn() {
return {
init: init,
home: home,
homeVod: homeVod,
category: category,
detail: detail,
play: play,
search: search,
};
}