mirror of
https://github.com/alantang1977/X.git
synced 2025-03-11 20:11:05 +02:00
Add files via upload
This commit is contained in:
parent
cea658c6b6
commit
d57ad925e9
1 changed files with 384 additions and 0 deletions
384
js/littleapple_open.js
Normal file
384
js/littleapple_open.js
Normal 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,
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue