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
|
||||
* Python 3.8
|
||||
* Node 10.18.1
|
||||
* xdotool
|
||||
|
||||
# Initial setup
|
||||
## Puppeteer module
|
||||
|
|
|
@ -12,5 +12,13 @@ The `profile_dir` specifies which directory to put Chromium user data directorie
|
|||
### Extension directory
|
||||
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
|
||||
Set `devtools` to `true` to launch Chromium with DevTools enabled by default.
|
||||
|
|
|
@ -6,5 +6,8 @@
|
|||
"profile_dir": "./profiles",
|
||||
"url": "chrome-extension://<extension-uuid>/index.html",
|
||||
"extension_dir": "./extension_files",
|
||||
"cycle_delay": 5000,
|
||||
"use_xdotool": false,
|
||||
"jiggle_delay": 20000,
|
||||
"devtools": false
|
||||
}
|
||||
|
|
|
@ -39,6 +39,9 @@ MessagesPuppeteer.profileDir = config.profile_dir || MessagesPuppeteer.profileDi
|
|||
MessagesPuppeteer.devtools = config.devtools || false
|
||||
MessagesPuppeteer.url = config.url
|
||||
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)
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import process from "process"
|
||||
import path from "path"
|
||||
import { exec, execSync } from "child_process"
|
||||
|
||||
import puppeteer from "puppeteer"
|
||||
import chrono from "chrono-node"
|
||||
|
@ -25,6 +26,9 @@ import { sleep } from "./util.js"
|
|||
export default class MessagesPuppeteer {
|
||||
static profileDir = "./profiles"
|
||||
static executablePath = undefined
|
||||
static cycleDelay = 5000
|
||||
static useXdotool = false
|
||||
static jiggleDelay = 30000
|
||||
static devtools = false
|
||||
static noSandbox = false
|
||||
static viewport = { width: 960, height: 840 }
|
||||
|
@ -43,6 +47,7 @@ export default class MessagesPuppeteer {
|
|||
}
|
||||
this.id = id
|
||||
this.ownID = ownID
|
||||
this.windowID = null
|
||||
this.sendPlaceholders = sendPlaceholders
|
||||
this.profilePath = profilePath
|
||||
this.updatedChats = new Set()
|
||||
|
@ -51,6 +56,7 @@ export default class MessagesPuppeteer {
|
|||
this.mostRecentReceipts = new Map()
|
||||
this.numChatNotifications = new Map()
|
||||
this.cycleTimerID = null
|
||||
this.jiggleTimerID = null
|
||||
this.taskQueue = new TaskQueue(this.id)
|
||||
this.client = client
|
||||
}
|
||||
|
@ -99,7 +105,14 @@ export default class MessagesPuppeteer {
|
|||
this.blankPage = await this.browser.newPage()
|
||||
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._preparePage(true)
|
||||
|
||||
|
@ -472,10 +485,9 @@ export default class MessagesPuppeteer {
|
|||
}
|
||||
|
||||
_cycleTimerStart() {
|
||||
// TODO Config for cycle delay
|
||||
this.cycleTimerID = setTimeout(
|
||||
() => this.taskQueue.push(() => this._cycleChatUnsafe()),
|
||||
5000)
|
||||
MessagesPuppeteer.cycleDelay)
|
||||
}
|
||||
|
||||
async _cycleChatUnsafe() {
|
||||
|
@ -515,21 +527,39 @@ export default class MessagesPuppeteer {
|
|||
}
|
||||
|
||||
chatIDToSync = chatListItem.id
|
||||
this.log(`Viewing chat ${chatIDToSync} to check for new read receipts`)
|
||||
await this._syncChat(chatIDToSync)
|
||||
break
|
||||
}
|
||||
|
||||
if (!chatIDToSync) {
|
||||
// TODO Confirm if this actually works...!
|
||||
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.log("Found no chats in need of read receipt updates")
|
||||
}
|
||||
|
||||
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() {
|
||||
// TODO Highly consider syncing anything that was missed since stopObserving...
|
||||
const chatID = await this.page.evaluate(() => window.__mautrixController.getCurrentChatID())
|
||||
|
@ -545,6 +575,9 @@ export default class MessagesPuppeteer {
|
|||
if (this.cycleTimerID == null) {
|
||||
this._cycleTimerStart()
|
||||
}
|
||||
if (MessagesPuppeteer.useXdotool && this.jiggleTimerID == null) {
|
||||
this._jiggleTimerStart()
|
||||
}
|
||||
}
|
||||
|
||||
async stopObserving() {
|
||||
|
@ -558,6 +591,10 @@ export default class MessagesPuppeteer {
|
|||
clearTimeout(this.cycleTimerID)
|
||||
this.cycleTimerID = null
|
||||
}
|
||||
if (this.jiggleTimerID != null) {
|
||||
clearTimeout(this.jiggleTimerID)
|
||||
this.jiggleTimerID = null
|
||||
}
|
||||
}
|
||||
|
||||
async getOwnProfile() {
|
||||
|
|
Loading…
Reference in New Issue