Files
migu_video/utils/zbpro.js
2026-01-15 20:07:15 +08:00

118 lines
4.4 KiB
JavaScript

import { printGreen, printMagenta, printRed } from "./colorOut.js"
import crypto from "node:crypto"
import { writeFileSync } from "node:fs"
import { gunzipSync } from "node:zlib"
const KEY_ARRAY = [121, 111, 117, 33, 106, 101, 64, 49, 57, 114, 114, 36, 50, 48, 121, 35]
const IV_ARRAY = [65, 114, 101, 121, 111, 117, 124, 62, 127, 110, 54, 38, 13, 97, 110, 63]
/**
* AES 解密
*/
function AESdecrypt(baseData, keyArray = KEY_ARRAY, ivArray = IV_ARRAY) {
let key = Buffer.from(keyArray)
let iv = Buffer.from(ivArray)
const data = Buffer.from(baseData, "base64")
const decipher = crypto.createDecipheriv("aes-128-cbc", key, iv)
decipher.setAutoPadding(true)
const dest = Buffer.concat([decipher.update(data), decipher.final()])
return dest.toString()
}
async function getAllURL() {
const channelsURLM3U = []
const channelsURLTXT = []
let sumChannel = 0
const headers = { Referer: "http://pro.fengcaizb.com" }
await fetch("http://pro.fengcaizb.com/channels/pro.gz", {
headers: headers
}).then(async pro_gz => {
// await fetch("http://ds.fengcaizb.com/channels/dszb3.gz").then(async pro_gz => {
if (!pro_gz?.ok) {
printRed("请求失败")
return ""
}
const bufferArray = await pro_gz.arrayBuffer()
const buffer = Buffer.from(bufferArray)
printMagenta("开始解压缩...")
const decompressed = gunzipSync(buffer)
printMagenta(`解压缩完成: ${buffer.length}字节 -> ${decompressed.length}字节`)
const resultJSON = decompressed.toString()
// console.log(result)
// console.log(pro_gz)
const result = JSON.parse(resultJSON)
channelsURLM3U.push(`#EXTM3U x-tvg-url="https://cdn.jsdelivr.net/gh/develop202/migu_video/playback.xml,https://ghfast.top/raw.githubusercontent.com/develop202/migu_video/refs/heads/main/playback.xml,https://hk.gh-proxy.org/raw.githubusercontent.com/develop202/migu_video/refs/heads/main/playback.xml,https://develop202.github.io/migu_video/playback.xml,https://raw.githubusercontents.com/develop202/migu_video/refs/heads/main/playback.xml" catchup="append" catchup-source="?playbackbegin=\${(b)yyyyMMddHHmmss}&playbackend=\${(e)yyyyMMddHHmmss}`)
let i = 0
let lastChannelCate = ""
for (const channel of result?.data) {
// 过滤广告频道
if (channel?.ct) {
// printYellow(`${channel?.title} 广告频道, 过滤`)
continue
}
if (channel?.province != lastChannelCate) {
channelsURLTXT.push(`${channel?.province},#genre#`)
lastChannelCate = channel?.province
}
for (const url of channel?.urls) {
i += 1
const decryptURL = AESdecrypt(url)
if (!decryptURL.startsWith("http")) {
// printYellow(`${i} ${channel?.title} 格式错误, 过滤`)
continue
}
if (decryptURL.indexOf("$") != -1) {
// printYellow(`${i} ${channel?.title} 存在特殊字符, 过滤`)
continue
}
// 超时
const controller = new AbortController();
const timeoutId = setTimeout(() => {
controller.abort()
// console.log("请求超时")
}, 300);
const test = await fetch(decryptURL, {
signal: controller.signal
})
.catch(_ => {
// console.log(err)
clearTimeout(timeoutId);
})
clearTimeout(timeoutId);
if (!test?.ok) {
// let msg = test == undefined ? "请求超时" : "无法播放"
// printYellow(`${i} ${channel?.title} ${msg}, 过滤`)
continue
}
const channelURLM3U = `#EXTINF:-1 tvg-id="${channel?.title}" tvg-name="${channel?.title}" tvg-logo="" group-title="${channel?.province}",${channel.title}\n${decryptURL}`
const channelURLTXT = `${channel?.title},${decryptURL}`
channelsURLM3U.push(channelURLM3U)
channelsURLTXT.push(channelURLTXT)
sumChannel += 1
printGreen(`${i} ${sumChannel} ${channel?.title} 添加成功!`)
}
}
})
const m3u = channelsURLM3U.join("\n")
const txt = channelsURLTXT.join("\n")
printGreen(`本次共更新${sumChannel}`)
return {
m3u: m3u,
txt: txt
}
}
async function updateChannels() {
const m3uFilePath = `${process.cwd()}/interface.txt`
const txtFilePath = `${process.cwd()}/interfaceTXT.txt`
const allURL = await getAllURL()
writeFileSync(m3uFilePath, allURL.m3u)
writeFileSync(txtFilePath, allURL.txt)
}
export default updateChannels