Merge 77da3cf3394eae3ea81a7742f3c51bb12e627bb6 into b4cf3b4c5f3e77eb7d28490b60f64ea7a94e47a4

This commit is contained in:
zhenjie1 2023-07-05 14:35:32 +08:00 committed by GitHub
commit 02d4f9dff6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 2388 additions and 52 deletions

View File

@ -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}"
},

View 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&regions=&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()
}

View 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()
}

View 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)
}
}

View 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()
}

View File

@ -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
View 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
View 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
}
}

View 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
View 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 })
})

View 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
}
}

View 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
View 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
}
}
}
}

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -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
View 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
View 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
View 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']
}
}

View 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>

View File

@ -3,6 +3,9 @@ import "./style.css"
import App from './App.vue'
import './samples/node-api'
import 'uno.css'
createApp(App)
.mount('#app')
.$nextTick(() => {

View File

@ -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) {

View File

@ -5,6 +5,7 @@
"module": "ESNext",
"moduleResolution": "Node",
"strict": true,
"noImplicitAny": false,
"jsx": "preserve",
"resolveJsonModule": true,
"isolatedModules": true,

35
unocss.config.ts Normal file
View 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(),
// ],
})

View File

@ -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.