mirror of
https://github.com/qitoqito/psyduck.git
synced 2026-01-12 04:30:42 +08:00
417 lines
15 KiB
JavaScript
417 lines
15 KiB
JavaScript
import fs from 'fs'
|
|
import path from 'path';
|
|
import {
|
|
fileURLToPath
|
|
} from 'url';
|
|
import ini from 'ini'
|
|
import axios from "axios";
|
|
import {decryptFile} from "./fileCrypto.js";
|
|
|
|
class Ql {
|
|
constructor() {
|
|
console.log(`Readme: 请先初始化config.ini,打开qitoqito_psyduck/config文件夹,将demo.ini重命名为config.ini\n 设置QINGLONG_ClientId和QINGLONG_ClientSecret(前面;符号要去掉才能正常解析)\n 如需使用脚本分身,请先自行创建分类ini\n 以京东为例,在指定的iniPath目录(默认qitoqito_psyduck/config)自行创建jd.ini\n\n [jd_checkCookie]\n map=jd_task_checkCookie\n ;title=自定义脚本名\n ;crontab=自定义定时(6 6 6 6 6)\n\n 将上述节点代码复制到jd.ini,jd_checkCookie就能映射到jd_task_checkCookie脚本\n`)
|
|
const dirpath = fileURLToPath(
|
|
import.meta.url);
|
|
const abspath = path.dirname(dirpath)
|
|
let iniText = fs.readFileSync(`${abspath}/config/config.ini`, 'UTF-8')
|
|
let obj = ini.parse(iniText)
|
|
this.panelJson = JSON.parse(fs.readFileSync(`${abspath}/config/panel.json`, 'UTF-8'))
|
|
this.env = obj.env
|
|
if (this.env.QINGLONG_ClientId) {
|
|
this.config = {
|
|
baseURL: this.env.QINGLONG_BaseUrl || 'http://127.0.0.1:5700',
|
|
clientId: this.env.QINGLONG_ClientId,
|
|
clientSecret: this.env.QINGLONG_ClientSecret
|
|
};
|
|
}
|
|
else {
|
|
this.config = null
|
|
}
|
|
this.token = null
|
|
}
|
|
|
|
// 获取 token
|
|
async getToken() {
|
|
try {
|
|
const response = await axios.get(`${this.config.baseURL}/open/auth/token`, {
|
|
params: {
|
|
client_id: this.config.clientId,
|
|
client_secret: this.config.clientSecret
|
|
}
|
|
});
|
|
this.token = response.data.data.token;
|
|
return this.token;
|
|
} catch (error) {
|
|
console.error('[Error] 获取qinglong token失败', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async setEnvs(data) {
|
|
const token = this.token
|
|
try {
|
|
const response = await axios.put(`${this.config.baseURL}/open/envs`, data, {
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`
|
|
}
|
|
});
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error('[Error] 更新环境变量失败:', error);
|
|
}
|
|
}
|
|
|
|
// 获取环境变量
|
|
async getEnvs(search = null) {
|
|
const token = this.token
|
|
try {
|
|
const response = await axios.get(`${this.config.baseURL}/open/envs?searchValue=${search}`, {
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`
|
|
}
|
|
});
|
|
return response.data.data;
|
|
} catch (error) {
|
|
console.error('[Error] 获取qinglong环境变量失败:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 添加环境变量
|
|
async addEnv(name, value, remarks = '') {
|
|
const token = this.token
|
|
try {
|
|
const response = await axios.post(`${this.config.baseURL}/open/envs`, [{
|
|
name,
|
|
value,
|
|
remarks
|
|
}], {
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`
|
|
}
|
|
});
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error('[Error] 添加qinglong环境变量失败');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 删除环境变量
|
|
async deleteEnv(envId) {
|
|
const token = this.token
|
|
try {
|
|
const response = await axios.delete(`${this.config.baseURL}/open/envs`, {
|
|
data: [envId],
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`
|
|
}
|
|
});
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error('[Error] 删除qinglong环境变量失败');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 获取定时任务列表
|
|
async getCrons() {
|
|
const token = this.token
|
|
try {
|
|
const response = await axios.get(`${this.config.baseURL}/open/crons`, {
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`
|
|
}
|
|
});
|
|
return response.data.data;
|
|
} catch (error) {
|
|
console.error('[Error] 获取qinglong定时任务失败');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 运行任务
|
|
async runCrons(cronIds) {
|
|
const token = this.token
|
|
try {
|
|
const response = await axios.put(`${this.config.baseURL}/open/crons/run`, cronIds, {
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`
|
|
}
|
|
});
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error('[Error] 运行qinglong任务失败');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 获取任务日志
|
|
async getCronLogs(cronId) {
|
|
const token = this.token
|
|
try {
|
|
const response = await axios.get(`${this.config.baseURL}/open/crons/${cronId}/log`, {
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`
|
|
}
|
|
});
|
|
return response.data.data;
|
|
} catch (error) {
|
|
console.error('获取任务日志失败:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async addCron(command) {
|
|
const token = this.token
|
|
try {
|
|
const response = await axios.post(`${this.config.baseURL}/open/crons`, command, {
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`
|
|
}
|
|
});
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error('[Error] 创建定时任务失败:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async delCron(command) {
|
|
const token = this.token
|
|
try {
|
|
const response = await axios.delete(`${this.config.baseURL}/open/crons`, {
|
|
data: [command.id || command._id],
|
|
headers: {
|
|
'Authorization': `Bearer ${token}`
|
|
}
|
|
});
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error('[Error] 删除定时任务失败:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async wait(t) {
|
|
return new Promise(e => setTimeout(e, t))
|
|
}
|
|
|
|
async create() {
|
|
if (!this.config) {
|
|
console.log("请先初始化config.ini,并设置青龙ClientID和ClientSecret")
|
|
return
|
|
}
|
|
await this.getToken()
|
|
let dirpath = fileURLToPath(
|
|
import.meta.url);
|
|
let abspath = path.dirname(dirpath)
|
|
let iniPath = this.env.iniPath || `${abspath}/config`
|
|
let crons = await this.getCrons()
|
|
let data = {}
|
|
let cronData = crons.data || crons
|
|
let label = crons.data ? true : false
|
|
for (let i of cronData) {
|
|
let command = i.command.match(/task\s*qitoqito_psyduck\/(\w+\.js)/)
|
|
if (command) {
|
|
let script = command[1]
|
|
data[script] = {
|
|
name: i.name,
|
|
schedule: i.schedule,
|
|
id: i.id,
|
|
command: i.command
|
|
}
|
|
}
|
|
}
|
|
let dicts = {}
|
|
let dir = fs.readdirSync(`${abspath}/parse`);
|
|
let panelJson = this.panelJson
|
|
let fileList = []
|
|
dir.forEach(async function(item, index) {
|
|
let config = panelJson.script[item] || {}
|
|
let delList = config.delete || []
|
|
let stat = fs.lstatSync(`${abspath}/parse/` + item)
|
|
if (stat.isDirectory() === true) {
|
|
for (let script of fs.readdirSync(`${abspath}/parse/${item}`)) {
|
|
if (script.match(/\w+\_\w+\_\w/)) {
|
|
fileList.push(`${abspath}/parse/${item}/${script}`)
|
|
}
|
|
}
|
|
}
|
|
}.bind(this))
|
|
await this.wait(1000)
|
|
for (let filePath of fileList) {
|
|
await decryptFile(filePath, filePath)
|
|
}
|
|
dir.forEach(async function(item, index) {
|
|
let config = panelJson.script[item] || {}
|
|
let delList = config.delete || []
|
|
let stat = fs.lstatSync(`${abspath}/parse/` + item)
|
|
if (stat.isDirectory() === true) {
|
|
if (fs.existsSync(`${iniPath}/${item}.ini`)) {
|
|
let iniText = fs.readFileSync(`${iniPath}/${item}.ini`, 'UTF-8')
|
|
let obj = ini.parse(iniText)
|
|
for (let filename in obj) {
|
|
if (obj[filename].map) {
|
|
let map = obj[filename].map
|
|
try {
|
|
let imp = await import (`${abspath}/parse/${item}/${map}.js`)
|
|
let psyDuck = new imp.Main()
|
|
psyDuck.env.delayTo = this.env.delayTo || null
|
|
let crontab = obj[filename].crontab || psyDuck.crontab()
|
|
let title = obj[filename].title || `${psyDuck.profile.title}分身`
|
|
let code = `
|
|
import path from 'path';
|
|
import {fileURLToPath, pathToFileURL} from 'url';
|
|
!(async () => {
|
|
let dirpath = fileURLToPath(import.meta.url).replace('.swap','');
|
|
let abspath = path.dirname(dirpath)
|
|
let filename = dirpath.match(/(\\w+)\\.js/)[1]
|
|
let type = filename.split('_')[0]
|
|
if (['js', 'jx', 'jr', 'jw'].includes(type)) {
|
|
type = 'jd'
|
|
}
|
|
let length = process.argv.length
|
|
let params = {
|
|
filename: "${map}",
|
|
mapping: filename,
|
|
title: "${title}",
|
|
}
|
|
if (length > 2) {
|
|
for (let i = 2; i < length; i++) {
|
|
let key = process.argv[i].match(/^-\\w+$/)
|
|
if (key) {
|
|
params[key[0].substr(1)] = process.argv[i + 1]
|
|
}
|
|
}
|
|
}
|
|
let jsPath = pathToFileURL(\`\${abspath}/parse/\${type}/${map}.js\`).href
|
|
let psyDuck = await import (jsPath)
|
|
let main = new psyDuck.Main()
|
|
await main.init(params)
|
|
})().catch((e) => {
|
|
if (e == 'End') {
|
|
console.log("End")
|
|
}else{
|
|
console.log(e)
|
|
}
|
|
process.exit()
|
|
})`
|
|
fs.writeFile(`${abspath}/${filename}.js`, code, function(err, data) {
|
|
if (err) {
|
|
throw err;
|
|
}
|
|
console.log(`🐯❄️ 写入成功: ${filename}.js`)
|
|
})
|
|
if (!data[`${filename}.js`]) {
|
|
dicts[`${filename}.js`] = {
|
|
name: `PsyDuck_${title}`,
|
|
schedule: crontab,
|
|
command: `task qitoqito_psyduck/${filename}.js`,
|
|
// labels: label ? [`PsyDuck`] : ''
|
|
}
|
|
if (label) {
|
|
dicts[`${filename}.js`].labels = [`PsyDuck`]
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.log(e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for (let script of fs.readdirSync(`${abspath}/parse/${item}`)) {
|
|
if (delList.includes(script)) {
|
|
for (let obj of cronData) {
|
|
if (obj.command.includes(script)) {
|
|
console.log(`🦊🐼 删除任务:`, script)
|
|
await this.delCron(obj)
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
try {
|
|
if (script.match(/\w+\_\w+\_\w/)) {
|
|
let imp = await
|
|
import (`${abspath}/parse/${item}/${script}`)
|
|
let psyDuck = new imp.Main()
|
|
psyDuck.env.delayTo = this.env.delayTo || null
|
|
let crontab = psyDuck.crontab()
|
|
let code = `
|
|
import path from 'path';
|
|
import {fileURLToPath, pathToFileURL} from 'url';
|
|
!(async () => {
|
|
let dirpath = fileURLToPath(import.meta.url).replace('.swap','');
|
|
let abspath = path.dirname(dirpath)
|
|
let filename = dirpath.match(/(\\w+)\\.js/)[1]
|
|
let type = filename.split('_')[0]
|
|
if (['js', 'jx', 'jr', 'jw'].includes(type)) {
|
|
type = 'jd'
|
|
}
|
|
let length = process.argv.length
|
|
let params = {
|
|
filename
|
|
}
|
|
if (length > 2) {
|
|
for (let i = 2; i < length; i++) {
|
|
let key = process.argv[i].match(/^-\\w+$/)
|
|
if (key) {
|
|
params[key[0].substr(1)] = process.argv[i + 1]
|
|
}
|
|
}
|
|
}
|
|
let jsPath = pathToFileURL(\`\${abspath}/parse/\${type}/\${filename}.js\`).href
|
|
let psyDuck = await import (jsPath)
|
|
let main = new psyDuck.Main()
|
|
await main.init(params)
|
|
})().catch((e) => {
|
|
if (e == 'End') {
|
|
console.log("End")
|
|
}else{
|
|
console.log(e)
|
|
}
|
|
process.exit()
|
|
})`
|
|
fs.writeFile(`${abspath}/${script}`, code, function(err, data) {
|
|
if (err) {
|
|
throw err;
|
|
}
|
|
console.log(`🐯❄️ 写入成功: ${script}`)
|
|
})
|
|
if (!data[script]) {
|
|
dicts[script] = {
|
|
name: `PsyDuck_${psyDuck.profile.title}`,
|
|
schedule: crontab,
|
|
command: `task qitoqito_psyduck/${script}`,
|
|
// labels: label ? [`PsyDuck`] : ''
|
|
}
|
|
if (label) {
|
|
dicts[script].labels = [`PsyDuck`]
|
|
}
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.log(`🐽🐽️ 写入失败: ${script}`)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}.bind(this))
|
|
await this.wait(10000)
|
|
let commands = Object.values(dicts)
|
|
for (let i in dicts) {
|
|
try {
|
|
let add = await this.addCron(dicts[i])
|
|
if (add.data.name) {
|
|
console.log('🐯❄️ 任务添加成功: ', i)
|
|
}
|
|
} catch (e) {
|
|
console.log('🐽🐽️ 任务添加失败: ', i)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
let qinglong = new Ql()
|
|
qinglong.create()
|