forked from fair/matrix-puppeteer-line
Jiggle mouse with xdotool to keep LINE alive
Even if Chrome is the only window in an X session, and even if the window is focused, the LINE extension stops getting new messages unless the mouse has moved recently. To work around that, use xdotool to move the mouse every so often.
This commit is contained in:
parent
915e3daa06
commit
e1b822bd52
1
SETUP.md
1
SETUP.md
|
@ -1,6 +1,7 @@
|
||||||
# Minimum Requirements
|
# Minimum Requirements
|
||||||
* Python 3.8
|
* Python 3.8
|
||||||
* Node 10.18.1
|
* Node 10.18.1
|
||||||
|
* xdotool
|
||||||
|
|
||||||
# Initial setup
|
# Initial setup
|
||||||
## Puppeteer module
|
## Puppeteer module
|
||||||
|
|
|
@ -12,5 +12,13 @@ The `profile_dir` specifies which directory to put Chromium user data directorie
|
||||||
### Extension directory
|
### Extension directory
|
||||||
The `extension_dir` specifies which directory contains the files for the LINE extension, which you must download yourself.
|
The `extension_dir` specifies which directory contains the files for the LINE extension, which you must download yourself.
|
||||||
|
|
||||||
|
### Cycle delay
|
||||||
|
`cycle_delay` specifies the period (in milliseconds) at which Puppeteer should view chats to check on their read receipts. Only chats with messages that haven't been fully read need to be checked.
|
||||||
|
|
||||||
|
### `xdotool`
|
||||||
|
Set `use_xdotool` to `true` to allow the Node process to manipulate the mouse cursor of the X server it runs in. Requires the `xdotool` utility to be installed. Highly recommended, especially when running in a virtual X server. Its default value is `false` so that running in a non-virtual X server won't interfere with a real mouse cursor.
|
||||||
|
|
||||||
|
`jiggle_delay` specifies the period (in milliseconds) between "jiggling" the mouse cursor (necessary to keep the LINE extension active). Only relevant when `use_xdotool` is `true`.
|
||||||
|
|
||||||
### DevTools
|
### DevTools
|
||||||
Set `devtools` to `true` to launch Chromium with DevTools enabled by default.
|
Set `devtools` to `true` to launch Chromium with DevTools enabled by default.
|
||||||
|
|
|
@ -6,5 +6,8 @@
|
||||||
"profile_dir": "./profiles",
|
"profile_dir": "./profiles",
|
||||||
"url": "chrome-extension://<extension-uuid>/index.html",
|
"url": "chrome-extension://<extension-uuid>/index.html",
|
||||||
"extension_dir": "./extension_files",
|
"extension_dir": "./extension_files",
|
||||||
|
"cycle_delay": 5000,
|
||||||
|
"use_xdotool": false,
|
||||||
|
"jiggle_delay": 20000,
|
||||||
"devtools": false
|
"devtools": false
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,9 @@ MessagesPuppeteer.profileDir = config.profile_dir || MessagesPuppeteer.profileDi
|
||||||
MessagesPuppeteer.devtools = config.devtools || false
|
MessagesPuppeteer.devtools = config.devtools || false
|
||||||
MessagesPuppeteer.url = config.url
|
MessagesPuppeteer.url = config.url
|
||||||
MessagesPuppeteer.extensionDir = config.extension_dir || MessagesPuppeteer.extensionDir
|
MessagesPuppeteer.extensionDir = config.extension_dir || MessagesPuppeteer.extensionDir
|
||||||
|
MessagesPuppeteer.cycleDelay = config.cycle_delay || MessagesPuppeteer.cycleDelay
|
||||||
|
MessagesPuppeteer.useXdotool = config.use_xdotool || MessagesPuppeteer.useXdotool
|
||||||
|
MessagesPuppeteer.jiggleDelay = config.jiggle_delay || MessagesPuppeteer.jiggleDelay
|
||||||
|
|
||||||
const api = new PuppetAPI(config.listen)
|
const api = new PuppetAPI(config.listen)
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
import process from "process"
|
import process from "process"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
|
import { exec, execSync } from "child_process"
|
||||||
|
|
||||||
import puppeteer from "puppeteer"
|
import puppeteer from "puppeteer"
|
||||||
import chrono from "chrono-node"
|
import chrono from "chrono-node"
|
||||||
|
@ -25,6 +26,9 @@ import { sleep } from "./util.js"
|
||||||
export default class MessagesPuppeteer {
|
export default class MessagesPuppeteer {
|
||||||
static profileDir = "./profiles"
|
static profileDir = "./profiles"
|
||||||
static executablePath = undefined
|
static executablePath = undefined
|
||||||
|
static cycleDelay = 5000
|
||||||
|
static useXdotool = false
|
||||||
|
static jiggleDelay = 30000
|
||||||
static devtools = false
|
static devtools = false
|
||||||
static noSandbox = false
|
static noSandbox = false
|
||||||
static viewport = { width: 960, height: 840 }
|
static viewport = { width: 960, height: 840 }
|
||||||
|
@ -43,6 +47,7 @@ export default class MessagesPuppeteer {
|
||||||
}
|
}
|
||||||
this.id = id
|
this.id = id
|
||||||
this.ownID = ownID
|
this.ownID = ownID
|
||||||
|
this.windowID = null
|
||||||
this.sendPlaceholders = sendPlaceholders
|
this.sendPlaceholders = sendPlaceholders
|
||||||
this.profilePath = profilePath
|
this.profilePath = profilePath
|
||||||
this.updatedChats = new Set()
|
this.updatedChats = new Set()
|
||||||
|
@ -51,6 +56,7 @@ export default class MessagesPuppeteer {
|
||||||
this.mostRecentReceipts = new Map()
|
this.mostRecentReceipts = new Map()
|
||||||
this.numChatNotifications = new Map()
|
this.numChatNotifications = new Map()
|
||||||
this.cycleTimerID = null
|
this.cycleTimerID = null
|
||||||
|
this.jiggleTimerID = null
|
||||||
this.taskQueue = new TaskQueue(this.id)
|
this.taskQueue = new TaskQueue(this.id)
|
||||||
this.client = client
|
this.client = client
|
||||||
}
|
}
|
||||||
|
@ -99,7 +105,14 @@ export default class MessagesPuppeteer {
|
||||||
this.blankPage = await this.browser.newPage()
|
this.blankPage = await this.browser.newPage()
|
||||||
await this.page.bringToFront()
|
await this.page.bringToFront()
|
||||||
|
|
||||||
this.log("Opening", MessagesPuppeteer.url)
|
if (MessagesPuppeteer.useXdotool) {
|
||||||
|
this.log("Finding window ID")
|
||||||
|
const buffer = execSync("xdotool search 'about:blank'")
|
||||||
|
this.windowID = Number.parseInt(buffer)
|
||||||
|
this.log(`Found window ID ${this.windowID}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.log(`Opening ${MessagesPuppeteer.url}`)
|
||||||
await this.page.setBypassCSP(true) // Needed to load content scripts
|
await this.page.setBypassCSP(true) // Needed to load content scripts
|
||||||
await this._preparePage(true)
|
await this._preparePage(true)
|
||||||
|
|
||||||
|
@ -472,10 +485,9 @@ export default class MessagesPuppeteer {
|
||||||
}
|
}
|
||||||
|
|
||||||
_cycleTimerStart() {
|
_cycleTimerStart() {
|
||||||
// TODO Config for cycle delay
|
|
||||||
this.cycleTimerID = setTimeout(
|
this.cycleTimerID = setTimeout(
|
||||||
() => this.taskQueue.push(() => this._cycleChatUnsafe()),
|
() => this.taskQueue.push(() => this._cycleChatUnsafe()),
|
||||||
5000)
|
MessagesPuppeteer.cycleDelay)
|
||||||
}
|
}
|
||||||
|
|
||||||
async _cycleChatUnsafe() {
|
async _cycleChatUnsafe() {
|
||||||
|
@ -515,21 +527,39 @@ export default class MessagesPuppeteer {
|
||||||
}
|
}
|
||||||
|
|
||||||
chatIDToSync = chatListItem.id
|
chatIDToSync = chatListItem.id
|
||||||
|
this.log(`Viewing chat ${chatIDToSync} to check for new read receipts`)
|
||||||
|
await this._syncChat(chatIDToSync)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!chatIDToSync) {
|
if (!chatIDToSync) {
|
||||||
// TODO Confirm if this actually works...!
|
this.log("Found no chats in need of read receipt updates")
|
||||||
this.log(`Found no chats in need of read receipt updates, so force-viewing ${currentChatID} just to keep LINE alive`)
|
|
||||||
await this._switchChat(currentChatID, true)
|
|
||||||
} else {
|
|
||||||
this.log(`Viewing chat ${chatIDToSync} to check for new read receipts`)
|
|
||||||
await this._syncChat(chatIDToSync)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._cycleTimerStart()
|
this._cycleTimerStart()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Jiggle the mouse periodically.
|
||||||
|
* Have to do this to keep the LINE extension "awake". Ridiculous, but necessary...
|
||||||
|
*/
|
||||||
|
_jiggleTimerStart() {
|
||||||
|
this.jiggleTimerID = setTimeout(() => this._jiggleMouse(), MessagesPuppeteer.jiggleDelay)
|
||||||
|
}
|
||||||
|
|
||||||
|
_jiggleMouse() {
|
||||||
|
this.log("Jiggling mouse")
|
||||||
|
exec(`xdotool mousemove --sync --window ${this.windowID} 0 0`, {},
|
||||||
|
(error, stdout, stderr) => {
|
||||||
|
if (error) {
|
||||||
|
this.log(`Error while jiggling mouse: ${error}`)
|
||||||
|
} else {
|
||||||
|
this.log("Jiggled mouse")
|
||||||
|
}
|
||||||
|
this._jiggleTimerStart()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async startObserving() {
|
async startObserving() {
|
||||||
// TODO Highly consider syncing anything that was missed since stopObserving...
|
// TODO Highly consider syncing anything that was missed since stopObserving...
|
||||||
const chatID = await this.page.evaluate(() => window.__mautrixController.getCurrentChatID())
|
const chatID = await this.page.evaluate(() => window.__mautrixController.getCurrentChatID())
|
||||||
|
@ -545,6 +575,9 @@ export default class MessagesPuppeteer {
|
||||||
if (this.cycleTimerID == null) {
|
if (this.cycleTimerID == null) {
|
||||||
this._cycleTimerStart()
|
this._cycleTimerStart()
|
||||||
}
|
}
|
||||||
|
if (MessagesPuppeteer.useXdotool && this.jiggleTimerID == null) {
|
||||||
|
this._jiggleTimerStart()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async stopObserving() {
|
async stopObserving() {
|
||||||
|
@ -558,6 +591,10 @@ export default class MessagesPuppeteer {
|
||||||
clearTimeout(this.cycleTimerID)
|
clearTimeout(this.cycleTimerID)
|
||||||
this.cycleTimerID = null
|
this.cycleTimerID = null
|
||||||
}
|
}
|
||||||
|
if (this.jiggleTimerID != null) {
|
||||||
|
clearTimeout(this.jiggleTimerID)
|
||||||
|
this.jiggleTimerID = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getOwnProfile() {
|
async getOwnProfile() {
|
||||||
|
|
Loading…
Reference in New Issue