first comit

This commit is contained in:
jqtmviyu 2023-03-27 18:23:56 +08:00
commit 5d03218cd9
8 changed files with 388 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules
*.toml

35
app.js Executable file
View File

@ -0,0 +1,35 @@
const schedule = require('node-schedule')
const { request } = require('./js/request')
const { getNowTime, configPaths, getConfig, isExpire } = require('./js/tools')
const { login } = require('./js/login')
const checkin = async () => {
// 遍历配置文件
const paths = await configPaths()
for (const path of paths) {
// 读取配置文件, 并转成对象
const config = await getConfig(path)
// 判断是否过期
if (isExpire(config)) {
const newCnfig = await login(config)
await request(newCnfig.checkinUrl, newCnfig.headers)
} else {
await request(config.checkinUrl, config.headers)
}
}
console.log('全部签到完成!')
}
const main = () => {
// 定时任务
schedule.scheduleJob('0 0 7 * * *', () => {
// 随机10分钟
setTimeout(() => {
checkin()
}, Math.random() * 10 * 60 * 1000)
})
// .invoke()
}
console.log(`开始执行任务-${getNowTime()}`)
main()

19
config/test.toml.example Normal file
View File

@ -0,0 +1,19 @@
fileName = "test"
loginUrl = "https://test/auth/login"
checkinUrl = "https://test/user/checkin"
email = "xxx@gmail.com"
password = "xxx"
expire_in = "xxx"
[headers]
Cookie = "uid=xxx; email=xxx%40gmail.com; key=xxx; ip=xxx; expire_in=xxx"
Host = "test"
Origin = "https://test"
Referer = "https://test/user"
sec-ch-ua = '"Google Chrome";v="111", "Not(A:Brand";v="8", "Chromium";v="111"'
sec-ch-ua-platform = "macOS"
User-Agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"
expire_in = "xxx"
Accept = "*/*"
Accept-Encoding = "gzip, deflate, br"
Connection = "keep-alive"

72
js/login.js Normal file
View File

@ -0,0 +1,72 @@
const axios = require('axios')
const qs = require('qs')
const cookie = require('cookie')
const fs = require('node:fs/promises')
const path = require('node:path')
const toml = require('@iarna/toml')
// 登录成功后, 更新config文件, 同时返回新的config对象
const login = async oldConfig => {
console.log('登录过期, 重新登录中...')
const { loginUrl, email, password } = oldConfig
const data = qs.stringify({ email, passwd: password })
const headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'sec-ch-ua': oldConfig.headers['sec-ch-ua'],
'sec-ch-ua-platform': oldConfig.headers['sec-ch-ua-platform'],
'User-Agent': oldConfig.headers['User-Agent'],
}
let res
res = await axios({
url: loginUrl,
method: 'post',
headers,
data,
maxRedirects: 0,
timeout: 10000,
})
console.log('res', res)
if (res.status == 200) {
console.log('res.data.msg', res.data.msg)
let cookieObj = {}
const setCookie = res.headers['set-cookie'] // array
setCookie.forEach(item => {
cookieObj = Object.assign(cookieObj, cookie.parse(item))
})
const cookieStr = qs.stringify(
{
lang: 'zh-cn',
udi: cookieObj.uid,
email: cookieObj.email,
key: cookieObj.key,
ip: cookieObj.ip,
expire_in: cookieObj['expire_in'],
},
{ delimiter: '; ' }
)
const newConfig = JSON.parse(JSON.stringify(oldConfig))
newConfig.headers.Cookie = cookieStr
newConfig['expire_in'] = cookieObj['expire_in']
// 如果 headers里还有expire_in, 也要更新
if (newConfig.headers.expire_in) {
newConfig.headers['expire_in'] = cookieObj['expire_in']
}
console.log('newConfig', newConfig)
updateConfig(newConfig) // 异步更新
return newConfig
}
}
// 更新config文件
const updateConfig = async newConfig => {
const filePath = path.resolve(
__dirname,
'../config',
newConfig.fileName + (newConfig.fileName.endsWith('.toml') ? '' : '.toml')
)
console.log('filePath', filePath)
await fs.writeFile(filePath, toml.stringify(newConfig), 'utf8')
console.log(`更新 ${newConfig.fileName} 文件成功`)
}
module.exports = { login }

27
js/request.js Normal file
View File

@ -0,0 +1,27 @@
const axios = require('axios')
const { getNowTime } = require('./tools')
const request = async (url, headers) => {
console.log(`\n\n------${getNowTime()} - ${url}:开始签到------\n`)
try {
const res = await axios({
url,
method: 'post',
headers,
timeout: 10000,
})
if (res?.data?.ret === 0) {
console.log(`------ ${getNowTime()} 签到成功 ------\n`)
console.log(res.data.msg)
} else {
console.log(`------ ${getNowTime()} 签到失败 ------\n`)
console.log(JSON.stringify(res))
}
} catch (error) {
console.log(error?.message)
} finally{
return new Promise(resolve => resolve())
}
}
module.exports = { request }

