mirror of
https://github.com/geekgeekrun/geekgeekrun.git
synced 2026-09-07 08:27:13 +08:00
add the rerun logic for read no reply auto reminder
This commit is contained in:
@@ -39,7 +39,6 @@ export async function launchBoss(browser: Browser) {
|
|||||||
pageMapByName['boss'] = null
|
pageMapByName['boss'] = null
|
||||||
const cp = browser.process()
|
const cp = browser.process()
|
||||||
cp?.kill()
|
cp?.kill()
|
||||||
process.exit(0)
|
|
||||||
})
|
})
|
||||||
return page
|
return page
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,161 +1,200 @@
|
|||||||
import { bootstrap, launchBoss } from './bootstrap'
|
import { bootstrap, launchBoss } from './bootstrap'
|
||||||
import { MsgStatus, type ChatListItem } from './types'
|
import { MsgStatus, type ChatListItem } from './types'
|
||||||
import { Page } from 'puppeteer'
|
import { Browser, Page } from 'puppeteer'
|
||||||
import { sendLookForwardReplyEmotion } from './boss-operation'
|
import { sendLookForwardReplyEmotion } from './boss-operation'
|
||||||
import { sleep, sleepWithRandomDelay } from '@geekgeekrun/utils/sleep.mjs'
|
import { sleep, sleepWithRandomDelay } from '@geekgeekrun/utils/sleep.mjs'
|
||||||
import attachListenerForKillSelfOnParentExited from '../../utils/attachListenerForKillSelfOnParentExited'
|
import attachListenerForKillSelfOnParentExited from '../../utils/attachListenerForKillSelfOnParentExited'
|
||||||
|
import { app } from 'electron'
|
||||||
|
|
||||||
export const pageMapByName: {
|
export const pageMapByName: {
|
||||||
boss?: Page | null
|
boss?: Page | null
|
||||||
} = {}
|
} = {}
|
||||||
|
|
||||||
export const runEntry = async () => {
|
let browser: null | Browser = null
|
||||||
try {
|
const mainLoop = async () => {
|
||||||
const canNotConfirmIfHasReadMsgTemplateList = [
|
if (browser) {
|
||||||
'Boss还没查看你的消息',
|
try {
|
||||||
'你与该职位竞争者PK情况',
|
await browser?.close()
|
||||||
'简历诊断提醒',
|
} catch {
|
||||||
'附件简历还没准备好',
|
//
|
||||||
'开场问题,期待你的回答'
|
} finally {
|
||||||
].map((it) => new RegExp(it))
|
browser = null
|
||||||
const browser = await bootstrap()
|
}
|
||||||
await Promise.all([launchBoss(browser)])
|
}
|
||||||
|
const canNotConfirmIfHasReadMsgTemplateList = [
|
||||||
|
'Boss还没查看你的消息',
|
||||||
|
'你与该职位竞争者PK情况',
|
||||||
|
'简历诊断提醒',
|
||||||
|
'附件简历还没准备好',
|
||||||
|
'开场问题,期待你的回答'
|
||||||
|
].map((it) => new RegExp(it))
|
||||||
|
browser = await bootstrap()
|
||||||
|
await Promise.all([launchBoss(browser)])
|
||||||
|
|
||||||
|
await sleep(1000)
|
||||||
|
pageMapByName.boss!.bringToFront()
|
||||||
|
await sleep(2000)
|
||||||
|
|
||||||
|
// check set security question tip modal
|
||||||
|
let setSecurityQuestionTipModelProxy = await pageMapByName.boss!.$(
|
||||||
|
'.dialog-wrap.dialog-account-safe'
|
||||||
|
)
|
||||||
|
if (setSecurityQuestionTipModelProxy) {
|
||||||
await sleep(1000)
|
await sleep(1000)
|
||||||
pageMapByName.boss!.bringToFront()
|
setSecurityQuestionTipModelProxy = await pageMapByName.boss!.$(
|
||||||
await sleep(2000)
|
|
||||||
|
|
||||||
// check set security question tip modal
|
|
||||||
let setSecurityQuestionTipModelProxy = await pageMapByName.boss!.$(
|
|
||||||
'.dialog-wrap.dialog-account-safe'
|
'.dialog-wrap.dialog-account-safe'
|
||||||
)
|
)
|
||||||
if (setSecurityQuestionTipModelProxy) {
|
const closeButtonProxy = await setSecurityQuestionTipModelProxy?.$('.close')
|
||||||
await sleep(1000)
|
|
||||||
setSecurityQuestionTipModelProxy = await pageMapByName.boss!.$(
|
|
||||||
'.dialog-wrap.dialog-account-safe'
|
|
||||||
)
|
|
||||||
const closeButtonProxy = await setSecurityQuestionTipModelProxy?.$('.close')
|
|
||||||
|
|
||||||
if (setSecurityQuestionTipModelProxy && closeButtonProxy) {
|
if (setSecurityQuestionTipModelProxy && closeButtonProxy) {
|
||||||
await closeButtonProxy.click()
|
await closeButtonProxy.click()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let cursorToContinueFind = 0
|
let cursorToContinueFind = 0
|
||||||
|
|
||||||
// eslint-disable-next-line no-constant-condition
|
// eslint-disable-next-line no-constant-condition
|
||||||
while (true) {
|
while (true) {
|
||||||
// find target boss - with unread icon, or recommend system message
|
// find target boss - with unread icon, or recommend system message
|
||||||
const friendListData = (await pageMapByName.boss!.evaluate(
|
const friendListData = (await pageMapByName.boss!.evaluate(
|
||||||
`
|
`
|
||||||
document.querySelector('.main-wrap .chat-user')?.__vue__?.list
|
document.querySelector('.main-wrap .chat-user')?.__vue__?.list
|
||||||
`
|
`
|
||||||
)) as Array<ChatListItem>
|
)) as Array<ChatListItem>
|
||||||
const toCheckItemAtIndex = friendListData.findIndex(
|
const toCheckItemAtIndex = friendListData.findIndex(
|
||||||
(it, index) =>
|
(it, index) =>
|
||||||
index >= cursorToContinueFind &&
|
index >= cursorToContinueFind &&
|
||||||
((it.lastIsSelf && it.lastMsgStatus === MsgStatus.HAS_READ) ||
|
((it.lastIsSelf && it.lastMsgStatus === MsgStatus.HAS_READ) ||
|
||||||
canNotConfirmIfHasReadMsgTemplateList.some((regExp) => regExp.test(it.lastText))) &&
|
canNotConfirmIfHasReadMsgTemplateList.some((regExp) => regExp.test(it.lastText))) &&
|
||||||
!it.unreadCount
|
!it.unreadCount
|
||||||
)
|
)
|
||||||
|
|
||||||
if (toCheckItemAtIndex < 0) {
|
if (toCheckItemAtIndex < 0) {
|
||||||
const isFinished = await pageMapByName.boss!.evaluate(
|
const isFinished = await pageMapByName.boss!.evaluate(
|
||||||
`(document.querySelector(
|
`(document.querySelector(
|
||||||
'.main-wrap .chat-user .user-list-content div[role=tfoot] .finished'
|
'.main-wrap .chat-user .user-list-content div[role=tfoot] .finished'
|
||||||
)?.textContent ?? '').includes('没有')`
|
)?.textContent ?? '').includes('没有')`
|
||||||
)
|
)
|
||||||
if (isFinished) {
|
if (isFinished) {
|
||||||
// list has all loaded and no more target job
|
// list has all loaded and no more target job
|
||||||
// go back to first job
|
// go back to first job
|
||||||
cursorToContinueFind = 0
|
cursorToContinueFind = 0
|
||||||
await pageMapByName.boss?.evaluate(() => {
|
await pageMapByName.boss?.evaluate(() => {
|
||||||
;(() => {
|
|
||||||
document
|
|
||||||
.querySelector('.chat-content .user-list .user-list-content')
|
|
||||||
?.__vue__.scrollToIndex(0)
|
|
||||||
})()
|
|
||||||
})
|
|
||||||
await sleep(10000)
|
|
||||||
} else {
|
|
||||||
cursorToContinueFind = friendListData.length - 1
|
|
||||||
await pageMapByName.boss?.evaluate(() => {
|
|
||||||
;(() => {
|
|
||||||
document
|
|
||||||
.querySelector('.chat-content .user-list .user-list-content')
|
|
||||||
?.__vue__.scrollToBottom()
|
|
||||||
})()
|
|
||||||
})
|
|
||||||
await sleep(3000)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
cursorToContinueFind = toCheckItemAtIndex
|
|
||||||
await pageMapByName.boss?.evaluate((toCheckItemAtIndex) => {
|
|
||||||
;(() => {
|
;(() => {
|
||||||
document
|
document
|
||||||
.querySelector('.chat-content .user-list .user-list-content')
|
.querySelector('.chat-content .user-list .user-list-content')
|
||||||
?.__vue__.scrollToIndex(toCheckItemAtIndex)
|
?.__vue__.scrollToIndex(0)
|
||||||
})()
|
})()
|
||||||
}, toCheckItemAtIndex)
|
|
||||||
await sleep(3000)
|
|
||||||
|
|
||||||
const targetElProxy = await (async () => {
|
|
||||||
const jsHandle = (
|
|
||||||
await pageMapByName.boss?.evaluateHandle((encryptJobId) => {
|
|
||||||
const jobLiEls = document.querySelectorAll(
|
|
||||||
'.main-wrap .chat-user .user-list-content ul[role=group] li[role=listitem]'
|
|
||||||
)
|
|
||||||
return [...jobLiEls].find((it) => {
|
|
||||||
return it.__vue__.source.encryptJobId === encryptJobId
|
|
||||||
})
|
|
||||||
}, friendListData[toCheckItemAtIndex].encryptJobId)
|
|
||||||
)?.asElement()
|
|
||||||
return jsHandle
|
|
||||||
})()
|
|
||||||
await targetElProxy?.click()
|
|
||||||
await pageMapByName.boss!.waitForResponse((response) => {
|
|
||||||
if (response.url().startsWith('https://www.zhipin.com/wapi/zpchat/geek/historyMsg')) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
})
|
||||||
}
|
await sleep(10000)
|
||||||
await sleepWithRandomDelay(1500)
|
|
||||||
const bossInfo = await pageMapByName.boss?.evaluate(() => {
|
|
||||||
return document.querySelector('.chat-conversation')?.__vue__['bossInfo$']
|
|
||||||
})
|
|
||||||
|
|
||||||
const historyMessageList =
|
|
||||||
(
|
|
||||||
await pageMapByName.boss?.evaluate(() => {
|
|
||||||
return (
|
|
||||||
document.querySelector('.main-wrap .chat-conversation .chat-record')?.__vue__
|
|
||||||
?.records$ ?? []
|
|
||||||
)
|
|
||||||
})
|
|
||||||
)?.filter((msg) => ['received', 'sent'].includes(msg.style)) ?? []
|
|
||||||
|
|
||||||
const lastGeekMessageSendTime =
|
|
||||||
historyMessageList.findLast((it) => it.style === 'sent')?.time ?? 0
|
|
||||||
if (
|
|
||||||
historyMessageList[historyMessageList.length - 1].style === 'sent' &&
|
|
||||||
historyMessageList[historyMessageList.length - 1].status === MsgStatus.HAS_READ &&
|
|
||||||
(!bossInfo.bothTalked ||
|
|
||||||
!historyMessageList.filter((it) => it.style === 'received').length) &&
|
|
||||||
// don't disturb too much
|
|
||||||
Date.now() - lastGeekMessageSendTime >= 8 * 60 * 60 * 1000
|
|
||||||
) {
|
|
||||||
await sleepWithRandomDelay(3250)
|
|
||||||
await sendLookForwardReplyEmotion(pageMapByName.boss!)
|
|
||||||
} else {
|
} else {
|
||||||
cursorToContinueFind += 1
|
cursorToContinueFind = friendListData.length - 1
|
||||||
|
await pageMapByName.boss?.evaluate(() => {
|
||||||
|
;(() => {
|
||||||
|
document
|
||||||
|
.querySelector('.chat-content .user-list .user-list-content')
|
||||||
|
?.__vue__.scrollToBottom()
|
||||||
|
})()
|
||||||
|
})
|
||||||
|
await sleep(3000)
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
cursorToContinueFind = toCheckItemAtIndex
|
||||||
|
await pageMapByName.boss?.evaluate((toCheckItemAtIndex) => {
|
||||||
|
;(() => {
|
||||||
|
document
|
||||||
|
.querySelector('.chat-content .user-list .user-list-content')
|
||||||
|
?.__vue__.scrollToIndex(toCheckItemAtIndex)
|
||||||
|
})()
|
||||||
|
}, toCheckItemAtIndex)
|
||||||
await sleep(3000)
|
await sleep(3000)
|
||||||
|
|
||||||
|
const targetElProxy = await (async () => {
|
||||||
|
const jsHandle = (
|
||||||
|
await pageMapByName.boss?.evaluateHandle((encryptJobId) => {
|
||||||
|
const jobLiEls = document.querySelectorAll(
|
||||||
|
'.main-wrap .chat-user .user-list-content ul[role=group] li[role=listitem]'
|
||||||
|
)
|
||||||
|
return [...jobLiEls].find((it) => {
|
||||||
|
return it.__vue__.source.encryptJobId === encryptJobId
|
||||||
|
})
|
||||||
|
}, friendListData[toCheckItemAtIndex].encryptJobId)
|
||||||
|
)?.asElement()
|
||||||
|
return jsHandle
|
||||||
|
})()
|
||||||
|
await targetElProxy?.click()
|
||||||
|
await pageMapByName.boss!.waitForResponse((response) => {
|
||||||
|
if (response.url().startsWith('https://www.zhipin.com/wapi/zpchat/geek/historyMsg')) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} catch (err) {
|
await sleepWithRandomDelay(1500)
|
||||||
console.error(err)
|
const bossInfo = await pageMapByName.boss?.evaluate(() => {
|
||||||
|
return document.querySelector('.chat-conversation')?.__vue__['bossInfo$']
|
||||||
|
})
|
||||||
|
|
||||||
|
const historyMessageList =
|
||||||
|
(
|
||||||
|
await pageMapByName.boss?.evaluate(() => {
|
||||||
|
return (
|
||||||
|
document.querySelector('.main-wrap .chat-conversation .chat-record')?.__vue__
|
||||||
|
?.records$ ?? []
|
||||||
|
)
|
||||||
|
})
|
||||||
|
)?.filter((msg) => ['received', 'sent'].includes(msg.style)) ?? []
|
||||||
|
|
||||||
|
const lastGeekMessageSendTime =
|
||||||
|
historyMessageList.findLast((it) => it.style === 'sent')?.time ?? 0
|
||||||
|
if (
|
||||||
|
historyMessageList[historyMessageList.length - 1].style === 'sent' &&
|
||||||
|
historyMessageList[historyMessageList.length - 1].status === MsgStatus.HAS_READ &&
|
||||||
|
(!bossInfo.bothTalked ||
|
||||||
|
!historyMessageList.filter((it) => it.style === 'received').length) &&
|
||||||
|
// don't disturb too much
|
||||||
|
Date.now() - lastGeekMessageSendTime >= 8 * 60 * 60 * 1000
|
||||||
|
) {
|
||||||
|
await sleepWithRandomDelay(3250)
|
||||||
|
await sendLookForwardReplyEmotion(pageMapByName.boss!)
|
||||||
|
} else {
|
||||||
|
cursorToContinueFind += 1
|
||||||
|
}
|
||||||
|
await sleep(3000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let isParentProcessDisconnect = false
|
||||||
|
process.once('disconnect', () => {
|
||||||
|
isParentProcessDisconnect = true
|
||||||
|
})
|
||||||
|
const rerunInterval = (() => {
|
||||||
|
let v = Number(process.env.MAIN_BOSSGEEKGO_RERUN_INTERVAL)
|
||||||
|
if (isNaN(v)) {
|
||||||
|
v = 3000
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
|
})()
|
||||||
|
export async function runEntry() {
|
||||||
|
process.on('disconnect', () => {
|
||||||
|
app.exit()
|
||||||
|
})
|
||||||
|
app.dock?.hide()
|
||||||
|
|
||||||
|
while (!isParentProcessDisconnect) {
|
||||||
|
try {
|
||||||
|
await mainLoop()
|
||||||
|
} catch (err) {
|
||||||
|
await browser?.close()
|
||||||
|
} finally {
|
||||||
|
browser = null
|
||||||
|
await sleep(rerunInterval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
process.exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
attachListenerForKillSelfOnParentExited()
|
attachListenerForKillSelfOnParentExited()
|
||||||
|
|||||||
Reference in New Issue
Block a user