mirror of
https://github.com/develop202/migu_video.git
synced 2025-12-16 14:59:32 +08:00
更新
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
/.git
|
||||
/node_modules
|
||||
/.workflow
|
||||
.git
|
||||
node_modules
|
||||
.workflow
|
||||
*.bak
|
||||
.github
|
||||
.gitignore
|
||||
|
||||
@@ -1,47 +1,39 @@
|
||||
version: '1.0'
|
||||
name: fetch
|
||||
displayName: fetch
|
||||
name: update
|
||||
displayName: update
|
||||
triggers:
|
||||
trigger: auto
|
||||
pr:
|
||||
branches:
|
||||
precise:
|
||||
- main
|
||||
schedule:
|
||||
- cron: '* 0 */2 * * ? *'
|
||||
- cron: '* 0 */6 * * ? *'
|
||||
variables:
|
||||
global:
|
||||
- GITHUB_TOKEN
|
||||
- TOKEN
|
||||
stages:
|
||||
- name: fetchurl
|
||||
displayName: fetchurl
|
||||
- name: update
|
||||
displayName: 更新
|
||||
strategy: naturally
|
||||
trigger: auto
|
||||
executor: []
|
||||
steps:
|
||||
- step: build@nodejs
|
||||
name: fetchurl
|
||||
displayName: fetchurl
|
||||
name: update_files
|
||||
displayName: 更新文件
|
||||
nodeVersion: 21.5.0
|
||||
commands:
|
||||
- git clone https://dream-deve:${TOKEN}@gitee.com/dream-deve/migu_video.git
|
||||
- '# git clone https://develop202:${GITHUB_TOKEN}@github.com/develop202/migu_video.git'
|
||||
- cd migu_video
|
||||
- '# 设置NPM源,提升安装速度'
|
||||
- npm config set registry https://registry.npmmirror.com
|
||||
- '# 执行编译命令 '
|
||||
- '# npm install && node fetchURLByWasm.js'
|
||||
- '# npm install && node fetchURLByAndroid.js'
|
||||
- '# npm install && node fetchURLByAndroidV2.js'
|
||||
- npm install && node fetchURLByAndroid720p.js
|
||||
- '# npm install && node fetchURLByWasmV2.js'
|
||||
- git config user.name "Gitee流水线"
|
||||
- git config user.email "actions@githee.com"
|
||||
- git add .
|
||||
- '# gitee流水线提交 '
|
||||
- git diff --quiet && git diff --staged --quiet || git commit -m "Update by Gitee流水线"
|
||||
- '# git push -f https://dream-deve:${TOKEN}@gitee.com/dream-deve/migu_video.git main:main'
|
||||
- git push
|
||||
caches: []
|
||||
notify: []
|
||||
strategy:
|
||||
retry: '0'
|
||||
timeout: 2
|
||||
timeout: 4
|
||||
21
README.md
21
README.md
@@ -20,8 +20,7 @@ https://gh-proxy.com/https://raw.githubusercontent.com/develop202/migu_video/ref
|
||||
|
||||
# 本地部署
|
||||
|
||||
使用node自带的http模块实现。
|
||||
|
||||
> [!warning]
|
||||
> 注意事项
|
||||
>
|
||||
> 1. 登录后使用不保证安全,请谨慎使用
|
||||
@@ -29,21 +28,21 @@ https://gh-proxy.com/https://raw.githubusercontent.com/develop202/migu_video/ref
|
||||
|
||||
## 配置
|
||||
|
||||
配置信息如下,默认仅本机可用
|
||||
配置信息如下,默认本机和局域网可用
|
||||
|
||||
| 变量名 | 默认值 | 类型 | 介绍 |
|
||||
| --------- | ----------------------- | ------ | ------------------------------------------ |
|
||||
| muserId | | string | 用户id,可在网页端登录获取 |
|
||||
| mtoken | | string | 用户token,可在网页端登录获取 |
|
||||
| mport | 1234 | number | 服务本地启动端口 |
|
||||
| mhost | <http://localhost:1234> | string | 访问地址,用于节目和epg地址生成 |
|
||||
| mrateType | 3 | number | 画质 2:标清 3:高清 4:蓝光(需要登录且有VIP) |
|
||||
| 变量名 | 默认值 | 类型 | 介绍 |
|
||||
| --------- | ------ | ------ | -------------------------------------------- |
|
||||
| muserId | | string | 用户id,可在网页端登录获取 |
|
||||
| mtoken | | string | 用户token,可在网页端登录获取 |
|
||||
| mport | 1234 | number | 本地运行端口号 |
|
||||
| mhost | | string | 公网/自定义访问地址 格式<http://你的ip:1234> |
|
||||
| mrateType | 3 | number | 画质 2:标清 3:高清 4:蓝光(需登录且有VIP) |
|
||||
|
||||
## node
|
||||
|
||||
### 环境要求
|
||||
|
||||
需要 NodeJS 15+ 环境
|
||||
需要 NodeJS 18+ 环境
|
||||
|
||||
### 安装
|
||||
|
||||
|
||||
76
app.js
76
app.js
@@ -16,6 +16,7 @@ let loading = false
|
||||
|
||||
const server = http.createServer(async (req, res) => {
|
||||
|
||||
// console.dir(req, { depth: null })
|
||||
while (loading) {
|
||||
await delay(50)
|
||||
}
|
||||
@@ -25,7 +26,7 @@ const server = http.createServer(async (req, res) => {
|
||||
// 获取请求方法、URL 和请求头
|
||||
const { method, url, headers } = req;
|
||||
|
||||
console.log()
|
||||
// printGreen("")
|
||||
printMagenta("请求地址:" + url)
|
||||
|
||||
if (method != "GET") {
|
||||
@@ -40,13 +41,27 @@ const server = http.createServer(async (req, res) => {
|
||||
}
|
||||
|
||||
// 响应接口内容
|
||||
if (url == "/" || url == "/interface.txt") {
|
||||
if (url == "/" || url == "/interface.txt" || url == "/m3u") {
|
||||
try {
|
||||
// 读取文件内容
|
||||
const data = readFileSync(process.cwd() + "/interface.txt");
|
||||
let data = readFileSync(process.cwd() + "/interface.txt");
|
||||
|
||||
let replaceHost = `http://${headers.host}`
|
||||
|
||||
if (host != "" && (headers["x-real-ip"] || headers["x-forwarded-for"] || host.indexOf(headers.host) != -1)) {
|
||||
replaceHost = host
|
||||
}
|
||||
|
||||
data = `${data}`.replaceAll("${replace}", replaceHost);
|
||||
|
||||
let contentType = 'text/plain;charset=UTF-8'
|
||||
if (url == "/m3u") {
|
||||
// contentType = "audio/mpegurl;charset=UTF-8"
|
||||
contentType = "audio/x-mpegurl; charset=utf-8"
|
||||
res.setHeader('content-disposition', "inline; filename=\"interface.m3u\"");
|
||||
}
|
||||
// 设置响应头
|
||||
res.setHeader('Content-Type', 'text/plain;charset=UTF-8');
|
||||
res.setHeader('Content-Type', contentType);
|
||||
res.statusCode = 200;
|
||||
res.end(data); // 发送文件内容
|
||||
|
||||
@@ -91,7 +106,6 @@ const server = http.createServer(async (req, res) => {
|
||||
let pid = urlSplit
|
||||
let params = ""
|
||||
|
||||
|
||||
if (urlSplit.match(/\?/)) {
|
||||
// 回放
|
||||
printGreen("处理传入参数")
|
||||
@@ -103,7 +117,6 @@ const server = http.createServer(async (req, res) => {
|
||||
printGrey("无参数传入")
|
||||
}
|
||||
|
||||
|
||||
if (isNaN(pid)) {
|
||||
res.writeHead(200, { "Content-Type": "application/json;charset=UTF-8" })
|
||||
res.end("地址错误")
|
||||
@@ -168,13 +181,43 @@ const server = http.createServer(async (req, res) => {
|
||||
return
|
||||
}
|
||||
|
||||
// 直接访问g开头的域名链接时概率会302到不能播放的地址,目前不清楚原因,在这重定向正确地址
|
||||
// printRed(resObj.url)
|
||||
if (resObj.url != "") {
|
||||
let z = 1
|
||||
while (z <= 6) {
|
||||
if (z >= 2) {
|
||||
printYellow(`获取失败,正在第${z - 1}次重试`)
|
||||
}
|
||||
axio
|
||||
const obj = await fetch(`${resObj.url}`, {
|
||||
method: "GET",
|
||||
redirect: "manual"
|
||||
})
|
||||
|
||||
const location = obj.headers.get("Location")
|
||||
if (location.startsWith("http://hlsz")) {
|
||||
resObj.url = location
|
||||
break
|
||||
}
|
||||
if (z == 6) {
|
||||
printRed(`获取失败`)
|
||||
resObj.url = ""
|
||||
} else {
|
||||
await delay(150)
|
||||
}
|
||||
z++
|
||||
}
|
||||
}
|
||||
|
||||
printGreen(`添加节目缓存 ${pid}`)
|
||||
// 加入缓存
|
||||
urlCache[pid] = {
|
||||
// 有效期2小时 节目调整改为2分钟
|
||||
valTime: Date.now() + (resObj.url == "" ? 2 * 60 * 1000 : 2 * 60 * 60 * 1000),
|
||||
// 有效期3小时 节目调整时改为1分钟
|
||||
valTime: Date.now() + (resObj.url == "" ? 1 * 60 * 1000 : 3 * 60 * 60 * 1000),
|
||||
url: resObj.url
|
||||
}
|
||||
// console.log(resObj.url)
|
||||
|
||||
if (resObj.url == "") {
|
||||
printRed(`${pid} 节目调整,暂不提供服务`)
|
||||
@@ -186,7 +229,6 @@ const server = http.createServer(async (req, res) => {
|
||||
}
|
||||
let playURL = resObj.url
|
||||
|
||||
|
||||
// console.dir(playURL, { depth: null })
|
||||
|
||||
// 添加回放参数
|
||||
@@ -199,7 +241,6 @@ const server = http.createServer(async (req, res) => {
|
||||
|
||||
printGreen("链接获取成功")
|
||||
|
||||
|
||||
res.writeHead(302, {
|
||||
'Content-Type': 'application/json;charset=UTF-8',
|
||||
location: playURL
|
||||
@@ -212,10 +253,10 @@ const server = http.createServer(async (req, res) => {
|
||||
|
||||
server.listen(port, async () => {
|
||||
|
||||
// 设置定时器,3小时更新一次
|
||||
// 设置定时器,6小时更新一次
|
||||
setInterval(async () => {
|
||||
printBlue(`\n准备更新文件 ${getDateTimeStr(new Date())}\n`)
|
||||
hours += 3
|
||||
hours += 6
|
||||
try {
|
||||
await update(hours)
|
||||
} catch (error) {
|
||||
@@ -224,7 +265,7 @@ server.listen(port, async () => {
|
||||
}
|
||||
|
||||
printBlue(`\n当前已运行${hours}小时`)
|
||||
}, 3 * 60 * 60 * 1000);
|
||||
}, 6 * 60 * 60 * 1000);
|
||||
|
||||
try {
|
||||
// 初始化数据
|
||||
@@ -234,10 +275,11 @@ server.listen(port, async () => {
|
||||
console.log(error)
|
||||
}
|
||||
|
||||
console.log()
|
||||
printYellow("每6小时更新一次")
|
||||
|
||||
printYellow("定时器设置完毕 每3小时更新一次")
|
||||
printYellow("Server running at port " + port)
|
||||
printYellow("访问地址: " + host)
|
||||
printGreen(`本地地址: http://localhost:${port}`)
|
||||
if (host != "") {
|
||||
printGreen(`自定义地址: ${host}`)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -4,13 +4,14 @@ const userId = process.env.muserId || ""
|
||||
const token = process.env.mtoken || ""
|
||||
// 本地运行端口号
|
||||
const port = process.env.mport || 1234
|
||||
// 访问地址,用于epg和节目访问。
|
||||
// 部署后访问地址是什么就填什么,默认只可本机使用
|
||||
const host = process.env.mhost || "http://localhost:1234"
|
||||
// 公网/自定义访问地址
|
||||
const host = process.env.mhost || ""
|
||||
// 画质
|
||||
// 4蓝光(需要登录且账号有VIP)
|
||||
// 3高清
|
||||
// 2标清
|
||||
const rateType = process.env.mrateType || 3
|
||||
// 是否刷新token,可能是导致封号的原因
|
||||
// const refreshToken = process.env.mrefreshToken || true
|
||||
|
||||
export { userId, token, port, host, rateType }
|
||||
export { userId, token, port, host, rateType/* , refreshToken */ }
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { dataList } from "./utils/fetchList.js"
|
||||
import { dataList, delay } from "./utils/fetchList.js"
|
||||
import { getAndroidURL720p } from "./utils/androidURL.js"
|
||||
import { appendFile, appendFileSync, renameFileSync, writeFile } from "./utils/fileUtil.js"
|
||||
import { updatePlaybackData } from "./utils/playback.js"
|
||||
import { printBlue, printGreen, printMagenta, printRed, printYellow } from "./utils/colorOut.js"
|
||||
import { printBlue, printGreen, printRed, printYellow } from "./utils/colorOut.js"
|
||||
|
||||
async function fetchURLByAndroid720p() {
|
||||
|
||||
@@ -10,11 +10,14 @@ async function fetchURLByAndroid720p() {
|
||||
|
||||
// 获取数据
|
||||
const datas = await dataList()
|
||||
|
||||
printGreen("数据获取成功!")
|
||||
// 必须绝对路径
|
||||
const path = process.cwd() + '/interface.txt.bak'
|
||||
// 创建写入空内容
|
||||
writeFile(path, "")
|
||||
|
||||
printYellow("正在更新...")
|
||||
// 回放
|
||||
const playbackFile = process.cwd() + '/playback.xml.bak'
|
||||
writeFile(playbackFile,
|
||||
@@ -26,30 +29,50 @@ async function fetchURLByAndroid720p() {
|
||||
|
||||
// 分类列表
|
||||
for (let i = 0; i < datas.length; i++) {
|
||||
printBlue(`分类###:${datas[i].name}`)
|
||||
|
||||
const data = datas[i].dataList
|
||||
|
||||
printBlue(`开始更新分类###: ${datas[i].name}`)
|
||||
// 写入节目
|
||||
for (let j = 0; j < data.length; j++) {
|
||||
|
||||
printMagenta(`${data[j].name}:`)
|
||||
const res = await updatePlaybackData(data[j], playbackFile)
|
||||
if (res) {
|
||||
printGreen(` 节目单更新成功`)
|
||||
} else {
|
||||
printRed(` 节目单更新失败`)
|
||||
}
|
||||
await updatePlaybackData(data[j], playbackFile)
|
||||
|
||||
// 获取链接
|
||||
const resObj = await getAndroidURL720p(data[j].pID)
|
||||
if (resObj.url == "") {
|
||||
printRed(` 节目调整,暂不提供服务`)
|
||||
continue
|
||||
|
||||
if (resObj.url != "") {
|
||||
let z = 1
|
||||
while (z <= 6) {
|
||||
if (z >= 2) {
|
||||
printYellow(`${data[j].name} 获取失败,正在第${z - 1}次重试`)
|
||||
}
|
||||
const obj = await fetch(`${resObj.url}`, {
|
||||
method: "GET",
|
||||
redirect: "manual"
|
||||
})
|
||||
|
||||
const location = obj.headers.get("Location")
|
||||
if (location.startsWith("http://hlsz")) {
|
||||
resObj.url = location
|
||||
break
|
||||
}
|
||||
if (z == 6) {
|
||||
resObj.url = ""
|
||||
} else {
|
||||
await delay(150)
|
||||
}
|
||||
z++
|
||||
}
|
||||
}
|
||||
|
||||
if (resObj.url == "") {
|
||||
printRed(`${data[j].name} 更新失败`)
|
||||
continue
|
||||
}
|
||||
// 写入节目
|
||||
appendFile(path, `#EXTINF:-1 tvg-id="${data[j].name}" tvg-name="${data[j].name}" tvg-logo="${data[j].pics.highResolutionH}" group-title="${datas[i].name}",${data[j].name}\n${resObj.url}\n`)
|
||||
printGreen(` 节目链接更新成功`)
|
||||
printGreen(`${data[j].name} 更新成功!`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +81,7 @@ async function fetchURLByAndroid720p() {
|
||||
renameFileSync(playbackFile, playbackFile.replace(".bak", ""))
|
||||
renameFileSync(path, path.replace(".bak", ""))
|
||||
const end = Date.now()
|
||||
printYellow(`本次耗时:${(end - start) / 1000}秒`)
|
||||
printYellow(`本次耗时: ${(end - start) / 1000}秒`)
|
||||
}
|
||||
|
||||
fetchURLByAndroid720p()
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
import { dataList } from "./utils/fetchList.js"
|
||||
import { getAndroidURL } from "./utils/androidURL.js"
|
||||
import refreshToken from "./utils/refreshToken.js"
|
||||
import { appendFile, appendFileSync, renameFileSync, writeFile } from "./utils/fileUtil.js"
|
||||
import { updatePlaybackData } from "./utils/playback.js"
|
||||
import { printBlue, printGreen, printMagenta, printRed, printYellow } from "./utils/colorOut.js"
|
||||
import { token as config_token, userId as config_userId } from "./config.js"
|
||||
|
||||
async function fetchURLByAndroid() {
|
||||
|
||||
const userId = process.env.USERID || config_userId
|
||||
const token = process.env.MIGU_TOKEN || config_token
|
||||
|
||||
const date = new Date()
|
||||
const start = date.getTime()
|
||||
|
||||
// 获取数据
|
||||
const datas = await dataList()
|
||||
|
||||
// 必须绝对路径
|
||||
const path = process.cwd() + '/interface.txt.bak'
|
||||
// 创建写入空内容
|
||||
writeFile(path, "")
|
||||
|
||||
// 回放
|
||||
const playbackFile = process.cwd() + '/playback.xml.bak'
|
||||
writeFile(playbackFile,
|
||||
`<?xml version="1.0" encoding="UTF-8"?>\n` +
|
||||
`<tv generator-info-name="Tak" generator-info-url="https://github.com/develop202/migu_video/">\n`)
|
||||
|
||||
if (!date.getHours()) {
|
||||
// 0点刷新token
|
||||
await refreshToken(userId, token) ? printGreen("token刷新成功") : printRed("token刷新失败")
|
||||
}
|
||||
|
||||
// 写入开头
|
||||
// appendFile(aptvPath, `#EXTM3U x-tvg-url="https://gitee.com/dream-deve/migu_video/raw/main/playback.xml" catchup="append" catchup-source="&playbackbegin=\${(b)yyyyMMddHHmmss}&playbackend=\${(e)yyyyMMddHHmmss}"\n`)
|
||||
appendFile(path, `#EXTM3U x-tvg-url="https://develop202.github.io/migu_video/playback.xml,https://raw.githubusercontent.com/develop202/migu_video/refs/heads/main/playback.xml,https://gh-proxy.com/https://raw.githubusercontent.com/develop202/migu_video/refs/heads/main/playback.xml" catchup="append" catchup-source="&playbackbegin=\${(b)yyyyMMddHHmmss}&playbackend=\${(e)yyyyMMddHHmmss}"\n`)
|
||||
|
||||
// 分类列表
|
||||
for (let i = 0; i < datas.length; i++) {
|
||||
printBlue(`分类###:${datas[i].name}`)
|
||||
|
||||
const data = datas[i].dataList
|
||||
// 写入节目
|
||||
for (let j = 0; j < data.length; j++) {
|
||||
|
||||
printMagenta(`${data[j].name}:`)
|
||||
const res = await updatePlaybackData(data[j], playbackFile)
|
||||
if (res) {
|
||||
printGreen(` 节目单更新成功`)
|
||||
} else {
|
||||
printRed(` 节目单更新失败`)
|
||||
}
|
||||
|
||||
// 获取链接
|
||||
const resObj = await getAndroidURL(userId, token, data[j].pID, 4)
|
||||
if (resObj.url == "") {
|
||||
printRed(` 节目调整,暂不提供服务`)
|
||||
continue
|
||||
}
|
||||
|
||||
// 写入节目
|
||||
appendFile(path, `#EXTINF:-1 svg-id="${data[j].name}" svg-name="${data[j].name}" tvg-logo="${data[j].pics.highResolutionH}" group-title="${datas[i].name}",${data[j].name}\n${resObj.url}\n`)
|
||||
printGreen(` 节目链接更新成功`)
|
||||
}
|
||||
}
|
||||
|
||||
appendFileSync(playbackFile, `</tv>\n`)
|
||||
|
||||
renameFileSync(playbackFile, playbackFile.replace(".bak", ""))
|
||||
renameFileSync(path, path.replace(".bak", ""))
|
||||
const end = Date.now()
|
||||
printYellow(`本次耗时:${(end - start) / 1000}秒`)
|
||||
}
|
||||
|
||||
fetchURLByAndroid()
|
||||
@@ -1,9 +1,9 @@
|
||||
import { dataList } from "./utils/fetchList.js"
|
||||
import { appendFile, appendFileSync, renameFileSync, writeFile } from "./utils/fileUtil.js"
|
||||
import { updatePlaybackData } from "./utils/playback.js"
|
||||
import { host, token, userId } from "./config.js"
|
||||
import { /* refreshToken as mrefreshToken, */ host, token, userId } from "./config.js"
|
||||
import refreshToken from "./utils/refreshToken.js"
|
||||
import { printBlue, printGreen, printMagenta, printRed, printYellow } from "./utils/colorOut.js"
|
||||
import { printGreen, printRed, printYellow } from "./utils/colorOut.js"
|
||||
|
||||
async function update(hours) {
|
||||
|
||||
@@ -12,6 +12,7 @@ async function update(hours) {
|
||||
let interfacePath = ""
|
||||
// 获取数据
|
||||
const datas = await dataList()
|
||||
printGreen("数据获取成功!")
|
||||
|
||||
if (!(hours % 24)) {
|
||||
// 必须绝对路径
|
||||
@@ -22,10 +23,14 @@ async function update(hours) {
|
||||
|
||||
if (!(hours % 24)) {
|
||||
// 每24小时刷新token
|
||||
if (!(userId == "" || token == "")) {
|
||||
if (userId != "" && token != "") {
|
||||
// if (mrefreshToken) {
|
||||
await refreshToken(userId, token) ? printGreen("token刷新成功") : printRed("token刷新失败")
|
||||
// } else {
|
||||
// printGreen(`跳过token刷新`)
|
||||
// }
|
||||
}
|
||||
appendFile(interfacePath, `#EXTM3U x-tvg-url="${host}/playback.xml" catchup="append" catchup-source="?playbackbegin=\${(b)yyyyMMddHHmmss}&playbackend=\${(e)yyyyMMddHHmmss}"\n`)
|
||||
appendFile(interfacePath, `#EXTM3U x-tvg-url="\${replace}/playback.xml" catchup="append" catchup-source="?playbackbegin=\${(b)yyyyMMddHHmmss}&playbackend=\${(e)yyyyMMddHHmmss}"\n`)
|
||||
}
|
||||
printYellow("正在更新...")
|
||||
// 回放
|
||||
@@ -36,26 +41,22 @@ async function update(hours) {
|
||||
|
||||
// 分类列表
|
||||
for (let i = 0; i < datas.length; i++) {
|
||||
if (!(hours % 24)) {
|
||||
printBlue(`分类###:${datas[i].name}`)
|
||||
}
|
||||
|
||||
const data = datas[i].dataList
|
||||
// 写入节目
|
||||
for (let j = 0; j < data.length; j++) {
|
||||
printMagenta(`${data[j].name}:`)
|
||||
const res = await updatePlaybackData(data[j], playbackFile)
|
||||
if (res) {
|
||||
printGreen(` 节目单更新成功`)
|
||||
} else {
|
||||
printRed(` 节目单更新失败`)
|
||||
}
|
||||
|
||||
await updatePlaybackData(data[j], playbackFile)
|
||||
|
||||
if (!(hours % 24)) {
|
||||
// 写入节目
|
||||
appendFile(interfacePath, `#EXTINF:-1 svg-id="${data[j].name}" svg-name="${data[j].name}" tvg-logo="${data[j].pics.highResolutionH}" group-title="${datas[i].name}",${data[j].name}\n${host}/${data[j].pID}\n`)
|
||||
printGreen(` 节目链接更新成功`)
|
||||
appendFile(interfacePath, `#EXTINF:-1 tvg-id="${data[j].name}" tvg-name="${data[j].name}" tvg-logo="${data[j].pics.highResolutionH}" group-title="${datas[i].name}",${data[j].name}\n\${replace}/${data[j].pID}\n`)
|
||||
// printGreen(` 节目链接更新成功`)
|
||||
}
|
||||
}
|
||||
if (!(hours % 24)) {
|
||||
printGreen(`分类###:${datas[i].name} 更新完成!`)
|
||||
}
|
||||
}
|
||||
|
||||
appendFileSync(playbackFile, `</tv>\n`)
|
||||
@@ -65,9 +66,9 @@ async function update(hours) {
|
||||
if (!(hours % 24)) {
|
||||
renameFileSync(interfacePath, interfacePath.replace(".bak", ""))
|
||||
}
|
||||
printYellow("更新完成")
|
||||
printYellow("更新完成!")
|
||||
const end = Date.now()
|
||||
printYellow(`本次耗时:${(end - start) / 1000}秒`)
|
||||
printYellow(`本次耗时: ${(end - start) / 1000}秒`)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -206,7 +206,8 @@ async function getAndroidURL(userId, token, pid, rateType) {
|
||||
|
||||
return {
|
||||
url: resURL,
|
||||
rateType: parseInt(rateType)
|
||||
rateType: parseInt(rateType),
|
||||
content: respData
|
||||
}
|
||||
|
||||
}
|
||||
@@ -265,7 +266,8 @@ async function getAndroidURL720p(pid) {
|
||||
|
||||
return {
|
||||
url: resURL,
|
||||
rateType: parseInt(rateType)
|
||||
rateType: parseInt(rateType),
|
||||
content: respData
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,26 +1,31 @@
|
||||
import { getLogDateTime } from "./time.js"
|
||||
|
||||
function basePrint(color, msg) {
|
||||
console.log(`${color}%s %s\x1B[0m`, `[${getLogDateTime(new Date())}]`, msg)
|
||||
}
|
||||
|
||||
function printRed(msg) {
|
||||
console.log('\x1B[31m%s\x1B[0m', msg)
|
||||
basePrint("\x1B[31m", msg)
|
||||
}
|
||||
|
||||
function printGreen(msg) {
|
||||
console.log('\x1B[32m%s\x1B[0m', msg)
|
||||
basePrint("\x1B[32m", msg)
|
||||
}
|
||||
|
||||
function printYellow(msg) {
|
||||
console.log('\x1B[33m%s\x1B[0m', msg)
|
||||
basePrint("\x1B[33m", msg)
|
||||
}
|
||||
|
||||
function printBlue(msg) {
|
||||
console.log('\x1B[34m%s\x1B[0m', msg)
|
||||
basePrint("\x1B[33m", msg)
|
||||
}
|
||||
|
||||
function printMagenta(msg) {
|
||||
console.log('\x1B[35m%s\x1B[0m', msg)
|
||||
basePrint("\x1B[35m", msg)
|
||||
}
|
||||
|
||||
function printGrey(msg) {
|
||||
console.log('\x1B[2m%s\x1B[0m', msg)
|
||||
basePrint("\x1B[2m", msg)
|
||||
}
|
||||
|
||||
export {
|
||||
|
||||
@@ -9,64 +9,41 @@ function delay(ms) {
|
||||
|
||||
// 获取分类集合
|
||||
async function cateList() {
|
||||
try {
|
||||
const resp = await axios.get("https://program-sc.miguvideo.com/live/v2/tv-data/1ff892f2b5ab4a79be6e25b69d2f5d05")
|
||||
let liveList = resp.data.body.liveList
|
||||
// 热门内容重复
|
||||
liveList = liveList.filter((item) => {
|
||||
return item.name != "热门"
|
||||
})
|
||||
const resp = await axios.get("https://program-sc.miguvideo.com/live/v2/tv-data/1ff892f2b5ab4a79be6e25b69d2f5d05")
|
||||
let liveList = resp.data.body.liveList
|
||||
// 热门内容重复
|
||||
liveList = liveList.filter((item) => {
|
||||
return item.name != "热门"
|
||||
})
|
||||
|
||||
// 央视作为首个分类
|
||||
liveList.sort((a, b) => {
|
||||
if (a.name === "央视") return -1;
|
||||
if (b.name === "央视") return 1
|
||||
return 0
|
||||
})
|
||||
// 央视作为首个分类
|
||||
liveList.sort((a, b) => {
|
||||
if (a.name === "央视") return -1;
|
||||
if (b.name === "央视") return 1
|
||||
return 0
|
||||
})
|
||||
|
||||
return liveList
|
||||
} catch (error) {
|
||||
throw error
|
||||
}
|
||||
return liveList
|
||||
}
|
||||
|
||||
// 所有数据
|
||||
async function dataList() {
|
||||
try {
|
||||
let cates = await cateList()
|
||||
let cates = await cateList()
|
||||
|
||||
for (let cate in cates) {
|
||||
try {
|
||||
const resp = await axios.get("https://program-sc.miguvideo.com/live/v2/tv-data/" + cates[cate].vomsID)
|
||||
cates[cate].dataList = resp.data.body.dataList
|
||||
} catch (error) {
|
||||
cates[cate].dataList = [];
|
||||
}
|
||||
for (let cate in cates) {
|
||||
try {
|
||||
const resp = await axios.get("https://program-sc.miguvideo.com/live/v2/tv-data/" + cates[cate].vomsID)
|
||||
cates[cate].dataList = resp.data.body.dataList
|
||||
} catch (error) {
|
||||
cates[cate].dataList = [];
|
||||
}
|
||||
|
||||
// 去除重复节目
|
||||
cates = uniqueData(cates)
|
||||
// console.dir(cates, { depth: null })
|
||||
// console.log(cates)
|
||||
return cates
|
||||
} catch (error) {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
// 获取电视链接
|
||||
async function getUrlInfo(contId) {
|
||||
try {
|
||||
const resp = await axios.get(`https://webapi.miguvideo.com/gateway/playurl/v2/play/playurlh5?contId=${contId}&rateType=999&clientId=-&startPlay=true&xh265=false&channelId=0131_200300220100002`)
|
||||
// console.log(resp.data.body.urlInfo.url)
|
||||
// console.log(resp.data)
|
||||
if (resp.data?.body?.urlInfo?.url) {
|
||||
return resp.data.body.urlInfo.url
|
||||
}
|
||||
return ""
|
||||
} catch (error) {
|
||||
throw error
|
||||
}
|
||||
// 去除重复节目
|
||||
cates = uniqueData(cates)
|
||||
// console.dir(cates, { depth: null })
|
||||
// console.log(cates)
|
||||
return cates
|
||||
}
|
||||
|
||||
// 对data的dataList去重
|
||||
@@ -120,4 +97,4 @@ function uniqueData(liveList) {
|
||||
return liveList
|
||||
}
|
||||
|
||||
export { cateList, dataList, getUrlInfo, delay }
|
||||
export { cateList, dataList, delay }
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
import puppeteer from 'puppeteer';
|
||||
|
||||
// 打开浏览器
|
||||
async function get_browser(path) {
|
||||
return await puppeteer.launch({
|
||||
args: [
|
||||
"--no-sandbox"
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
// 创建页面
|
||||
async function get_page(browser) {
|
||||
return await browser.newPage();
|
||||
}
|
||||
|
||||
// 获取url
|
||||
async function get_url(page, video_id) {
|
||||
let url = ""
|
||||
let base_url = ""
|
||||
page.on("requestfinished", request => {
|
||||
if (request.url().startsWith("https://hlszymgsplive.miguvideo.com/")) {
|
||||
url = request.url()
|
||||
}
|
||||
if (request.url().startsWith("https://h5live.gslb.cmvideo.cn/")) {
|
||||
base_url = request.url()
|
||||
}
|
||||
})
|
||||
await page.goto('https://m.miguvideo.com/m/liveDetail/' + video_id, { waitUntil: "networkidle2" });
|
||||
return url, base_url
|
||||
}
|
||||
|
||||
// 关闭浏览器
|
||||
async function close_browser(browser) {
|
||||
await browser.close()
|
||||
}
|
||||
|
||||
export { get_browser, get_page, get_url, close_browser }
|
||||
27
utils/net.js
Normal file
27
utils/net.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import os from "os"
|
||||
|
||||
function getLocalIPv(ver = 4) {
|
||||
const ips = []
|
||||
const inter = os.networkInterfaces()
|
||||
// console.dir(inter, { depth: null })
|
||||
for (let net in inter) {
|
||||
|
||||
// console.dir(net, { depth: null })
|
||||
// console.log()
|
||||
for (let netPort of inter[net]) {
|
||||
// netPort = inter[net][netPort]
|
||||
// console.dir(netPort, { depth: null })
|
||||
if (netPort.family === `IPv${ver}`) {
|
||||
// console.dir(netPort, { depth: null })
|
||||
ips.push(netPort.address)
|
||||
}
|
||||
}
|
||||
}
|
||||
// console.log()
|
||||
// console.dir(ips, { depth: null })
|
||||
return ips
|
||||
}
|
||||
|
||||
export {
|
||||
getLocalIPv
|
||||
}
|
||||
@@ -16,4 +16,8 @@ function getDateTimeStr(date) {
|
||||
`${String(date.getHours()).padStart(2, "0")}:${String(date.getMinutes()).padStart(2, "0")}:${String(date.getSeconds()).padStart(2, "0")}`
|
||||
}
|
||||
|
||||
export { getDateString, getTimeString, getDateTimeString, getDateTimeStr }
|
||||
function getLogDateTime(date) {
|
||||
return `${getDateTimeStr(date)}:${String(date.getMilliseconds()).padStart(3, "0")}`
|
||||
}
|
||||
|
||||
export { getDateString, getTimeString, getDateTimeString, getDateTimeStr, getLogDateTime }
|
||||
|
||||
Reference in New Issue
Block a user