├── doc └── img.jpg ├── babel.config.js ├── src ├── assets │ └── home.ico ├── vue.d.ts ├── shims-vue.d.ts ├── config.d.ts ├── shims-tsx.d.ts ├── main.ts ├── router │ └── index.ts ├── views │ ├── home.vue │ ├── about.vue │ └── config.vue ├── components │ ├── nologin.vue │ └── user.vue ├── main │ └── rpc.ts ├── background.ts ├── App.vue ├── function │ └── send.ts └── store │ └── index.ts ├── .prettierrc ├── .gitignore ├── .eslintrc ├── public └── index.html ├── .github └── workflows │ └── build.yml ├── tsconfig.json ├── README.md ├── LICENSE ├── vue.config.js └── package.json /doc/img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Curtion/douyu-gift/HEAD/doc/img.jpg -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['@vue/cli-plugin-babel/preset'] 3 | }; 4 | -------------------------------------------------------------------------------- /src/assets/home.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Curtion/douyu-gift/HEAD/src/assets/home.ico -------------------------------------------------------------------------------- /src/vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import Vue from 'vue' 3 | export default Vue 4 | } 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "semi": false, 4 | "printWidth": 200, 5 | "trailingCommas": "none" 6 | } -------------------------------------------------------------------------------- /src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | declare module 'vue/types/vue' { 3 | interface Vue { 4 | $db: any 5 | $auto: any 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/config.d.ts: -------------------------------------------------------------------------------- 1 | interface Fans { 2 | name: string 3 | intimacy: string 4 | today: string 5 | ranking: string 6 | send: string // 赠送比例 7 | roomid: string 8 | } 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw? 22 | 23 | #Electron-builder output 24 | /dist_electron -------------------------------------------------------------------------------- /src/shims-tsx.d.ts: -------------------------------------------------------------------------------- 1 | import Vue, { VNode } from 'vue' 2 | 3 | declare global { 4 | namespace JSX { 5 | // tslint:disable no-empty-interface 6 | interface Element extends VNode {} 7 | // tslint:disable no-empty-interface 8 | interface ElementClass extends Vue {} 9 | interface IntrinsicElements { 10 | [elem: string]: any 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import store from './store' 5 | import ElementUI from 'element-ui' 6 | import 'element-ui/lib/theme-chalk/index.css' 7 | const db = require('electron').remote.getGlobal('db') 8 | Vue.config.productionTip = false 9 | Vue.use(ElementUI) 10 | 11 | Vue.prototype.$db = db 12 | Vue.prototype.$auto = null 13 | const vm = new Vue({ 14 | router, 15 | store, 16 | render: h => h(App) 17 | }).$mount('#app') 18 | 19 | export default vm 20 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "env": { 4 | "node": true 5 | }, 6 | "plugins": [ 7 | "@typescript-eslint" 8 | ], 9 | "extends": [ 10 | "plugin:vue/recommended", 11 | "@vue/prettier", 12 | "@vue/typescript" 13 | ], 14 | "parserOptions": { 15 | "ecmaVersion": 6, 16 | "sourceType": "module", 17 | "ecmaFeatures": { 18 | "modules": true 19 | }, 20 | "parser": "@typescript-eslint/parser" 21 | }, 22 | "rules": { 23 | "no-console": "off", 24 | "prettier/prettier": "error", 25 | "comma-dangle": [ 26 | "error", 27 | "never" 28 | ] 29 | } 30 | } -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 斗鱼续牌工具 10 | 11 | 12 | 13 | 17 |
18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/router/index.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import Home from '../views/home.vue' 4 | Vue.use(VueRouter) 5 | 6 | const routes = [ 7 | { 8 | path: '/', 9 | name: 'home', 10 | component: Home 11 | }, 12 | { 13 | path: '/config', 14 | name: 'config', 15 | component: () => import('../views/config.vue') 16 | }, 17 | { 18 | path: '/about', 19 | name: 'about', 20 | component: () => import('../views/about.vue') 21 | } 22 | ] 23 | 24 | const router = new VueRouter({ 25 | mode: 'hash', 26 | base: process.env.BASE_URL, 27 | routes 28 | }) 29 | 30 | export default router 31 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build/release 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*.*.*' 7 | 8 | jobs: 9 | release: 10 | runs-on: ${{ matrix.os }} 11 | 12 | strategy: 13 | matrix: 14 | os: [windows-2019] 15 | 16 | steps: 17 | - name: Check out Git repository 18 | uses: actions/checkout@v1 19 | 20 | - name: Install Node.js, NPM and Yarn 21 | uses: actions/setup-node@v1 22 | with: 23 | node-version: 10 24 | - name: Build/release Electron app 25 | env: 26 | GH_TOKEN: ${{ secrets.github_token }} 27 | run: | 28 | yarn install 29 | (Get-Content "node_modules/builder-util/out/util.js").Replace("^[\w","^[.\w")| out-file "node_modules/builder-util/out/util.js" 30 | yarn electron:build --publish always 31 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "strict": true, 6 | "jsx": "preserve", 7 | "importHelpers": true, 8 | "moduleResolution": "node", 9 | "experimentalDecorators": true, 10 | "esModuleInterop": true, 11 | "allowSyntheticDefaultImports": true, 12 | "sourceMap": true, 13 | "baseUrl": ".", 14 | "types": [ 15 | "webpack-env" 16 | ], 17 | "paths": { 18 | "@/*": [ 19 | "src/*" 20 | ] 21 | }, 22 | "lib": [ 23 | "esnext", 24 | "dom", 25 | "dom.iterable", 26 | "scripthost" 27 | ] 28 | }, 29 | "include": [ 30 | "src/**/*.ts", 31 | "src/**/*.tsx", 32 | "src/**/*.vue", 33 | "tests/**/*.ts", 34 | "tests/**/*.tsx" 35 | ], 36 | "exclude": [ 37 | "node_modules" 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /src/views/home.vue: -------------------------------------------------------------------------------- 1 | 11 | 27 | 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 新版本说明 2 | 请使用新软件: https://github.com/Curtion/douyu-keep 3 | 4 | 新软件新增了一些功能和执行模式. 详情请看说明页面. 5 | 6 | 当前旧软件仍然可以使用,但是不会修复已知bug, 也不会新增功能. 7 | 8 | # 旧软件说明 9 | 10 | 功能: 设置比例分配荧光棒,开机自动启动,任务完成后自动关闭软件。 11 | 12 | ![](./doc/img.jpg) 13 | 14 | [点击这里进行下载](https://github.com/Curtion/douyu-gift/releases) 15 | 16 | # 说明 17 | 18 | 使用 Vue + ElementUI + TypeScript 驱动,仅用于学习用途。这是第二版,第一版使用了 jQuery + Electron; 19 | 第二版从代码上更清晰,但是功能不变,仍然只是自动赠送荧光棒。 20 | 21 | 当前 releases 只构建了 Windows X86_64 版本,如果需要 Linux 或者 Mac 版本请在`vue.config.js`配置,[相关配置文档](https://nklayman.github.io/vue-cli-plugin-electron-builder/guide/configuration.html#configuring-electron-builder) 22 | 23 | # 克隆 24 | 25 | `https://github.com/Curtion/douyu-gift.git` 26 | 27 | # 安装 28 | 29 | `yarn install` 30 | 31 | # 开发 32 | 33 | `yarn electron:serve` 34 | 35 | # 构建 36 | 37 | `yarn electron:build` 38 | 39 | # 感谢 40 | 41 | ![icon](https://img.icons8.com/color/96/000000/intellij-idea.png) 42 | 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Curtion 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/components/nologin.vue: -------------------------------------------------------------------------------- 1 | 4 | 43 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | pluginOptions: { 3 | electronBuilder: { 4 | builderOptions: { 5 | publish: ['github'], 6 | appId: 'com.3gxk.app', 7 | productName: '斗鱼续牌工具', //项目名 8 | copyright: 'Copyright © 2014-2021', //版权信息 9 | directories: { 10 | output: './dist' //输出文件路径 11 | }, 12 | win: { 13 | //win相关配置 14 | icon: './src/assets/home.ico', //图标,当前图标在根目录下,注意这里有两个坑 15 | target: [ 16 | { 17 | target: 'nsis', //利用nsis制作安装程序 18 | arch: [ 19 | 'x64' //64位 20 | ] 21 | } 22 | ] 23 | }, 24 | nsis: { 25 | oneClick: false, // 是否一键安装 26 | allowElevation: true, // 允许请求提升。 如果为false,则用户必须使用提升的权限重新启动安装程序。 27 | allowToChangeInstallationDirectory: true, // 允许修改安装目录 28 | installerIcon: './src/assets/home.ico', // 安装图标 29 | uninstallerIcon: './src/assets/home.ico', //卸载图标 30 | installerHeaderIcon: './src/assets/home.ico', // 安装时头部图标 31 | createDesktopShortcut: true, // 创建桌面图标 32 | createStartMenuShortcut: true, // 创建开始菜单图标 33 | shortcutName: '斗鱼续牌工具' // 图标名称 34 | } 35 | } 36 | } 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /src/main/rpc.ts: -------------------------------------------------------------------------------- 1 | import { ipcMain } from 'electron' 2 | const AutoLaunch = require('auto-launch') // 自动启动 3 | let douyuAutoLauncher = new AutoLaunch({ 4 | name: 'douyu-git', 5 | path: process.execPath 6 | }) 7 | ipcMain.on('AutoLaunch', (event, arg) => { 8 | // 设置开启启动 9 | if (arg === 0) { 10 | douyuAutoLauncher 11 | .isEnabled() 12 | .then((isEnabled: boolean) => { 13 | if (!isEnabled) { 14 | event.returnValue = true 15 | return 16 | } 17 | douyuAutoLauncher.disable() 18 | event.returnValue = true 19 | }) 20 | .catch((err: Error) => { 21 | event.returnValue = err.toString() 22 | }) 23 | } 24 | if (arg === 1) { 25 | douyuAutoLauncher 26 | .isEnabled() 27 | .then((isEnabled: boolean) => { 28 | if (isEnabled) { 29 | event.returnValue = true 30 | return 31 | } 32 | douyuAutoLauncher.enable() 33 | event.returnValue = true 34 | }) 35 | .catch((err: Error) => { 36 | event.returnValue = err.toString() 37 | }) 38 | } 39 | if (arg === 3) { 40 | douyuAutoLauncher 41 | .isEnabled() 42 | .then((isEnabled: boolean) => { 43 | event.returnValue = isEnabled 44 | }) 45 | .catch((err: Error) => { 46 | event.returnValue = err.toString() 47 | }) 48 | } 49 | }) 50 | -------------------------------------------------------------------------------- /src/views/about.vue: -------------------------------------------------------------------------------- 1 | 22 | 40 | 57 | -------------------------------------------------------------------------------- /src/background.ts: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | import { app, protocol, BrowserWindow } from 'electron' 3 | import electron from 'electron' 4 | import { createProtocol, installVueDevtools } from 'vue-cli-plugin-electron-builder/lib' 5 | import './main/rpc.ts' // rpc订阅 6 | require('electron-referer')('https://www.douyu.com/') 7 | // 兼容多平台 8 | const platform = process.platform === 'win32' ? '\\' : '/' 9 | const isDevelopment = process.env.NODE_ENV !== 'production' 10 | const Store = require('electron-store') 11 | let paths = process.execPath.split(platform) 12 | paths.pop() 13 | const db = new Store() 14 | ;(global as any).db = db 15 | let win: BrowserWindow | null 16 | protocol.registerSchemesAsPrivileged([{ scheme: 'app', privileges: { secure: true, standard: true } }]) 17 | 18 | function createWindow() { 19 | electron.Menu.setApplicationMenu(null) 20 | win = new BrowserWindow({ 21 | width: 800, 22 | height: 400, 23 | webPreferences: { 24 | nodeIntegration: true, 25 | webSecurity: false, 26 | enableRemoteModule: true 27 | }, 28 | resizable: false 29 | }) 30 | if (process.env.WEBPACK_DEV_SERVER_URL) { 31 | win.loadURL(process.env.WEBPACK_DEV_SERVER_URL as string) 32 | if (!process.env.IS_TEST) win.webContents.openDevTools() 33 | } else { 34 | createProtocol('app') 35 | win.loadURL('app://./index.html') 36 | } 37 | win.on('closed', () => { 38 | win = null 39 | }) 40 | } 41 | 42 | app.on('window-all-closed', () => { 43 | if (process.platform !== 'darwin') { 44 | app.quit() 45 | } 46 | }) 47 | 48 | app.on('activate', () => { 49 | if (win === null) { 50 | createWindow() 51 | } 52 | }) 53 | 54 | app.on('ready', async () => { 55 | if (isDevelopment && !process.env.IS_TEST) { 56 | await installVueDevtools() 57 | } 58 | createWindow() 59 | }) 60 | 61 | if (isDevelopment) { 62 | if (process.platform === 'win32') { 63 | process.on('message', data => { 64 | if (data === 'graceful-exit') { 65 | app.quit() 66 | } 67 | }) 68 | } else { 69 | process.on('SIGTERM', () => { 70 | app.quit() 71 | }) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 28 | 48 | 49 | 93 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "douyu", 3 | "version": "1.4.2", 4 | "author": "Curtion", 5 | "description": "斗鱼自动赠送荧光棒", 6 | "private": true, 7 | "scripts": { 8 | "serve": "vue-cli-service serve", 9 | "build": "vue-cli-service build", 10 | "lint": "vue-cli-service lint", 11 | "electron:build": "vue-cli-service electron:build", 12 | "electron:serve": "vue-cli-service electron:serve", 13 | "postinstall": "electron-builder install-app-deps", 14 | "postuninstall": "electron-builder install-app-deps" 15 | }, 16 | "main": "background.js", 17 | "dependencies": { 18 | "auto-launch": "^5.0.5", 19 | "axios": "^0.21.1", 20 | "core-js": "^3.3.2", 21 | "cron": "^1.8.2", 22 | "electron-log": "^4.3.4", 23 | "electron-store": "^5.2.0", 24 | "element-ui": "^2.12.0", 25 | "mathjs": "^7.5.1", 26 | "node-sass": "^4.13.1", 27 | "sass-loader": "^8.0.0", 28 | "vue": "^2.6.10", 29 | "vue-class-component": "^7.0.2", 30 | "vue-property-decorator": "^8.3.0", 31 | "vue-router": "^3.1.3", 32 | "vuex": "^3.0.1" 33 | }, 34 | "devDependencies": { 35 | "@vue/cli-plugin-babel": "^4.0.0", 36 | "@vue/cli-plugin-eslint": "^4.0.0", 37 | "@vue/cli-plugin-router": "^4.0.0", 38 | "@vue/cli-plugin-typescript": "^4.0.0", 39 | "@vue/cli-plugin-vuex": "^4.0.0", 40 | "@vue/cli-service": "^4.0.0", 41 | "@vue/eslint-config-prettier": "^5.0.0", 42 | "@vue/eslint-config-typescript": "^4.0.0", 43 | "electron": "11.5.0", 44 | "electron-chromedriver": "^7.0.0", 45 | "electron-referer": "^0.3.0", 46 | "eslint": "^5.16.0", 47 | "eslint-plugin-prettier": "^3.1.1", 48 | "eslint-plugin-vue": "^5.0.0", 49 | "prettier": "^1.18.2", 50 | "typescript": "~3.5.3", 51 | "vue-cli-plugin-electron-builder": "^1.4.1", 52 | "vue-template-compiler": "^2.6.10" 53 | }, 54 | "eslintConfig": { 55 | "root": true, 56 | "env": { 57 | "node": true 58 | }, 59 | "extends": [ 60 | "plugin:vue/essential", 61 | "@vue/prettier", 62 | "@vue/typescript" 63 | ], 64 | "rules": {}, 65 | "parserOptions": { 66 | "parser": "@typescript-eslint/parser" 67 | } 68 | }, 69 | "postcss": { 70 | "plugins": { 71 | "autoprefixer": {} 72 | } 73 | }, 74 | "browserslist": [ 75 | "> 1%", 76 | "last 2 versions" 77 | ] 78 | } -------------------------------------------------------------------------------- /src/function/send.ts: -------------------------------------------------------------------------------- 1 | import store from '../store/index' 2 | import axios from 'axios' 3 | const { session } = require('electron').remote 4 | import { Message } from 'element-ui' 5 | const log = require('electron-log') 6 | interface DyAndsid { 7 | dy: string 8 | sid: string 9 | } 10 | async function init(fans: any) { 11 | log.info('开始赠送') 12 | let DySid = await getDyAndsid() 13 | const sid = (DySid as DyAndsid).sid 14 | const dy = (DySid as DyAndsid).dy 15 | let Remaining = store.state.gift.num // 剩余数量 16 | log.info('sid获取成功:' + sid) 17 | log.info('dy获取成功:' + dy) 18 | for (let [index, item] of fans.entries()) { 19 | let num = Math.floor(store.state.gift.num * Number.parseInt((item as Fans).send) * 0.01) 20 | if (index === fans.length - 1) { 21 | // 最后一次全部赠送,防止分配不均 22 | num = Remaining 23 | } 24 | let gift = { 25 | prop: 268, 26 | rid: (item as Fans).roomid, 27 | num, 28 | sid, 29 | dy 30 | } 31 | await pushGift(gift) 32 | Remaining = Remaining - num 33 | } 34 | return true 35 | } 36 | function getDyAndsid() { 37 | return new Promise((resolve, reject) => { 38 | ;(session.defaultSession as Electron.Session).cookies 39 | .get({ domain: 'douyu.com' }) 40 | .then(cookies => { 41 | let arr: DyAndsid = { 42 | dy: '', 43 | sid: '' 44 | } 45 | cookies.forEach(item => { 46 | if (item.name === 'dy_did') { 47 | arr.dy = item.value 48 | } 49 | if (item.name === 'acf_uid') { 50 | arr.sid = item.value 51 | } 52 | }) 53 | resolve(arr) 54 | }) 55 | .catch(error => { 56 | log.warn('sid、dy获取失败') 57 | reject(error) 58 | }) 59 | }) 60 | } 61 | function getDidAndRid(roomid: string) { 62 | return new Promise((resolve, reject) => { 63 | log.info('获取"' + roomid + '"房间获取did值开始') 64 | axios.get('https://www.douyu.com/' + roomid).then(res => { 65 | let rid = res.data.match(/\$ROOM\.room_id =(.*?);/)[1].trim() 66 | let did = res.data.match(/owner_uid =(.*?);/)[1].trim() 67 | if (did !== undefined) { 68 | log.info('获取"' + roomid + '"房间获取did值结束,成功:' + did) 69 | resolve([did, rid !== undefined ? rid : roomid]) 70 | } else { 71 | log.warn('获取"' + roomid + '"房间获取did值结束,失败') 72 | reject('did获取错误') 73 | } 74 | }) 75 | }) 76 | } 77 | function pushGift(payload: any) { 78 | return new Promise((resolve, reject) => { 79 | getDidAndRid(payload.rid).then((DidAndRid: any) => { 80 | const [did, rid] = DidAndRid 81 | setTimeout(() => { 82 | log.info('赠送"' + rid + '"房间开始,数量:' + payload.num) 83 | Message('开始请求' + rid + '房间') 84 | let data = new FormData() 85 | data.append('rid', rid) 86 | data.append('prop_id', payload.prop) 87 | data.append('num', payload.num) 88 | data.append('sid', payload.sid) 89 | data.append('did', did) 90 | data.append('dy', payload.dy) 91 | axios 92 | .post('https://www.douyu.com/member/prop/send', data) 93 | .then((res: any) => { 94 | log.info('赠送"' + payload.rid + '"房间结束,赠送结果:' + JSON.stringify(res.data)) 95 | resolve() 96 | }) 97 | .catch(err => { 98 | reject(err) 99 | }) 100 | }, 3000) 101 | }) 102 | }) 103 | } 104 | export default init 105 | -------------------------------------------------------------------------------- /src/components/user.vue: -------------------------------------------------------------------------------- 1 | 34 | 153 | 187 | -------------------------------------------------------------------------------- /src/store/index.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import axios from 'axios' 4 | import { Message } from 'element-ui' 5 | import vm from '../main' 6 | Vue.use(Vuex) 7 | 8 | export default new Vuex.Store({ 9 | state: { 10 | isLogin: false, 11 | user: { 12 | tel: '', // 手机号 13 | level: '' // 等级img地址 14 | }, 15 | gift: { 16 | num: 0, //荧光棒数量 17 | gif: '' // 荧光棒礼物图标地址 18 | }, 19 | fans: [], // 粉丝牌数据, 20 | loading: false, 21 | isStart: false // 任务是否正在进行 22 | }, 23 | mutations: { 24 | /** 25 | * 登录得状态 26 | * 27 | * @param {*} state 28 | * @param {boolean} status 29 | */ 30 | login(state: any, status: boolean) { 31 | state.isLogin = status 32 | }, 33 | /** 34 | * 用户信息,手机号与等级 35 | * 36 | * @param {*} state 37 | * @param {*} { tel, level } 38 | */ 39 | user(state: any, { tel, level }: any) { 40 | state.user.tel = tel 41 | state.user.level = level 42 | }, 43 | /** 44 | * 查询荧光棒得数量 45 | * 46 | * @param {*} state 47 | * @param {*} number 48 | */ 49 | gift(state: any, { num, gif }: any) { 50 | state.gift.num = num 51 | state.gift.gif = gif 52 | }, 53 | /** 54 | * 粉丝牌数据 55 | * @param {*} state 56 | * @param {*} payload 57 | */ 58 | fans(state: any, payload: any) { 59 | state.fans = payload 60 | }, 61 | isStart(state, payload: boolean) { 62 | state.isStart = payload 63 | } 64 | }, 65 | actions: { 66 | /** 67 | * 检测是否登录,在初始化软件时检测/或者关闭登录窗口时检测 68 | * 69 | * @param {*} { commit } 70 | */ 71 | checkLogin({ commit }: any) { 72 | axios 73 | .get('https://www.douyu.com/member/cp/cp_rpc_ajax') 74 | .then(res => { 75 | if (typeof res.data === 'object') { 76 | commit('login', true) 77 | commit('user', { 78 | tel: res.data.info.mobile_phone, 79 | level: res.data.exp_info.current.pic_url 80 | }) 81 | } else { 82 | commit('login', false) 83 | } 84 | }) 85 | .catch(err => { 86 | Message({ 87 | type: 'error', 88 | message: err 89 | }) 90 | }) 91 | }, 92 | /** 93 | * 获取荧光棒数量 94 | * 95 | * @param {*} { commit } 96 | */ 97 | getgift({ commit, dispatch }: any) { 98 | return new Promise((resolve, reject) => { 99 | let params: FormData = new FormData() 100 | params.append('rid', '4120796') 101 | axios 102 | .post('https://www.douyu.com/member/prop/query', params, { 103 | headers: { 104 | 'Content-Type': 'multipart/form-data' 105 | } 106 | }) 107 | .then(res => { 108 | let isOn: boolean = false 109 | let index: number = 0 110 | isOn = res.data.data.list.some((element: any, i: number) => { 111 | if (element.prop_id === 268) { 112 | index = i 113 | return true 114 | } 115 | }) 116 | if (isOn) { 117 | commit('gift', { 118 | num: res.data.data.list[index].count, 119 | gif: res.data.data.list[index].gif 120 | }) 121 | } else { 122 | commit('gift', { num: 0, git: '' }) 123 | } 124 | dispatch('getFansList', false) 125 | resolve() 126 | }) 127 | .catch(() => { 128 | reject() 129 | }) 130 | }) 131 | }, 132 | getFansList({ commit, state }, isLoad = true) { 133 | return new Promise((resolve, reject) => { 134 | state.loading = true 135 | axios 136 | .get('https://www.douyu.com/member/cp/getFansBadgeList') 137 | .then(async res => { 138 | let table = res.data.match(/fans-badge-list">([\S\s]*?)<\/table>/)[1] 139 | let list = table.match(//g) 140 | let arr: Array = [] 141 | list.slice(1).forEach((element: string) => { 142 | let obj: Fans = { 143 | name: '', 144 | intimacy: '', 145 | today: '', 146 | ranking: '', 147 | send: '', 148 | roomid: '' 149 | } 150 | ;(element.match(//g) as Array).slice(1, 5).forEach((val: string, index: number) => { 151 | obj.send = '' 152 | switch (index) { 153 | case 0: 154 | obj.name = val.replace(/<([\s\S]*?)>/g, '').trim() 155 | val.match(/href="\/([\s\S]*?)"/) 156 | obj.roomid = RegExp.$1 157 | break 158 | case 1: 159 | obj.intimacy = val.replace(/<([\s\S]*?)>/g, '').trim() 160 | break 161 | case 2: 162 | obj.today = val.replace(/<([\s\S]*?)>/g, '').trim() 163 | break 164 | case 3: 165 | obj.ranking = val.replace(/<([\s\S]*?)>/g, '').trim() 166 | break 167 | default: 168 | break 169 | } 170 | }) 171 | arr.push(obj) 172 | }) 173 | state.loading = false 174 | commit('fans', arr) 175 | if (isLoad) { 176 | vm.$db.set('fans', arr) 177 | } 178 | resolve() 179 | }) 180 | .catch(() => { 181 | reject() 182 | }) 183 | }) 184 | }, 185 | /** 186 | * 保存配置到文件 187 | */ 188 | saveNumberConfig({ commit }, payload) { 189 | commit('fans', payload) 190 | vm.$db.set('fans', payload) 191 | } 192 | } 193 | }) 194 | -------------------------------------------------------------------------------- /src/views/config.vue: -------------------------------------------------------------------------------- 1 | 47 | 176 | 207 | --------------------------------------------------------------------------------