WIP: testing #40

Draft
yuessir wants to merge 6 commits from yuessir/matrix-puppeteer-line:testing into testing
5 changed files with 167 additions and 81 deletions

View File

@ -10,5 +10,6 @@
"cycle_delay": 5000, "cycle_delay": 5000,
"use_xdotool": false, "use_xdotool": false,
"jiggle_delay": 20000, "jiggle_delay": 20000,
"devtools": false "devtools": false,
"timeZone": "Asia/Taipei"
} }

View File

@ -19,9 +19,10 @@
}, },
"dependencies": { "dependencies": {
"arg": "^4.1.3", "arg": "^4.1.3",
"chrono-node": "^2.1.7", "chrono-node": "^2.3.8",
"systemd-daemon": "^1.1.2", "dayjs": "^1.11.3",
"puppeteer": "9.1.1" "puppeteer": "9.1.1",
"systemd-daemon": "^1.1.2"
}, },
"devDependencies": { "devDependencies": {
"babel-eslint": "^10.1.0", "babel-eslint": "^10.1.0",

View File

@ -22,6 +22,7 @@
* @return {Promise<Date>} * @return {Promise<Date>}
*/ */
window.__chronoParseDate = function (text, ref, option) {} window.__chronoParseDate = function (text, ref, option) {}
window.__tryParseDateByTimeZone = function (text, ref, option) { }
/** /**
* @param {...string} text - The objects to log. * @param {...string} text - The objects to log.
* @return {Promise<void>} * @return {Promise<void>}
@ -143,7 +144,7 @@ class MautrixController {
* @private * @private
*/ */
async _tryParseDate(text, ref, option) { async _tryParseDate(text, ref, option) {
const parsed = await window.__chronoParseDate(text, ref, option) const parsed = await window.__tryParseDateByTimeZone(text, ref, option)
return parsed ? new Date(parsed) : null return parsed ? new Date(parsed) : null
} }

View File

@ -42,7 +42,7 @@ MessagesPuppeteer.extensionDir = config.extension_dir || MessagesPuppeteer.exten
MessagesPuppeteer.cycleDelay = config.cycle_delay || MessagesPuppeteer.cycleDelay MessagesPuppeteer.cycleDelay = config.cycle_delay || MessagesPuppeteer.cycleDelay
MessagesPuppeteer.useXdotool = config.use_xdotool || MessagesPuppeteer.useXdotool MessagesPuppeteer.useXdotool = config.use_xdotool || MessagesPuppeteer.useXdotool
MessagesPuppeteer.jiggleDelay = config.jiggle_delay || MessagesPuppeteer.jiggleDelay MessagesPuppeteer.jiggleDelay = config.jiggle_delay || MessagesPuppeteer.jiggleDelay
MessagesPuppeteer.timeZone = config.timeZone || MessagesPuppeteer.timeZone
const api = new PuppetAPI(config.listen) const api = new PuppetAPI(config.listen)
function stop() { function stop() {

View File

@ -22,6 +22,9 @@ import chrono from "chrono-node"
import TaskQueue from "./taskqueue.js" import TaskQueue from "./taskqueue.js"
import { sleep } from "./util.js" import { sleep } from "./util.js"
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc.js';
import timezone from 'dayjs/plugin/timezone.js';
export default class MessagesPuppeteer { export default class MessagesPuppeteer {
static profileDir = "./profiles" static profileDir = "./profiles"
@ -34,7 +37,7 @@ export default class MessagesPuppeteer {
static viewport = { width: 960, height: 840 } static viewport = { width: 960, height: 840 }
static url = undefined static url = undefined
static extensionDir = "extension_files" static extensionDir = "extension_files"
static timeZone = "Asia/Taipei"
/** /**
* *
* @param {string} id * @param {string} id
@ -142,7 +145,7 @@ export default class MessagesPuppeteer {
await this.page.exposeFunction("__mautrixLoggedOut", await this.page.exposeFunction("__mautrixLoggedOut",
this._onLoggedOut.bind(this)) this._onLoggedOut.bind(this))
await this.page.exposeFunction("__chronoParseDate", chrono.parseDate) await this.page.exposeFunction("__chronoParseDate", chrono.parseDate)
await this.page.exposeFunction("__tryParseDateByTimeZone", this._tryParseDateByTimeZone.bind(this))
// NOTE Must *always* re-login on a browser session, so no need to check if already logged in // NOTE Must *always* re-login on a browser session, so no need to check if already logged in
this.loginRunning = false this.loginRunning = false
this.loginCancelled = false this.loginCancelled = false
@ -150,6 +153,28 @@ export default class MessagesPuppeteer {
this.log("Startup complete") this.log("Startup complete")
} }
async _tryParseDateByTimeZone(text, ref, option) {
const localTz = MessagesPuppeteer.timeZone // This is the ISO string
dayjs.extend(utc);
dayjs.extend(timezone);
const localTime = dayjs.tz(new Date(), localTz)
const localOffset = localTime.utcOffset() // returns in minutes
const custom = chrono.casual.clone()
custom.refiners.push({
refine: (results) => {
Array.from(results).forEach((result) => {
// Returns the time with the offset in included (must use minutes)
result.start.imply('timezoneOffset', localOffset)
result.end && result.end.imply('timezoneOffset', localOffset)
})
return results
}})
const parsed = custom.parseDate(text, ref, option)
this.log(`parsed ${parsed}`)
return parsed
}
async _preparePage(navigateTo) { async _preparePage(navigateTo) {
await this.page.bringToFront() await this.page.bringToFront()
if (navigateTo) { if (navigateTo) {
@ -729,6 +754,41 @@ export default class MessagesPuppeteer {
return `#joined_group_list_body > li[data-chatid="${id}"]` return `#joined_group_list_body > li[data-chatid="${id}"]`
} }
_contactCountSelector() {
return `#contact_wrap_friends .MdLFT04Head._contactlist_header span[id=contact_friend_count]`
}
async _getWholeContactResults(page, distance) {
await page.bringToFront()
await page.waitForSelector("#contact_wrap_friends > ul.MdCMN03List")
const contactTotalCount = 0
this.log(` distance is ${distance}`)
let incred = 0
const element = await page.$(this._contactCountSelector())
const foundContactCount = await element.evaluate(
element => {
return Number.parseInt(element?.innerText) || 0
})
this.log(` contact_friend_count is ${foundContactCount}`)
//infiniting contact list scrolling
while (incred <= distance) {
if (foundContactCount <= contactTotalCount) {
return
}
incred += 100
this.log(`scrollPosition at ${incred}/${distance}`)
await page.evaluate(d => {
const scrollableSection = document.querySelector("#contact_mode_contact_list");
scrollableSection.scrollTop = 300 + scrollableSection.offsetHeight + d;
}, incred);
}
const $lis = await page.$$("#contact_wrap_friends > ul.MdCMN03List >li")
//lookup lazy loading count
const lis = $lis.slice(contactTotalCount, Math.Infinity)
contactTotalCount = $lis.length
}
async _switchChat(chatID, forceView = false) { async _switchChat(chatID, forceView = false) {
// TODO Allow passing in an element directly // TODO Allow passing in an element directly
this.log(`Switching to chat ${chatID}`) this.log(`Switching to chat ${chatID}`)
@ -777,7 +837,30 @@ export default class MessagesPuppeteer {
} }
chatItem = await this.page.$(this._groupItemSelector(chatID)) chatItem = await this.page.$(this._groupItemSelector(chatID))
} else { } else {
needRealClick = true
const unselectedTabButton = await this.page.$(`#leftSide li[data-type=friends_list] > button:not(.ExSelected)`)
if (unselectedTabButton) {
switchedTabs = true
await unselectedTabButton.evaluate(e => e.click())
await this.page.waitForSelector("#wrap_contact_list > div.MdScroll")
let ulstyleheight = await this.page.evaluate(() => {
const ulList = document.querySelector('#contact_wrap_friends > ul.MdCMN03List')
return getComputedStyle(ulList).getPropertyValue("height")
})
const leg = parseInt(ulstyleheight, 10)
this.log(`found contact_wrap_friends height is ${leg}px`)
this.log(`starting to scroll to buttom`)
await this._getWholeContactResults(this.page, leg)
this.log(`finished to scroll to buttom`)
}
await this.page.waitForTimeout(300)
chatItem = await this.page.$(this._friendItemSelector(chatID)) chatItem = await this.page.$(this._friendItemSelector(chatID))
this.log(`Chat ${chatID} not in recents list, so bot is creating a new chat`)
await this._interactWithPage(async () => {
await chatItem.click()
})
} }
if (!chatItem) { if (!chatItem) {