48
js/tools.js Normal file
View File

@ -0,0 +1,48 @@
const fs = require('node:fs/promises')
const path = require('node:path')
const TOML = require('@iarna/toml')
const getNowTime = () => {
return new Date()['toLocaleDateString']()
}
// 监听文件变化
// 遍历配置文件目录下有多少个配置文件, 返回数组
const configPaths = async () => {
try {
let list = []
const files = await fs.readdir(path.resolve(__dirname, '../config'))
files.forEach(file => {
if (file.endsWith('.toml')) {
list.push(path.join(__dirname, '../config', file))
}
})
return list
} catch (error) {
console.log('遍历配置文件失败:\n', error)
}
}
// 异步读取toml文件并返回对象
const getConfig = async path => {
try {
const tomlData = await fs.readFile(path, 'utf8')
const parsedData = TOML.parse(tomlData)
return parsedData
} catch (err) {
console.log('读取toml失败:\n', err)
}
}
// 判断是否登录过期
const isExpire = config => {
const now = Math.floor(Date.now() / 1000)
if (+config.expire_in < now) {
return true
} else {
return false
}
}
module.exports= {isExpire, configPaths, getConfig, getNowTime}

19
package.json Normal file
View File

@ -0,0 +1,19 @@
{
"name": "autoCheckin",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "node ./app.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@iarna/toml": "^2.2.5",
"axios": "^1.3.4",
"cookie": "^0.5.0",
"node-schedule": "^2.1.1",
"qs": "^6.11.1"
}
}

166
pnpm-lock.yaml Normal file
View File

@ -0,0 +1,166 @@
lockfileVersion: 5.4
specifiers:
'@iarna/toml': ^2.2.5
axios: ^1.3.4
cookie: ^0.5.0
node-schedule: ^2.1.1
qs: ^6.11.1
dependencies:
'@iarna/toml': 2.2.5
axios: 1.3.4
cookie: 0.5.0
node-schedule: 2.1.1
qs: 6.11.1
packages:
/@iarna/toml/2.2.5:
resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==}
dev: false
/asynckit/0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
dev: false
/axios/1.3.4:
resolution: {integrity: sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==}
dependencies:
follow-redirects: 1.15.2
form-data: 4.0.0
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
dev: false
/call-bind/1.0.2:
resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==}
dependencies:
function-bind: 1.1.1
get-intrinsic: 1.2.0
dev: false
/combined-stream/1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
dependencies:
delayed-stream: 1.0.0
dev: false
/cookie/0.5.0:
resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
engines: {node: '>= 0.6'}
dev: false
/cron-parser/4.8.1:
resolution: {integrity: sha512-jbokKWGcyU4gl6jAfX97E1gDpY12DJ1cLJZmoDzaAln/shZ+S3KBFBuA2Q6WeUN4gJf/8klnV1EfvhA2lK5IRQ==}
engines: {node: '>=12.0.0'}
dependencies:
luxon: 3.3.0
dev: false
/delayed-stream/1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
dev: false
/follow-redirects/1.15.2:
resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
dev: false
/form-data/4.0.0:
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
engines: {node: '>= 6'}
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
mime-types: 2.1.35
dev: false
/function-bind/1.1.1:
resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
dev: false
/get-intrinsic/1.2.0:
resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==}
dependencies:
function-bind: 1.1.1
has: 1.0.3
has-symbols: 1.0.3
dev: false
/has-symbols/1.0.3:
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
engines: {node: '>= 0.4'}
dev: false
/has/1.0.3:
resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
engines: {node: '>= 0.4.0'}
dependencies:
function-bind: 1.1.1
dev: false
/long-timeout/0.1.1:
resolution: {integrity: sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w==}
dev: false
/luxon/3.3.0:
resolution: {integrity: sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg==}
engines: {node: '>=12'}
dev: false
/mime-db/1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
dev: false
/mime-types/2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
dependencies:
mime-db: 1.52.0
dev: false
/node-schedule/2.1.1:
resolution: {integrity: sha512-OXdegQq03OmXEjt2hZP33W2YPs/E5BcFQks46+G2gAxs4gHOIVD1u7EqlYLYSKsaIpyKCK9Gbk0ta1/gjRSMRQ==}
engines: {node: '>=6'}
dependencies:
cron-parser: 4.8.1
long-timeout: 0.1.1
sorted-array-functions: 1.3.0
dev: false
/object-inspect/1.12.3:
resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==}
dev: false
/proxy-from-env/1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
dev: false
/qs/6.11.1:
resolution: {integrity: sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ==}
engines: {node: '>=0.6'}
dependencies:
side-channel: 1.0.4
dev: false
/side-channel/1.0.4:
resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
dependencies:
call-bind: 1.0.2
get-intrinsic: 1.2.0
object-inspect: 1.12.3
dev: false
/sorted-array-functions/1.3.0:
resolution: {integrity: sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA==}
dev: false