🎉初始化仓库
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
.idea
|
38
README.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# R-plugin
|
||||||
|
个人团队用的Yunzai-bot插件,插件的各种业务来源于周围人
|
||||||
|
<img src="https://cdn.jsdelivr.net/gh/xianxincoder/xianxincoder/assets/github-contribution-grid-snake.svg">
|
||||||
|
|
||||||
|
## 🗃️文件架构
|
||||||
|
apps -- 业务核心
|
||||||
|
|
||||||
|
config -- 配置文件
|
||||||
|
|
||||||
|
model -- 核心文件[建议不动]
|
||||||
|
|
||||||
|
resource -- 资源文件
|
||||||
|
|
||||||
|
test -- 爬虫文件[python]
|
||||||
|
|
||||||
|
index -- 主入口
|
||||||
|
|
||||||
|
## 📔使用说明
|
||||||
|
1. `test -- main.py`爬取链接
|
||||||
|
> python3 main.py
|
||||||
|
2. 下载mongodb
|
||||||
|
> linux系统下自己装一个mongodb,上一个密码(不上有风险)
|
||||||
|
3. 在`Yunzai-Bot`安装mongodb依赖
|
||||||
|
> pnpm i mongodb
|
||||||
|
4. 下载插件
|
||||||
|
> 注:可以不用mongodb这些操作,只是用不了一些命令而已
|
||||||
|
|
||||||
|
## 📦业务
|
||||||
|

|
||||||
|
|
||||||
|
## 🤳版本
|
||||||
|

