Last active
June 17, 2023 00:37
-
-
Save langheran/dbfb77fde26f19b31279f828c7f32f6c to your computer and use it in GitHub Desktop.
C:\Users\Nisim Hurst\Utilities\Autohotkey\UserScripts\Speechify.user.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Speechify.user.js | |
// @namespace http://tampermonkey.net/ | |
// @version 0.1 | |
// @description try to take over the world! | |
// @author You | |
// @match https://app.speechify.com/item/* | |
// @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== | |
// @require http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js | |
// @require http://www.phpied.com/files/rgbcolor/rgbcolor.js | |
// @grant GM_addStyle | |
// @grant GM_setClipboard | |
// @grant GM_notification | |
// @grant GM_getValue | |
// @grant GM_setValue | |
// @grant GM_download | |
// ==/UserScript== | |
class AudioState { | |
constructor() { | |
// The AudioContext cannot be instanciated before action of the user. | |
// This is a small lazy trick. | |
var context; | |
this.getContext = function() { | |
if (typeof context === "undefined") | |
{ | |
window.AudioContext = window.AudioContext || window.webkitAudioContext; | |
context = new AudioContext(); | |
} | |
return context; | |
}; | |
this.videoAudioSrc; | |
this.midFilter; | |
this.gainNode; | |
this.bassFilter; | |
this.trebleFilter; | |
} | |
}; | |
function getElementsByText(str, tag = 'a') { | |
return Array.prototype.slice.call(document.getElementsByTagName(tag)).filter(el => el.innerText.trim() === str.trim()); | |
} | |
function sleep(ms) { | |
return new Promise(resolve => setTimeout(resolve, ms)); | |
} | |
function findall(selector) { | |
return document.querySelectorAll(selector); | |
} | |
function waitForElm(selector, isText=false) { | |
return new Promise(resolve => { | |
const elem = document.querySelector(selector); | |
if (elem) { | |
return resolve(elem); | |
} | |
const observer = new MutationObserver(mutations => { | |
const elem = document.querySelector(selector); | |
if (elem) { | |
resolve(elem); | |
observer.disconnect(); | |
} | |
}); | |
observer.observe(document.body, { | |
childList: true, | |
subtree: true | |
}); | |
}); | |
} | |
function waitSelectVoice(count=99999999){ | |
return new Promise(async resolve => { | |
let elem = getElementsByText('Select Voice', 'h3')[0]; | |
while(!elem && count>0){ | |
count--; | |
await sleep(500); | |
elem = getElementsByText('Select Voice', 'h3')[0]; | |
} | |
resolve(elem); | |
}); | |
} | |
function waitForSelectorElm(selector, count=99999999){ | |
return new Promise(async resolve => { | |
let elem = findall(selector)[0]; | |
while(!elem && count>0){ | |
count--; | |
await sleep(500); | |
elem = findall(selector)[0]; | |
} | |
resolve(elem); | |
}); | |
} | |
function waitForTitle(){ | |
return new Promise(async resolve => { | |
let elem = document.title; | |
while(!elem || /.*Listen to text with.*/.test(elem)){ | |
await sleep(500); | |
elem = document.title; | |
} | |
resolve(elem); | |
}); | |
} | |
const mouseClickEvents = ['mousedown', 'click', 'mouseup']; | |
function simulateMouseClick(element){ | |
mouseClickEvents.forEach(mouseEventType => | |
element.dispatchEvent( | |
new MouseEvent(mouseEventType, { | |
view: unsafeWindow, | |
bubbles: true, | |
cancelable: true, | |
buttons: 1 | |
}) | |
) | |
); | |
} | |
function toSeconds(timeStr) { | |
var l = (timeStr.match(/:/g) || []).length | |
if (l < 2){ | |
timeStr = `0:${timeStr}`; | |
} | |
const [hours, minutes, seconds] = timeStr.split(':').map(Number); | |
return hours * 3600 + minutes * 60 + seconds; | |
} | |
(async function() { | |
'use strict'; | |
GM_addStyle(".bg-glass-300 { background-color: black; }"); | |
// debugger; | |
const title = await waitForTitle(); | |
// alert(title); | |
const notificationDetails = { | |
title: title, | |
timeout: 2000 | |
}; | |
var shiftDown = false; | |
var ctrlDown = false; | |
var altDown = false; | |
var playbtn = undefined; | |
var playbtnC = undefined; | |
var isObservingPosition = false; | |
var isLoadingScrollPosition = false; | |
var prevWidth = GM_getValue('prevWidth' + title, false); | |
var prevHeight = GM_getValue('prevHeight' + title, false); | |
if (!prevWidth || prevWidth<630){ | |
unsafeWindow.resizeTo(627,353); | |
unsafeWindow.moveTo(1136,638); | |
unsafeWindow.resizeTo(627,353); | |
}else{ | |
unsafeWindow.resizeTo(1551,879); | |
unsafeWindow.moveTo(1136,638); | |
unsafeWindow.resizeTo(1551,879); | |
} | |
var state = new AudioState(); | |
function doc_keyUp(e) { | |
switch (e.keyCode) { | |
case 16: | |
shiftDown = false; | |
break; | |
case 17: | |
ctrlDown = false; | |
break; | |
case 18: | |
altDown = false; | |
break; | |
default: | |
break; | |
} | |
} | |
function myConfirm(...args){ | |
shiftDown = false; | |
ctrlDown = false; | |
altDown = false; | |
return confirm(...args); | |
} | |
async function doc_keyDown(e) { | |
switch (e.keyCode) { | |
case 16: | |
shiftDown = true; | |
break; | |
case 17: | |
ctrlDown = true; | |
break; | |
case 18: | |
altDown = true; | |
break; | |
case 67: //c | |
GM_setValue('playButton' + title, !GM_getValue('playButton' + title, false)); | |
setPlayButtonVisitbility(); | |
break; | |
case 65: | |
// debugger; | |
autoScroll(); | |
break; | |
case 32: //space | |
e.preventDefault(); | |
if (!playbtn){ | |
ensurePlayBtn(true); | |
await sleep(500); | |
} | |
ensurePlayBtn(true); | |
//if(playbtn) | |
//{ | |
if (document.activeElement!==playbtn){ | |
simulateMouseClick(playbtn); | |
} | |
// playbtn.style.setProperty("display", "none", "important"); | |
//} | |
break; | |
case 90: | |
debugger; | |
break; | |
case 73: //i | |
//set up color properties to iterate through | |
var colorProperties = ['color', 'background-color']; | |
//iterate through every element in reverse order... | |
// debugger; | |
var elems = [ | |
$("iframe").contents().find("*"), | |
$("*") | |
]; | |
for(let es of elems){ | |
es.get().reverse().forEach((obj) => { | |
var color = null; | |
for (var prop in colorProperties) { | |
prop = colorProperties[prop]; | |
//if we can't find this property or it's null, continue | |
console.log(obj); | |
if (!$(obj).css(prop)) continue; | |
console.log('aaa'); | |
//create RGBColor object | |
color = new RGBColor($(obj).css(prop)); | |
if (color.ok) { | |
//good to go, let's build up this RGB baby! | |
//subtract each color component from 255 | |
$(obj).css(prop, 'rgb(' + (255 - color.r) + ', ' + (255 - color.g) + ', ' + (255 - color.b) + ')'); | |
} | |
color = null; //some cleanup | |
} | |
}); | |
} | |
break; | |
case 79: //o | |
var previousPosition = GM_getValue('savedPosition' + title, false); | |
var maxPosition = GM_getValue('maxPosition' + title, false); | |
if (!isObservingPosition || !maxPosition){ | |
observePosition(); | |
await sleep(1000); | |
previousPosition = GM_getValue('savedPosition' + title, false); | |
maxPosition = GM_getValue('maxPosition' + title, false); | |
} | |
if (altDown && isObservingPosition){ | |
if(!previousPosition || myConfirm("Unset previous position @"+previousPosition)){ | |
var pos = document.querySelector("div.min-h-screen.bg-pageBackground > div:nth-child(2) > div > div").scrollTop; | |
GM_setValue('savedPosition' + title, pos); | |
GM_setValue('maxPosition' + title, pos); | |
} | |
} | |
else | |
{ | |
// var forwardbtn = document.querySelector("button.ml-2.flex.h-6.items-center.justify-center.text-glass-500"); | |
// if (previousPosition && forwardbtn){ | |
// while(currentPosition < previousPosition){ | |
// await sleep(500); | |
// simulateMouseClick(forwardbtn); | |
// } | |
// } | |
if (shiftDown){ | |
if (previousPosition){ | |
document.querySelector("div.min-h-screen.bg-pageBackground > div:nth-child(2) > div > div").scrollTo(0,previousPosition); | |
} | |
}else{ | |
if (maxPosition){ | |
document.querySelector("div.min-h-screen.bg-pageBackground > div:nth-child(2) > div > div").scrollTo(0,maxPosition); | |
} | |
} | |
} | |
autoScroll(); | |
break; | |
case 85: //u | |
navigator.clipboard.writeText( | |
window.location.href | |
) | |
alert('Copied!'); | |
break; | |
// case 65: | |
// setVolume(1); | |
// break; | |
// case 66: | |
// setVolume(0.3); | |
// break; | |
default: | |
break; | |
} | |
} | |
document.addEventListener('keyup', doc_keyUp, false); | |
document.addEventListener('keydown', doc_keyDown, false); | |
let hideElements = []; | |
//const elem = await waitSelectVoice(); | |
// // elem.parentElement.parentElement.parentElement.removeChild(elem.parentElement.parentElement); | |
// hideElements.push(elem.parentElement.parentElement); | |
// hideElements.forEach(item => { | |
// item.style.setProperty("display", "none", "important"); | |
// }); | |
// // debugger; | |
async function autoScroll(){ | |
var settings = document.querySelector("div.fixed.bottom-9.right-5.z-2000.cursor-pointer > div > div") | |
if (settings){ | |
simulateMouseClick(settings); | |
} | |
var autoscroll = document.querySelector("#toggleAutoscroll"); | |
if (autoscroll){ | |
if(autoscroll.checked){ | |
simulateMouseClick(autoscroll); | |
} | |
simulateMouseClick(autoscroll); | |
} | |
if (settings){ | |
simulateMouseClick(settings); | |
} | |
} | |
async function ensurePlayBtn(force=false){ | |
if (!playbtn || force){ | |
try{ | |
// const playbtn=await waitForSelectorElm('*[aria-label^="Pause"]') | |
// .catch(error=>{ | |
// console.error(error); | |
// }); | |
playbtn=await Promise.race([waitForSelectorElm('button.css-1wqny6f', 2), waitForSelectorElm('button.css-1rrad81', 2)]); | |
// debugger; | |
}catch(err){console.log(err)} | |
} | |
} | |
async function ensurePlaying(){ | |
if(!playbtn){ | |
return; | |
} | |
try{ | |
// await Promise.race([waitForHTML(playbtn, '<svg width="14" height="15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1.548 15c.337 0 .623-.135.96-.328l9.808-5.67c.698-.412.942-.681.942-1.127 0-.446-.244-.715-.942-1.12L2.507 1.078c-.336-.193-.622-.32-.959-.32-.622 0-1.01.472-1.01 1.204v11.828C.539 14.52.927 15 1.549 15z" fill="currentColor"></path></svg>')]); | |
var html = '<svg width="12" height="16"'; | |
var count = 999999; | |
await new Promise(async resolve => { | |
if (!playbtn){ | |
resolve(false); | |
} | |
// debugger; | |
while(!playbtn.innerHTML.startsWith(html) && count>0){ | |
await ensurePlayBtn(true); | |
count--; | |
await sleep(1000); | |
// console.log(playbtn.innerHTML); | |
// console.log(html); | |
// console.log(playbtn.innerHTML.startsWith(html)); | |
} | |
// debugger; | |
resolve(true); | |
}); | |
}catch(err){console.log(err)} | |
} | |
async function setPlayButtonVisitbility(){ | |
let playbtnVisible = GM_getValue('playButton' + title, false); | |
await ensurePlayBtn(true); | |
if(playbtn) | |
{ | |
try{ | |
let container = playbtn.parentElement.parentElement.parentElement.parentElement; | |
// debugger; | |
if (container.className == 'container flex h-full items-center justify-center'){ | |
// debugger; | |
container = container.parentElement; | |
} | |
unsafeWindow.localStorage.setItem('autoscroll', true); | |
setTimeout( | |
()=>{window.dispatchEvent(new Event('resize'));}, | |
500 | |
); | |
if (playbtnVisible) | |
{ | |
container.style.setProperty("display", "block", "important"); | |
document.querySelector("header").style.setProperty('display', 'block', 'important'); | |
} | |
else | |
{ | |
container.style.setProperty("display", "none", "important"); | |
document.querySelector("header").style.setProperty('display', 'none', 'important') | |
} | |
}catch(e){} | |
var container; | |
try{ | |
container=await waitForSelectorElm('.font-ABCDiatype>div>div>button'); | |
container = container.parentElement.parentElement.parentElement; | |
if (playbtnVisible) | |
{ | |
container.style.setProperty("display", "block", "important"); | |
} | |
else | |
{ | |
container.style.setProperty("display", "none", "important"); | |
} | |
}catch(e){} | |
try{ | |
container=await waitForSelectorElm('.PSPDFKit-Container'); | |
container = container.parentElement; | |
if (playbtnVisible) | |
{ | |
//container.style.setProperty("padding-left", "66px", "important"); | |
} | |
else | |
{ | |
//container.style.setProperty("padding-left", "0px", "important"); | |
} | |
}catch(e){} | |
try{ | |
findall('*[aria-label^="Open Intercom Messenger"]').forEach(function(item) { | |
item.style.setProperty("display", "none", "important"); | |
}); | |
}catch(e){} | |
} | |
} | |
setPlayButtonVisitbility(); | |
setVolume(); | |
const container0=await waitForSelectorElm('.bg-glass-200'); | |
// const container=await waitForSelectorElm('.bg-glass-300>div:first-child'); | |
// debugger; | |
// console.log(container); | |
// container.style.setProperty("height", "100%", "important"); | |
// container.style.setProperty("top", "0px", "important"); | |
// navigator.mediaDevices | |
// .selectAudioOutput() | |
// .then((device) => { | |
// console.log(`${device.kind}: ${device.label} id = ${device.deviceId}`); | |
// }); | |
async function observePosition(){ | |
if(isObservingPosition){ | |
return; | |
} | |
var selector = "div.mt-1.flex.w-full.justify-between.pl-2.pr-2.text-glass-500 > span:nth-child(1)"; | |
await waitForElm(selector); | |
// debugger; | |
await ensurePlayBtn(true); | |
// debugger; | |
await ensurePlaying(); | |
// debugger; | |
const observer = new MutationObserver(mutations => { | |
const elem = document.querySelector(selector); | |
if (elem) { | |
// resolve(elem); | |
// observer.disconnect(); | |
// GM_setValue('playPosition' + title, toSeconds(elem.innerText)); | |
// debugger; | |
// currentPosition = toSeconds(elem.innerText); | |
var pos = document.querySelector("div.min-h-screen.bg-pageBackground > div:nth-child(2) > div > div").scrollTop; | |
isObservingPosition = true; | |
GM_setValue('playPosition' + title, pos); | |
var maxPos = GM_getValue('maxPosition' + title, 0); | |
if (maxPos <= pos){ | |
GM_setValue('maxPosition' + title, pos); | |
} | |
} | |
}); | |
observer.observe(document.body, { | |
childList: true, | |
subtree: true | |
}); | |
} | |
sleep(100).then(async () => { | |
await ensurePlaying(); | |
await sleep(1000); | |
if (isLoadingScrollPosition){ | |
document.querySelector("div.min-h-screen.bg-pageBackground > div:nth-child(2) > div > div").scrollTo(0,GM_getValue('playPosition' + title, 0)); | |
document.querySelector("div.min-h-screen.bg-pageBackground > div:nth-child(2) > div > div").scrollTo(0,GM_getValue('playPosition' + title, 0)); | |
} | |
var x = unsafeWindow.innerWidth / 2; | |
var y = unsafeWindow.innerHeight / 2; | |
sleep(2000).then(async () => { | |
var reg = new RegExp("[\w]+","g"); | |
var elem = document.elementFromPoint(x, y); | |
// debugger; | |
// simulateMouseClick(elem); | |
// try{ | |
// $($(elem).parents().get().find(itm => $(itm).find("span").length))[0].click(); | |
// }catch(e){} | |
// try{ | |
// simulateMouseClick($($(elem).parents().get().find(itm => $(itm).find("span").length))[0]); | |
// }catch(e){} | |
while(elem && $(elem).parent()[0] && !$(elem).find('*[class^="SentencePlayer"]')[0]){ | |
elem = $(elem).parent()[0]; | |
} | |
elem = $(elem).find('*[class^="SentencePlayer"]')[0]; | |
try{ | |
elem.click(); | |
}catch(e){} | |
try{ | |
if (isLoadingScrollPosition){ | |
simulateMouseClick(elem); | |
} | |
}catch(e){} | |
setPlayButtonVisitbility(); | |
await sleep(500); | |
setPlayButtonVisitbility(); | |
await sleep(500); | |
setPlayButtonVisitbility(); | |
observePosition(); | |
}); | |
}); | |
function setVolume() { | |
var videoVolume = GM_getValue('volume' + title, 0.1); | |
if (videoVolume) | |
{ | |
window.postMessage({ type: "VOLUME", volume: videoVolume }, "*"); | |
} | |
// detect available wheel event | |
var support = "onwheel" in document.createElement("div") ? "wheel" : // Modern browsers support "wheel" | |
document.onmousewheel !== undefined ? "mousewheel" : // Webkit and IE support at least "mousewheel" | |
"DOMMouseScroll"; // let"s assume that remaining browsers are older Firefox | |
document.addEventListener(support, function (event) { | |
if (!altDown){ | |
return; | |
} | |
event.preventDefault(); | |
var volume = GM_getValue('volume' + title, 0.1); | |
var volumeDelta = 2; | |
var deltaY = support == "mousewheel" ? event.wheelDelta : (event.deltaY || event.detail); | |
// Optimize volume change for touchpad | |
if (Math.abs(deltaY) < 2) { | |
volumeDelta = Math.max(Math.floor(Math.abs(deltaY)), 1)/100; | |
} | |
volume += (deltaY > 0 ? -volumeDelta : volumeDelta)/100; | |
// Limit the volume between 0 and 100 | |
volume = Math.max(0, Math.min(1, volume)); | |
window.postMessage({ type: "VOLUME", volume: volume }, "*"); | |
GM_setValue('volume' + title, volume); | |
videoVolume = GM_getValue('volume' + title, 0.1); | |
// Prevent the page to scroll | |
event.preventDefault(); | |
event.stopImmediatePropagation(); | |
return false; | |
}, { passive: false }); | |
} | |
unsafeWindow.addEventListener("resize", e => { | |
sleep(500).then(async () => { | |
const elem = await waitSelectVoice(4); | |
if (elem){ | |
elem.parentElement.parentElement.style.setProperty("display", "none", "important"); | |
} | |
var newWidth = window.innerWidth; | |
if (Math.abs(prevWidth-newWidth)>100) | |
{ | |
prevWidth = newWidth; | |
GM_setValue('prevWidth' + title, prevWidth); | |
} | |
GM_setValue('prevHeight' + title, window.innerHeight); | |
}); | |
}); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment