Fix Periscope autoplay by waiting for button to exist

This commit is contained in:
Max Goodhart
2020-11-11 22:23:57 -08:00
parent 07619eaee7
commit 8df7dab144

View File

@@ -1,4 +1,7 @@
import { ipcRenderer, webFrame } from 'electron' import { ipcRenderer, webFrame } from 'electron'
import throttle from 'lodash/throttle'
const SCAN_THROTTLE = 500
const VIDEO_OVERRIDE_STYLE = ` const VIDEO_OVERRIDE_STYLE = `
* { * {
@@ -63,6 +66,10 @@ const NO_SCROLL_STYLE = `
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
const pageReady = new Promise((resolve) =>
document.addEventListener('DOMContentLoaded', resolve, { once: true }),
)
class RotationController { class RotationController {
constructor(video) { constructor(video) {
this.video = video this.video = video
@@ -89,42 +96,48 @@ class RotationController {
} }
} }
function lockdownMediaTags() { // Watch for media tags and mute them as soon as possible.
webFrame.executeJavaScript(` async function lockdownMediaTags() {
for (const el of document.querySelectorAll('video, audio')) { const lockdown = throttle(() => {
if (el.__sw) { webFrame.executeJavaScript(`
continue for (const el of document.querySelectorAll('video, audio')) {
if (el.__sw) {
continue
}
// Prevent sites from re-muting the video (Periscope, I'm looking at you!)
Object.defineProperty(el, 'muted', { writable: true, value: false })
// Prevent Facebook from pausing the video after page load.
Object.defineProperty(el, 'pause', { writable: false, value: () => {} })
el.__sw = true
} }
// Prevent sites from re-muting the video (Periscope, I'm looking at you!) `)
Object.defineProperty(el, 'muted', { writable: true, value: false }) }, SCAN_THROTTLE)
// Prevent Facebook from pausing the video after page load. await pageReady
Object.defineProperty(el, 'pause', { writable: false, value: () => {} }) const observer = new MutationObserver(lockdown)
el.__sw = true observer.observe(document.body, { subtree: true, childList: true })
}
`)
} }
// Watch for media tags and mute them as soon as possible. function waitForQuery(query) {
function watchMediaTags(kind, onFirstOfKind) { return new Promise(async (resolve) => {
let foundMatch = false const scan = throttle(() => {
const observer = new MutationObserver((mutationList) => { const el = document.querySelector(query)
if (kind) { if (el) {
const el = document.querySelector(kind) resolve(el)
if (el && !foundMatch) { observer.disconnect()
onFirstOfKind(el)
foundMatch = true
} }
} }, SCAN_THROTTLE)
lockdownMediaTags()
}) await pageReady
document.addEventListener('DOMContentLoaded', () => { const observer = new MutationObserver(scan)
observer.observe(document.body, { subtree: true, childList: true }) observer.observe(document.body, { subtree: true, childList: true })
scan()
}) })
} }
async function waitForVideo(kind) { async function waitForVideo(kind) {
const waitForTag = new Promise((resolve) => watchMediaTags(kind, resolve)) lockdownMediaTags()
let video = await Promise.race([waitForTag, sleep(10000)])
let video = await Promise.race([waitForQuery(kind), sleep(10 * 1000)])
if (video) { if (video) {
return { video } return { video }
} }
@@ -145,8 +158,11 @@ const periscopeHacks = {
location.host === 'www.pscp.tv' || location.host === 'www.periscope.tv' location.host === 'www.pscp.tv' || location.host === 'www.periscope.tv'
) )
}, },
onLoad() { async onLoad() {
const playButton = document.querySelector('.PlayButton') const playButton = await Promise.race([
waitForQuery('.PlayButton'),
sleep(1000),
])
if (playButton) { if (playButton) {
playButton.click() playButton.click()
} }
@@ -186,7 +202,7 @@ const periscopeHacks = {
async function findVideo(kind) { async function findVideo(kind) {
if (periscopeHacks.isMatch()) { if (periscopeHacks.isMatch()) {
periscopeHacks.onLoad() await periscopeHacks.onLoad()
} }
const { video, iframe } = await waitForVideo(kind) const { video, iframe } = await waitForVideo(kind)