|
||||||
|
|
||||||
|
## 🚀后记
|
||||||
|
* 文件借鉴了很多插件,精简个人认为可以精简的内容。
|
||||||
|
* 素材来源于网络,仅供交流学习使用
|
||||||
|
* 严禁用于任何商业用途和非法行为
|
||||||
|
* 如果对你有帮助辛苦给个star,这是对我最大的鼓励
|
35
apps/cat.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// 主库
|
||||||
|
import { segment } from 'oicq'
|
||||||
|
import fetch from 'node-fetch'
|
||||||
|
// 配置文件库
|
||||||
|
import config from '../model/index.js'
|
||||||
|
|
||||||
|
export class cat extends plugin {
|
||||||
|
constructor () {
|
||||||
|
super({
|
||||||
|
name: '猫',
|
||||||
|
dsc: '猫相关指令',
|
||||||
|
event: 'message.group',
|
||||||
|
priority: 500,
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
reg: '^#(cat)$', fnc: 'cat'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
this.catConfig = config.getConfig('cat')
|
||||||
|
}
|
||||||
|
|
||||||
|
async cat (e) {
|
||||||
|
const numb = this.catConfig.count
|
||||||
|
let images = []
|
||||||
|
let reqRes = [...await fetch(`https://shibe.online/api/cats?count=${numb}`).then(data => data.json()), ...await fetch(`https://api.thecatapi.com/v1/images/search?limit=${numb}`).then(data => data.json()).then(json => json.map(item => item.url))]
|
||||||
|
e.reply('涩图也不看了,就看猫是吧, 探索中...')
|
||||||
|
reqRes.forEach(item => {
|
||||||
|
images.push({
|
||||||
|
message: segment.image(item), nickname: this.e.sender.card || this.e.user_id, user_id: this.e.user_id
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return !!(await this.reply(await Bot.makeForwardMsg(images)))
|
||||||
|
}
|
||||||
|
}
|
61
apps/doctor.js
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// 主库
|
||||||
|
import { segment } from 'oicq'
|
||||||
|
import fetch from 'node-fetch'
|
||||||
|
// 爬虫库
|
||||||
|
import puppeteer from '../../../lib/puppeteer/puppeteer.js'
|
||||||
|
|
||||||
|
export class doctor extends plugin {
|
||||||
|
constructor () {
|
||||||
|
super({
|
||||||
|
name: '医药查询',
|
||||||
|
dsc: '医药相关指令',
|
||||||
|
event: 'message.group',
|
||||||
|
priority: 500,
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
reg: '^#*医药查询 (.*)$',
|
||||||
|
fnc: 'doctor'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async doctor (e) {
|
||||||
|
let keyword = e.msg.split(' ')[1]
|
||||||
|
const url = `https://api2.dayi.org.cn/api/search2?keyword=${keyword}&pageNo=1&pageSize=10`
|
||||||
|
let res = await fetch(url)
|
||||||
|
.then((resp) => resp.json())
|
||||||
|
.then((resp) => resp.list)
|
||||||
|
let msg = []
|
||||||
|
for (const element of res) {
|
||||||
|
const title = this.removeTag(element.title)
|
||||||
|
const template = `
|
||||||
|
${title}\n
|
||||||
|
标签:${element.secondTitle}\n
|
||||||
|
介绍:${element.introduction}
|
||||||
|
`
|
||||||
|
// 如果完全匹配,直接响应页面
|
||||||
|
if (title === keyword) {
|
||||||
|
const browser = await puppeteer.browserInit()
|
||||||
|
const page = await browser.newPage()
|
||||||
|
await page.goto(`https://www.dayi.org.cn/drug/${element.id}`)
|
||||||
|
let buff = await page.screenshot({
|
||||||
|
fullPage: true, type: 'jpeg', omitBackground: false, quality: 90
|
||||||
|
})
|
||||||
|
browser.close()
|
||||||
|
await e.reply(segment.image(buff))
|
||||||
|
}
|
||||||
|
msg.push({
|
||||||
|
message: { type: 'text', text: `${template}` }, nickname: Bot.nickname, user_id: Bot.uin
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/** 最后回复消息 */
|
||||||
|
return !!this.reply(await Bot.makeForwardMsg(msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除标签
|
||||||
|
removeTag (title) {
|
||||||
|
const titleRex = /<[^>]+>/g
|
||||||
|
return title.replace(titleRex, '')
|
||||||
|
}
|
||||||
|
}
|
46
apps/help.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import Help from '../model/help.js'
|
||||||
|
import puppeteer from '../../../lib/puppeteer/puppeteer.js'
|
||||||
|
import md5 from 'md5'
|
||||||
|
|
||||||
|
let helpData = {
|
||||||
|
md5: '',
|
||||||
|
img: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
export class help extends plugin {
|
||||||
|
constructor (e) {
|
||||||
|
super({
|
||||||
|
name: 'RConsole插件帮助',
|
||||||
|
dsc: 'RConsole插件帮助插件帮助',
|
||||||
|
event: 'message',
|
||||||
|
priority: 500,
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
reg: '^#*R(插件)?(命令|帮助|菜单|help|说明|功能|指令|使用说明)$',
|
||||||
|
fnc: 'help'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rule - 闲心插件帮助
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async help () {
|
||||||
|
let data = await Help.get(this.e)
|
||||||
|
if (!data) return
|
||||||
|
let img = await this.cache(data)
|
||||||
|
await this.reply(img)
|
||||||
|
}
|
||||||
|
|
||||||
|
async cache (data) {
|
||||||
|
let tmp = md5(JSON.stringify(data))
|
||||||
|
if (helpData.md5 == tmp) return helpData.img
|
||||||
|
|
||||||
|
helpData.img = await puppeteer.screenshot('help', data)
|
||||||
|
helpData.md5 = tmp
|
||||||
|
|
||||||
|
return helpData.img
|
||||||
|
}
|
||||||
|
}
|
82
apps/hotSearch.js
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import _ from 'lodash'
|
||||||
|
import fetch from 'node-fetch'
|
||||||
|
|
||||||
|
export class hotSearch extends plugin {
|
||||||
|
constructor () {
|
||||||
|
super({
|
||||||
|
name: '热搜查询',
|
||||||
|
dsc: '热搜相关指令',
|
||||||
|
event: 'message.group',
|
||||||
|
priority: 500,
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
reg: '^#(热搜)(.*)$', fnc: 'hotSearch'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async hotSearch (e) {
|
||||||
|
let keyword = e.msg.replace(/#|热搜/g, '').trim()
|
||||||
|
// 虎扑/知乎/36氪/百度/哔哩哔哩/贴吧/微博/抖音/豆瓣/少数派/IT资讯/微信
|
||||||
|
let url = 'https://api.vvhan.com/api/hotlist?type='
|
||||||
|
switch (keyword) {
|
||||||
|
case '虎扑':
|
||||||
|
url += 'hupu'
|
||||||
|
break
|
||||||
|
case '知乎':
|
||||||
|
url += 'zhihuHot'
|
||||||
|
break
|
||||||
|
case '36氪':
|
||||||
|
url += '36Ke'
|
||||||
|
break
|
||||||
|
case '百度':
|
||||||
|
url += 'baiduRD'
|
||||||
|
break
|
||||||
|
case '哔哩哔哩':
|
||||||
|
url += 'bili'
|
||||||
|
break
|
||||||
|
case '贴吧':
|
||||||
|
url += 'baiduRY'
|
||||||
|
break
|
||||||
|
case '微博':
|
||||||
|
url += 'wbHot'
|
||||||
|
break
|
||||||
|
case '抖音':
|
||||||
|
url += 'douyinHot'
|
||||||
|
break
|
||||||
|
case '豆瓣':
|
||||||
|
url += 'douban'
|
||||||
|
break
|
||||||
|
case '少数派':
|
||||||
|
url += 'ssPai'
|
||||||
|
break
|
||||||
|
case 'IT资讯':
|
||||||
|
url += 'itInfo'
|
||||||
|
break
|
||||||
|
case '微信':
|
||||||
|
url += 'wxHot'
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
url += 'history'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
let msg = []
|
||||||
|
let res = await fetch(url)
|
||||||
|
.then((resp) => resp.json())
|
||||||
|
.then((resp) => resp.data)
|
||||||
|
.catch((err) => logger.error(err))
|
||||||
|
res.forEach((element) => {
|
||||||
|
const template = `
|
||||||
|
标题:${element.title}\n
|
||||||
|
简介:${_.isNull(element.desc) ? '' : element.desc}\n
|
||||||
|
热度:${element.hot}\n
|
||||||
|
访问详情:${element.url}\n
|
||||||
|
`
|
||||||
|
msg.push({
|
||||||
|
message: { type: 'text', text: `${template}` }, nickname: Bot.nickname, user_id: Bot.uin
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return !!this.reply(await Bot.makeForwardMsg(msg))
|
||||||
|
}
|
||||||
|
}
|
275
apps/mystery.js
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
// 主库
|
||||||
|
import { segment } from 'oicq'
|
||||||
|
import common from '../../../lib/common/common.js'
|
||||||
|
import fetch from 'node-fetch'
|
||||||
|
// 配置文件
|
||||||
|
import config from '../model/index.js'
|
||||||
|
// 其他库
|
||||||
|
import _ from 'lodash'
|
||||||
|
import mongodb from 'mongodb'
|
||||||
|
|
||||||
|
// Mongodb初始化
|
||||||
|
function initMongo () {
|
||||||
|
const MongoClient = mongodb.MongoClient
|
||||||
|
const url = 'mongodb://localhost:27017/'
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
MongoClient.connect(url, (err, db) => {
|
||||||
|
const dbo = db.db('test')
|
||||||
|
if (err) {
|
||||||
|
throw err // 和调用 reject(err) 效果类似
|
||||||
|
}
|
||||||
|
let collection = dbo.collection('temp')
|
||||||
|
resolve(collection)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const mongo = initMongo()
|
||||||
|
|
||||||
|
export class mystery extends plugin {
|
||||||
|
constructor () {
|
||||||
|
super({
|
||||||
|
name: '神秘区域',
|
||||||
|
dsc: '神秘指令',
|
||||||
|
event: 'message.group',
|
||||||
|
priority: 500,
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
reg: '^#(雀食|确实)$', fnc: 'mystery'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reg: '^#来份涩图$', fnc: 'setu'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reg: '^#(累了)$', fnc: 'cospro'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reg: '^#(啊?|啊?)$', fnc: 'aaa'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
reg: '^#沃日吗$', fnc: 'tuiimg'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
this.mysteryConfig = config.getConfig('mystery')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 接受到消息都会先执行一次
|
||||||
|
async accept () {
|
||||||
|
let oldReply = this.e.reply
|
||||||
|
|
||||||
|
this.e.reply = async function (msgs, quote, data) {
|
||||||
|
if (!msgs) return false
|
||||||
|
if (!Array.isArray(msgs)) msgs = [msgs]
|
||||||
|
let result = await oldReply(msgs, quote, data)
|
||||||
|
|
||||||
|
if (!result || !result.message_id) {
|
||||||
|
let isxml = false
|
||||||
|
|
||||||
|
for (let msg of msgs) {
|
||||||
|
if (msg && msg?.type == 'xml' && msg?.data) {
|
||||||
|
msg.data = msg.data.replace(/^<\?xml.*update=.*?>/g, '<?xml update="1.0" encoding="utf-8" ?>')
|
||||||
|
isxml = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isxml) {
|
||||||
|
result = await oldReply(msgs, quote, data)
|
||||||
|
} else {
|
||||||
|
let MsgList = [{
|
||||||
|
message: msgs, nickname: Bot.nickname, user_id: Bot.uin
|
||||||
|
}]
|
||||||
|
|
||||||
|
let forwardMsg = await Bot.makeForwardMsg(MsgList)
|
||||||
|
|
||||||
|
forwardMsg.data = forwardMsg.data
|
||||||
|
.replace('<?xml update="1.0" encoding="utf-8"?>', '<?xml update="1.0" encoding="utf-8" ?>')
|
||||||
|
.replace(/\n/g, '')
|
||||||
|
.replace(/<title color="#777777" size="26">(.+?)<\/title>/g, '___')
|
||||||
|
.replace(/___+/, '<title color="#777777" size="26">请点击查看内容</title>')
|
||||||
|
msgs = forwardMsg
|
||||||
|
result = await oldReply(msgs, quote, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result || !result.message_id) {
|
||||||
|
logger.error('风控消息处理失败,请登录手机QQ查看是否可手动解除风控!')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async mystery (e) {
|
||||||
|
// 最大页数
|
||||||
|
const maxPage = this.mysteryConfig.mystery.maxPage
|
||||||
|
const maxPigObj = this.mysteryConfig.mystery.maxPigObj
|
||||||
|
// 限制最大图片数量
|
||||||
|
const imageCountLimit = this.mysteryConfig.mystery.imageCountLimit
|
||||||
|
// 随机算法
|
||||||
|
const page = _.random(1, maxPage)
|
||||||
|
const randomIndex = _.random(0, maxPigObj - 1)
|
||||||
|
// 回复
|
||||||
|
this.reply('确实是吧, 正在探索...')
|
||||||
|
// 请求
|
||||||
|
let images = []
|
||||||
|
let imgData = []
|
||||||
|
let url = `https://www.cos6.net/wp-json/wp/v2/posts?page=${page}`
|
||||||
|
await fetch(url)
|
||||||
|
.then((resp) => {
|
||||||
|
return resp.json()
|
||||||
|
})
|
||||||
|
.then((json) => {
|
||||||
|
if (!json.length) {
|
||||||
|
this.e.reply('探索失败,你再我去一次吧')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const content = json[randomIndex].content
|
||||||
|
images = this.getImages(content.rendered)
|
||||||
|
// 如果图片为空直接返回
|
||||||
|
if (images.length === 0) {
|
||||||
|
this.e.reply('探索失败,你再我去一次吧')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// 洗牌
|
||||||
|
images = _.shuffle(images)
|
||||||
|
// 限制长度
|
||||||
|
if (images.length > imageCountLimit) {
|
||||||
|
images = images.slice(1, imageCountLimit + 1)
|
||||||
|
}
|
||||||
|
// 循环队列
|
||||||
|
images.forEach((item) => {
|
||||||
|
imgData.push({
|
||||||
|
message: segment.image(item),
|
||||||
|
nickname: this.e.sender.card || this.e.user_id,
|
||||||
|
user_id: this.e.user_id
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch((err) => logger.error(err))
|
||||||
|
return !!(await this.reply(await Bot.makeForwardMsg(imgData)))
|
||||||
|
}
|
||||||
|
|
||||||
|
async cospro (e) {
|
||||||
|
let req = [...await fetch('https://imgapi.cn/cos2.php?return=jsonpro').then((resp) => resp.json()).then((json) => json.imgurls), ...await fetch('https://imgapi.cn/cos.php?return=jsonpro').then((resp) => resp.json()).then((json) => json.imgurls)]
|
||||||
|
e.reply('哪天克火掉一定是在这个群里面...')
|
||||||
|
let images = []
|
||||||
|
req.forEach(item => {
|
||||||
|
images.push({
|
||||||
|
message: segment.image(encodeURI(item)),
|
||||||
|
nickname: this.e.sender.card || this.e.user_id,
|
||||||
|
user_id: this.e.user_id
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return !!(await this.reply(await Bot.makeForwardMsg(images)))
|
||||||
|
}
|
||||||
|
|
||||||
|
async aaa (e) {
|
||||||
|
// https://yingtall.com/wp-json/wp/v2/posts?page=64
|
||||||
|
// 最大页数
|
||||||
|
const maxPage = this.mysteryConfig.aaa.maxPage
|
||||||
|
const maxPigObj = this.mysteryConfig.aaa.maxPigObj
|
||||||
|
// 限制最大图片数量
|
||||||
|
const imageCountLimit = this.mysteryConfig.aaa.imageCountLimit
|
||||||
|
// 随机算法
|
||||||
|
const page = _.random(1, maxPage)
|
||||||
|
const randomIndex = _.random(0, maxPigObj - 1)
|
||||||
|
// 回复
|
||||||
|
this.reply('真变态啊...')
|
||||||
|
// 请求
|
||||||
|
let images = []
|
||||||
|
let imgData = []
|
||||||
|
let url = `https://yingtall.com/wp-json/wp/v2/posts?page=${page}`
|
||||||
|
await fetch(url)
|
||||||
|
.then((resp) => {
|
||||||
|
return resp.json()
|
||||||
|
})
|
||||||
|
.then((json) => {
|
||||||
|
if (!json.length) {
|
||||||
|
this.e.reply('探索失败,你再我去一次吧')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const content = json[randomIndex].content
|
||||||
|
images = this.getImages2(content.rendered)
|
||||||
|
console.log(images)
|
||||||
|
// 如果图片为空直接返回
|
||||||
|
if (images.length === 0) {
|
||||||
|
this.e.reply('探索失败,你再我去一次吧')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// 洗牌
|
||||||
|
images = _.shuffle(images)
|
||||||
|
// 限制长度
|
||||||
|
if (images.length > imageCountLimit) {
|
||||||
|
images = images.slice(1, imageCountLimit + 1)
|
||||||
|
}
|
||||||
|
// 循环队列
|
||||||
|
images.forEach((item) => {
|
||||||
|
imgData.push({
|
||||||
|
message: segment.image(item),
|
||||||
|
nickname: this.e.sender.card || this.e.user_id,
|
||||||
|
user_id: this.e.user_id
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch((err) => logger.error(err))
|
||||||
|
return !!(await this.reply(await Bot.makeForwardMsg(imgData)))
|
||||||
|
}
|
||||||
|
|
||||||
|
async setu (e) {
|
||||||
|
const numb = this.mysteryConfig.setu.count
|
||||||
|
// 图源
|
||||||
|
const urlList = ['https://iw233.cn/api.php?sort=random', 'https://iw233.cn/API/Random.php']
|
||||||
|
e.reply('探索中...')
|
||||||
|
let images = []
|
||||||
|
for (let i = numb; i > 0; i--) {
|
||||||
|
urlList.forEach(url => {
|
||||||
|
images.push({
|
||||||
|
message: segment.image(url), nickname: this.e.sender.card || this.e.user_id, user_id: this.e.user_id
|
||||||
|
})
|
||||||
|
})
|
||||||
|
await common.sleep(200)
|
||||||
|
}
|
||||||
|
return !!(await this.reply(await Bot.makeForwardMsg(images)))
|
||||||
|
}
|
||||||
|
|
||||||
|
async tuiimg (e) {
|
||||||
|
const MAX_SIZE = this.mysteryConfig.tuiimg.count
|
||||||
|
this.reply('这群早晚被你整没了...')
|
||||||
|
let images = []
|
||||||
|
const template = {
|
||||||
|
nickname: this.e.sender.card || this.e.user_id, user_id: this.e.user_id
|
||||||
|
}
|
||||||
|
await mongo.then(conn => {
|
||||||
|
return conn.aggregate([{ $sample: { size: MAX_SIZE } }]).toArray()
|
||||||
|
}).then((result) => {
|
||||||
|
console.log(result)
|
||||||
|
result.forEach((item) => {
|
||||||
|
images.push({
|
||||||
|
message: segment.image(item.url), ...template
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return !!(await this.reply(await Bot.makeForwardMsg(images), false, 60))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 正则:获取图片
|
||||||
|
getImages (string) {
|
||||||
|
const imgRex = /(http|https):\/\/([\w.]+\/?)\S*.(jpg|JPG|png|PNG|gif|GIF|jpeg|JPEG)/g
|
||||||
|
const images = []
|
||||||
|
let img
|
||||||
|
while ((img = imgRex.exec(string))) {
|
||||||
|
images.push(encodeURI(img[0]))
|
||||||
|
}
|
||||||
|
return images
|
||||||
|
}
|
||||||
|
|
||||||
|
// 正则:获取图片
|
||||||
|
getImages2 (string) {
|
||||||
|
const imgRex = /<img.*?src="(.*?)"[^>]+>/g
|
||||||
|
const images = []
|
||||||
|
let img
|
||||||
|
while ((img = imgRex.exec(string))) {
|
||||||
|
images.push(encodeURI(img[1]))
|
||||||
|
}
|
||||||
|
return images
|
||||||
|
}
|
||||||
|
}
|
55
apps/recommend.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import fetch from 'node-fetch'
|
||||||
|
|
||||||
|
export class recommend extends plugin {
|
||||||
|
constructor () {
|
||||||
|
super({
|
||||||
|
name: '推荐软件',
|
||||||
|
dsc: '推荐相关指令',
|
||||||
|
event: 'message.group',
|
||||||
|
priority: 500,
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
/** 命令正则匹配 */
|
||||||
|
reg: '^#电脑软件推荐$', /** 执行方法 */
|
||||||
|
fnc: 'computerRecommended'
|
||||||
|
}, {
|
||||||
|
/** 命令正则匹配 */
|
||||||
|
reg: '^#安卓软件推荐$', /** 执行方法 */
|
||||||
|
fnc: 'androidRecommended'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async computerRecommended (e) {
|
||||||
|
let url = 'https://www.ghxi.com/ghapi?type=query&n=pc'
|
||||||
|
/** 调用接口获取数据 */
|
||||||
|
let res = await fetch(url).catch((err) => logger.error(err))
|
||||||
|
|
||||||
|
/** 接口结果,json字符串转对象 */
|
||||||
|
res = await res.json()
|
||||||
|
let msg = []
|
||||||
|
res.data.list.forEach((element) => {
|
||||||
|
const template = `推荐软件:${element.title}\n地址:${element.url}\n`
|
||||||
|
msg.push({
|
||||||
|
message: { type: 'text', text: `${template}` }, nickname: Bot.nickname, user_id: Bot.uin
|
||||||
|
})
|
||||||
|
})
|
||||||
|
/** 最后回复消息 */
|
||||||
|
return !!this.reply(await Bot.makeForwardMsg(msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
async androidRecommended (e) {
|
||||||
|
let url = 'https://www.ghxi.com/ghapi?type=query&n=and'
|
||||||
|
let res = await fetch(url).catch((err) => logger.error(err))
|
||||||
|
res = await res.json()
|
||||||
|
let msg = []
|
||||||
|
res.data.list.forEach((element) => {
|
||||||
|
const template = `推荐软件:${element.title}\n地址:${element.url}\n`
|
||||||
|
msg.push({
|
||||||
|
message: { type: 'text', text: `${template}` }, nickname: Bot.nickname, user_id: Bot.uin
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return !!this.reply(await Bot.makeForwardMsg(msg))
|
||||||
|
}
|
||||||
|
}
|
30
apps/tools.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import fetch from 'node-fetch'
|
||||||
|
import md5 from 'md5'
|
||||||
|
|
||||||
|
export class tools extends plugin {
|
||||||
|
constructor () {
|
||||||
|
super({
|
||||||
|
name: '工具和学习类',
|
||||||
|
dsc: '工具相关指令',
|
||||||
|
event: 'message.group',
|
||||||
|
priority: 500,
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
reg: '^#(翻译)(.*)$', fnc: 'trans'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 翻译插件
|
||||||
|
async trans (e) {
|
||||||
|
let place = e.msg.replace(/#|翻译/g, '').trim()
|
||||||
|
let url = /[\u4E00-\u9FFF]+/g.test(place) ? `http://api.fanyi.baidu.com/api/trans/vip/translate?from=zh&to=en&appid=20210422000794040&salt=542716863&sign=${md5('20210422000794040' + place + '542716863' + 'HooD_ndgwcGH6SAnxGrM')}&q=${place}` : `http://api.fanyi.baidu.com/api/trans/vip/translate?from=en&to=zh&appid=20210422000794040&salt=542716863&sign=${md5('20210422000794040' + place + '542716863' + 'HooD_ndgwcGH6SAnxGrM')}&q=${place}`
|
||||||
|
await fetch(url)
|
||||||
|
.then(resp => resp.json())
|
||||||
|
.then(text => text.trans_result)
|
||||||
|
.then(res => this.reply(`${res[0].dst}`, true))
|
||||||
|
.catch((err) => logger.error(err))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
37
apps/update.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// 主库
|
||||||
|
import Version from '../model/version.js'
|
||||||
|
import config from '../model/index.js'
|
||||||
|
import puppeteer from '../../../lib/puppeteer/puppeteer.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理插件更新
|
||||||
|
*/
|
||||||
|
export class update extends plugin {
|
||||||
|
constructor () {
|
||||||
|
super({
|
||||||
|
name: '更新插件',
|
||||||
|
dsc: '更新插件代码',
|
||||||
|
event: 'message',
|
||||||
|
priority: 4000,
|
||||||
|
rule: [
|
||||||
|
{
|
||||||
|
reg: '^#*R(插件)?版本$',
|
||||||
|
fnc: 'version'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
this.versionData = config.getConfig('version')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rule - 插件版本信息
|
||||||
|
*/
|
||||||
|
async version () {
|
||||||
|
const data = await new Version(this.e).getData(
|
||||||
|
this.versionData.slice(0, 3)
|
||||||
|
)
|
||||||
|
let img = await puppeteer.screenshot('version', data)
|
||||||
|
this.e.reply(img)
|
||||||
|
}
|
||||||
|
}
|
2
config/cat.yaml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# 发送张数
|
||||||
|
count: 10
|
54
config/help.yaml
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
- group: 医学功能
|
||||||
|
list:
|
||||||
|
- icon: 记录
|
||||||
|
title: "#医药查询 疾病/症状/医院/医生/药品"
|
||||||
|
desc: 便利的医药查询功能
|
||||||
|
- group: 猫猫图
|
||||||
|
list:
|
||||||
|
- icon: 树脂
|
||||||
|
title: "#猫猫|cat 开始吸猫"
|
||||||
|
desc: 猫咪图捕捉
|
||||||
|
- group: 神秘功能合集
|
||||||
|
list:
|
||||||
|
- icon: 养成计算
|
||||||
|
title: "#雀食/#确实"
|
||||||
|
desc: 原汤化原食
|
||||||
|
- icon: 史莱姆
|
||||||
|
title: "#来份涩图"
|
||||||
|
desc: 涩涩的
|
||||||
|
- icon: weapon
|
||||||
|
title: "#累了"
|
||||||
|
desc: 疲惫往往是过度劳累
|
||||||
|
- icon: 攻略
|
||||||
|
title: "#啊?"
|
||||||
|
desc: 啊?
|
||||||
|
- icon: sign
|
||||||
|
title: "#沃日吗"
|
||||||
|
desc: 什么鬼?
|
||||||
|
- group: 热搜功能合集
|
||||||
|
list:
|
||||||
|
- icon: 打卡
|
||||||
|
title: "#热搜 虎扑/知乎/36氪/百度/哔哩哔哩/贴吧/微博/抖音/豆瓣/少数派/IT资讯/微信"
|
||||||
|
desc: 开局五子棋游戏
|
||||||
|
- group: 工具类合集
|
||||||
|
list:
|
||||||
|
- icon: 绑定账号
|
||||||
|
title: "#翻译 xxx"
|
||||||
|
desc: 百度翻译
|
||||||
|
- icon: 纠缠之缘
|
||||||
|
title: "#电脑软件推荐"
|
||||||
|
desc: 推荐PC软件
|
||||||
|
- icon: ledger
|
||||||
|
title: "#安卓软件推荐"
|
||||||
|
desc: 推荐安卓软件
|
||||||
|
- group: 其他指令[实验]
|
||||||
|
list:
|
||||||
|
- icon: 问号
|
||||||
|
title: "#RConsole插件版本"
|
||||||
|
desc: "查看,最近维护的版本信息"
|
||||||
|
- icon: 史莱姆
|
||||||
|
title: "#RConsole插件更新"
|
||||||
|
desc: "进行更新RConsole插件"
|
||||||
|
- icon: 原石
|
||||||
|
title: "#RConsole插件强制更新"
|
||||||
|
desc: "进行强制更新RConsole插件"
|
16
config/mystery.yaml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
mystery:
|
||||||
|
# 最大页数
|
||||||
|
maxPage: 15
|
||||||
|
maxPigObj: 10
|
||||||
|
# 限制最大图片数量
|
||||||
|
imageCountLimit: 20
|
||||||
|
aaa:
|
||||||
|
# 最大页数
|
||||||
|
maxPage: 15
|
||||||
|
maxPigObj: 10
|
||||||
|
# 限制最大图片数量
|
||||||
|
imageCountLimit: 20
|
||||||
|
setu:
|
||||||
|
count: 10
|
||||||
|
tuiimg:
|
||||||
|
count: 10
|
10
config/version.yaml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
- {
|
||||||
|
version: 1.0,
|
||||||
|
data:
|
||||||
|
[
|
||||||
|
更改单个组件<span class="cmd">#任助理</span>架构为插件架构,
|
||||||
|
添加<span class="cmd">#R帮助</span>获取插件帮助,
|
||||||
|
添加<span class="cmd">#R版本</span>获取插件版本,
|
||||||
|
更新风控缓解、重构系统文件
|
||||||
|
],
|
||||||
|
}
|
BIN
img/help.jpg
Normal file
After Width: | Height: | Size: 230 KiB |
BIN
img/version.jpg
Normal file
After Width: | Height: | Size: 30 KiB |
27
model/base.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
export default class base {
|
||||||
|
constructor (e = {}) {
|
||||||
|
this.e = e
|
||||||
|
this.userId = e?.user_id
|
||||||
|
this.model = 'RConsole-plugin'
|
||||||
|
this._path = process.cwd().replace(/\\/g, '/')
|
||||||
|
}
|
||||||
|
|
||||||
|
get prefix () {
|
||||||
|
return `Yz:RConsole-plugin:${this.model}:`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 截图默认数据
|
||||||
|
* @param saveId html保存id
|
||||||
|
* @param tplFile 模板html路径
|
||||||
|
* @param pluResPath 插件资源路径
|
||||||
|
*/
|
||||||
|
get screenData () {
|
||||||
|
return {
|
||||||
|
saveId: this.userId,
|
||||||
|
tplFile: `./plugins/RConsole-plugin/resources/html/${this.model}/${this.model}.html`,
|
||||||
|
/** 绝对路径 */
|
||||||
|
pluResPath: `${this._path}/plugins/RConsole-plugin/resources/`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
model/help.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import base from './base.js'
|
||||||
|
import config from './index.js'
|
||||||
|
import cfg from '../../../lib/config/config.js'
|
||||||
|
|
||||||
|
export default class Help extends base {
|
||||||
|
constructor (e) {
|
||||||
|
super(e)
|
||||||
|
this.model = 'help'
|
||||||
|
}
|
||||||
|
|
||||||
|
static async get (e) {
|
||||||
|
let html = new Help(e)
|
||||||
|
return await html.getData()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getData () {
|
||||||
|
let helpData = config.getConfig('help')
|
||||||
|
|
||||||
|
let groupCfg = cfg.getGroup(this.group_id)
|
||||||
|
|
||||||
|
if (groupCfg.disable && groupCfg.disable.length) {
|
||||||
|
helpData.map((item) => {
|
||||||
|
if (groupCfg.disable.includes(item.group)) {
|
||||||
|
item.disable = true
|
||||||
|
}
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let versionData = config.getConfig('version')
|
||||||
|
|
||||||
|
const version =
|
||||||
|
(versionData && versionData.length && versionData[0].version) || '1.0.0'
|
||||||
|
|
||||||
|
return {
|
||||||
|
...this.screenData,
|
||||||
|
saveId: 'help',
|
||||||
|
version,
|
||||||
|
helpData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
87
model/index.js
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import fs from 'node:fs'
|
||||||
|
import _ from 'lodash'
|
||||||
|
import YAML from 'yaml'
|
||||||
|
import chokidar from 'chokidar'
|
||||||
|
|
||||||
|
class RConfig {
|
||||||
|
constructor () {
|
||||||
|
// 配置文件
|
||||||
|
this.configPath = './plugins/RConsole-plugin/config/'
|
||||||
|
this.config = {}
|
||||||
|
|
||||||
|
// 监听文件
|
||||||
|
this.watcher = { config: {} }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取配置文件
|
||||||
|
getConfig (name) {
|
||||||
|
let ignore = []
|
||||||
|
|
||||||
|
if (ignore.includes(`${name}`)) {
|
||||||
|
return this.getYaml(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getYaml(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取配置yaml
|
||||||
|
* @param app 功能
|
||||||
|
* @param name 名称
|
||||||
|
* @param type 默认跑配置-defSet,用户配置-config
|
||||||
|
*/
|
||||||
|
getYaml (name) {
|
||||||
|
// 获取文件路径
|
||||||
|
let file = this.getFilePath(name)
|
||||||
|
// 解析xml
|
||||||
|
const yaml = YAML.parse(fs.readFileSync(file, 'utf8'))
|
||||||
|
// 监听文件
|
||||||
|
this.watch(file, name)
|
||||||
|
return yaml
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文件路径
|
||||||
|
* @param app
|
||||||
|
* @param name
|
||||||
|
* @param type
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
getFilePath (name) {
|
||||||
|
return `${this.configPath}${name}.yaml`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 听配置文件
|
||||||
|
* @param file
|
||||||
|
* @param app
|
||||||
|
* @param name
|
||||||
|
* @param type
|
||||||
|
*/
|
||||||
|
watch (file, name) {
|
||||||
|
const watcher = chokidar.watch(file)
|
||||||
|
|
||||||
|
watcher.on('change', (path) => {
|
||||||
|
logger.mark(`[修改配置文件][${name}]`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存配置
|
||||||
|
* @param app
|
||||||
|
* @param name
|
||||||
|
* @param type
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
saveSet (name, data) {
|
||||||
|
let file = this.getFilePath(name)
|
||||||
|
if (_.isEmpty(data)) {
|
||||||
|
fs.existsSync(file) && fs.unlinkSync(file)
|
||||||
|
} else {
|
||||||
|
let yaml = YAML.stringify(data)
|
||||||
|
fs.writeFileSync(file, yaml, 'utf8')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new RConfig()
|
22
model/version.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import base from './base.js'
|
||||||
|
|
||||||
|
export default class Version extends base {
|
||||||
|
constructor (e) {
|
||||||
|
super(e)
|
||||||
|
this.model = 'version'
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 生成版本信息图片 */
|
||||||
|
async getData (versionData) {
|
||||||
|
const version =
|
||||||
|
(versionData && versionData.length && versionData[0].version) || '1.0.0'
|
||||||
|
let data = {
|
||||||
|
...this.screenData,
|
||||||
|
userId: version,
|
||||||
|
quality: 100,
|
||||||
|
saveId: version,
|
||||||
|
versionData
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
}
|
140
resources/html/help/help.css
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: "tttgbnumber";
|
||||||
|
src: url("../../../../../resources/font/tttgbnumber.ttf");
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
width: 788px;
|
||||||
|
color: #1e1f20;
|
||||||
|
transform: scale(1.5);
|
||||||
|
transform-origin: 0 0;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
width: 788px;
|
||||||
|
padding: 20px 15px 10px 15px;
|
||||||
|
background-image: url(../../img/bg.jpeg);
|
||||||
|
background-size: 100%;
|
||||||
|
}
|
||||||
|
.head_box {
|
||||||
|
border-radius: 15px;
|
||||||
|
font-family: 'tttgbnumber';
|
||||||
|
padding: 10px 20px;
|
||||||
|
position: relative;
|
||||||
|
color: white;
|
||||||
|
box-shadow: 0 5px 10px 0 rgb(0 0 0 / 15%);
|
||||||
|
}
|
||||||
|
.head_box .id_text {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
.head_box .day_text {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
.head_box .genshin_logo {
|
||||||
|
position: absolute;
|
||||||
|
top: -10px;
|
||||||
|
right: 15px;
|
||||||
|
width: 97px;
|
||||||
|
}
|
||||||
|
.base_info {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
.uid {
|
||||||
|
font-family: tttgbnumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data_box {
|
||||||
|
border-radius: 15px;
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
padding: 20px 0px 5px 0px;
|
||||||
|
background: transparent;
|
||||||
|
box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, 0.8);
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.tab_lable {
|
||||||
|
position: absolute;
|
||||||
|
top: -10px;
|
||||||
|
left: -8px;
|
||||||
|
background-color: rgb(76, 76, 76);
|
||||||
|
box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, 0.8);
|
||||||
|
color: #fff;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 3px 10px;
|
||||||
|
border-radius: 15px 0px 15px 15px;
|
||||||
|
z-index: 20;
|
||||||
|
}
|
||||||
|
.data_line {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
}
|
||||||
|
.data_line_item {
|
||||||
|
width: 100px;
|
||||||
|
text-align: center;
|
||||||
|
/*margin: 0 20px;*/
|
||||||
|
}
|
||||||
|
.num {
|
||||||
|
font-family: tttgbnumber;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
.data_box .lable {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #7f858a;
|
||||||
|
line-height: 1;
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list{
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list .item {
|
||||||
|
width: 235px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: white;
|
||||||
|
background: transparent;
|
||||||
|
box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, 0.8);
|
||||||
|
padding: 8px 6px 8px 6px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin: 0 0px 10px 10px;
|
||||||
|
}
|
||||||
|
.list .item .icon{
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
position: relative;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.list .item .title{
|
||||||
|
font-size: 16px;
|
||||||
|
margin-left: 6px;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
/* .list .item .title .text{
|
||||||
|
white-space: nowrap;
|
||||||
|
} */
|
||||||
|
.list .item .title .dec{
|
||||||
|
font-size: 12px;
|
||||||
|
color: #999;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
.logo{
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
color: white;
|
||||||
|
font-family: 'tttgbnumber';
|
||||||
|
}
|
45
resources/html/help/help.html
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
type="text/css"
|
||||||
|
href="{{pluResPath}}html/help/help.css"
|
||||||
|
/>
|
||||||
|
<link rel="preload" href="{{resPath}}font/tttgbnumber.ttf" as="font" />
|
||||||
|
<link rel="preload" href="{{pluResPath}}img/bg.jpeg" as="image" />
|
||||||
|
<link rel="preload" href="{{pluResPath}}img/rank/top.png" as="image" />
|
||||||
|
<link rel="shortcut icon" href="#" />
|
||||||
|
</head>
|
||||||
|
{{@headStyle}}
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="container" id="container">
|
||||||
|
<div class="head_box">
|
||||||
|
<div class="id_text">R-Plugin</div>
|
||||||
|
<h2 class="day_text">使用说明-v{{update}}</h2>
|
||||||
|
<img class="genshin_logo" src="{{pluResPath}}img/rank/top.png" />
|
||||||
|
</div>
|
||||||
|
{{each helpData val}}
|
||||||
|
<div class="data_box">
|
||||||
|
<div class="tab_lable">
|
||||||
|
{{val.group}}{{val.disable ? ' - 已禁用' : ''}}
|
||||||
|
</div>
|
||||||
|
<div class="list">
|
||||||
|
{{each val.list item}}
|
||||||
|
<div class="item">
|
||||||
|
<img class="icon" src="{{pluResPath}}img/icon/{{item.icon}}.png" />
|
||||||
|
<div class="title">
|
||||||
|
<div class="text">{{@item.title}}</div>
|
||||||
|
<div class="dec">{{item.desc}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
<div class="logo">Created By Yunzai-Bot & R-Plugin</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
82
resources/html/version/version.css
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: "tttgbnumber";
|
||||||
|
src: url("../../../../../resources/font/tttgbnumber.ttf");
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: "tttgbnumber";
|
||||||
|
transform: scale(1.5);
|
||||||
|
transform-origin: 0 0;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
width: 536px;
|
||||||
|
background-image: url(../../img/bg.jpeg);
|
||||||
|
background-size: 100%;
|
||||||
|
padding: 10px 0 10px 0;
|
||||||
|
}
|
||||||
|
.version-card {
|
||||||
|
background: transparent;
|
||||||
|
margin: 5px 10px 8px 10px;
|
||||||
|
position: relative;
|
||||||
|
box-shadow: 0 0 1px 0 #ccc, 2px 2px 4px 0 rgba(50, 50, 50, 0.8);
|
||||||
|
overflow: hidden;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
.version-card .title {
|
||||||
|
background: rgba(0, 0, 0, 0.4);
|
||||||
|
box-shadow: 0 0 1px 0 #fff;
|
||||||
|
color: white;
|
||||||
|
font-family: Number, YS;
|
||||||
|
padding: 10px 20px;
|
||||||
|
text-align: left;
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 8px 20px 8px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.version-card .content {
|
||||||
|
padding: 10px 15px;
|
||||||
|
font-size: 12px;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
box-shadow: 0 0 1px 0 #fff;
|
||||||
|
font-family: "HYWenHei-55W";
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
.version-card ul {
|
||||||
|
font-size: 14px;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
.version-card ul li {
|
||||||
|
margin: 3px 0;
|
||||||
|
}
|
||||||
|
.version-card .cmd {
|
||||||
|
color: #d3bc8e;
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 0 3px;
|
||||||
|
margin: 1px 2px;
|
||||||
|
}
|
||||||
|
.version-card .strong {
|
||||||
|
color: #67a9e4;
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 0 3px;
|
||||||
|
margin: 1px 2px;
|
||||||
|
}
|
||||||
|
.logo{
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
color: white;
|
||||||
|
font-family: 'tttgbnumber';
|
||||||
|
}
|
32
resources/html/version/version.html
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
|
||||||
|
<link rel="shortcut icon" href="#" />
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
type="text/css"
|
||||||
|
href="{{pluResPath}}html/version/version.css"
|
||||||
|
/>
|
||||||
|
<link rel="preload" href="{{resPath}}font/tttgbnumber.ttf" as="font" />
|
||||||
|
<link rel="preload" href="{{pluResPath}}img/bg.jpeg" as="image" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container" id="container">
|
||||||
|
{{each versionData item idx}}
|
||||||
|
<div class="version-card">
|
||||||
|
<div class="title">{{item.update}}{{idx ? '': ' - 当前版本'}}</div>
|
||||||
|
<div class="content">
|
||||||
|
<ul>
|
||||||
|
{{each item.data sub}}
|
||||||
|
<li>{{@sub}}</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
<div class="logo">Created By Yunzai-Bot & R-Plugin</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<script type="text/javascript"></script>
|
||||||
|
</html>
|
BIN
resources/img/bg.jpeg
Normal file
After Width: | Height: | Size: 464 KiB |
0
resources/img/gobang/.keep
Normal file
BIN
resources/img/gobang/bg.png
Normal file
After Width: | Height: | Size: 279 KiB |
0
resources/img/icon/.keep
Normal file
BIN
resources/img/icon/abyss.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
resources/img/icon/ledger.png
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
resources/img/icon/moster.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
resources/img/icon/paimon.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
resources/img/icon/role.png
Normal file
After Width: | Height: | Size: 6.3 KiB |
BIN
resources/img/icon/sign.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
resources/img/icon/team.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
resources/img/icon/weapon.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
resources/img/icon/wiki.png
Normal file
After Width: | Height: | Size: 9.3 KiB |
BIN
resources/img/icon/养成计算.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
resources/img/icon/原石.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
resources/img/icon/史莱姆.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
resources/img/icon/打卡.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
resources/img/icon/攻略.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
resources/img/icon/星辉.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
resources/img/icon/树脂.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
resources/img/icon/米游社.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
resources/img/icon/纠缠之缘.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
resources/img/icon/绑定账号.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
resources/img/icon/统计.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
resources/img/icon/记录.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
resources/img/icon/问号.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
0
resources/img/mypk/.keep
Normal file
BIN
resources/img/mypk/战圣.png
Normal file
After Width: | Height: | Size: 437 KiB |
BIN
resources/img/mypk/战士.png
Normal file
After Width: | Height: | Size: 205 KiB |
BIN
resources/img/mypk/战将.png
Normal file
After Width: | Height: | Size: 366 KiB |
BIN
resources/img/mypk/战渣.png
Normal file
After Width: | Height: | Size: 492 KiB |
BIN
resources/img/mypk/战狂.png
Normal file
After Width: | Height: | Size: 546 KiB |
BIN
resources/img/mypk/战王.png
Normal file
After Width: | Height: | Size: 246 KiB |
BIN
resources/img/mypk/战神.png
Normal file
After Width: | Height: | Size: 415 KiB |
0
resources/img/other/.keep
Normal file
BIN
resources/img/other/pking.gif
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
resources/img/other/原神.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
0
resources/img/rank/.keep
Normal file
BIN
resources/img/rank/top.png
Normal file
After Width: | Height: | Size: 89 KiB |
BIN
resources/img/rank/top0.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
resources/img/rank/top1.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
resources/img/rank/top2.png
Normal file
After Width: | Height: | Size: 10 KiB |
23974
test/get-pip.py
Normal file
130
test/main.py
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
import asyncio
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
import motor
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
|
url = 'https://www.tuiimg.com/meinv/'
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.35",
|
||||||
|
'Pragma': 'no-cache',
|
||||||
|
'Accept-Encoding': 'gzip, deflate',
|
||||||
|
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
|
||||||
|
'Cache-Control': 'no-cache',
|
||||||
|
'Connection': 'keep-alive',
|
||||||
|
"Content-Type": "text/html;charset=utf-8"}
|
||||||
|
|
||||||
|
# 请求分类页面的并发限制(不要一次请求太多分类)
|
||||||
|
sem_page = asyncio.Semaphore(5)
|
||||||
|
|
||||||
|
|
||||||
|
async def fetch_content(url):
|
||||||
|
'''
|
||||||
|
根据url获取内容
|
||||||
|
:param url: 网页的url
|
||||||
|
:return:
|
||||||
|
'''
|
||||||
|
async with sem_page:
|
||||||
|
print(f'开始解析链接:{url}')
|
||||||
|
max_retries = 3
|
||||||
|
attempt = 0
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
async with aiohttp.ClientSession(
|
||||||
|
headers=headers, connector=aiohttp.TCPConnector(ssl=False)
|
||||||
|
) as session:
|
||||||
|
async with session.get(url, timeout=10) as resp:
|
||||||
|
return await resp.text()
|
||||||
|
break
|
||||||
|
except (
|
||||||
|
asyncio.TimeoutError
|
||||||
|
):
|
||||||
|
if attempt < max_retries:
|
||||||
|
print("解析链接异常,稍后自动重试:{} times:{}".format(url, attempt))
|
||||||
|
attempt += 1
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
async def page_pic(connect, pic_page):
|
||||||
|
'''
|
||||||
|
处理一套图片,分文件夹存放
|
||||||
|
:param connect: Mongodb连接
|
||||||
|
:param pic_page: 一套图片的url
|
||||||
|
:return:
|
||||||
|
'''
|
||||||
|
bs = BeautifulSoup(pic_page, 'lxml')
|
||||||
|
div = bs.find('div', {'class': "content"})
|
||||||
|
img_temp_link = div.find('img')['src']
|
||||||
|
img_base_link = img_temp_link[0:-5]
|
||||||
|
all_text = bs.find('i', id='allbtn').get_text()
|
||||||
|
pattern = re.compile("\((.*?)\)")
|
||||||
|
total = pattern.search(all_text).group(1).split("/")[1]
|
||||||
|
img_urls = []
|
||||||
|
for i in range(1, int(total) + 1):
|
||||||
|
img_url = img_base_link + str(i) + '.jpg'
|
||||||
|
img_urls.append(img_url)
|
||||||
|
task = [insert_url(connect, url_temp) for url_temp in img_urls]
|
||||||
|
await asyncio.gather(*task)
|
||||||
|
|
||||||
|
|
||||||
|
async def page_main(url):
|
||||||
|
'''
|
||||||
|
单页下载
|
||||||
|
:param url: 单页的url
|
||||||
|
:return: None
|
||||||
|
'''
|
||||||
|
connect = build_connect()
|
||||||
|
main_page_text = await fetch_content(url)
|
||||||
|
bs = BeautifulSoup(main_page_text, 'lxml')
|
||||||
|
a_all = bs.find_all('a', {'class': 'pic'})
|
||||||
|
page_urls = []
|
||||||
|
for a in a_all:
|
||||||
|
page_urls.append(a['href'])
|
||||||
|
tasks = [fetch_content(pic_url) for pic_url in page_urls]
|
||||||
|
pic_pages = await asyncio.gather(*tasks)
|
||||||
|
pics = [page_pic(connect, pic_page) for pic_page in pic_pages]
|
||||||
|
await asyncio.gather(*pics)
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
'''
|
||||||
|
遍历所有页面的url进行下载
|
||||||
|
:return:
|
||||||
|
'''
|
||||||
|
# await target_folder()
|
||||||
|
start = time.time()
|
||||||
|
mainPageText = await fetch_content(url)
|
||||||
|
bs = BeautifulSoup(mainPageText, 'lxml')
|
||||||
|
page_count = bs.find('div', {'class', 'page'}).find('a', {'class', "end"}).get_text()
|
||||||
|
page_urls = []
|
||||||
|
for i in range(1, int(page_count) + 1):
|
||||||
|
page_url = f'{url}list_{i}.html'
|
||||||
|
page_urls.append(page_url)
|
||||||
|
tasks = [page_main(page_url) for page_url in page_urls]
|
||||||
|
await asyncio.gather(*tasks)
|
||||||
|
end = time.time()
|
||||||
|
print(f"耗时:{end - start:.2f}秒")
|
||||||
|
|
||||||
|
|
||||||
|
# 单例建立MongoDB连接
|
||||||
|
def build_connect():
|
||||||
|
client = motor.motor_tornado.MotorClient('localhost', 27017)
|
||||||
|
db = client.test
|
||||||
|
return db.temp
|
||||||
|
|
||||||
|
|
||||||
|
def insert_url(connect, url_temp):
|
||||||
|
query = {'url': url_temp}
|
||||||
|
return connect.update_one(query, {"$set": query}, True)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# linux下用此方法
|
||||||
|
# asyncio.run(main())
|
||||||
|
# windows下上面的方法会报错(会在运行完成后报错,不影响下载),可以换成用下面这两行
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
loop.run_until_complete(main())
|
4
test/requirements.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
aiohttp~=3.8.3
|
||||||
|
motor~=3.1.1
|
||||||
|
beautifulsoup4~=4.11.1
|
||||||
|
pymongo~=4.3.2
|