mirror of
https://github.com/electron-vite/electron-vite-vue
synced 2025-04-25 05:56:57 +08:00
Merge 77da3cf3394eae3ea81a7742f3c51bb12e627bb6 into b4cf3b4c5f3e77eb7d28490b60f64ea7a94e47a4
This commit is contained in:
commit
02d4f9dff6
@ -4,7 +4,7 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/electron-userland/electron-builder/master/packages/app-builder-lib/scheme.json",
|
||||
"appId": "YourAppID",
|
||||
"asar": true,
|
||||
"asar": false,
|
||||
"directories": {
|
||||
"output": "release/${version}"
|
||||
},
|
||||
|
152
electron/main/gpt/batchApplication.ts
Normal file
152
electron/main/gpt/batchApplication.ts
Normal file
@ -0,0 +1,152 @@
|
||||
import type { Browser, Page } from 'puppeteer'
|
||||
import puppeteer from 'puppeteer-extra'
|
||||
import StealthPlugin from 'puppeteer-extra-plugin-stealth'
|
||||
import { clog } from "../tools";
|
||||
import { awaitWrap, randomNum } from '../tools';
|
||||
import login from '../login'
|
||||
import Mock from 'mockjs'
|
||||
import axios from 'axios'
|
||||
import { SocksProxyAgent } from 'socks-proxy-agent'
|
||||
import proxyChain from 'proxy-chain'
|
||||
// const proxyChain = require('proxy-chain');
|
||||
|
||||
puppeteer.use(StealthPlugin())
|
||||
|
||||
|
||||
function getProxy(options = {} as any) {
|
||||
const log = clog(options)
|
||||
log('开始获取代理ip')
|
||||
return axios.get('http://api.proxy.ipidea.io/getBalanceProxyIp?num=1&return_type=json&lb=1&sb=0&flow=1®ions=&protocol=socks5', {
|
||||
// return axios.get('https://www.miyaip.com/api/ProxyGenerage/PublicGenerateProxy?country=us&city=jaffrey®ion=nh&num=1&apiSwitch=0&mealType=2&genType=2&username=nmfk549724@163.com&secret=E3BCBmiyaipC23358C250F5', {
|
||||
// return axios.get('http://api.tianqiip.com/getip?secret=loy0r7fpmnlshm8l&num=1&type=json&port=3&time=3&mr=1&sign=5f73ab58ad7ab40346311014bef59b79', {
|
||||
timeout: 10 * 1000,
|
||||
}).then(res => {
|
||||
|
||||
// // const [user, pass] = res.data.split(':')
|
||||
// // return { user, pass, ip, port }
|
||||
// // // return axios.get('https://www.miyaip.com/api/ProxyGenerage/PublicGenerateProxy?country=us&city=cairo®ion=ny&num=1&apiSwitch=0&mealType=2&genType=2&username=nmfk549724@163.com&secret=E3BCBmiyaipC23358C250F5').then(res => {
|
||||
// const [ip, port] = res.data.replace(/(\n|\r\s)/g, '').split(':')
|
||||
// console.log({ ip, port, })
|
||||
// // const [ip, pory, user, pass] = res.data.split(':')
|
||||
return res.data.data[0]
|
||||
})
|
||||
return Promise.resolve({
|
||||
ip: '43.130.10.70',
|
||||
port: '22993',
|
||||
// user: '1E783B07miyaip489C251B3FA7',
|
||||
// pass: '1g7E3M4U5w03vO'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取组织id
|
||||
async function getOrgId(page: Page, options: any) {
|
||||
const log = clog(options)
|
||||
log('准备进入组织页面')
|
||||
await page.goto('https://platform.openai.com/account/org-settings')
|
||||
await page.waitForSelector('input')
|
||||
log('开始获取组织id')
|
||||
const orgId = await page.$$eval('input', (inputs: HTMLInputElement[]) => inputs?.[1].value || '')
|
||||
log('获取组织id成功', { orgId })
|
||||
return orgId
|
||||
}
|
||||
|
||||
// 申请
|
||||
export async function application(page: Page, options = {} as any) {
|
||||
const log = clog(options)
|
||||
|
||||
log('准备进入申请页面')
|
||||
await page.goto('https://openai.com/waitlist/gpt-4-api')
|
||||
|
||||
log('等待出现输入框')
|
||||
await page.waitForSelector('input')
|
||||
|
||||
log('开始申请')
|
||||
|
||||
const f = Mock.mock('@first')
|
||||
const l = Mock.mock('@last')
|
||||
console.log(f, l);
|
||||
|
||||
await page.type('#firstname', f)
|
||||
await page.type('#lastname', l)
|
||||
await page.type('#email', options.user)
|
||||
await page.type('#organizationId', options.orgId)
|
||||
|
||||
const i = randomNum(1, 4)
|
||||
|
||||
log('选择申请类型', { i })
|
||||
page.evaluate((i) => {
|
||||
document.querySelector('#primaryUse').nextSibling.childNodes[i].childNodes[1].click()
|
||||
}, i)
|
||||
|
||||
log('等待 gpt 生成描述')
|
||||
const desc = await generateDescription(i)
|
||||
await page.type('#ideas', desc)
|
||||
|
||||
log('点击提交申请')
|
||||
const isSuccess = await page.evaluate((selector, searchText) => {
|
||||
const elements = Array.from(document.querySelectorAll(selector));
|
||||
const target = elements.find(el => el.textContent.trim() === searchText);
|
||||
|
||||
if (target) target.click()
|
||||
return !!target
|
||||
}, 'button', 'Join waitlist')
|
||||
|
||||
if (isSuccess) {
|
||||
log('提交成功,等待 gpt 返回结果')
|
||||
console.log('isSuccess', isSuccess)
|
||||
await page.waitForSelector('button[type="submit"] + .ui-richtext')
|
||||
const text = await page.evaluate(() => document.querySelector('button[type="submit"] + .ui-richtext').textContent)
|
||||
log('gpt 返回已结果', { result: text })
|
||||
}
|
||||
|
||||
|
||||
// await page.click('form[data-gtm-form-interact-id] button[type="submit"]')
|
||||
}
|
||||
|
||||
|
||||
// 生成描述
|
||||
export async function generateDescription(desIndex = 0): Promise<string> {
|
||||
const types = {
|
||||
1: 'Build a new product',
|
||||
2: 'Integrate into an existing product',
|
||||
3: 'General exploration of capabilities',
|
||||
4: 'Academic research',
|
||||
}
|
||||
|
||||
return axios({
|
||||
url: 'https://api.openai-proxy.com/v1/chat/completions',
|
||||
method: 'post',
|
||||
headers: {
|
||||
Authorization: `Bearer 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`
|
||||
},
|
||||
data: {
|
||||
max_tokens: 1024,
|
||||
model: 'gpt-3.5-turbo',
|
||||
messages: [
|
||||
{ "role": "user", "content": `我在申请gpt4.0,我的类型是 ${types[desIndex]},不要解释,给我一段申请的理由,以我的身份,以英语形式发给我,结尾不要带任何名字或位置,三四句话就行` },
|
||||
]
|
||||
},
|
||||
timeout: 1000 * 30,
|
||||
}).then(res => {
|
||||
console.log('gpt 生成描述', res.data.choices[0].message.content)
|
||||
return res.data.choices[0].message.content
|
||||
})
|
||||
}
|
||||
|
||||
export async function batchApplication(options) {
|
||||
const log = clog(options)
|
||||
log('开始', { ident: 'gpt-batch-4.0' })
|
||||
|
||||
const [error, [page, browser]] = await awaitWrap(login.openai(options))
|
||||
if (error) return log('登录失败', { error, ident: 'gpt-batch-4.0' })
|
||||
|
||||
await page.waitForSelector('.ovr-section')
|
||||
|
||||
const orgId = await getOrgId(page, options)
|
||||
options.orgId = orgId
|
||||
console.log('orgId', orgId)
|
||||
|
||||
await application(page, options)
|
||||
|
||||
browser.close()
|
||||
}
|
48
electron/main/gpt/getLink.ts
Normal file
48
electron/main/gpt/getLink.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import { clog } from "../tools";
|
||||
import login from "../login";
|
||||
|
||||
export async function getLink(options) {
|
||||
const log = clog(options)
|
||||
log('开始', { ident: 'gpt-link', ...options })
|
||||
const [page, browser] = await login.chatgpt({ ...options, changeUS: false })
|
||||
|
||||
// await page.waitForTimeout(500)
|
||||
|
||||
await page.waitForSelector('body > div.absolute.inset-0', { timeout: 0 })
|
||||
await page.evaluate(() => {
|
||||
const $mark = document.querySelector("body > div.absolute.inset-0")
|
||||
if ($mark) $mark.hidden = true
|
||||
document.body.style.pointerEvents = 'all'
|
||||
})
|
||||
|
||||
log('隐藏欢迎页面')
|
||||
|
||||
await page.waitForSelector('.gold-new-button', { visible: true })
|
||||
log('等待升级plus按钮出现')
|
||||
await page.waitForTimeout(500)
|
||||
|
||||
await page.evaluate(() => {
|
||||
const $mark = document.querySelector("body > div.absolute.inset-0")
|
||||
if ($mark) $mark.remove()
|
||||
})
|
||||
|
||||
log('开始点击升级plus按钮')
|
||||
await page.click('.gold-new-button')
|
||||
|
||||
const [response] = await Promise.all([
|
||||
page.waitForNavigation({ waitUntil: 'domcontentloaded', timeout: 0 }),
|
||||
page.evaluate((selector, searchText) => {
|
||||
const elements = Array.from(document.querySelectorAll(selector));
|
||||
const target = elements.find(el => el.textContent.trim() === searchText);
|
||||
target && target.click()
|
||||
}, 'button', 'Upgrade plan')
|
||||
])
|
||||
|
||||
if (response.ok()) {
|
||||
const url = response._request._frame._url
|
||||
log('获取链接成功', { result: url, type: 'success' })
|
||||
browser.close()
|
||||
return url
|
||||
}
|
||||
browser.close()
|
||||
}
|
93
electron/main/gpt/index.ts
Normal file
93
electron/main/gpt/index.ts
Normal file
@ -0,0 +1,93 @@
|
||||
import { ipcMain } from 'electron'
|
||||
import { getLink } from './getLink'
|
||||
import { validate } from './validate'
|
||||
import { batchApplication } from './batchApplication'
|
||||
import { chunk } from 'lodash'
|
||||
import { sleep } from '../tools'
|
||||
|
||||
const parseAccount = text => text.split('\n').filter(Boolean).map(v => {
|
||||
v = v.split(/(——|-)+/).filter(v => !['-', '——'].includes(v))
|
||||
return v
|
||||
})
|
||||
|
||||
ipcMain.handle('gpt-link', async (event, arg) => {
|
||||
const { text } = arg
|
||||
// 进程数
|
||||
const processNum = 2
|
||||
const totalArr = parseAccount(text)
|
||||
const accounts = chunk(totalArr, Math.ceil(totalArr.length / processNum))
|
||||
|
||||
async function run (accounts) {
|
||||
for(let i = 0; i < accounts.length; i++) {
|
||||
const [user, pass] = accounts[i]
|
||||
const link = await getLink({ user, pass, index: i, id: user, ...arg })
|
||||
console.log('process', i, user, link)
|
||||
}
|
||||
}
|
||||
const links = []
|
||||
for(let i = 0; i < accounts.length; i++) {
|
||||
if (i !== 0) await sleep(2000)
|
||||
run(accounts[i])
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.handle('gpt-result', async (event, arg) => {
|
||||
const { text } = arg
|
||||
const accounts = parseAccount(text)
|
||||
|
||||
const links = []
|
||||
for(let i = 0; i < accounts.length; i++) {
|
||||
const [user, pass] = accounts[i]
|
||||
const link = await validate({ user, pass, index: i, id: user })
|
||||
links.push({
|
||||
i,
|
||||
user,
|
||||
link
|
||||
})
|
||||
console.log('process', i, user, link)
|
||||
}
|
||||
// browser && browser.close()
|
||||
})
|
||||
|
||||
|
||||
ipcMain.handle('gpt-batch-4.0', async (event, arg) => {
|
||||
const { text } = arg
|
||||
const accounts = parseAccount(text)
|
||||
|
||||
const links = []
|
||||
for(let i = 0; i < accounts.length; i++) {
|
||||
const [user, pass] = accounts[i]
|
||||
const link = await batchApplication({ user, pass, index: i, id: user })
|
||||
links.push({
|
||||
i,
|
||||
user,
|
||||
link
|
||||
})
|
||||
console.log('process', i, user, link)
|
||||
}
|
||||
// browsers.forEach(browser => browser.close())
|
||||
})
|
||||
|
||||
|
||||
const actions = {
|
||||
'gpt-link': getLink,
|
||||
'gpt-result': validate,
|
||||
'gpt-batch-4.0': batchApplication
|
||||
}
|
||||
|
||||
export async function runActions(action: keyof typeof actions, options: any) {
|
||||
const { text } = options
|
||||
const accounts = parseAccount(text)
|
||||
|
||||
const links = []
|
||||
for(let i = 0; i < accounts.length; i++) {
|
||||
const [user, pass] = accounts[i]
|
||||
const link = await batchApplication({ user, pass, index: i, id: user })
|
||||
links.push({
|
||||
i,
|
||||
user,
|
||||
link
|
||||
})
|
||||
console.log('process', i, user, link)
|
||||
}
|
||||
}
|
28
electron/main/gpt/validate.ts
Normal file
28
electron/main/gpt/validate.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { clog } from "../tools";
|
||||
import login from "../login";
|
||||
|
||||
export async function validate(options) {
|
||||
const log = clog(options)
|
||||
log('开始', { ident: 'gpt-validate' })
|
||||
const [page, browser] = await login.chatgpt(options)
|
||||
|
||||
await page.waitForSelector('body > div.absolute.inset-0')
|
||||
await page.evaluate(() => {
|
||||
const $mark = document.querySelector("body > div.absolute.inset-0")
|
||||
if ($mark) $mark.hidden = true
|
||||
document.body.style.pointerEvents = 'all'
|
||||
})
|
||||
log('隐藏欢迎页面,开始检测')
|
||||
|
||||
await page.waitForTimeout(2000)
|
||||
|
||||
const isSuccess = await page.evaluate((selector, searchText) => {
|
||||
const elements = Array.from(document.querySelectorAll(selector));
|
||||
const target = elements.find(el => el.textContent.trim() === searchText);
|
||||
return !!target
|
||||
}, 'button', 'GPT-4')
|
||||
log('获取链接成功', { result: isSuccess ? '充值成功😘' : '充值失败😭', type: isSuccess ? 'success' : 'fail' })
|
||||
|
||||
console.log(isSuccess)
|
||||
browser.close()
|
||||
}
|
@ -1,6 +1,24 @@
|
||||
import { app, BrowserWindow, shell, ipcMain } from 'electron'
|
||||
import { release } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import './poe/index'
|
||||
import './gpt/index'
|
||||
import { browsers, test1 } from './tools'
|
||||
|
||||
import puppeteer from 'puppeteer-extra'
|
||||
import StealthPlugin from 'puppeteer-extra-plugin-stealth'
|
||||
puppeteer.use(StealthPlugin())
|
||||
|
||||
|
||||
// test1()
|
||||
// puppeteer.launch({
|
||||
// headless: false,
|
||||
// args: [
|
||||
// '--no-sandbox',
|
||||
// '--disable-setuid-sandbox',
|
||||
// '--proxy-server=socks5://127.0.0.1:40000'
|
||||
// ]
|
||||
// })
|
||||
|
||||
// The built directory structure
|
||||
//
|
||||
@ -34,7 +52,7 @@ if (!app.requestSingleInstanceLock()) {
|
||||
// Read more on https://www.electronjs.org/docs/latest/tutorial/security
|
||||
// process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'
|
||||
|
||||
let win: BrowserWindow | null = null
|
||||
export let win: BrowserWindow | null = null
|
||||
// Here, you can also use other preload
|
||||
const preload = join(__dirname, '../preload/index.js')
|
||||
const url = process.env.VITE_DEV_SERVER_URL
|
||||
@ -43,6 +61,8 @@ const indexHtml = join(process.env.DIST, 'index.html')
|
||||
async function createWindow() {
|
||||
win = new BrowserWindow({
|
||||
title: 'Main window',
|
||||
width: 1000,
|
||||
height: 800,
|
||||
icon: join(process.env.PUBLIC, 'favicon.ico'),
|
||||
webPreferences: {
|
||||
preload,
|
||||
@ -56,8 +76,10 @@ async function createWindow() {
|
||||
|
||||
if (process.env.VITE_DEV_SERVER_URL) { // electron-vite-vue#298
|
||||
win.loadURL(url)
|
||||
console.log('process.env.VITE_DEV_SERVER_URL', process.env.VITE_DEV_SERVER_URL);
|
||||
|
||||
// Open devTool if the app is not packaged
|
||||
win.webContents.openDevTools()
|
||||
// win.webContents.openDevTools()
|
||||
} else {
|
||||
win.loadFile(indexHtml)
|
||||
}
|
||||
@ -115,3 +137,8 @@ ipcMain.handle('open-win', (_, arg) => {
|
||||
childWindow.loadFile(indexHtml, { hash: arg })
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.handle('stop', async (event, arg) => {
|
||||
browsers.forEach(browser => browser.close())
|
||||
return true
|
||||
})
|
||||
|
373
electron/main/login.ts
Normal file
373
electron/main/login.ts
Normal file
@ -0,0 +1,373 @@
|
||||
import type { Page, Browser } from 'puppeteer'
|
||||
import { browsers, clog, statusCheck } from './tools'
|
||||
import { awaitWrap, browserAndPage, randomNum } from './tools'
|
||||
|
||||
const login = {
|
||||
// poe 邮箱登录
|
||||
async poe_email(options, getCodeFn: Function, tryCount = 1): Promise<[Page, Browser]> {
|
||||
const log = clog(options)
|
||||
|
||||
if (tryCount > 2) {
|
||||
log('重试次数已达上限')
|
||||
throw '重试次数已达上限'
|
||||
return
|
||||
}
|
||||
|
||||
log('启动浏览器')
|
||||
|
||||
const { browser, page } = await browserAndPage({ ...options, proxy: true })
|
||||
|
||||
log('正在进入登录页面')
|
||||
await page.goto('https://poe.com/login')
|
||||
|
||||
log('设置登录方式')
|
||||
await page.evaluate((selector, searchText) => {
|
||||
const elements = Array.from(document.querySelectorAll(selector));
|
||||
const target = elements.find(el => el.textContent.trim() === searchText);
|
||||
|
||||
if (!target) return false
|
||||
|
||||
const text = target.nextElementSibling?.textContent || ''
|
||||
if (text.includes('email')) target.nextElementSibling.click()
|
||||
}, 'button', 'Go')
|
||||
|
||||
log('开始输入邮箱')
|
||||
await page.waitForSelector('input[type="email"]')
|
||||
await page.type('input[type="email"]', options.user)
|
||||
await page.waitForTimeout(1000)
|
||||
await statusCheck(
|
||||
async () => await page.keyboard.press('Enter'),
|
||||
async () => await page.$('.LoadingDots_wrapper__lXyQd'), // LoadingDots_wrapper__lXyQd
|
||||
)
|
||||
|
||||
// 检查是否有错误
|
||||
const isOk = await Promise.race([
|
||||
page.waitForSelector('.InfoText_error__OQwmg').then(() => false),
|
||||
page.waitForSelector('input[class^="VerificationCodeInput_verificationCodeInput"]').then(() => true)
|
||||
])
|
||||
|
||||
console.log('isOk', isOk)
|
||||
if (!isOk) {
|
||||
const reason = await page.$eval('.InfoText_error__OQwmg', (el: HTMLElement) => el.textContent.trim())
|
||||
if (reason.startsWith('Something')) {
|
||||
await page.waitForTimeout(3482)
|
||||
await statusCheck(
|
||||
async () => await page.keyboard.press('Enter'),
|
||||
async () => await page.$('.LoadingDots_wrapper__lXyQd'), // LoadingDots_wrapper__lXyQd
|
||||
)
|
||||
} else {
|
||||
log('', { result: `登录失败: ${reason}` })
|
||||
browser.close()
|
||||
throw '登录失败'
|
||||
}
|
||||
// return login.poe_email(options, getCodeFn, tryCount + 1)
|
||||
}
|
||||
|
||||
// await page.keyboard.press('Enter')
|
||||
log('开始输入密码')
|
||||
|
||||
const code = await getCodeFn(options, { page, browser })
|
||||
|
||||
await page.type('input[class^=VerificationCodeInput_verificationCodeInput]', code)
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
await page.waitForNavigation()
|
||||
|
||||
return [page, browser]
|
||||
},
|
||||
|
||||
async poe_google(options, tryCount = 1): Promise<[Page, Browser]> {
|
||||
let resolve: (value: [Page, Browser] | PromiseLike<[Page, Browser]>) => void,
|
||||
reject
|
||||
const log = clog(options)
|
||||
const p = new Promise<[Page, Browser]>((res, rej) => {
|
||||
resolve = res
|
||||
reject = rej
|
||||
})
|
||||
|
||||
const env = {
|
||||
GUSER: options.user,
|
||||
GPASS: options.pass
|
||||
}
|
||||
const { browser, page } = await browserAndPage(options)
|
||||
|
||||
log('开始访问 poe')
|
||||
await page.goto('https://poe.com')
|
||||
log('已进入 poe')
|
||||
await page.waitForTimeout(randomNum(1000, 2600))
|
||||
|
||||
log('准备进入 google 登录页')
|
||||
|
||||
page.click('.ContinueWithGoogleButton_buttonContentWrapper__Mrp0W')
|
||||
const [err, response] = await awaitWrap(page.waitForNavigation({ timeout: 10000 }))
|
||||
if (err) {
|
||||
reject({ text: '登录报错', try: true })
|
||||
return p
|
||||
}
|
||||
log('已进入 google 登录页')
|
||||
|
||||
if (response.ok()) {
|
||||
await page.waitForSelector('input[type="email"]')
|
||||
log('准备输入账号')
|
||||
await page.type('input[type="email"]', env.GUSER)
|
||||
await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
await page.keyboard.press('Enter')
|
||||
])
|
||||
log('已输入账号,准备输入密码')
|
||||
if (await isError(page)) {
|
||||
reject({ text: '登录报错', try: true })
|
||||
return p
|
||||
}
|
||||
|
||||
await page.waitForSelector('input[type="password"]', { visible: true })
|
||||
await page.type('input[type="password"]', env.GPASS)
|
||||
log('已输入密码,开始登录')
|
||||
await Promise.all([
|
||||
page.waitForFunction(() => location.href === 'https://poe.com/'),
|
||||
await page.keyboard.press('Enter')
|
||||
])
|
||||
if (await isError(page)) {
|
||||
reject({ text: '登录报错', try: true })
|
||||
return p
|
||||
}
|
||||
|
||||
log('登录成功,准备进入 poe')
|
||||
resolve([page, browser])
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
if (tryCount < 4) {
|
||||
log(`google 登录失败,准备 ${tryCount} 次重试`)
|
||||
await page.close()
|
||||
return await login.poe_google(options, tryCount + 1)
|
||||
} else {
|
||||
log('google 登录失败,重试次数已达上限')
|
||||
reject('google 登录失败')
|
||||
}
|
||||
|
||||
return p
|
||||
},
|
||||
|
||||
async openai(options): Promise<[Page, Browser]> {
|
||||
const { user, pass } = options
|
||||
const log = clog(options)
|
||||
|
||||
log('启动浏览器')
|
||||
|
||||
const { browser, page } = await browserAndPage({ ...options, changeUS: false })
|
||||
|
||||
log('准备进入 gpt 登录')
|
||||
await page.goto('https://platform.openai.com')
|
||||
|
||||
|
||||
log('等待出现输入框')
|
||||
await page.waitForSelector('#username', { visible: true, timeout: 10000 })
|
||||
|
||||
// 输入账号
|
||||
log('输入账号')
|
||||
await page.type('#username', user)
|
||||
await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.keyboard.press('Enter')
|
||||
])
|
||||
|
||||
log('等待出现密码输入框')
|
||||
await page.waitForSelector('#password', { visible: true })
|
||||
log('输入密码')
|
||||
await page.type('#password', pass)
|
||||
|
||||
|
||||
log('准备登录')
|
||||
await Promise.all([
|
||||
page.waitForNavigation({ timeout: 10000 }),
|
||||
page.keyboard.press('Enter')
|
||||
])
|
||||
|
||||
log('登录成功')
|
||||
|
||||
return [page, browser]
|
||||
},
|
||||
|
||||
/**
|
||||
* 登录邮箱并获取验证码
|
||||
*/
|
||||
async mail_get_code(options): Promise<[Page, Browser, {
|
||||
code?: string,
|
||||
validateCode: () => Promise<string>
|
||||
}]> {
|
||||
const { emailText = 'Poe' } = options
|
||||
const log = clog(options)
|
||||
const { browser, page } = await browserAndPage({ ...options })
|
||||
|
||||
log('准备进入邮箱登录页')
|
||||
const [error] = await awaitWrap(page.goto('https://www.mail.com/', { waitUntil: 'domcontentloaded' }))
|
||||
|
||||
await page.waitForSelector('.header-bar .button-login')
|
||||
await page.click('.header-bar .button-login')
|
||||
|
||||
log('输入帐密')
|
||||
await page.waitForTimeout(500)
|
||||
await page.waitForSelector('input#login-email')
|
||||
await page.waitForTimeout(500)
|
||||
await page.type('input#login-email', options.user)
|
||||
await page.type('input#login-password', options.pass)
|
||||
await page.keyboard.press('Enter')
|
||||
log('开始登录')
|
||||
|
||||
/**
|
||||
*
|
||||
* @param reload 是否点击刷新验证码按钮
|
||||
*/
|
||||
async function validateCode() {
|
||||
log('开始获取code')
|
||||
let $iframe = await page.$('#thirdPartyFrame_home')
|
||||
let frame = await $iframe?.contentFrame()
|
||||
|
||||
if (!frame) {
|
||||
log('未找到页面,刷新重试中...')
|
||||
await page.reload()
|
||||
return await validateCode()
|
||||
}
|
||||
|
||||
const [err] = await awaitWrap(frame.waitForSelector('ul.inbox-container li', { timeout: 4000 }))
|
||||
if (err) {
|
||||
console.log(err)
|
||||
console.log('有报错')
|
||||
await frame.waitForSelector('.ico.sync')
|
||||
const sync = await page.$('.ico.sync')
|
||||
if (!sync) {
|
||||
console.log('未找到刷新按钮')
|
||||
log('未找到刷新按钮')
|
||||
return ''
|
||||
}
|
||||
await frame.click('.ico.sync')
|
||||
await frame.waitForTimeout(4000)
|
||||
return await validate()
|
||||
}
|
||||
|
||||
return await validate()
|
||||
|
||||
|
||||
// console.log('type', type)
|
||||
// if (type === 'list') {
|
||||
// return await validate()
|
||||
// }
|
||||
|
||||
|
||||
await frame.waitForSelector('.ico.sync')
|
||||
await frame.click('.ico.sync')
|
||||
await frame.waitForTimeout(1000)
|
||||
|
||||
await frame.waitForSelector('ul.inbox-container li')
|
||||
log('查找邮箱')
|
||||
|
||||
async function validate() {
|
||||
const $li = await frame.evaluate((emailText) => {
|
||||
const $li: any = Array.from(document.querySelectorAll('ul.inbox-container li')).find($li => {
|
||||
let sender = $li.querySelector('.sender')?.textContent || ''
|
||||
return sender.includes(emailText)
|
||||
})
|
||||
|
||||
if ($li) $li.click()
|
||||
return $li
|
||||
}, emailText)
|
||||
|
||||
if (!$li) {
|
||||
log('未找到邮箱')
|
||||
return ''
|
||||
} else {
|
||||
log('等待出现验证码 iframe')
|
||||
await page.waitForSelector('#thirdPartyFrame_mail')
|
||||
log('出现了验证码 iframe,寻找他的 iframe')
|
||||
$iframe = await page.$('#thirdPartyFrame_mail')
|
||||
frame = await $iframe?.contentFrame()
|
||||
|
||||
await frame.waitForSelector('iframe#mail-detail')
|
||||
log('出现验证码 iframe')
|
||||
|
||||
$iframe = await frame.$('iframe#mail-detail')
|
||||
frame = await $iframe?.contentFrame()
|
||||
|
||||
log('等待验证码')
|
||||
await frame.waitForSelector('table table table ')
|
||||
const code = (await frame.$eval('table table table tr:nth-of-type(5)', el => el.textContent)) || ''
|
||||
return code.trim()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await awaitWrap(page.waitForNavigation({ waitUntil: 'load' }))
|
||||
const code = await validateCode()
|
||||
|
||||
log(`邮箱验证码 ${code}`)
|
||||
return [page, browser, { code, validateCode }]
|
||||
},
|
||||
|
||||
async chatgpt(options, tryCount = 1): Promise<[Page, Browser]> {
|
||||
let resolve: (value: [Page, Browser] | PromiseLike<[Page, Browser]>) => void,
|
||||
reject
|
||||
const log = clog(options)
|
||||
const p = new Promise<[Page, Browser]>((res, rej) => {
|
||||
resolve = res
|
||||
reject = rej
|
||||
})
|
||||
|
||||
const env = {
|
||||
GUSER: options.user,
|
||||
GPASS: options.pass
|
||||
}
|
||||
|
||||
const { browser, page } = await browserAndPage({ ...options, changeUS: false })
|
||||
log('开始访问 gpt')
|
||||
await page.goto('https://chat.openai.com/auth/login')
|
||||
await page.waitForSelector('button')
|
||||
|
||||
// log('准备进入 google 登录页')
|
||||
const [response] = await Promise.all([
|
||||
page.waitForNavigation({ timeout: 0 }),
|
||||
page.click('button')
|
||||
])
|
||||
// log('已进入 google 登录页')
|
||||
|
||||
if (!response.ok()) {
|
||||
log('进入 google 登录页失败')
|
||||
reject('进入 google 登录页失败')
|
||||
return p
|
||||
}
|
||||
|
||||
log('准备输入账号')
|
||||
await page.type('#username', env.GUSER)
|
||||
await Promise.all([
|
||||
page.waitForNavigation({ timeout: 0 }),
|
||||
page.keyboard.press('Enter')
|
||||
])
|
||||
|
||||
log('已输入账号,准备输入密码')
|
||||
await page.waitForSelector('#password', { visible: true })
|
||||
await page.type('#password', env.GPASS)
|
||||
log('已输入密码,开始登录')
|
||||
|
||||
await Promise.all([
|
||||
page.waitForNavigation({ timeout: 10000, waitUntil: 'domcontentloaded' }),
|
||||
page.keyboard.press('Enter')
|
||||
])
|
||||
log('登录成功')
|
||||
resolve([page, browser])
|
||||
|
||||
return p
|
||||
},
|
||||
|
||||
closeAll() {
|
||||
browsers.map(b => b.close())
|
||||
}
|
||||
}
|
||||
|
||||
export default login
|
||||
|
||||
async function isError(page: Page) {
|
||||
const text = await page.evaluate(() => (document.querySelector('p')?.textContent || ''));
|
||||
// const text = await page.evaluate('p', element => element.textContent);
|
||||
return text && text.includes('error')
|
||||
}
|
193
electron/main/poe/cookie.ts
Normal file
193
electron/main/poe/cookie.ts
Normal file
@ -0,0 +1,193 @@
|
||||
import type { Browser, Page } from 'puppeteer'
|
||||
import puppeteer from 'puppeteer-extra'
|
||||
import StealthPlugin from 'puppeteer-extra-plugin-stealth'
|
||||
import { browserAndPage, browsers, clog, createPromise, statusCheck } from "../tools"
|
||||
import login from '../login'
|
||||
puppeteer.use(StealthPlugin())
|
||||
|
||||
export async function getCookie(options) {
|
||||
console.log('options', options);
|
||||
const log = clog(options)
|
||||
log('开始', { ident: 'link_7day' })
|
||||
|
||||
let { p, resolve, reject } = createPromise<string>()
|
||||
|
||||
login.mail_get_code({ ...options, changeUS: false }).then(async ([page, browser, options]) => {
|
||||
const isOk = await statusCheck(
|
||||
() => options.code,
|
||||
async () => {
|
||||
log('未获取验证码,重试一次', { ident: 'link_7day' })
|
||||
options.code = await options.validateCode()
|
||||
return options.code
|
||||
},
|
||||
{ interval: 4000 }
|
||||
)
|
||||
resolve(options.code)
|
||||
browser.close()
|
||||
})
|
||||
|
||||
const [page, browser] = await login.poe_email(options, async () => {
|
||||
const code = await p
|
||||
console.log('获取验证码结果', code)
|
||||
if (!code) {
|
||||
log('获取验证码失败', { ident: 'link_7day' })
|
||||
reject('获取验证码失败')
|
||||
throw '获取验证码失败'
|
||||
}
|
||||
|
||||
return code
|
||||
}).catch(() => '' as any)
|
||||
|
||||
// 登录失败了
|
||||
if (!page) {
|
||||
console.log('登录失败了')
|
||||
browsers.map(b => b.close())
|
||||
return
|
||||
}
|
||||
|
||||
const cookies = await page.cookies()
|
||||
const token = cookies.find(v => v.name === 'p-b')?.value
|
||||
|
||||
log('获取token', { result: token })
|
||||
console.log('cookies', cookies)
|
||||
// browser.close()
|
||||
// await page.waitForTimeout(2000)
|
||||
browser.close()
|
||||
// const { page } = await login.poe_email(options)
|
||||
}
|
||||
|
||||
async function recharge(options: {
|
||||
browser: Browser,
|
||||
page: Page,
|
||||
user: string,
|
||||
liao: any,
|
||||
}) {
|
||||
const { browser, page, liao, ...args } = options
|
||||
const log = clog(args)
|
||||
log('开始充值')
|
||||
await page.waitForSelector('#cardNumber')
|
||||
|
||||
await page.evaluate(() => {
|
||||
const btn: HTMLElement = document.querySelector('.AddressAutocomplete-manual-entry .Link')
|
||||
if (btn) btn.click()
|
||||
})
|
||||
|
||||
await page.evaluate((email: string) => {
|
||||
const el: HTMLInputElement = document.querySelector('#email')
|
||||
if (el) el.value = email
|
||||
}, options.user)
|
||||
|
||||
await page.type('#cardNumber', liao.bank)
|
||||
await page.type('#cardExpiry', liao.date)
|
||||
await page.type('#cardCvc', liao.cvc)
|
||||
await page.type('#billingName', liao.name)
|
||||
await page.select('#billingCountry', liao.nation)
|
||||
await page.type('#billingAddressLine1', liao.address)
|
||||
await page.type('#billingLocality', liao.city)
|
||||
await page.type('#billingPostalCode', liao.postalCode)
|
||||
await page.waitForTimeout(1000)
|
||||
await page.click('.SubmitButton-IconContainer')
|
||||
|
||||
// await page.waitForTimeout(9000)
|
||||
|
||||
// await page.waitForSelector('iframe')
|
||||
// let $frame = await page.$('iframe')
|
||||
// let frame = await $frame.contentFrame()
|
||||
|
||||
// console.log('$frame', $frame)
|
||||
// // console.log('frame', frame)
|
||||
// await $frame.waitForSelector('iframe')
|
||||
// $frame = await frame.$('iframe')
|
||||
// frame = await $frame.contentFrame()
|
||||
// await frame.waitForSelector('iframe')
|
||||
// $frame = await frame.$('iframe')
|
||||
// frame = await $frame.contentFrame()
|
||||
|
||||
// await frame.waitForSelector('#checkbox', { timeout: 0 })
|
||||
// await frame.click('#checkbox')
|
||||
// await page.waitForNavigation()
|
||||
console.log('充值成功')
|
||||
log('充值成功')
|
||||
}
|
||||
|
||||
function existDialog(page: Page) {
|
||||
return page.evaluate((selector, searchText) => {
|
||||
const elements = Array.from(document.querySelectorAll(selector));
|
||||
const target = elements.find(el => el.textContent.trim() === searchText);
|
||||
target && target.click()
|
||||
|
||||
return !!target
|
||||
}, 'button', 'Start free trial')
|
||||
}
|
||||
|
||||
export async function getLink(options, [page, browser]: [Page, Browser]) {
|
||||
const log = clog(options)
|
||||
log('开始', { ident: 'poe-link' })
|
||||
await page.waitForTimeout(1000)
|
||||
const isExistDialog = await existDialog(page)
|
||||
|
||||
isExistDialog && log('检测到充值弹窗,无需前往设置页')
|
||||
|
||||
if (!isExistDialog) {
|
||||
await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.goto('https://poe.com/settings')
|
||||
])
|
||||
log('已进入设置页面, 检查中')
|
||||
|
||||
const existMange = await page.evaluate(() => {
|
||||
const mange = document.querySelector('[class*="SettingsSubscriptionSection_manageSubscription"]')
|
||||
if (mange) return true
|
||||
return false
|
||||
})
|
||||
|
||||
if (existMange) {
|
||||
log('已经订阅')
|
||||
return
|
||||
}
|
||||
await page.waitForSelector('[class*=SettingsSubscriptionSection_subscribeButton]', { timeout: 0 })
|
||||
|
||||
page.waitForTimeout(500)
|
||||
log('点击显示订阅套餐按钮')
|
||||
// await page.click('[class*=SettingsSubscriptionSection_subscribeButton]')
|
||||
|
||||
const disabled = await page.$eval('[class*=SettingsSubscriptionSection_subscribeButton]', (el: HTMLButtonElement) => el.disabled)
|
||||
if (disabled) {
|
||||
log('订阅按钮不可用,地区不可用')
|
||||
return
|
||||
}
|
||||
|
||||
await statusCheck(
|
||||
async () => {
|
||||
return page.evaluate(() => {
|
||||
const $el = document.querySelector("[class*=SettingsSubscriptionSection_subscribeButton]")
|
||||
console.log('$el', $el)
|
||||
$el.click();
|
||||
})
|
||||
},
|
||||
// async () => page.click('[class*=SettingsSubscriptionSection_subscribeButton]'),
|
||||
async () => page.$('.Modal_modal__SxITf'),
|
||||
)
|
||||
}
|
||||
|
||||
// log('显示更多套餐')
|
||||
// await page.waitForSelector('[class*=WebSubscriptionFreeTrial_viewAllPlansButton]')
|
||||
// await page.click('[class*=WebSubscriptionFreeTrial_viewAllPlansButton]')
|
||||
// log('点击最后一个套餐')
|
||||
// await page.waitForSelector('[class*=WebSubscriptionPaywall_plans]')
|
||||
// await page.click('[class*=WebSubscriptionPaywall_plans] > button:last-child')
|
||||
|
||||
// 点击订阅
|
||||
log('4, 开始点击订阅')
|
||||
await page.waitForSelector('[class*=WebSubscriptionPaywall_button]', { timeout: 0 })
|
||||
page.click('[class*=WebSubscriptionPaywall_button]')
|
||||
const [response] = await Promise.all([
|
||||
page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
|
||||
])
|
||||
|
||||
if (response.ok()) {
|
||||
const url = response._request._frame._url
|
||||
log('获取链接成功', { result: url, type: 'success' })
|
||||
return url
|
||||
}
|
||||
}
|
69
electron/main/poe/getLink.ts
Normal file
69
electron/main/poe/getLink.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { clog } from '../tools'
|
||||
import type { Page } from 'puppeteer'
|
||||
import path from 'path'
|
||||
import login from '../login'
|
||||
|
||||
function existDialog(page: Page) {
|
||||
return page.evaluate((selector, searchText) => {
|
||||
const elements = Array.from(document.querySelectorAll(selector));
|
||||
const target = elements.find(el => el.textContent.trim() === searchText);
|
||||
target && target.click()
|
||||
|
||||
return !!target
|
||||
}, 'button', 'Start free trial')
|
||||
}
|
||||
|
||||
export async function getLink(options) {
|
||||
const log = clog(options)
|
||||
log('开始', { ident: 'poe-link' })
|
||||
return login.poe_google(options).then(async ([page, browser]) => {
|
||||
await page.waitForTimeout(1000)
|
||||
const isExistDialog = await existDialog(page)
|
||||
|
||||
isExistDialog && log('检测到充值弹窗,无需前往设置页')
|
||||
|
||||
if (!isExistDialog) {
|
||||
await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.goto('https://poe.com/settings')
|
||||
])
|
||||
log('已进入设置页面, 检查中')
|
||||
await page.waitForSelector('[class*=SettingsSubscriptionSection_subscribeButton]')
|
||||
log('点击显示订阅套餐按钮')
|
||||
await page.click('[class*=SettingsSubscriptionSection_subscribeButton]')
|
||||
}
|
||||
|
||||
log('显示更多套餐')
|
||||
await page.waitForSelector('[class*=WebSubscriptionFreeTrial_viewAllPlansButton]')
|
||||
await page.click('[class*=WebSubscriptionFreeTrial_viewAllPlansButton]')
|
||||
log('点击最后一个套餐')
|
||||
await page.waitForSelector('[class*=WebSubscriptionPaywall_plans]')
|
||||
await page.click('[class*=WebSubscriptionPaywall_plans] > button:last-child')
|
||||
|
||||
// 点击订阅
|
||||
log('4, 开始点击订阅')
|
||||
page.click('[class*=WebSubscriptionPaywall_button]')
|
||||
const [response] = await Promise.all([
|
||||
page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
|
||||
])
|
||||
|
||||
if (response.ok()) {
|
||||
const url = response._request._frame._url
|
||||
log('获取链接成功', { result: url, type: 'success' })
|
||||
browser.close()
|
||||
return url
|
||||
}
|
||||
browser.close()
|
||||
}).catch(error => {
|
||||
console.log('error ->', error.try, error.text, error)
|
||||
if (error?.try) {
|
||||
return getLink(options)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
|
||||
function resolve(url) {
|
||||
return path.resolve(__dirname, '../src/poe/', url)
|
||||
}
|
102
electron/main/poe/index.js
Normal file
102
electron/main/poe/index.js
Normal file
@ -0,0 +1,102 @@
|
||||
import { getLink } from './getLink'
|
||||
import { validate } from './validate'
|
||||
import { ipcMain } from 'electron'
|
||||
import { link_7day } from './link_7day'
|
||||
import { getCookie } from './cookie'
|
||||
import { browserAndPage } from '../tools'
|
||||
|
||||
export const parseAccount = text => text.split('\n').filter(Boolean).map(v => {
|
||||
v = v.split(/(——|-)+/).filter(v => !['-', '——'].includes(v))
|
||||
return v
|
||||
})
|
||||
|
||||
ipcMain.handle('getLink', async (event, arg) => {
|
||||
const { text } = arg
|
||||
const accounts = parseAccount(text)
|
||||
|
||||
const links = []
|
||||
for (let i = 0; i < accounts.length; i++) {
|
||||
const [user, pass, auxiliary] = accounts[i]
|
||||
const link = await getLink({ user, pass, auxiliary, index: i, id: user })
|
||||
// .catch(err => {
|
||||
// console.log('error ->', err)
|
||||
// })
|
||||
links.push({
|
||||
i,
|
||||
user,
|
||||
link
|
||||
})
|
||||
console.log('process', i, user, link)
|
||||
}
|
||||
return links
|
||||
})
|
||||
|
||||
ipcMain.handle('get-poe-link-7day', async (event, arg) => {
|
||||
const { text, liao } = arg
|
||||
const accounts = parseAccount(text)
|
||||
|
||||
const links = []
|
||||
for (let i = 0; i < accounts.length; i++) {
|
||||
const [user, pass, auxiliary] = accounts[i]
|
||||
const link = await link_7day({ user, pass, auxiliary, index: i, id: user, liao })
|
||||
// .catch(err => {
|
||||
// console.log('error ->', err)
|
||||
// })
|
||||
links.push({
|
||||
i,
|
||||
user,
|
||||
link
|
||||
})
|
||||
console.log('process', i, user, link)
|
||||
}
|
||||
return links
|
||||
})
|
||||
|
||||
|
||||
|
||||
ipcMain.handle('get-poe-cookie', async (event, arg) => {
|
||||
const { text, liao } = arg
|
||||
const accounts = parseAccount(text)
|
||||
|
||||
const links = []
|
||||
for (let i = 0; i < accounts.length; i++) {
|
||||
const [user, pass, auxiliary] = accounts[i]
|
||||
const link = await getCookie({ user, pass, auxiliary, index: i, id: user, liao })
|
||||
// .catch(err => {
|
||||
// console.log('error ->', err)
|
||||
// })
|
||||
links.push({
|
||||
i,
|
||||
user,
|
||||
link
|
||||
})
|
||||
console.log('process', i, user, link)
|
||||
}
|
||||
return links
|
||||
})
|
||||
|
||||
|
||||
ipcMain.handle('poe-result', async (event, arg) => {
|
||||
const { text } = arg
|
||||
const accounts = parseAccount(text)
|
||||
|
||||
const links = []
|
||||
for (let i = 0; i < accounts.length; i++) {
|
||||
const [user, pass, auxiliary] = accounts[i]
|
||||
const link = await validate({ user, pass, auxiliary, index: i, id: user })
|
||||
// .catch(err => {
|
||||
// console.log('error ->', err)
|
||||
// })
|
||||
links.push({
|
||||
i,
|
||||
user,
|
||||
link
|
||||
})
|
||||
console.log('process', i, user, link)
|
||||
}
|
||||
return links
|
||||
})
|
||||
|
||||
ipcMain.handle('start-one-chrom', async (event, arg) => {
|
||||
browserAndPage({ proxy: true })
|
||||
})
|
217
electron/main/poe/link_7day.ts
Normal file
217
electron/main/poe/link_7day.ts
Normal file
@ -0,0 +1,217 @@
|
||||
import type { Browser, Page } from 'puppeteer'
|
||||
import puppeteer from 'puppeteer-extra'
|
||||
import StealthPlugin from 'puppeteer-extra-plugin-stealth'
|
||||
import { awaitWrap, browserAndPage, browsers, clog, createPromise, statusCheck } from "../tools"
|
||||
import login from '../login'
|
||||
puppeteer.use(StealthPlugin())
|
||||
|
||||
export async function link_7day(options) {
|
||||
console.log('options', options);
|
||||
const log = clog(options)
|
||||
log('开始', { ident: 'link_7day' })
|
||||
|
||||
let { p, resolve, reject } = createPromise<string>()
|
||||
|
||||
login.mail_get_code({ ...options, changeUS: false }).then(async ([page, browser, options]) => {
|
||||
const isOk = await statusCheck(
|
||||
() => options.code,
|
||||
async () => {
|
||||
log('未获取验证码,重试一次', { ident: 'link_7day' })
|
||||
options.code = await options.validateCode()
|
||||
return options.code
|
||||
},
|
||||
{ interval: 4000 }
|
||||
)
|
||||
resolve(options.code)
|
||||
browser.close()
|
||||
})
|
||||
|
||||
const [page, browser] = await login.poe_email(options, async () => {
|
||||
const code = await p
|
||||
console.log('获取验证码结果', code)
|
||||
if (!code) {
|
||||
log('获取验证码失败', { ident: 'link_7day' })
|
||||
reject('获取验证码失败')
|
||||
throw '获取验证码失败'
|
||||
}
|
||||
|
||||
return code
|
||||
}).catch(() => '' as any)
|
||||
|
||||
// 登录失败了
|
||||
if (!page) {
|
||||
console.log('登录失败了')
|
||||
browsers.map(b => b.close())
|
||||
return
|
||||
}
|
||||
|
||||
const url = await getLink(options, [page, browser])
|
||||
|
||||
return url
|
||||
if (url && options.liao) {
|
||||
await recharge({ ...options, page, browser })
|
||||
}
|
||||
|
||||
// browser.close()
|
||||
// await page.waitForTimeout(2000)
|
||||
// browser.close()
|
||||
// const { page } = await login.poe_email(options)
|
||||
}
|
||||
|
||||
async function test() {
|
||||
const url = 'https://checkout.stripe.com/c/pay/cs_live_a1MXhrEYuI3qJEjw85zmuIxjFsgswafv0xlcxUGAOIeyiGJBGLA56mvRto#fidkdWxOYHwnPyd1blppbHNgWjxITDJsdEROY3Y1NjZpNTc8Q1RMU3ZTNicpJ2N3amhWYHdzYHcnP3F3cGApJ2lkfGpwcVF8dWAnPyd2bGtiaWBabHFgaCcpJ2BrZGdpYFVpZGZgbWppYWB3dic%2FcXdwYHgl'
|
||||
const liao = {"bank":"4833160230060672","cvc":"727","date":"04/26","name":"Zackary Wais","address":"1200LakeshoreaveApt8G","city":"Oakland","postalCode":"94606","nation":"US"}
|
||||
const user = 'neletegcongder@mail.com'
|
||||
|
||||
const { page, browser } = await browserAndPage()
|
||||
await page.goto(url, { waitUntil: 'domcontentloaded' })
|
||||
await recharge({ browser, page, user, liao })
|
||||
}
|
||||
|
||||
// test()
|
||||
|
||||
async function recharge(options: {
|
||||
browser: Browser,
|
||||
page: Page,
|
||||
user: string,
|
||||
liao: any,
|
||||
}) {
|
||||
const { browser, page, liao, ...args } = options
|
||||
const log = clog(args)
|
||||
log('开始充值')
|
||||
await page.waitForSelector('#cardNumber')
|
||||
|
||||
await page.evaluate(() => {
|
||||
const btn: HTMLElement = document.querySelector('.AddressAutocomplete-manual-entry .Link')
|
||||
if (btn) btn.click()
|
||||
})
|
||||
|
||||
const isEmail = await page.evaluate((email: string) => {
|
||||
const el: HTMLInputElement = document.querySelector('#email')
|
||||
return !!el
|
||||
}, options.user)
|
||||
if (isEmail) await page.type('#email', options.user)
|
||||
|
||||
|
||||
await page.type('#cardNumber', liao.bank)
|
||||
await page.type('#cardExpiry', liao.date)
|
||||
await page.type('#cardCvc', liao.cvc)
|
||||
await page.type('#billingName', liao.name)
|
||||
await page.select('#billingCountry', liao.nation)
|
||||
await page.type('#billingAddressLine1', liao.address)
|
||||
await page.type('#billingLocality', liao.city)
|
||||
await page.type('#billingPostalCode', liao.postalCode)
|
||||
await page.waitForTimeout(1000)
|
||||
await page.click('.SubmitButton-IconContainer')
|
||||
|
||||
// await page.waitForTimeout(8000)
|
||||
|
||||
// const [error, config] = await awaitWrap(page.solveRecaptchas())
|
||||
// if (error) {
|
||||
// log('充值失败', { result: '充值失败', })
|
||||
// } else {
|
||||
// console.log(config)
|
||||
// log('充值成功', { result: '充值成功', })
|
||||
// }
|
||||
|
||||
// await page.waitForSelector('iframe')
|
||||
// let $frame = await page.$('iframe')
|
||||
// let frame = await $frame.contentFrame()
|
||||
|
||||
// console.log('$frame', $frame)
|
||||
// // console.log('frame', frame)
|
||||
// await frame.waitForSelector('iframe')
|
||||
// $frame = await frame.$('iframe')
|
||||
// frame = await $frame.contentFrame()
|
||||
// await frame.waitForSelector('iframe')
|
||||
// $frame = await frame.$('iframe')
|
||||
// frame = await $frame.contentFrame()
|
||||
|
||||
// await frame.waitForSelector('#checkbox', { timeout: 0 })
|
||||
// await frame.click('#checkbox')
|
||||
await page.waitForNavigation()
|
||||
console.log('充值成功')
|
||||
log('充值成功')
|
||||
}
|
||||
|
||||
function existDialog(page: Page) {
|
||||
return page.evaluate((selector, searchText) => {
|
||||
const elements = Array.from(document.querySelectorAll(selector));
|
||||
const target = elements.find(el => el.textContent.trim() === searchText);
|
||||
target && target.click()
|
||||
|
||||
return !!target
|
||||
}, 'button', 'Start free trial')
|
||||
}
|
||||
|
||||
export async function getLink(options, [page, browser]: [Page, Browser]) {
|
||||
const log = clog(options)
|
||||
log('开始', { ident: 'poe-link' })
|
||||
await page.waitForTimeout(1000)
|
||||
const isExistDialog = await existDialog(page)
|
||||
|
||||
isExistDialog && log('检测到充值弹窗,无需前往设置页')
|
||||
|
||||
if (!isExistDialog) {
|
||||
await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.goto('https://poe.com/settings')
|
||||
])
|
||||
log('已进入设置页面, 检查中')
|
||||
|
||||
const existMange = await page.evaluate(() => {
|
||||
const mange = document.querySelector('[class*="SettingsSubscriptionSection_manageSubscription"]')
|
||||
if (mange) return true
|
||||
return false
|
||||
})
|
||||
|
||||
if (existMange) {
|
||||
log('已经订阅')
|
||||
return
|
||||
}
|
||||
await page.waitForSelector('[class*=SettingsSubscriptionSection_subscribeButton]', { timeout: 0 })
|
||||
|
||||
page.waitForTimeout(500)
|
||||
log('点击显示订阅套餐按钮')
|
||||
// await page.click('[class*=SettingsSubscriptionSection_subscribeButton]')
|
||||
|
||||
const disabled = await page.$eval('[class*=SettingsSubscriptionSection_subscribeButton]', (el: HTMLButtonElement) => el.disabled)
|
||||
if (disabled) {
|
||||
log('订阅按钮不可用,地区不可用')
|
||||
return
|
||||
}
|
||||
|
||||
await statusCheck(
|
||||
async () => {
|
||||
return page.evaluate(() => {
|
||||
const $el = document.querySelector("[class*=SettingsSubscriptionSection_subscribeButton]")
|
||||
console.log('$el', $el)
|
||||
$el.click();
|
||||
})
|
||||
},
|
||||
// async () => page.click('[class*=SettingsSubscriptionSection_subscribeButton]'),
|
||||
async () => page.$('.Modal_modal__SxITf'),
|
||||
)
|
||||
}
|
||||
|
||||
// log('显示更多套餐')
|
||||
// await page.waitForSelector('[class*=WebSubscriptionFreeTrial_viewAllPlansButton]')
|
||||
// await page.click('[class*=WebSubscriptionFreeTrial_viewAllPlansButton]')
|
||||
// log('点击最后一个套餐')
|
||||
// await page.waitForSelector('[class*=WebSubscriptionPaywall_plans]')
|
||||
// await page.click('[class*=WebSubscriptionPaywall_plans] > button:last-child')
|
||||
|
||||
// 点击订阅
|
||||
log('4, 开始点击订阅')
|
||||
await page.waitForSelector('[class*=WebSubscriptionPaywall_button]', { timeout: 0 })
|
||||
page.click('[class*=WebSubscriptionPaywall_button]')
|
||||
const [response] = await Promise.all([
|
||||
page.waitForNavigation({ waitUntil: 'domcontentloaded' }),
|
||||
])
|
||||
|
||||
if (response.ok()) {
|
||||
const url = response._request._frame._url
|
||||
log('获取链接成功', { result: url, type: 'success' })
|
||||
return url
|
||||
}
|
||||
}
|
26
electron/main/poe/validate.js
Normal file
26
electron/main/poe/validate.js
Normal file
@ -0,0 +1,26 @@
|
||||
import login from '../login'
|
||||
import path from 'path'
|
||||
import { clog } from '../tools'
|
||||
|
||||
export async function validate (options) {
|
||||
const log = clog(options)
|
||||
log('开始', { ident: 'poe-validate' })
|
||||
const [page, browser] = await login.poe_google(options)
|
||||
|
||||
await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.goto('https://poe.com/settings')
|
||||
])
|
||||
|
||||
log('已进入设置页面, 检查中', { ident: 'poe-validate' })
|
||||
|
||||
const length = await page.$$eval('.SettingsSubscriptionSection_botLimitSection__j4mSO > div:first-child > div', (doms) => doms.length)
|
||||
const resultTxt = length === 1 ? '失败😭' : '成功😘'
|
||||
log(resultTxt, { type: length === 1 ? 'fail' : 'success', result: length === 1 ? '失败😭' : '成功😘' })
|
||||
|
||||
browser.close()
|
||||
}
|
||||
|
||||
function resolve (url) {
|
||||
return path.resolve(__dirname, '../src/poe/', url)
|
||||
}
|
236
electron/main/tools.ts
Normal file
236
electron/main/tools.ts
Normal file
@ -0,0 +1,236 @@
|
||||
import type { Page } from "puppeteer"
|
||||
import puppeteer from 'puppeteer-extra'
|
||||
import StealthPlugin from 'puppeteer-extra-plugin-stealth'
|
||||
import RecaptchaPlugin from 'puppeteer-extra-plugin-recaptcha'
|
||||
import chromeLauncher from 'chrome-launcher'
|
||||
import { win } from './index'
|
||||
import fakeUa from 'fake-useragent'
|
||||
import axios from "axios"
|
||||
puppeteer.use(StealthPlugin())
|
||||
puppeteer.use(RecaptchaPlugin({
|
||||
provider: {
|
||||
id: '2captcha',
|
||||
token: '25bd4a3638f3836b0d119007cbc21954'
|
||||
},
|
||||
visualFeedback: true
|
||||
}))
|
||||
|
||||
|
||||
export function test1() {
|
||||
// puppeteer-extra is a drop-in replacement for puppeteer,
|
||||
// it augments the installed puppeteer with plugin functionality
|
||||
const puppeteer = require('puppeteer-extra')
|
||||
|
||||
// add recaptcha plugin and provide it your 2captcha token (= their apiKey)
|
||||
// 2captcha is the builtin solution provider but others would work as well.
|
||||
// Please note: You need to add funds to your 2captcha account for this to work
|
||||
const RecaptchaPlugin = require('puppeteer-extra-plugin-recaptcha')
|
||||
puppeteer.use(
|
||||
RecaptchaPlugin({
|
||||
provider: {
|
||||
id: '2captcha',
|
||||
token: '25bd4a3638f3836b0d119007cbc21954' // REPLACE THIS WITH YOUR OWN 2CAPTCHA API KEY ⚡
|
||||
},
|
||||
visualFeedback: true // colorize reCAPTCHAs (violet = detected, green = solved)
|
||||
})
|
||||
)
|
||||
|
||||
// puppeteer usage as normal
|
||||
puppeteer.launch({ headless: false }).then(async browser => {
|
||||
const page = await browser.newPage()
|
||||
await page.goto('https://www.google.com/recaptcha/api2/demo')
|
||||
|
||||
// That's it, a single line of code to solve reCAPTCHAs 🎉
|
||||
const {
|
||||
captchas,
|
||||
filtered,
|
||||
solutions,
|
||||
solved,
|
||||
error
|
||||
} = await page.solveRecaptchas()
|
||||
|
||||
console.log({ captchas, filtered, solutions, solved, error })
|
||||
|
||||
await Promise.all([
|
||||
page.waitForNavigation(),
|
||||
page.click(`#recaptcha-demo-submit`)
|
||||
])
|
||||
await page.screenshot({ path: 'response.png', fullPage: true })
|
||||
await browser.close()
|
||||
})
|
||||
}
|
||||
|
||||
//生成从minNum到maxNum的随机数
|
||||
export function randomNum (min, max) {
|
||||
return parseInt(Math.random() * (max - min + 1) + min)
|
||||
}
|
||||
|
||||
// promise 错误处理
|
||||
export function awaitWrap<T, U = any>(promise: Promise<T>): Promise<[U | null, T | null]> {
|
||||
return promise
|
||||
.then<[null, T]>((data: T) => [null, data])
|
||||
.catch<[U, null]>(err => [err, null])
|
||||
}
|
||||
|
||||
// 设置页面请求
|
||||
export function pageRequest (page: Page) {
|
||||
page.setRequestInterception(true)
|
||||
page.on('request', (request) => {
|
||||
if (['stylesheet', 'font'].indexOf(request.resourceType()) !== -1) {
|
||||
request.abort()
|
||||
} else {
|
||||
request.continue()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const browsers = []
|
||||
|
||||
export async function browserAndPage (options: any = {}) {
|
||||
const { request, changeUS = true, proxy = false } = options
|
||||
|
||||
async function proxyCommand () {
|
||||
// const proxy = (await axios.get('http://127.0.0.1:10101/api/get_ip_list?num=1&country=US&state=all&city=all&zip=all&isp=all&t=1&port=40000&ip_time=1')).data
|
||||
console.log('proxy', proxy);
|
||||
|
||||
// return proxy ?
|
||||
return `--proxy-server=socks5://127.0.0.1:40000`
|
||||
}
|
||||
|
||||
const args = [
|
||||
'--no-sandbox',
|
||||
'--disable-setuid-sandbox',
|
||||
'--disable-web-security',
|
||||
'--disable-features=IsolateOrigins,site-per-process,SitePerProcess',
|
||||
'--flag-switches-begin --disable-site-isolation-trials --flag-switches-end'
|
||||
]
|
||||
|
||||
proxy ? args.push(await proxyCommand()) : null
|
||||
|
||||
// proxy ? args.push(await proxyCommand()) : ''
|
||||
|
||||
const browser = await puppeteer.launch({
|
||||
headless: false,
|
||||
args
|
||||
})
|
||||
|
||||
browsers.push(browser)
|
||||
const close = browser.close
|
||||
browser.close = async function () {
|
||||
let i = browsers.find(b => b === browser)
|
||||
await close.call(this)
|
||||
if (i !== -1) browsers.slice(i, 1)
|
||||
}
|
||||
|
||||
const page = await browser.newPage()
|
||||
console.log('fakeUa', fakeUa());
|
||||
|
||||
changeUS && page.setUserAgent(fakeUa())
|
||||
await page.setExtraHTTPHeaders({
|
||||
'accept-language': 'en-US,en;q=0.9,hy;q=0.8'
|
||||
})
|
||||
|
||||
if (request) pageRequest(page)
|
||||
|
||||
return { browser, page }
|
||||
}
|
||||
|
||||
function getProxy () {
|
||||
return axios({
|
||||
url: 'http://api.tianqiip.com/getip?secret=loy0r7fpmnlshm8l&num=1&type=json&port=3&time=5&mr=1&sign=5f73ab58ad7ab40346311014bef59b79',
|
||||
method: 'get',
|
||||
}).then(res => {
|
||||
console.log('proxy', res.data.data[0])
|
||||
return res.data.data[0]
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 记录日志
|
||||
*/
|
||||
export function clog(options) {
|
||||
return (info, data = {}) => {
|
||||
if (win) {
|
||||
win?.webContents?.send?.('progress', { ...options, info, ...data })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个 promise
|
||||
*/
|
||||
export function createPromise<T> () {
|
||||
let resolve: (value: T | PromiseLike<T>) => void,
|
||||
reject
|
||||
const p = new Promise<T>((res, rej) => {
|
||||
resolve = res
|
||||
reject = rej
|
||||
})
|
||||
return { resolve, reject, p }
|
||||
}
|
||||
|
||||
async function findElement (page: Page, selector: string, searchText: string) {
|
||||
return page.evaluate((selector, searchText) => {
|
||||
const elements = Array.from(document.querySelectorAll(selector));
|
||||
const target = elements.find(el => el.textContent.trim() === searchText);
|
||||
return target
|
||||
}, selector, searchText)
|
||||
}
|
||||
|
||||
/**
|
||||
* 元素检查,被点击或按下按键后,检查是否成功,不成功测重试或其他操作
|
||||
*/
|
||||
export async function statusCheck(
|
||||
operationsFn: Function,
|
||||
checkFn: Function,
|
||||
options: {interval?: number, tryCount?: number} = {}
|
||||
) {
|
||||
options.interval = options.interval ?? 1000
|
||||
options.tryCount = options.tryCount ?? 1
|
||||
let { interval, tryCount } = options
|
||||
const { p, resolve, reject } = createPromise<boolean>()
|
||||
await operationsFn()
|
||||
const pass = await checkFn()
|
||||
console.log('检查状态', !!pass)
|
||||
if (pass) {
|
||||
resolve(true)
|
||||
} else {
|
||||
if (tryCount <= 5) {
|
||||
await sleep(interval)
|
||||
options.tryCount++
|
||||
return await statusCheck(operationsFn, checkFn, options)
|
||||
} else {
|
||||
resolve(false)
|
||||
}
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
export function sleep (time = 1000) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, time)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 将方法重试n次
|
||||
*/
|
||||
export function retry(fn: Function, tryCount = 1) {
|
||||
return async function (...args) {
|
||||
try {
|
||||
return await fn(...args)
|
||||
} catch (error) {
|
||||
if (tryCount <= 5) {
|
||||
await sleep(1000)
|
||||
tryCount++
|
||||
return await retry(fn, tryCount)(...args)
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
30
package.json
30
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "electron-vue-vite",
|
||||
"version": "2.0.0",
|
||||
"name": "poe_gpt",
|
||||
"version": "1.0.0",
|
||||
"main": "dist-electron/main/index.js",
|
||||
"description": "Really simple Electron + Vue + Vite boilerplate.",
|
||||
"author": "草鞋没号 <308487730@qq.com>",
|
||||
@ -15,23 +15,45 @@
|
||||
],
|
||||
"debug": {
|
||||
"env": {
|
||||
"VITE_DEV_SERVER_URL": "http://127.0.0.1:3344/"
|
||||
"VITE_DEV_SERVER_URL": "http://127.0.0.1:3200/"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc --noEmit && vite build && electron-builder",
|
||||
"build": "vite build && electron-builder",
|
||||
"build:64": "vite build && electron-builder --win --x64",
|
||||
"build:32": "vite build && electron-builder --win --x32",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^4.1.0",
|
||||
"@vitejs/plugin-vue-jsx": "^3.0.1",
|
||||
"electron": "^25.0.1",
|
||||
"electron-builder": "^24.4.0",
|
||||
"typescript": "^5.0.2",
|
||||
"unplugin-auto-import": "^0.16.4",
|
||||
"unplugin-vue-components": "^0.25.0",
|
||||
"vite": "^4.1.4",
|
||||
"vite-plugin-electron": "^0.12.0",
|
||||
"vite-plugin-electron-renderer": "^0.14.1",
|
||||
"vue": "^3.2.47",
|
||||
"vue-tsc": "^1.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vueuse/core": "^10.1.2",
|
||||
"axios": "^1.4.0",
|
||||
"chrome-launcher": "^0.15.2",
|
||||
"fake-useragent": "^1.0.1",
|
||||
"lodash": "^4.17.21",
|
||||
"mockjs": "^1.1.0",
|
||||
"naive-ui": "^2.34.4",
|
||||
"proxy-chain": "^2.3.0",
|
||||
"puppeteer": "^13.3.2",
|
||||
"puppeteer-extra": "^3.3.6",
|
||||
"puppeteer-extra-plugin-recaptcha": "^3.6.8",
|
||||
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
||||
"sass": "^1.62.1",
|
||||
"socks-proxy-agent": "^8.0.1",
|
||||
"unocss": "^0.52.7"
|
||||
}
|
||||
}
|
||||
|
BIN
response.png
Normal file
BIN
response.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
421
src/App.vue
421
src/App.vue
@ -1,51 +1,390 @@
|
||||
<script setup lang="ts">
|
||||
import HelloWorld from './components/HelloWorld.vue'
|
||||
<script setup lang="tsx">
|
||||
import { ipcRenderer } from 'electron'
|
||||
import { NButton } from 'naive-ui'
|
||||
import { useClipboard, useLocalStorage } from '@vueuse/core'
|
||||
import Business from './Business.vue'
|
||||
|
||||
const input = useLocalStorage('accountInput', 'pollcribracacom@mail.com-----XAxeEgy34j')
|
||||
// const input = ref('126vdsjmgyanpgqrvb@ddmvp.icu----EOJ2NgPfS')
|
||||
// const input = ref('traceetakashi6274@gmail.com----kedaraditi0214----kedaraditi4760@hotmail.com')
|
||||
|
||||
const accountArr = computed(() => {
|
||||
const text = input.value.split('\n').filter(Boolean).map(v => {
|
||||
return v.split(/(——|-)+/).filter(v => !['-', '——'].includes(v))
|
||||
})
|
||||
return text
|
||||
})
|
||||
|
||||
const result = ref('')
|
||||
const liao = useLocalStorage('result', '')
|
||||
|
||||
const list = useLocalStorage('list', [] as any[])
|
||||
const listInstock = ref([] as any[])
|
||||
listInstock.value = list.value.filter(v => v.instock === true)
|
||||
|
||||
const filterInput = ref('')
|
||||
|
||||
const renderList = computed(() => {
|
||||
// 成功的排在前面
|
||||
let data = list.value.sort((a, b) => {
|
||||
if (a.type === 'success' && b.type !== 'success') {
|
||||
return -1
|
||||
} else if (a.type !== 'success' && b.type === 'success') {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}).filter(v => v.instock !== true)
|
||||
|
||||
if (filterInput.value) {
|
||||
data = data.filter(v => {
|
||||
return v.user.startsWith(filterInput.value)
|
||||
})
|
||||
}
|
||||
|
||||
return data
|
||||
})
|
||||
|
||||
|
||||
const remainingData = computed(() => {
|
||||
return accountArr.value.filter((item, i) => {
|
||||
const user = item[0]
|
||||
const target = list.value.find((v) => v.user === user)
|
||||
if (target && target.type === 'success') {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
})
|
||||
|
||||
function copyRemaining() {
|
||||
const text = remainingData.value.map(v => `${v[0]}----${v[1]}`).join('\n')
|
||||
copyText(text)
|
||||
}
|
||||
|
||||
const remainingColumns = [{
|
||||
title: '序列',
|
||||
render: (row, index) => h('span', undefined, index + 1),
|
||||
width: 60
|
||||
},
|
||||
{
|
||||
title: '邮箱',
|
||||
key: '0',
|
||||
width: 300
|
||||
},
|
||||
{
|
||||
title: '密码',
|
||||
key: '1',
|
||||
width: 220
|
||||
},
|
||||
]
|
||||
|
||||
ipcRenderer.on('progress', (event, args) => {
|
||||
const { user } = args
|
||||
const target = list.value.find((item) => item.user === user)
|
||||
|
||||
if (target) {
|
||||
Object.assign(target, args)
|
||||
} else {
|
||||
list.value.push(args)
|
||||
}
|
||||
})
|
||||
|
||||
// function handler () {
|
||||
// const data = {
|
||||
// 'getLink'
|
||||
// }
|
||||
// }
|
||||
|
||||
function getLink(val?: string) {
|
||||
ipcRenderer.invoke('getLink', { text: val || input.value }).then((res) => {
|
||||
console.log(res);
|
||||
})
|
||||
}
|
||||
|
||||
function getLink_7day(val?: string) {
|
||||
let liaoObj
|
||||
if (liao.value) {
|
||||
const [_1, bank, cvc, cardExpiry, name, address, city, _2, postalCode, nation] = liao.value.split('|').map(v => v.trim())
|
||||
liaoObj = { bank, cvc, date: cardExpiry, name, address, city, postalCode, nation }
|
||||
}
|
||||
|
||||
console.log(liaoObj)
|
||||
ipcRenderer.invoke('get-poe-link-7day', { text: val || input.value, liao: liaoObj }).then((res) => {
|
||||
console.log(res);
|
||||
})
|
||||
}
|
||||
|
||||
function getResult(val?: string) {
|
||||
ipcRenderer.invoke('poe-result', { text: val || input.value }).then((res) => {
|
||||
console.log(res);
|
||||
})
|
||||
}
|
||||
|
||||
function stopHandler() {
|
||||
ipcRenderer.invoke('stop')
|
||||
}
|
||||
function startOneChromHandler() {
|
||||
ipcRenderer.invoke('start-one-chrom')
|
||||
}
|
||||
|
||||
function gptLinkHandler() {
|
||||
ipcRenderer.invoke('gpt-link', { text: input.value })
|
||||
}
|
||||
|
||||
function gptResultHandler() {
|
||||
ipcRenderer.invoke('gpt-result', { text: input.value })
|
||||
}
|
||||
|
||||
const listSuccess = computed(() => {
|
||||
return list.value.filter((item) => item.instock !== true && item.type === 'success')
|
||||
})
|
||||
|
||||
function copyAllSuccess() {
|
||||
const text = listSuccess.value.map((item, i) => `${i + 1}. ${item.user}----${item.result}`).join('\n')
|
||||
copyText(text)
|
||||
}
|
||||
|
||||
const listFail = computed(() => {
|
||||
return list.value.filter((item) => item.type !== 'success')
|
||||
})
|
||||
|
||||
function copyFailHandler() {
|
||||
const text = listFail.value.map((item) => `${item.user}----${item.pass}`).join('\n\n')
|
||||
copyText(text)
|
||||
}
|
||||
|
||||
function clearLocalHandler() {
|
||||
list.value = list.value.filter(v => v.instock === true)
|
||||
}
|
||||
|
||||
const { copy } = useClipboard()
|
||||
function copyText(text: any) {
|
||||
copy(text)
|
||||
}
|
||||
function copyAccount(item: any) {
|
||||
copy(item.user + '----' + item.pass + '----' + item.auxiliary)
|
||||
}
|
||||
|
||||
function application() {
|
||||
ipcRenderer.invoke('gpt-batch-4.0', { text: input.value })
|
||||
}
|
||||
|
||||
// 申请结果
|
||||
function applicationResult() {
|
||||
ipcRenderer.invoke('gpt-batch-4.0-result', { text: input.value })
|
||||
}
|
||||
|
||||
const showBusiness = ref(false)
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '序列',
|
||||
render: (row, index) => h('span', undefined, index + 1),
|
||||
width: 60
|
||||
},
|
||||
{
|
||||
title: '邮箱',
|
||||
key: 'user',
|
||||
width: 300
|
||||
},
|
||||
{
|
||||
title: '进度',
|
||||
key: 'info',
|
||||
width: 220
|
||||
},
|
||||
{
|
||||
title: '结果',
|
||||
key: 'result',
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
width: 230,
|
||||
align: 'left',
|
||||
fixed: 'right',
|
||||
render: (row: any) => {
|
||||
/**
|
||||
* poe-link
|
||||
* 再次提链: [type: fail, loading: false]
|
||||
* 复制链接: [type: success, loading: false]
|
||||
* 充值结果: [type: success, loading: false]
|
||||
*/
|
||||
|
||||
/**
|
||||
* poe-validate
|
||||
* 充值结果: [type: fail, loading: false]
|
||||
*/
|
||||
const rechargeResult = () => {
|
||||
let link = row.ident === 'poe-link' && !row.loading
|
||||
let validate = row.ident === 'poe-validate' && row.type !== 'success' && !row.loading
|
||||
return link || validate
|
||||
}
|
||||
|
||||
return <n-space>
|
||||
{row.ident === 'poe-link' && row.type === 'success' && !row.loading
|
||||
? <NButton text type="primary" onClick={() => copyText(`${row.user}\n${row.result}`)}>复制链接</NButton>
|
||||
: null
|
||||
}
|
||||
|
||||
{row.type === 'success'
|
||||
? <NButton text type="primary" onClick={() => row.instock = true}>标记入库</NButton>
|
||||
: null
|
||||
}
|
||||
|
||||
{row.ident === 'poe-link' && row.type !== 'success' && !row.loading
|
||||
? <NButton text type="primary" onClick={() => getLink(`${row.user}----${row.pass}----${row.auxiliary}`)}>再次提链</NButton>
|
||||
: null
|
||||
}
|
||||
|
||||
<NButton text type="primary" onClick={() => copyAccount(row)}>复制帐密</NButton>
|
||||
|
||||
{rechargeResult() //.ident === 'poe-link' && row.type === 'success' && !row.loading
|
||||
? <NButton text type="info" onClick={() => getResult(`${row.user}----${row.pass}----${row.auxiliary}`)}>充值结果</NButton>
|
||||
: null
|
||||
}
|
||||
|
||||
</n-space>
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const liaoColumns = [
|
||||
{
|
||||
key: 'bank',
|
||||
title: '银行'
|
||||
},
|
||||
{
|
||||
key: 'cvc',
|
||||
title: 'cvc'
|
||||
},
|
||||
{
|
||||
key: 'date',
|
||||
title: '日期'
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
title: '名字'
|
||||
},
|
||||
{
|
||||
key: 'address',
|
||||
title: '地址'
|
||||
},
|
||||
{
|
||||
key: 'city',
|
||||
title: '城市'
|
||||
},
|
||||
{
|
||||
key: 'postalCode',
|
||||
title: '邮政编码'
|
||||
},
|
||||
{
|
||||
key: 'nation',
|
||||
title: '国家'
|
||||
}
|
||||
]
|
||||
|
||||
const liaoData = computed(() => {
|
||||
if (liao.value) {
|
||||
const [_1, bank, cvc, cardExpiry, name, address, city, _2, postalCode, nation] = liao.value.split('|').map(v => v.trim())
|
||||
return { bank, cvc, date: cardExpiry, name, address, city, postalCode, nation }
|
||||
}
|
||||
return {}
|
||||
})
|
||||
|
||||
function getLiao() {
|
||||
let liaoObj = liaoData.value
|
||||
copy(JSON.stringify(liaoObj))
|
||||
return liaoObj
|
||||
}
|
||||
|
||||
function handler(proxyType, name) {
|
||||
const isProxy = proxyType === 'proxy'
|
||||
console.log(proxyType, name, isProxy)
|
||||
let liaoObj
|
||||
// if (liao.value) {
|
||||
// const [_1, bank, cvc, cardExpiry, name, address, city, _2, postalCode, nation] = liao.value.split('|').map(v => v.trim())
|
||||
// liaoObj = { bank, cvc, date: cardExpiry, name, address, city, postalCode, nation }
|
||||
// }
|
||||
|
||||
ipcRenderer.invoke(name, { text: input.value, liao: liaoObj, proxy: isProxy })
|
||||
}
|
||||
|
||||
console.log("[App.vue]", `Hello world from Electron ${process.versions.electron}!`)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<a href="https://www.electronjs.org/" target="_blank">
|
||||
<img src="./assets/electron.svg" class="logo electron" alt="Electron logo" />
|
||||
</a>
|
||||
<a href="https://vitejs.dev/" target="_blank">
|
||||
<img src="./assets/vite.svg" class="logo" alt="Vite logo" />
|
||||
</a>
|
||||
<a href="https://vuejs.org/" target="_blank">
|
||||
<img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
|
||||
</a>
|
||||
</div>
|
||||
<HelloWorld msg="Electron + Vite + Vue" />
|
||||
<div class="flex-center">
|
||||
Place static files into the <code>/public</code> folder
|
||||
<img style="width: 2.4em; margin-left: .4em;" src="/logo.svg" alt="Logo">
|
||||
<div class="left" flex-1>
|
||||
<p>帐密: {{ accountArr.length }}</p>
|
||||
<textarea class="textarea w-full min-w-100 max-w-94vw" v-model="input" rows="20" />
|
||||
|
||||
<div flex items-center>
|
||||
<p>liao:</p>
|
||||
<NInput class="textarea w-full min-w-100 max-w-94vw flex-1 mr-3" v-model:value="liao" />
|
||||
<NButton @click="getLiao">复制</NButton>
|
||||
</div>
|
||||
|
||||
<NDataTable v-if="liaoData.bank" :data="[liaoData]" :scroll-x="1000" :columns="liaoColumns" />
|
||||
|
||||
<div>
|
||||
<div flex gap-3 mt-3 items-center>
|
||||
<span w-15>poe:</span>
|
||||
<TheButton type="primary" dashed @select="key => handler(key, 'getLink')">提取链接</TheButton>
|
||||
<TheButton type="primary" dashed @select="key => handler(key, 'poe-result')">充值结果</TheButton>
|
||||
<TheButton type="warning" dashed @select="key => handler(key, 'get-poe-link-7day')">提取链接-7天</TheButton>
|
||||
<TheButton type="warning" dashed @select="key => handler(key, 'get-poe-cookie')">获取cookie</TheButton>
|
||||
</div>
|
||||
<div flex gap-3 mt-3 items-center>
|
||||
<span w-15>gpt4.0:</span>
|
||||
<TheButton type="primary" dashed @select="key => handler(key, 'gpt-batch-4.0')">申请4.0</TheButton>
|
||||
<TheButton type="primary" dashed @select="key => handler(key, 'gpt-batch-4.0-result')">检查申请结果(mail邮箱)
|
||||
</TheButton>
|
||||
</div>
|
||||
<div flex gap-3 mt-3 items-center>
|
||||
<span w-15 class="whitespace-nowrap">gpt plus:</span>
|
||||
<TheButton type="primary" dashed @select="key => handler(key, 'gpt-link')">gpt提链</TheButton>
|
||||
<TheButton type="primary" dashed @select="key => handler(key, 'gpt-result')">充值结果</TheButton>
|
||||
</div>
|
||||
<div flex gap-3 mt-3 items-center>
|
||||
<span w-15>操作:</span>
|
||||
<NButton type="error" dashed @click="stopHandler">关闭所有浏览器</NButton>
|
||||
<NButton type="primary" dashed @click="startOneChromHandler">开一个浏览器测试</NButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right" flex-1>
|
||||
<p>结果</p>
|
||||
|
||||
<n-space mb-3>
|
||||
<n-button type="primary" dashed @click="copyAllSuccess">复制全部成功 {{ listSuccess.length }}个</n-button>
|
||||
<n-button type="error" dashed @click="copyFailHandler">复制全部失败 {{ listFail.length }}个</n-button>
|
||||
<n-button type="error" dashed @dblclick="clearLocalHandler">清除记录(双击)</n-button>
|
||||
<n-button type="info" dashed @click="showBusiness = true">库存</n-button>
|
||||
|
||||
<n-input v-model:value="filterInput" clearable />
|
||||
</n-space>
|
||||
<NDataTable :data="renderList" :columns="columns" :scroll-x="1000" />
|
||||
</div>
|
||||
|
||||
<div flex items-center gap-4>
|
||||
<p>剩余:{{ remainingData.length }}</p>
|
||||
<NButton type="primary" @click="copyRemaining">复制</NButton>
|
||||
</div>
|
||||
<NDataTable :data="remainingData" :columns="remainingColumns"></NDataTable>
|
||||
|
||||
<Business v-if="showBusiness" @close="showBusiness = false" :data="list"/>
|
||||
<div h-10></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.flex-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 6em;
|
||||
padding: 1.5em;
|
||||
will-change: filter;
|
||||
transition: filter 300ms;
|
||||
}
|
||||
|
||||
.logo.electron:hover {
|
||||
filter: drop-shadow(0 0 2em #9FEAF9);
|
||||
}
|
||||
|
||||
.logo:hover {
|
||||
filter: drop-shadow(0 0 2em #646cffaa);
|
||||
}
|
||||
|
||||
.logo.vue:hover {
|
||||
filter: drop-shadow(0 0 2em #42b883aa);
|
||||
<style lang="scss" scoped>
|
||||
.textarea:nth-of-type() {
|
||||
width: 100%;
|
||||
display: block;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
|
108
src/Business.vue
Normal file
108
src/Business.vue
Normal file
@ -0,0 +1,108 @@
|
||||
<script lang="tsx" setup>
|
||||
import { useLocalStorage } from '@vueuse/core';
|
||||
|
||||
const emits = defineEmits(['close'])
|
||||
const { data } = defineProps<{
|
||||
data: any[]
|
||||
}>()
|
||||
|
||||
const show = ref(true)
|
||||
|
||||
watch(show, () => {
|
||||
if (!show.value) emits('close')
|
||||
})
|
||||
|
||||
const key = useLocalStorage('modal_ident', '')
|
||||
const keys = computed(() => {
|
||||
return data.map((item) => item.ident)
|
||||
})
|
||||
const input = ref('')
|
||||
|
||||
const list = computed(() => {
|
||||
// 未卖
|
||||
const unsold = data.filter((item) => {
|
||||
return item.sold !== true
|
||||
}).sort((a, b) => b.soldTime - a.soldTime)
|
||||
// 已卖
|
||||
const sold = data.filter((item) => {
|
||||
return item.sold === true
|
||||
}).sort((a, b) => b.soldTime - a.soldTime)
|
||||
const newData = [...unsold, ...sold]
|
||||
|
||||
return newData.filter((item) => {
|
||||
return item.instock === true && item.ident === key.value && (input.value ? item.user.startsWith(input.value) : true)
|
||||
})
|
||||
})
|
||||
|
||||
// 标记已卖
|
||||
function handleMarkSold(row) {
|
||||
row.sold = true
|
||||
row.soldTime = Date.now()
|
||||
}
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '序列',
|
||||
render: (row, index) => h('span', undefined, index + 1),
|
||||
width: 60
|
||||
},
|
||||
{
|
||||
title: '邮箱',
|
||||
key: 'user',
|
||||
width: 220,
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
key: 'info',
|
||||
width: 80,
|
||||
render: (row) => {
|
||||
return <n-space>
|
||||
{row.sold === true
|
||||
? <n-tag type="info">已卖</n-tag>
|
||||
: <n-tag type="success">未卖</n-tag>
|
||||
}
|
||||
</n-space>
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '结果',
|
||||
key: 'result',
|
||||
ellipsis: true
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
width: 100,
|
||||
align: 'left',
|
||||
fixed: 'right',
|
||||
render: (row: any) => {
|
||||
return <n-space>
|
||||
{row.sold !== true
|
||||
? <n-button text type="primary" onClick={() => handleMarkSold(row)}>标记已卖</n-button>
|
||||
: null
|
||||
}
|
||||
</n-space>
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NModal v-model:show="show">
|
||||
<n-card class="w-90%! max-w-1000px!" title="库存" :bordered="false" size="huge" role="dialog" aria-modal="true">
|
||||
<n-input placeholder="搜索邮箱" v-model:value="input" />
|
||||
<n-tabs type="line" animated v-model:value="key">
|
||||
<n-tab-pane v-for="(item, index) in keys" :key="index" :name="item" />
|
||||
</n-tabs>
|
||||
|
||||
<NDataTable :data="list" :columns="columns" :scroll-x="1000"></NDataTable>
|
||||
<template #header-extra>
|
||||
<span px-3 class="cursor-pointer" @click="emits('close')">X</span>
|
||||
</template>
|
||||
<!-- <pre>{{ data }}</pre> -->
|
||||
</n-card>
|
||||
</NModal>
|
||||
</template>
|
178
src/auto-imports.d.ts
vendored
Normal file
178
src/auto-imports.d.ts
vendored
Normal file
@ -0,0 +1,178 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// @ts-nocheck
|
||||
// Generated by unplugin-auto-import
|
||||
export {}
|
||||
declare global {
|
||||
const EffectScope: typeof import('vue')['EffectScope']
|
||||
const computed: typeof import('vue')['computed']
|
||||
const createApp: typeof import('vue')['createApp']
|
||||
const customRef: typeof import('vue')['customRef']
|
||||
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
||||
const defineComponent: typeof import('vue')['defineComponent']
|
||||
const effectScope: typeof import('vue')['effectScope']
|
||||
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
||||
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
||||
const h: typeof import('vue')['h']
|
||||
const inject: typeof import('vue')['inject']
|
||||
const isProxy: typeof import('vue')['isProxy']
|
||||
const isReactive: typeof import('vue')['isReactive']
|
||||
const isReadonly: typeof import('vue')['isReadonly']
|
||||
const isRef: typeof import('vue')['isRef']
|
||||
const markRaw: typeof import('vue')['markRaw']
|
||||
const nextTick: typeof import('vue')['nextTick']
|
||||
const onActivated: typeof import('vue')['onActivated']
|
||||
const onBeforeMount: typeof import('vue')['onBeforeMount']
|
||||
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
|
||||
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
|
||||
const onDeactivated: typeof import('vue')['onDeactivated']
|
||||
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
|
||||
const onMounted: typeof import('vue')['onMounted']
|
||||
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
||||
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
||||
const onScopeDispose: typeof import('vue')['onScopeDispose']
|
||||
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
||||
const onUnmounted: typeof import('vue')['onUnmounted']
|
||||
const onUpdated: typeof import('vue')['onUpdated']
|
||||
const provide: typeof import('vue')['provide']
|
||||
const reactive: typeof import('vue')['reactive']
|
||||
const readonly: typeof import('vue')['readonly']
|
||||
const ref: typeof import('vue')['ref']
|
||||
const resolveComponent: typeof import('vue')['resolveComponent']
|
||||
const shallowReactive: typeof import('vue')['shallowReactive']
|
||||
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
||||
const shallowRef: typeof import('vue')['shallowRef']
|
||||
const toRaw: typeof import('vue')['toRaw']
|
||||
const toRef: typeof import('vue')['toRef']
|
||||
const toRefs: typeof import('vue')['toRefs']
|
||||
const toValue: typeof import('vue')['toValue']
|
||||
const triggerRef: typeof import('vue')['triggerRef']
|
||||
const unref: typeof import('vue')['unref']
|
||||
const useAttrs: typeof import('vue')['useAttrs']
|
||||
const useCssModule: typeof import('vue')['useCssModule']
|
||||
const useCssVars: typeof import('vue')['useCssVars']
|
||||
const useSlots: typeof import('vue')['useSlots']
|
||||
const watch: typeof import('vue')['watch']
|
||||
const watchEffect: typeof import('vue')['watchEffect']
|
||||
const watchPostEffect: typeof import('vue')['watchPostEffect']
|
||||
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
|
||||
}
|
||||
// for type re-export
|
||||
declare global {
|
||||
// @ts-ignore
|
||||
export type { Component, ComponentPublicInstance, ComputedRef, InjectionKey, PropType, Ref, VNode } from 'vue'
|
||||
}
|
||||
// for vue template auto import
|
||||
import { UnwrapRef } from 'vue'
|
||||
declare module 'vue' {
|
||||
interface ComponentCustomProperties {
|
||||
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
|
||||
readonly computed: UnwrapRef<typeof import('vue')['computed']>
|
||||
readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
|
||||
readonly customRef: UnwrapRef<typeof import('vue')['customRef']>
|
||||
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
|
||||
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
|
||||
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
|
||||
readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']>
|
||||
readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']>
|
||||
readonly h: UnwrapRef<typeof import('vue')['h']>
|
||||
readonly inject: UnwrapRef<typeof import('vue')['inject']>
|
||||
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
|
||||
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
|
||||
readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']>
|
||||
readonly isRef: UnwrapRef<typeof import('vue')['isRef']>
|
||||
readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']>
|
||||
readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']>
|
||||
readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']>
|
||||
readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']>
|
||||
readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']>
|
||||
readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']>
|
||||
readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']>
|
||||
readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']>
|
||||
readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']>
|
||||
readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']>
|
||||
readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']>
|
||||
readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']>
|
||||
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']>
|
||||
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
|
||||
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
|
||||
readonly provide: UnwrapRef<typeof import('vue')['provide']>
|
||||
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
|
||||
readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
|
||||
readonly ref: UnwrapRef<typeof import('vue')['ref']>
|
||||
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
|
||||
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
|
||||
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
|
||||
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
|
||||
readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']>
|
||||
readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
|
||||
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
|
||||
readonly toValue: UnwrapRef<typeof import('vue')['toValue']>
|
||||
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
|
||||
readonly unref: UnwrapRef<typeof import('vue')['unref']>
|
||||
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
|
||||
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
|
||||
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
|
||||
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
|
||||
readonly watch: UnwrapRef<typeof import('vue')['watch']>
|
||||
readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']>
|
||||
readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']>
|
||||
readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']>
|
||||
}
|
||||
}
|
||||
declare module '@vue/runtime-core' {
|
||||
interface ComponentCustomProperties {
|
||||
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
|
||||
readonly computed: UnwrapRef<typeof import('vue')['computed']>
|
||||
readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
|
||||
readonly customRef: UnwrapRef<typeof import('vue')['customRef']>
|
||||
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
|
||||
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
|
||||
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
|
||||
readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']>
|
||||
readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']>
|
||||
readonly h: UnwrapRef<typeof import('vue')['h']>
|
||||
readonly inject: UnwrapRef<typeof import('vue')['inject']>
|
||||
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
|
||||
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
|
||||
readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']>
|
||||
readonly isRef: UnwrapRef<typeof import('vue')['isRef']>
|
||||
readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']>
|
||||
readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']>
|
||||
readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']>
|
||||
readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']>
|
||||
readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']>
|
||||
readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']>
|
||||
readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']>
|
||||
readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']>
|
||||
readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']>
|
||||
readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']>
|
||||
readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']>
|
||||
readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']>
|
||||
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']>
|
||||
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
|
||||
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
|
||||
readonly provide: UnwrapRef<typeof import('vue')['provide']>
|
||||
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
|
||||
readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
|
||||
readonly ref: UnwrapRef<typeof import('vue')['ref']>
|
||||
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
|
||||
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
|
||||
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
|
||||
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
|
||||
readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']>
|
||||
readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
|
||||
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
|
||||
readonly toValue: UnwrapRef<typeof import('vue')['toValue']>
|
||||
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
|
||||
readonly unref: UnwrapRef<typeof import('vue')['unref']>
|
||||
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
|
||||
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
|
||||
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
|
||||
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
|
||||
readonly watch: UnwrapRef<typeof import('vue')['watch']>
|
||||
readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']>
|
||||
readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']>
|
||||
readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']>
|
||||
}
|
||||
}
|
25
src/components.d.ts
vendored
Normal file
25
src/components.d.ts
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// @ts-nocheck
|
||||
// Generated by unplugin-vue-components
|
||||
// Read more: https://github.com/vuejs/core/pull/3399
|
||||
import '@vue/runtime-core'
|
||||
|
||||
export {}
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
export interface GlobalComponents {
|
||||
HelloWorld: typeof import('./components/HelloWorld.vue')['default']
|
||||
NButton: typeof import('naive-ui')['NButton']
|
||||
NCard: typeof import('naive-ui')['NCard']
|
||||
NDataTable: typeof import('naive-ui')['NDataTable']
|
||||
NDropdown: typeof import('naive-ui')['NDropdown']
|
||||
NInput: typeof import('naive-ui')['NInput']
|
||||
NModal: typeof import('naive-ui')['NModal']
|
||||
NSpace: typeof import('naive-ui')['NSpace']
|
||||
NTabPane: typeof import('naive-ui')['NTabPane']
|
||||
NTabs: typeof import('naive-ui')['NTabs']
|
||||
NTag: typeof import('naive-ui')['NTag']
|
||||
TheButton: typeof import('./components/TheButton.vue')['default']
|
||||
}
|
||||
}
|
30
src/components/TheButton.vue
Normal file
30
src/components/TheButton.vue
Normal file
@ -0,0 +1,30 @@
|
||||
<script lang="ts" setup>
|
||||
const options = [
|
||||
{
|
||||
label: '不加代理',
|
||||
key: 'notProxy',
|
||||
},
|
||||
{
|
||||
label: '加代理(port: 40000)',
|
||||
key: "proxy"
|
||||
},
|
||||
]
|
||||
|
||||
const emits = defineEmits(['select'])
|
||||
|
||||
const handler = (key: string) => {
|
||||
|
||||
emits('select', key)
|
||||
}
|
||||
|
||||
const config = useAttrs()
|
||||
</script>
|
||||
|
||||
|
||||
<template>
|
||||
<n-dropdown trigger="hover" :options="options" @select="handler">
|
||||
<n-button v-bind="config">
|
||||
<slot></slot>
|
||||
</n-button>
|
||||
</n-dropdown>
|
||||
</template>
|
@ -3,6 +3,9 @@ import "./style.css"
|
||||
import App from './App.vue'
|
||||
import './samples/node-api'
|
||||
|
||||
import 'uno.css'
|
||||
|
||||
|
||||
createApp(App)
|
||||
.mount('#app')
|
||||
.$nextTick(() => {
|
||||
|
@ -1,3 +1,5 @@
|
||||
button:focus{outline-color: transparent !important;}
|
||||
|
||||
:root {
|
||||
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
@ -27,8 +29,8 @@ body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
place-items: center;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@ -66,11 +68,14 @@ code {
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
button,input,textarea{outline: none;}
|
||||
|
||||
#app {
|
||||
max-width: 1280px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
|
@ -5,6 +5,7 @@
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Node",
|
||||
"strict": true,
|
||||
"noImplicitAny": false,
|
||||
"jsx": "preserve",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
|
35
unocss.config.ts
Normal file
35
unocss.config.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import {
|
||||
defineConfig,
|
||||
presetAttributify,
|
||||
presetIcons,
|
||||
presetUno,
|
||||
presetWebFonts,
|
||||
// transformerDirectives,
|
||||
// transformerVariantGroup,
|
||||
} from 'unocss'
|
||||
|
||||
export default defineConfig({
|
||||
// shortcuts: [
|
||||
// ['btn', 'px-4 py-1 rounded inline-block bg-teal-600 text-white cursor-pointer hover:bg-teal-700 disabled:cursor-default disabled:bg-gray-600 disabled:opacity-50'],
|
||||
// ['icon-btn', 'text-[0.9em] inline-block cursor-pointer select-none opacity-75 transition duration-200 ease-in-out hover:opacity-100 hover:text-teal-600 !outline-none'],
|
||||
// ],
|
||||
presets: [
|
||||
presetUno(),
|
||||
presetAttributify(),
|
||||
presetIcons({
|
||||
scale: 1.2,
|
||||
warn: true,
|
||||
}),
|
||||
presetWebFonts({
|
||||
fonts: {
|
||||
sans: 'DM Sans',
|
||||
serif: 'DM Serif Display',
|
||||
mono: 'DM Mono',
|
||||
},
|
||||
}),
|
||||
],
|
||||
// transformers: [
|
||||
// transformerDirectives(),
|
||||
// transformerVariantGroup(),
|
||||
// ],
|
||||
})
|
@ -2,8 +2,13 @@ import { rmSync } from 'node:fs'
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import electron from 'vite-plugin-electron'
|
||||
import Components from 'unplugin-vue-components/vite'
|
||||
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'
|
||||
import renderer from 'vite-plugin-electron-renderer'
|
||||
import pkg from './package.json'
|
||||
import Unocss from 'unocss/vite'
|
||||
import AutoImport from 'unplugin-auto-import/vite'
|
||||
import vueJsx from '@vitejs/plugin-vue-jsx'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(({ command }) => {
|
||||
@ -16,6 +21,27 @@ export default defineConfig(({ command }) => {
|
||||
return {
|
||||
plugins: [
|
||||
vue(),
|
||||
vueJsx(),
|
||||
Unocss(),
|
||||
AutoImport({
|
||||
imports: [
|
||||
'vue',
|
||||
],
|
||||
dts: 'src/auto-imports.d.ts',
|
||||
dirs: [],
|
||||
vueTemplate: true,
|
||||
}),
|
||||
// https://github.com/antfu/unplugin-vue-components
|
||||
Components({
|
||||
resolvers: [NaiveUiResolver()],
|
||||
// allow auto load markdown components under `./src/components/`
|
||||
extensions: ['vue', 'md'],
|
||||
// allow auto import and register components used in markdown
|
||||
include: [/\.vue$/, /\.vue\?vue/, /\.md$/],
|
||||
dts: 'src/components.d.ts',
|
||||
}),
|
||||
|
||||
|
||||
electron([
|
||||
{
|
||||
// Main-Process entry file of the Electron App.
|
||||
|
Loading…
x
Reference in New Issue
Block a user