Last active
September 26, 2023 04:00
-
-
Save UUoocl/5c82968370559141be5ff3db5fa19486 to your computer and use it in GitHub Desktop.
Play Google Slides transparently and connect to OBS with webSockets
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
const { contextBridge, ipcRenderer } = require('electron'); | |
const cameraID = ipcRenderer.sendSync('camera-ID'); | |
window.addEventListener('DOMContentLoaded', () => { | |
//console.log("cameraID ", cameraID ) | |
const dataElement = document.createElement(`data`); | |
dataElement.setAttribute("id", "cameraID"); | |
dataElement.setAttribute("data-camera-Id", cameraID); | |
window.document.body.insertBefore(dataElement, window.document.body.firstChild); | |
//window.document.body.append(dataElem); | |
const video = document.querySelector("video"); | |
console.log("cameraID ", cameraID ) | |
const constraints = { | |
audio: false, | |
video: { | |
deviceId: `${cameraID}`, | |
aspectRatio: 1.7777777778, | |
}, | |
}; | |
navigator.mediaDevices | |
.getUserMedia(constraints) | |
.then((stream) => { | |
const videoTracks = stream.getVideoTracks(); | |
console.log("Got stream with constraints:", constraints); | |
console.log(`Using video device: ${videoTracks[0].label}`); | |
stream.onremovetrack = () => { | |
console.log("Stream ended"); | |
}; | |
video.srcObject = stream; | |
video.play(); | |
}) | |
.catch((error) => { | |
if (error.name === "OverconstrainedError") { | |
console.error( | |
`The resolution ${constraints.video.width.exact}x${constraints.video.height.exact} px is not supported by your device.`, | |
); | |
} else if (error.name === "NotAllowedError") { | |
console.error( | |
"You need to grant this page permission to access your camera and microphone.", | |
); | |
} else { | |
console.error(`getUserMedia error: ${error.name}`, error); | |
} | |
}); | |
}) |
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
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="UTF-8"> | |
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --> | |
<title>Camera</title> | |
</head> | |
<body style ="overflow: hidden; padding: 0; margin: 0;"> | |
<video style="width: 100%; height: 100%;"></video> | |
</body> | |
</html> |
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
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="UTF-8"> | |
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --> | |
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'"> | |
<title>Transparent Google Slides Player</title> | |
</head> | |
<body> | |
<h3><label for="Link">Enter a Published Google Slide Link:</label></h3> | |
<input type="text" id="Link" name="Link" size=150 value="https://docs.google.com/presentation/d/e/2PACX-1vRVpsaZJbgTiremeDpWaIW3M2gt0rmSj4bf_ymuH5panELG2cZcL1dwwaKhA6jNjIMozaUBBx1sZ5gQ/pub?start=false&loop=false&delayms=3000"/><br><br> | |
<h4>Connect to OBS WebSocket Server? (optional)</h4> | |
<label for="IP">Enter IP address or "localhost":</label> | |
<input type="text" id="IP" name="IP" value="localhost"/><br> | |
<label for="Port">Enter Port Number:</label> | |
<input type="text" id="Port" name="Port" value="4455"/><br> | |
<label for="PW">Enter Password:</label> | |
<input type="text" id="PW" name="PW" value="YourPasswordGoesHere"/><br> | |
<h4><input type="checkbox" id="cameraWindow" name="cameraWindow" value=> | |
<label for="cameraWindow">Open Camera Window</label></h4> | |
<label for="installedCameras">Choose a camera:</label> | |
<select name="cameras" id="cameras"> | |
<option value="">--Please choose a camera--</option></select> | |
<br><br> | |
<h4><input type="checkbox" id="poseWindow" name="poseWindow" value=> | |
<label for="poseWindow">Open Pose Detection Window</label></h4> | |
<br><br> | |
<input type="button" id="SubmitButton" value="submit"/> | |
<script src="./renderer.js"></script> | |
</body> | |
</html> |
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
/* Transparent Google Slides player | |
2023 by uuoocl🪵 | |
MIT license | |
An app to play Google Slides with a tranparent background | |
*/ | |
// Modules to control application life and create native browser window | |
const { app, BrowserWindow, ipcMain} = require('electron') | |
const path = require('path') | |
let slidesWindow; | |
var websocketIP, websocketPort, websocketPassword, winCamera; | |
async function createWindow () { | |
// Create the browser window. | |
const mainWindow = new BrowserWindow({ | |
width: 1280, | |
height: 720, | |
title: __dirname, | |
webPreferences: { | |
preload: path.join(__dirname, 'preload.js') | |
} | |
}) | |
ipcMain.on('wsConnect-IP', (event) => { | |
console.log("sending websocket details to new window") | |
event.returnValue = websocketIP | |
}) | |
ipcMain.on('wsConnect-Port', (event) => { | |
console.log("sending websocket details to new window") | |
event.returnValue = websocketPort | |
}) | |
ipcMain.on('wsConnect-PW', (event) => { | |
console.log("sending websocket details to new window") | |
speakerViewWindow = event.sender; | |
event.returnValue = websocketPassword | |
}) | |
ipcMain.on('camera-ID', (event) => { | |
console.log("sending camera ID to camera window") | |
event.returnValue = winCamera; | |
}) | |
ipcMain.on('change-slide', (event, Direction) => { | |
if(Direction == "Next"){ | |
console.log("sending next slide message to slide window") | |
slidesWindow.webContents.send('next-slide'); | |
}else{ | |
console.log("sending previous slide message to slide window") | |
slidesWindow.webContents.send('previous-slide'); | |
} | |
}) | |
ipcMain.on('open-slide-window', (event, IP, Port, PW, Link) => { | |
slidesWindow = new BrowserWindow({ | |
width: 1919, | |
height: 1079, | |
frame: false, | |
movable: false, | |
titleBarOverlay: false, | |
backgroundThrottling: false, | |
transparent: true, | |
titleBarStyle: 'customButtonsOnHover', | |
webPreferences: { | |
preload: path.join(__dirname, 'slides-preload.js') | |
} | |
}) | |
websocketIP = IP; | |
websocketPort = Port; | |
websocketPassword = PW; | |
mainLink = Link; | |
slidesWindow.loadURL(Link); | |
//slidesWindow.webContents.openDevTools() | |
slidesWindow.webContents.setWindowOpenHandler(({ event,url }) => { | |
console.log(event) | |
if (true) { | |
return { | |
action: 'allow', | |
backgroundThrottling: false, | |
overrideBrowserWindowOptions: { | |
frame: true, | |
fullscreenable: false, | |
backgroundColor: 'white', | |
webPreferences: { | |
preload: path.join(__dirname,'slides-popup-preload.js') | |
} | |
} | |
} | |
} | |
return { action: 'deny' } | |
}) | |
console.log("sending appPath to new window") | |
}) | |
ipcMain.on('open-camera-window', (event, cameraId) => { | |
console.log(`camera ID = ${cameraId}`) | |
cameraWindow = new BrowserWindow({ | |
width: 1920, | |
height: 1080, | |
frame: false, | |
titleBarOverlay: false, | |
backgroundThrottling: false, | |
transparent: true, | |
titleBarStyle: 'customButtonsOnHover', | |
webPreferences: { | |
preload: path.join(__dirname, 'camera-preload.js') | |
} | |
}) | |
winCamera = cameraId; | |
cameraWindow.loadFile('camera.html'); | |
}) | |
ipcMain.on('open-pose-window', (event) => { | |
poseWindow = new BrowserWindow({ | |
width: 650, | |
height: 460, | |
x: 0, | |
y: 0, | |
frame: true, | |
titleBarOverlay: false, | |
backgroundThrottling: false, | |
transparent: true, | |
titleBarStyle: 'customButtonsOnHover', | |
webPreferences: { | |
preload: path.join(__dirname, 'pose-preload.js') | |
} | |
}) | |
poseWindow.loadFile('pose.html'); | |
}) | |
// and load the index.html of the app. | |
mainWindow.loadFile('index.html') | |
// Open the DevTools. | |
// mainWindow.webContents.openDevTools() | |
} | |
// This method will be called when Electron has finished | |
// initialization and is ready to create browser windows. | |
// Some APIs can only be used after this event occurs. | |
app.whenReady().then(() => { | |
createWindow() | |
app.on('activate', function () { | |
// On macOS it's common to re-create a window in the app when the | |
// dock icon is clicked and there are no other windows open. | |
if (BrowserWindow.getAllWindows().length === 0) createWindow() | |
}) | |
}) | |
// Quit when all windows are closed, except on macOS. There, it's common | |
// for applications and their menu bar to stay active until the user quits | |
// explicitly with Cmd + Q. | |
app.on('window-all-closed', function () { | |
if (process.platform !== 'darwin') app.quit() | |
}) |
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
{ | |
"name": "Transparent-Google-Slides-player", | |
"productName": "Transparent-Google-Slides-player", | |
"description": "An app to play Google Slides with a transparent background", | |
"keywords": [], | |
"main": "./main.js", | |
"version": "0.0.4", | |
"author": "UUoocl", | |
"scripts": { | |
"start": "electron ." | |
}, | |
"dependencies": {}, | |
"devDependencies": { | |
"electron": "26.0.0" | |
} | |
} |
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
const { contextBridge, ipcRenderer } = require('electron') | |
contextBridge.exposeInMainWorld('electronAPI', { | |
changeSlide: (Direction) => ipcRenderer.send('change-slide', Direction) | |
}) |
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
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="UTF-8"> | |
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP --> | |
<link href="./style.css" rel="stylesheet"> | |
<!-- <script src="https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision/vision_bundle.js" | |
crossorigin="anonymous"></script> --> | |
<title>MediaPipe Pose</title> | |
</head> | |
<body> | |
<body> | |
<section id="demos" class="invisible"> | |
<div class="detectOnClick"> | |
<div id="liveView" class="videoView"> | |
<button id="webcamButton" class="mdc-button mdc-button--raised"> | |
<span class="mdc-button__ripple"></span> | |
<span class="mdc-button__label">ENABLE WEBCAM</span> | |
</button> | |
<div style="position: relative;"> | |
<video id="webcam" style="width: 1280px; height: 720px; position: abso" autoplay playsinline></video> | |
<canvas class="output_canvas" id="output_canvas" width="1280" height="720" style="position: absolute; left: 0px; top: 0px;"></canvas> | |
</div> | |
</div> | |
</section> | |
<!-- You can also require other files to run in this process --> | |
<!-- <script src="./node_modules/@mediapipe/tasks-vision/vision_bundle.js" type="module"></script> --> | |
<script type="module"> | |
import { PoseLandmarker, FilesetResolver, DrawingUtils } from "https://cdn.skypack.dev/@mediapipe/tasks-vision@0.10.0"; | |
const demosSection = document.getElementById("demos"); | |
let poseLandmarker = undefined; | |
let runningMode = "IMAGE"; | |
let enableWebcamButton; | |
let webcamRunning = false; | |
const videoHeight = "360px"; | |
const videoWidth = "640px"; | |
var nextControl = "off"; | |
var previousControl = "off"; | |
// Before we can use PoseLandmarker class we must wait for it to finish | |
// loading. Machine Learning models can be large and take a moment to | |
// get everything needed to run. | |
const createPoseLandmarker = async () => { | |
const vision = await FilesetResolver.forVisionTasks("https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.0/wasm"); | |
poseLandmarker = await PoseLandmarker.createFromOptions(vision, { | |
baseOptions: { | |
modelAssetPath: `https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task`, | |
delegate: "GPU" | |
}, | |
runningMode: runningMode, | |
numPoses: 1 | |
}); | |
demosSection.classList.remove("invisible"); | |
}; | |
createPoseLandmarker(); | |
/******************************************************************** | |
// Demo 2: Continuously grab image from webcam stream and detect it. | |
********************************************************************/ | |
const video = document.getElementById("webcam"); | |
const canvasElement = document.getElementById("output_canvas"); | |
const canvasCtx = canvasElement.getContext("2d"); | |
const drawingUtils = new DrawingUtils(canvasCtx); | |
// Check if webcam access is supported. | |
const hasGetUserMedia = () => { var _a; return !!((_a = navigator.mediaDevices) === null || _a === void 0 ? void 0 : _a.getUserMedia); }; | |
// If webcam supported, add event listener to button for when user | |
// wants to activate it. | |
if (hasGetUserMedia()) { | |
enableWebcamButton = document.getElementById("webcamButton"); | |
enableWebcamButton.addEventListener("click", enableCam); | |
} | |
else { | |
console.warn("getUserMedia() is not supported by your browser"); | |
} | |
// Enable the live webcam view and start detection. | |
function enableCam(event) { | |
if (!poseLandmarker) { | |
console.log("Wait! poseLandmaker not loaded yet."); | |
return; | |
} | |
if (webcamRunning === true) { | |
webcamRunning = false; | |
enableWebcamButton.innerText = "ENABLE PREDICTIONS"; | |
} | |
else { | |
webcamRunning = true; | |
enableWebcamButton.innerText = "DISABLE PREDICTIONS"; | |
} | |
// getUsermedia parameters. | |
const constraints = { | |
video: true | |
}; | |
// Activate the webcam stream. | |
navigator.mediaDevices.getUserMedia(constraints).then((stream) => { | |
video.srcObject = stream; | |
video.addEventListener("loadeddata", predictWebcam); | |
}); | |
} | |
let lastVideoTime = -1; | |
async function predictWebcam() { | |
canvasElement.style.height = videoHeight; | |
video.style.height = videoHeight; | |
canvasElement.style.width = videoWidth; | |
video.style.width = videoWidth; | |
// Now let's start detecting the stream. | |
if (runningMode === "IMAGE") { | |
runningMode = "VIDEO"; | |
await poseLandmarker.setOptions({ runningMode: "VIDEO" }); | |
} | |
let startTimeMs = performance.now(); | |
if (lastVideoTime !== video.currentTime) { | |
lastVideoTime = video.currentTime; | |
poseLandmarker.detectForVideo(video, startTimeMs, (result) => { | |
canvasCtx.save(); | |
canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height); | |
for (const landmark of result.landmarks) { | |
if(landmark[16].y<landmark[0].y && nextControl == "off" && previousControl == "off"){ | |
window.electronAPI.changeSlide("Next"); | |
nextControl = "on"; | |
console.log(landmark[16].y," Right ", nextControl) | |
} | |
if(landmark[15].y<landmark[0].y && nextControl == "off" && previousControl == "off"){ | |
window.electronAPI.changeSlide("Previous"); | |
previousControl = "on"; | |
console.log(landmark[15].y," Left ", previousControl) | |
} | |
if(landmark[15].y > landmark[0].y){ | |
previousControl = "off"; | |
} | |
if(landmark[16].y > landmark[0].y){ | |
nextControl = "off"; | |
} | |
drawingUtils.drawLandmarks(landmark, { | |
radius: (data) => DrawingUtils.lerp(data.from.z, -0.15, 0.1, 5, 1) | |
}); | |
drawingUtils.drawConnectors(landmark, PoseLandmarker.POSE_CONNECTIONS); | |
} | |
canvasCtx.restore(); | |
}); | |
} | |
// Call this function again to keep predicting when the browser is ready. | |
if (webcamRunning === true) { | |
window.requestAnimationFrame(predictWebcam); | |
} | |
} | |
</script> | |
</body> | |
</html> |
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
const { contextBridge, ipcRenderer } = require('electron') | |
var windowId; | |
contextBridge.exposeInMainWorld('electronAPI', { | |
slideWindow: (IP, Port, PW, Link) => ipcRenderer.send('open-slide-window', IP, Port, PW, Link), | |
cameraWindow: (CameraID) => ipcRenderer.send('open-camera-window', CameraID), | |
poseWindow: () => ipcRenderer.send('open-pose-window'), | |
getCameraId: () => ipcRenderer.send('get-cameras') | |
}) | |
ipcRenderer.on('SET_CAMERA_SOURCE', async (event, deviceName, deviceID) => { | |
console.log(deviceID) | |
var x = document.getElementById("cameras"); | |
var option = document.createElement("option"); | |
option.text = deviceName; | |
option.id = deviceID; | |
x.add(option); | |
window.document.body.insertBefore(windowId, window.document.body.firstChild); | |
}) |
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
const button = document.getElementById('SubmitButton'); | |
window.addEventListener('DOMContentLoaded', async() => { | |
getCameras(); | |
}) | |
function getCameras(){ | |
console.log("list of cameras") | |
navigator.mediaDevices | |
.enumerateDevices() | |
.then((devices) => { | |
devices.forEach((device) => { | |
if(device.kind == "videoinput"){ | |
console.log(device) | |
console.log(`${device.kind}: ${device.label} id = ${device.deviceId}`); | |
var x = document.getElementById("cameras"); | |
var option = document.createElement("option"); | |
option.text = device.label; | |
option.id = device.deviceId; | |
x.add(option); | |
} | |
}); | |
}) | |
} | |
button.addEventListener("click", newWindow); | |
function newWindow() { | |
const IP = document.getElementById('IP').value; | |
const Port = document.getElementById('Port').value; | |
const PW = document.getElementById('PW').value; | |
const Link = document.getElementById('Link').value; | |
const OpenCamera = document.getElementById('cameraWindow'); | |
console.log("OpenCamera",OpenCamera.checked) | |
const OpenPose = document.getElementById('poseWindow'); | |
console.log("OpenPose", OpenPose.checked) | |
var e = document.getElementById("cameras"); | |
console.log(e.value) | |
console.log(e.options[e.selectedIndex].text) | |
var value = e.value; | |
var CameraID = e.options[e.selectedIndex].id; | |
console.log(`${IP}, ${Port}, ${PW}, ${Link}, ${CameraID}`); | |
if(OpenCamera.checked){ | |
window.electronAPI.cameraWindow(CameraID); | |
} | |
window.electronAPI.slideWindow(IP, Port, PW, Link); | |
if(OpenPose.checked){ | |
window.electronAPI.poseWindow(); | |
} | |
} |
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
const {ipcRenderer } = require('electron'); | |
const websocketIP = ipcRenderer.sendSync('wsConnect-IP'); | |
const websocketPort = ipcRenderer.sendSync('wsConnect-Port'); | |
const websocketPassword = ipcRenderer.sendSync('wsConnect-PW'); | |
var obs; | |
var sceneInNotes, advSSmessage, notesScrollSpeed = 2, scaleAmount = 1, scrollPlay = true, resumeScrollSpeed, widthAmount; | |
window.addEventListener('DOMContentLoaded', () => { | |
if (window.trustedTypes && window.trustedTypes.createPolicy) { | |
window.trustedTypes.createPolicy('default', { | |
createHTML: (string) => string, | |
createScriptURL: string => string, // warning: this is unsafe! | |
createScript: string => string // warning: this is unsafe! | |
}); | |
} | |
setTimeout(obsConnect, 2000); | |
setTimeout(setup, 200); | |
}) | |
function setup() { | |
const slowScroll = document.createElement('div'); | |
slowScroll.setAttribute("id","ScrollSlowButton"); | |
slowScroll.innerText = "⏪"; | |
slowScroll.setAttribute("role", "button"); | |
slowScroll.setAttribute("class", "goog-inline-block jfk-button jfk-button-standard jfk-button-narrow jfk-button-collapse-right"); | |
slowScroll.setAttribute("tabindex", "0"); | |
slowScroll.setAttribute("title", "scroll slower"); | |
slowScroll.setAttribute("value", "undefined"); | |
slowScroll.setAttribute("style", "user-select: none;font-size: 20px"); | |
const fastScroll = document.createElement('div'); | |
fastScroll.setAttribute("id","ScrollfastButton"); | |
fastScroll.innerText = "⏩"; | |
fastScroll.setAttribute("role", "button"); | |
fastScroll.setAttribute("class", "goog-inline-block jfk-button jfk-button-standard jfk-button-narrow jfk-button-collapse-left"); | |
fastScroll.setAttribute("tabindex", "0"); | |
fastScroll.setAttribute("title", "scroll slower"); | |
fastScroll.setAttribute("value", "undefined"); | |
fastScroll.setAttribute("style", "user-select: none;font-size: 20px"); | |
const pauseScroll = document.createElement('div'); | |
pauseScroll.setAttribute("id","pauseButton"); | |
pauseScroll.innerText = "⏸️"; | |
pauseScroll.setAttribute("role", "button"); | |
pauseScroll.setAttribute("class", "goog-inline-block jfk-button jfk-button-standard jfk-button-narrow jfk-button-collapse-right"); | |
pauseScroll.setAttribute("tabindex", "0"); | |
pauseScroll.setAttribute("title", "scroll slower"); | |
pauseScroll.setAttribute("value", "undefined"); | |
pauseScroll.setAttribute("style", "user-select: none;font-size: 20px"); | |
//window.document.body.div[0].append(div); | |
window.document.querySelector('div[class="punch-viewer-speakernotes-zoom-container"]').append(slowScroll); | |
window.document.querySelector('div[class="punch-viewer-speakernotes-zoom-container"]').append(pauseScroll); | |
window.document.querySelector('div[class="punch-viewer-speakernotes-zoom-container"]').append(fastScroll); | |
const pauseButton = document.getElementById('pauseButton'); | |
const fastButton = document.getElementById('ScrollfastButton'); | |
const slowButton = document.getElementById('ScrollSlowButton'); | |
pauseButton.addEventListener("click",scrollPause); | |
fastButton.addEventListener("click",scrollFaster); | |
slowButton.addEventListener("click",scrollSlower); | |
window.addEventListener("keydown", (event) => { | |
console.log(event.code) | |
switch (event.code) { | |
case "F8": | |
scrollSlower(); | |
break; | |
case "F9": | |
scrollPause() | |
break; | |
case "F10": | |
scrollFaster() | |
break; | |
case "Equal": | |
notesZoomIn(); | |
break; | |
case "Minus": | |
notesZoomOut(); | |
break; | |
} | |
}) | |
} | |
function obsConnect(){ | |
obs = new OBSWebSocket(); | |
console.log("obs connect") | |
const { obsWebSocketVersion, | |
negotiatedRpcVersion | |
} = obs.connect(`ws://${websocketIP}:${websocketPort}`, websocketPassword, { | |
rpcVersion: 1 | |
}); | |
console.log(`Connected to server ${obsWebSocketVersion} (using RPC ${negotiatedRpcVersion})`) | |
listenforOBSchange(); | |
setInterval(noteInspection, 500); | |
setInterval(notesScroll, 50); | |
} | |
function listenforOBSchange(){ | |
console.log("turn on OBS listeners") | |
obs.on('CurrentProgramSceneChanged', function(event) { | |
console.log("I got it too") | |
//let SceneName = event.sceneName; | |
console.log(event) | |
}) | |
obs.on('VendorEvent', function(event) { | |
console.log("WS Request received") | |
console.log(event) | |
let elem; | |
switch (event.eventData.message) { | |
case "Next": | |
nextSlide(); | |
/* console.log("Right event") | |
elem = document.querySelectorAll('div[class="punch-viewer-speakernotes-page-next"]')[0] | |
elem.click(); */ | |
/* window.focus() | |
keySim("39"); | |
//setTimeout(keySim("78"),1000); | |
window.opener.focus(); */ | |
break; | |
case "Previous": | |
previousSlide(); | |
/* console.log("Left event") | |
elem = document.querySelectorAll('div[class="punch-viewer-speakernotes-page-previous"]')[0] | |
elem.click(); | |
*/ | |
//setTimeout(keySim("78"),1000); | |
//window.opener.focus(); | |
break; | |
case "Notes Zoom In": | |
console.log("Notes Zoom In") | |
notesZoomIn; | |
break; | |
case "Notes Zoom Out": | |
console.log("Notes Zoom Out") | |
notesZoomOut; | |
break; | |
case "Notes Scroll Faster": | |
console.log("Notes Scroll Faster") | |
scrollFaster; | |
break; | |
case "Notes-Scroll-Slower": | |
console.log("Notes Scroll Slower") | |
scrollSlower; | |
break; | |
} | |
}) | |
} | |
function nextSlide(){ | |
console.log("Right event") | |
elem = document.querySelectorAll('div[class="punch-viewer-speakernotes-page-next"]')[0] | |
elem.click(); | |
} | |
function previousSlide(){ | |
console.log("Left event") | |
elem = document.querySelectorAll('div[class="punch-viewer-speakernotes-page-previous"]')[0] | |
elem.click(); | |
} | |
function notesZoomIn(){ | |
elem = document.querySelectorAll('div[class="punch-viewer-speakernotes-text-body-zoomable"]')[0]; | |
scaleAmount = scaleAmount + .15; | |
widthAmount = 100000/(1000*scaleAmount); | |
elem.style.width = `${widthAmount}%`; | |
elem.style.transform = `scale(${scaleAmount})`; | |
} | |
function notesZoomOut(){ | |
elem = document.querySelectorAll('div[class="punch-viewer-speakernotes-text-body-zoomable"]')[0] | |
scaleAmount = scaleAmount - .15; | |
widthAmount = 100000/(1000*scaleAmount); | |
elem.style.width = `${widthAmount}%`; | |
elem.style.transform = `scale(${scaleAmount})`; | |
} | |
function scrollFaster(){ | |
if(scrollPlay == false){ | |
notesScrollSpeed = Math.abs(resumeScrollSpeed) -.5; | |
} | |
scrollPlay = true; | |
notesScrollSpeed = notesScrollSpeed + .5; | |
} | |
function scrollSlower(){ | |
if(scrollPlay == false){ | |
notesScrollSpeed = (Math.abs(resumeScrollSpeed)*-1) + 1; | |
} | |
scrollPlay = true; | |
notesScrollSpeed = notesScrollSpeed - 1; | |
} | |
function scrollPause(){ | |
console.log("Paused") | |
if(scrollPlay == true){ | |
scrollPlay = false; | |
resumeScrollSpeed = notesScrollSpeed; | |
notesScrollSpeed = 0; | |
}else{ | |
scrollPlay = true; | |
notesScrollSpeed = resumeScrollSpeed; | |
} | |
} | |
function noteInspection() { | |
const elem = document.querySelectorAll('div[class="punch-viewer-speakernotes-text-body-zoomable"]')[0]; | |
if(elem){ | |
//get Scene name | |
if(elem.textContent.includes('{{')){ | |
var start_pos = elem.textContent.indexOf('{{') + 2; | |
var end_pos = elem.textContent.indexOf('}}',start_pos); | |
var scene_to_set = elem.textContent.substring(start_pos,end_pos); | |
console.log(scene_to_set); | |
if(scene_to_set != sceneInNotes ){ | |
sceneInNotes = scene_to_set; | |
obs.call('SetCurrentProgramScene', {sceneName: sceneInNotes}); | |
} | |
} | |
//Get message to send to Advanced Scene Switcher | |
if(elem.textContent.includes('||')){ | |
start_pos = elem.textContent.indexOf('||') + 2; | |
end_pos = elem.textContent.indexOf('||',start_pos); | |
var message_to_send = elem.textContent.substring(start_pos,end_pos) | |
console.log(message_to_send); | |
if(message_to_send != advSSmessage ){ | |
advSSmessage = message_to_send; | |
obs.call("CallVendorRequest", {vendorName:"AdvancedSceneSwitcher",requestType:"AdvancedSceneSwitcherMessage",requestData:{message:advSSmessage}}); | |
console.log("WebSocket message Sent") | |
} | |
} | |
} | |
} | |
function notesScroll(){ | |
//console.log("Notes scroll") | |
const elem = document.querySelectorAll('div[class="punch-viewer-speakernotes-text-body-scrollable"]')[0]; | |
if(elem){ | |
elem.scrollBy(0,notesScrollSpeed); | |
elem.scrollBy({ | |
behavior: "smooth" | |
}); | |
} | |
} | |
function keySim(k){ | |
console.log(`Key press ${k}`) | |
document.dispatchEvent( | |
new KeyboardEvent("keydown", { | |
keyCode: k | |
}) | |
); | |
} | |
//obs-ws-js library | |
var OBSWebSocket = (function () { | |
function _defineProperties(target, props) { | |
for (var i = 0; i < props.length; i++) { | |
var descriptor = props[i]; | |
descriptor.enumerable = descriptor.enumerable || false; | |
descriptor.configurable = true; | |
if ("value" in descriptor) descriptor.writable = true; | |
Object.defineProperty(target, descriptor.key, descriptor); | |
} | |
} | |
function _createClass(Constructor, protoProps, staticProps) { | |
if (protoProps) _defineProperties(Constructor.prototype, protoProps); | |
if (staticProps) _defineProperties(Constructor, staticProps); | |
Object.defineProperty(Constructor, "prototype", { | |
writable: false | |
}); | |
return Constructor; | |
} | |
function _extends() { | |
_extends = Object.assign ? Object.assign.bind() : function (target) { | |
for (var i = 1; i < arguments.length; i++) { | |
var source = arguments[i]; | |
for (var key in source) { | |
if (Object.prototype.hasOwnProperty.call(source, key)) { | |
target[key] = source[key]; | |
} | |
} | |
} | |
return target; | |
}; | |
return _extends.apply(this, arguments); | |
} | |
function _inheritsLoose(subClass, superClass) { | |
subClass.prototype = Object.create(superClass.prototype); | |
subClass.prototype.constructor = subClass; | |
_setPrototypeOf(subClass, superClass); | |
} | |
function _getPrototypeOf(o) { | |
_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) { | |
return o.__proto__ || Object.getPrototypeOf(o); | |
}; | |
return _getPrototypeOf(o); | |
} | |
function _setPrototypeOf(o, p) { | |
_setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { | |
o.__proto__ = p; | |
return o; | |
}; | |
return _setPrototypeOf(o, p); | |
} | |
function _isNativeReflectConstruct() { | |
if (typeof Reflect === "undefined" || !Reflect.construct) return false; | |
if (Reflect.construct.sham) return false; | |
if (typeof Proxy === "function") return true; | |
try { | |
Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); | |
return true; | |
} catch (e) { | |
return false; | |
} | |
} | |
function _construct(Parent, args, Class) { | |
if (_isNativeReflectConstruct()) { | |
_construct = Reflect.construct.bind(); | |
} else { | |
_construct = function _construct(Parent, args, Class) { | |
var a = [null]; | |
a.push.apply(a, args); | |
var Constructor = Function.bind.apply(Parent, a); | |
var instance = new Constructor(); | |
if (Class) _setPrototypeOf(instance, Class.prototype); | |
return instance; | |
}; | |
} | |
return _construct.apply(null, arguments); | |
} | |
function _isNativeFunction(fn) { | |
return Function.toString.call(fn).indexOf("[native code]") !== -1; | |
} | |
function _wrapNativeSuper(Class) { | |
var _cache = typeof Map === "function" ? new Map() : undefined; | |
_wrapNativeSuper = function _wrapNativeSuper(Class) { | |
if (Class === null || !_isNativeFunction(Class)) return Class; | |
if (typeof Class !== "function") { | |
throw new TypeError("Super expression must either be null or a function"); | |
} | |
if (typeof _cache !== "undefined") { | |
if (_cache.has(Class)) return _cache.get(Class); | |
_cache.set(Class, Wrapper); | |
} | |
function Wrapper() { | |
return _construct(Class, arguments, _getPrototypeOf(this).constructor); | |
} | |
Wrapper.prototype = Object.create(Class.prototype, { | |
constructor: { | |
value: Wrapper, | |
enumerable: false, | |
writable: true, | |
configurable: true | |
} | |
}); | |
return _setPrototypeOf(Wrapper, Class); | |
}; | |
return _wrapNativeSuper(Class); | |
} | |
function _objectWithoutPropertiesLoose(source, excluded) { | |
if (source == null) return {}; | |
var target = {}; | |
var sourceKeys = Object.keys(source); | |
var key, i; | |
for (i = 0; i < sourceKeys.length; i++) { | |
key = sourceKeys[i]; | |
if (excluded.indexOf(key) >= 0) continue; | |
target[key] = source[key]; | |
} | |
return target; | |
} | |
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; | |
function createCommonjsModule(fn) { | |
var module = { exports: {} }; | |
return fn(module, module.exports), module.exports; | |
} | |
function commonjsRequire (target) { | |
throw new Error('Could not dynamically require "' + target + '". Please configure the dynamicRequireTargets option of @rollup/plugin-commonjs appropriately for this require call to behave properly.'); | |
} | |
/** | |
* Helpers. | |
*/ | |
var s = 1000; | |
var m = s * 60; | |
var h = m * 60; | |
var d = h * 24; | |
var w = d * 7; | |
var y = d * 365.25; | |
/** | |
* Parse or format the given `val`. | |
* | |
* Options: | |
* | |
* - `long` verbose formatting [false] | |
* | |
* @param {String|Number} val | |
* @param {Object} [options] | |
* @throws {Error} throw an error if val is not a non-empty string or a number | |
* @return {String|Number} | |
* @api public | |
*/ | |
var ms = function(val, options) { | |
options = options || {}; | |
var type = typeof val; | |
if (type === 'string' && val.length > 0) { | |
return parse(val); | |
} else if (type === 'number' && isFinite(val)) { | |
return options.long ? fmtLong(val) : fmtShort(val); | |
} | |
throw new Error( | |
'val is not a non-empty string or a valid number. val=' + | |
JSON.stringify(val) | |
); | |
}; | |
/** | |
* Parse the given `str` and return milliseconds. | |
* | |
* @param {String} str | |
* @return {Number} | |
* @api private | |
*/ | |
function parse(str) { | |
str = String(str); | |
if (str.length > 100) { | |
return; | |
} | |
var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec( | |
str | |
); | |
if (!match) { | |
return; | |
} | |
var n = parseFloat(match[1]); | |
var type = (match[2] || 'ms').toLowerCase(); | |
switch (type) { | |
case 'years': | |
case 'year': | |
case 'yrs': | |
case 'yr': | |
case 'y': | |
return n * y; | |
case 'weeks': | |
case 'week': | |
case 'w': | |
return n * w; | |
case 'days': | |
case 'day': | |
case 'd': | |
return n * d; | |
case 'hours': | |
case 'hour': | |
case 'hrs': | |
case 'hr': | |
case 'h': | |
return n * h; | |
case 'minutes': | |
case 'minute': | |
case 'mins': | |
case 'min': | |
case 'm': | |
return n * m; | |
case 'seconds': | |
case 'second': | |
case 'secs': | |
case 'sec': | |
case 's': | |
return n * s; | |
case 'milliseconds': | |
case 'millisecond': | |
case 'msecs': | |
case 'msec': | |
case 'ms': | |
return n; | |
default: | |
return undefined; | |
} | |
} | |
/** | |
* Short format for `ms`. | |
* | |
* @param {Number} ms | |
* @return {String} | |
* @api private | |
*/ | |
function fmtShort(ms) { | |
var msAbs = Math.abs(ms); | |
if (msAbs >= d) { | |
return Math.round(ms / d) + 'd'; | |
} | |
if (msAbs >= h) { | |
return Math.round(ms / h) + 'h'; | |
} | |
if (msAbs >= m) { | |
return Math.round(ms / m) + 'm'; | |
} | |
if (msAbs >= s) { | |
return Math.round(ms / s) + 's'; | |
} | |
return ms + 'ms'; | |
} | |
/** | |
* Long format for `ms`. | |
* | |
* @param {Number} ms | |
* @return {String} | |
* @api private | |
*/ | |
function fmtLong(ms) { | |
var msAbs = Math.abs(ms); | |
if (msAbs >= d) { | |
return plural(ms, msAbs, d, 'day'); | |
} | |
if (msAbs >= h) { | |
return plural(ms, msAbs, h, 'hour'); | |
} | |
if (msAbs >= m) { | |
return plural(ms, msAbs, m, 'minute'); | |
} | |
if (msAbs >= s) { | |
return plural(ms, msAbs, s, 'second'); | |
} | |
return ms + ' ms'; | |
} | |
/** | |
* Pluralization helper. | |
*/ | |
function plural(ms, msAbs, n, name) { | |
var isPlural = msAbs >= n * 1.5; | |
return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : ''); | |
} | |
/** | |
* This is the common logic for both the Node.js and web browser | |
* implementations of `debug()`. | |
*/ | |
function setup(env) { | |
createDebug.debug = createDebug; | |
createDebug.default = createDebug; | |
createDebug.coerce = coerce; | |
createDebug.disable = disable; | |
createDebug.enable = enable; | |
createDebug.enabled = enabled; | |
createDebug.humanize = ms; | |
createDebug.destroy = destroy; | |
Object.keys(env).forEach(key => { | |
createDebug[key] = env[key]; | |
}); | |
/** | |
* The currently active debug mode names, and names to skip. | |
*/ | |
createDebug.names = []; | |
createDebug.skips = []; | |
/** | |
* Map of special "%n" handling functions, for the debug "format" argument. | |
* | |
* Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". | |
*/ | |
createDebug.formatters = {}; | |
/** | |
* Selects a color for a debug namespace | |
* @param {String} namespace The namespace string for the debug instance to be colored | |
* @return {Number|String} An ANSI color code for the given namespace | |
* @api private | |
*/ | |
function selectColor(namespace) { | |
let hash = 0; | |
for (let i = 0; i < namespace.length; i++) { | |
hash = ((hash << 5) - hash) + namespace.charCodeAt(i); | |
hash |= 0; // Convert to 32bit integer | |
} | |
return createDebug.colors[Math.abs(hash) % createDebug.colors.length]; | |
} | |
createDebug.selectColor = selectColor; | |
/** | |
* Create a debugger with the given `namespace`. | |
* | |
* @param {String} namespace | |
* @return {Function} | |
* @api public | |
*/ | |
function createDebug(namespace) { | |
let prevTime; | |
let enableOverride = null; | |
let namespacesCache; | |
let enabledCache; | |
function debug(...args) { | |
// Disabled? | |
if (!debug.enabled) { | |
return; | |
} | |
const self = debug; | |
// Set `diff` timestamp | |
const curr = Number(new Date()); | |
const ms = curr - (prevTime || curr); | |
self.diff = ms; | |
self.prev = prevTime; | |
self.curr = curr; | |
prevTime = curr; | |
args[0] = createDebug.coerce(args[0]); | |
if (typeof args[0] !== 'string') { | |
// Anything else let's inspect with %O | |
args.unshift('%O'); | |
} | |
// Apply any `formatters` transformations | |
let index = 0; | |
args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => { | |
// If we encounter an escaped % then don't increase the array index | |
if (match === '%%') { | |
return '%'; | |
} | |
index++; | |
const formatter = createDebug.formatters[format]; | |
if (typeof formatter === 'function') { | |
const val = args[index]; | |
match = formatter.call(self, val); | |
// Now we need to remove `args[index]` since it's inlined in the `format` | |
args.splice(index, 1); | |
index--; | |
} | |
return match; | |
}); | |
// Apply env-specific formatting (colors, etc.) | |
createDebug.formatArgs.call(self, args); | |
const logFn = self.log || createDebug.log; | |
logFn.apply(self, args); | |
} | |
debug.namespace = namespace; | |
debug.useColors = createDebug.useColors(); | |
debug.color = createDebug.selectColor(namespace); | |
debug.extend = extend; | |
debug.destroy = createDebug.destroy; // XXX Temporary. Will be removed in the next major release. | |
Object.defineProperty(debug, 'enabled', { | |
enumerable: true, | |
configurable: false, | |
get: () => { | |
if (enableOverride !== null) { | |
return enableOverride; | |
} | |
if (namespacesCache !== createDebug.namespaces) { | |
namespacesCache = createDebug.namespaces; | |
enabledCache = createDebug.enabled(namespace); | |
} | |
return enabledCache; | |
}, | |
set: v => { | |
enableOverride = v; | |
} | |
}); | |
// Env-specific initialization logic for debug instances | |
if (typeof createDebug.init === 'function') { | |
createDebug.init(debug); | |
} | |
return debug; | |
} | |
function extend(namespace, delimiter) { | |
const newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace); | |
newDebug.log = this.log; | |
return newDebug; | |
} | |
/** | |
* Enables a debug mode by namespaces. This can include modes | |
* separated by a colon and wildcards. | |
* | |
* @param {String} namespaces | |
* @api public | |
*/ | |
function enable(namespaces) { | |
createDebug.save(namespaces); | |
createDebug.namespaces = namespaces; | |
createDebug.names = []; | |
createDebug.skips = []; | |
let i; | |
const split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); | |
const len = split.length; | |
for (i = 0; i < len; i++) { | |
if (!split[i]) { | |
// ignore empty strings | |
continue; | |
} | |
namespaces = split[i].replace(/\*/g, '.*?'); | |
if (namespaces[0] === '-') { | |
createDebug.skips.push(new RegExp('^' + namespaces.slice(1) + '$')); | |
} else { | |
createDebug.names.push(new RegExp('^' + namespaces + '$')); | |
} | |
} | |
} | |
/** | |
* Disable debug output. | |
* | |
* @return {String} namespaces | |
* @api public | |
*/ | |
function disable() { | |
const namespaces = [ | |
...createDebug.names.map(toNamespace), | |
...createDebug.skips.map(toNamespace).map(namespace => '-' + namespace) | |
].join(','); | |
createDebug.enable(''); | |
return namespaces; | |
} | |
/** | |
* Returns true if the given mode name is enabled, false otherwise. | |
* | |
* @param {String} name | |
* @return {Boolean} | |
* @api public | |
*/ | |
function enabled(name) { | |
if (name[name.length - 1] === '*') { | |
return true; | |
} | |
let i; | |
let len; | |
for (i = 0, len = createDebug.skips.length; i < len; i++) { | |
if (createDebug.skips[i].test(name)) { | |
return false; | |
} | |
} | |
for (i = 0, len = createDebug.names.length; i < len; i++) { | |
if (createDebug.names[i].test(name)) { | |
return true; | |
} | |
} | |
return false; | |
} | |
/** | |
* Convert regexp to namespace | |
* | |
* @param {RegExp} regxep | |
* @return {String} namespace | |
* @api private | |
*/ | |
function toNamespace(regexp) { | |
return regexp.toString() | |
.substring(2, regexp.toString().length - 2) | |
.replace(/\.\*\?$/, '*'); | |
} | |
/** | |
* Coerce `val`. | |
* | |
* @param {Mixed} val | |
* @return {Mixed} | |
* @api private | |
*/ | |
function coerce(val) { | |
if (val instanceof Error) { | |
return val.stack || val.message; | |
} | |
return val; | |
} | |
/** | |
* XXX DO NOT USE. This is a temporary stub function. | |
* XXX It WILL be removed in the next major release. | |
*/ | |
function destroy() { | |
console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.'); | |
} | |
createDebug.enable(createDebug.load()); | |
return createDebug; | |
} | |
var common = setup; | |
/* eslint-env browser */ | |
var browser$1 = createCommonjsModule(function (module, exports) { | |
/** | |
* This is the web browser implementation of `debug()`. | |
*/ | |
exports.formatArgs = formatArgs; | |
exports.save = save; | |
exports.load = load; | |
exports.useColors = useColors; | |
exports.storage = localstorage(); | |
exports.destroy = (() => { | |
let warned = false; | |
return () => { | |
if (!warned) { | |
warned = true; | |
console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.'); | |
} | |
}; | |
})(); | |
/** | |
* Colors. | |
*/ | |
exports.colors = [ | |
'#0000CC', | |
'#0000FF', | |
'#0033CC', | |
'#0033FF', | |
'#0066CC', | |
'#0066FF', | |
'#0099CC', | |
'#0099FF', | |
'#00CC00', | |
'#00CC33', | |
'#00CC66', | |
'#00CC99', | |
'#00CCCC', | |
'#00CCFF', | |
'#3300CC', | |
'#3300FF', | |
'#3333CC', | |
'#3333FF', | |
'#3366CC', | |
'#3366FF', | |
'#3399CC', | |
'#3399FF', | |
'#33CC00', | |
'#33CC33', | |
'#33CC66', | |
'#33CC99', | |
'#33CCCC', | |
'#33CCFF', | |
'#6600CC', | |
'#6600FF', | |
'#6633CC', | |
'#6633FF', | |
'#66CC00', | |
'#66CC33', | |
'#9900CC', | |
'#9900FF', | |
'#9933CC', | |
'#9933FF', | |
'#99CC00', | |
'#99CC33', | |
'#CC0000', | |
'#CC0033', | |
'#CC0066', | |
'#CC0099', | |
'#CC00CC', | |
'#CC00FF', | |
'#CC3300', | |
'#CC3333', | |
'#CC3366', | |
'#CC3399', | |
'#CC33CC', | |
'#CC33FF', | |
'#CC6600', | |
'#CC6633', | |
'#CC9900', | |
'#CC9933', | |
'#CCCC00', | |
'#CCCC33', | |
'#FF0000', | |
'#FF0033', | |
'#FF0066', | |
'#FF0099', | |
'#FF00CC', | |
'#FF00FF', | |
'#FF3300', | |
'#FF3333', | |
'#FF3366', | |
'#FF3399', | |
'#FF33CC', | |
'#FF33FF', | |
'#FF6600', | |
'#FF6633', | |
'#FF9900', | |
'#FF9933', | |
'#FFCC00', | |
'#FFCC33' | |
]; | |
/** | |
* Currently only WebKit-based Web Inspectors, Firefox >= v31, | |
* and the Firebug extension (any Firefox version) are known | |
* to support "%c" CSS customizations. | |
* | |
* TODO: add a `localStorage` variable to explicitly enable/disable colors | |
*/ | |
// eslint-disable-next-line complexity | |
function useColors() { | |
// NB: In an Electron preload script, document will be defined but not fully | |
// initialized. Since we know we're in Chrome, we'll just detect this case | |
// explicitly | |
if (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) { | |
return true; | |
} | |
// Internet Explorer and Edge do not support colors. | |
if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) { | |
return false; | |
} | |
// Is webkit? http://stackoverflow.com/a/16459606/376773 | |
// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 | |
return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || | |
// Is firebug? http://stackoverflow.com/a/398120/376773 | |
(typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || | |
// Is firefox >= v31? | |
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages | |
(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || | |
// Double check webkit in userAgent just in case we are in a worker | |
(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); | |
} | |
/** | |
* Colorize log arguments if enabled. | |
* | |
* @api public | |
*/ | |
function formatArgs(args) { | |
args[0] = (this.useColors ? '%c' : '') + | |
this.namespace + | |
(this.useColors ? ' %c' : ' ') + | |
args[0] + | |
(this.useColors ? '%c ' : ' ') + | |
'+' + module.exports.humanize(this.diff); | |
if (!this.useColors) { | |
return; | |
} | |
const c = 'color: ' + this.color; | |
args.splice(1, 0, c, 'color: inherit'); | |
// The final "%c" is somewhat tricky, because there could be other | |
// arguments passed either before or after the %c, so we need to | |
// figure out the correct index to insert the CSS into | |
let index = 0; | |
let lastC = 0; | |
args[0].replace(/%[a-zA-Z%]/g, match => { | |
if (match === '%%') { | |
return; | |
} | |
index++; | |
if (match === '%c') { | |
// We only are interested in the *last* %c | |
// (the user may have provided their own) | |
lastC = index; | |
} | |
}); | |
args.splice(lastC, 0, c); | |
} | |
/** | |
* Invokes `console.debug()` when available. | |
* No-op when `console.debug` is not a "function". | |
* If `console.debug` is not available, falls back | |
* to `console.log`. | |
* | |
* @api public | |
*/ | |
exports.log = console.debug || console.log || (() => {}); | |
/** | |
* Save `namespaces`. | |
* | |
* @param {String} namespaces | |
* @api private | |
*/ | |
function save(namespaces) { | |
try { | |
if (namespaces) { | |
exports.storage.setItem('debug', namespaces); | |
} else { | |
exports.storage.removeItem('debug'); | |
} | |
} catch (error) { | |
// Swallow | |
// XXX (@Qix-) should we be logging these? | |
} | |
} | |
/** | |
* Load `namespaces`. | |
* | |
* @return {String} returns the previously persisted debug modes | |
* @api private | |
*/ | |
function load() { | |
let r; | |
try { | |
r = exports.storage.getItem('debug'); | |
} catch (error) { | |
// Swallow | |
// XXX (@Qix-) should we be logging these? | |
} | |
// If debug isn't set in LS, and we're in Electron, try to load $DEBUG | |
if (!r && typeof process !== 'undefined' && 'env' in process) { | |
r = process.env.DEBUG; | |
} | |
return r; | |
} | |
/** | |
* Localstorage attempts to return the localstorage. | |
* | |
* This is necessary because safari throws | |
* when a user disables cookies/localstorage | |
* and you attempt to access it. | |
* | |
* @return {LocalStorage} | |
* @api private | |
*/ | |
function localstorage() { | |
try { | |
// TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context | |
// The Browser also has localStorage in the global context. | |
return localStorage; | |
} catch (error) { | |
// Swallow | |
// XXX (@Qix-) should we be logging these? | |
} | |
} | |
module.exports = common(exports); | |
const {formatters} = module.exports; | |
/** | |
* Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. | |
*/ | |
formatters.j = function (v) { | |
try { | |
return JSON.stringify(v); | |
} catch (error) { | |
return '[UnexpectedJSONParseError]: ' + error.message; | |
} | |
}; | |
}); | |
var eventemitter3 = createCommonjsModule(function (module) { | |
var has = Object.prototype.hasOwnProperty | |
, prefix = '~'; | |
/** | |
* Constructor to create a storage for our `EE` objects. | |
* An `Events` instance is a plain object whose properties are event names. | |
* | |
* @constructor | |
* @private | |
*/ | |
function Events() {} | |
// | |
// We try to not inherit from `Object.prototype`. In some engines creating an | |
// instance in this way is faster than calling `Object.create(null)` directly. | |
// If `Object.create(null)` is not supported we prefix the event names with a | |
// character to make sure that the built-in object properties are not | |
// overridden or used as an attack vector. | |
// | |
if (Object.create) { | |
Events.prototype = Object.create(null); | |
// | |
// This hack is needed because the `__proto__` property is still inherited in | |
// some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5. | |
// | |
if (!new Events().__proto__) prefix = false; | |
} | |
/** | |
* Representation of a single event listener. | |
* | |
* @param {Function} fn The listener function. | |
* @param {*} context The context to invoke the listener with. | |
* @param {Boolean} [once=false] Specify if the listener is a one-time listener. | |
* @constructor | |
* @private | |
*/ | |
function EE(fn, context, once) { | |
this.fn = fn; | |
this.context = context; | |
this.once = once || false; | |
} | |
/** | |
* Add a listener for a given event. | |
* | |
* @param {EventEmitter} emitter Reference to the `EventEmitter` instance. | |
* @param {(String|Symbol)} event The event name. | |
* @param {Function} fn The listener function. | |
* @param {*} context The context to invoke the listener with. | |
* @param {Boolean} once Specify if the listener is a one-time listener. | |
* @returns {EventEmitter} | |
* @private | |
*/ | |
function addListener(emitter, event, fn, context, once) { | |
if (typeof fn !== 'function') { | |
throw new TypeError('The listener must be a function'); | |
} | |
var listener = new EE(fn, context || emitter, once) | |
, evt = prefix ? prefix + event : event; | |
if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++; | |
else if (!emitter._events[evt].fn) emitter._events[evt].push(listener); | |
else emitter._events[evt] = [emitter._events[evt], listener]; | |
return emitter; | |
} | |
/** | |
* Clear event by name. | |
* | |
* @param {EventEmitter} emitter Reference to the `EventEmitter` instance. | |
* @param {(String|Symbol)} evt The Event name. | |
* @private | |
*/ | |
function clearEvent(emitter, evt) { | |
if (--emitter._eventsCount === 0) emitter._events = new Events(); | |
else delete emitter._events[evt]; | |
} | |
/** | |
* Minimal `EventEmitter` interface that is molded against the Node.js | |
* `EventEmitter` interface. | |
* | |
* @constructor | |
* @public | |
*/ | |
function EventEmitter() { | |
this._events = new Events(); | |
this._eventsCount = 0; | |
} | |
/** | |
* Return an array listing the events for which the emitter has registered | |
* listeners. | |
* | |
* @returns {Array} | |
* @public | |
*/ | |
EventEmitter.prototype.eventNames = function eventNames() { | |
var names = [] | |
, events | |
, name; | |
if (this._eventsCount === 0) return names; | |
for (name in (events = this._events)) { | |
if (has.call(events, name)) names.push(prefix ? name.slice(1) : name); | |
} | |
if (Object.getOwnPropertySymbols) { | |
return names.concat(Object.getOwnPropertySymbols(events)); | |
} | |
return names; | |
}; | |
/** | |
* Return the listeners registered for a given event. | |
* | |
* @param {(String|Symbol)} event The event name. | |
* @returns {Array} The registered listeners. | |
* @public | |
*/ | |
EventEmitter.prototype.listeners = function listeners(event) { | |
var evt = prefix ? prefix + event : event | |
, handlers = this._events[evt]; | |
if (!handlers) return []; | |
if (handlers.fn) return [handlers.fn]; | |
for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) { | |
ee[i] = handlers[i].fn; | |
} | |
return ee; | |
}; | |
/** | |
* Return the number of listeners listening to a given event. | |
* | |
* @param {(String|Symbol)} event The event name. | |
* @returns {Number} The number of listeners. | |
* @public | |
*/ | |
EventEmitter.prototype.listenerCount = function listenerCount(event) { | |
var evt = prefix ? prefix + event : event | |
, listeners = this._events[evt]; | |
if (!listeners) return 0; | |
if (listeners.fn) return 1; | |
return listeners.length; | |
}; | |
/** | |
* Calls each of the listeners registered for a given event. | |
* | |
* @param {(String|Symbol)} event The event name. | |
* @returns {Boolean} `true` if the event had listeners, else `false`. | |
* @public | |
*/ | |
EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) { | |
var evt = prefix ? prefix + event : event; | |
if (!this._events[evt]) return false; | |
var listeners = this._events[evt] | |
, len = arguments.length | |
, args | |
, i; | |
if (listeners.fn) { | |
if (listeners.once) this.removeListener(event, listeners.fn, undefined, true); | |
switch (len) { | |
case 1: return listeners.fn.call(listeners.context), true; | |
case 2: return listeners.fn.call(listeners.context, a1), true; | |
case 3: return listeners.fn.call(listeners.context, a1, a2), true; | |
case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true; | |
case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true; | |
case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true; | |
} | |
for (i = 1, args = new Array(len -1); i < len; i++) { | |
args[i - 1] = arguments[i]; | |
} | |
listeners.fn.apply(listeners.context, args); | |
} else { | |
var length = listeners.length | |
, j; | |
for (i = 0; i < length; i++) { | |
if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true); | |
switch (len) { | |
case 1: listeners[i].fn.call(listeners[i].context); break; | |
case 2: listeners[i].fn.call(listeners[i].context, a1); break; | |
case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break; | |
case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break; | |
default: | |
if (!args) for (j = 1, args = new Array(len -1); j < len; j++) { | |
args[j - 1] = arguments[j]; | |
} | |
listeners[i].fn.apply(listeners[i].context, args); | |
} | |
} | |
} | |
return true; | |
}; | |
/** | |
* Add a listener for a given event. | |
* | |
* @param {(String|Symbol)} event The event name. | |
* @param {Function} fn The listener function. | |
* @param {*} [context=this] The context to invoke the listener with. | |
* @returns {EventEmitter} `this`. | |
* @public | |
*/ | |
EventEmitter.prototype.on = function on(event, fn, context) { | |
return addListener(this, event, fn, context, false); | |
}; | |
/** | |
* Add a one-time listener for a given event. | |
* | |
* @param {(String|Symbol)} event The event name. | |
* @param {Function} fn The listener function. | |
* @param {*} [context=this] The context to invoke the listener with. | |
* @returns {EventEmitter} `this`. | |
* @public | |
*/ | |
EventEmitter.prototype.once = function once(event, fn, context) { | |
return addListener(this, event, fn, context, true); | |
}; | |
/** | |
* Remove the listeners of a given event. | |
* | |
* @param {(String|Symbol)} event The event name. | |
* @param {Function} fn Only remove the listeners that match this function. | |
* @param {*} context Only remove the listeners that have this context. | |
* @param {Boolean} once Only remove one-time listeners. | |
* @returns {EventEmitter} `this`. | |
* @public | |
*/ | |
EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) { | |
var evt = prefix ? prefix + event : event; | |
if (!this._events[evt]) return this; | |
if (!fn) { | |
clearEvent(this, evt); | |
return this; | |
} | |
var listeners = this._events[evt]; | |
if (listeners.fn) { | |
if ( | |
listeners.fn === fn && | |
(!once || listeners.once) && | |
(!context || listeners.context === context) | |
) { | |
clearEvent(this, evt); | |
} | |
} else { | |
for (var i = 0, events = [], length = listeners.length; i < length; i++) { | |
if ( | |
listeners[i].fn !== fn || | |
(once && !listeners[i].once) || | |
(context && listeners[i].context !== context) | |
) { | |
events.push(listeners[i]); | |
} | |
} | |
// | |
// Reset the array, or remove it completely if we have no more listeners. | |
// | |
if (events.length) this._events[evt] = events.length === 1 ? events[0] : events; | |
else clearEvent(this, evt); | |
} | |
return this; | |
}; | |
/** | |
* Remove all listeners, or those of the specified event. | |
* | |
* @param {(String|Symbol)} [event] The event name. | |
* @returns {EventEmitter} `this`. | |
* @public | |
*/ | |
EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) { | |
var evt; | |
if (event) { | |
evt = prefix ? prefix + event : event; | |
if (this._events[evt]) clearEvent(this, evt); | |
} else { | |
this._events = new Events(); | |
this._eventsCount = 0; | |
} | |
return this; | |
}; | |
// | |
// Alias methods names because people roll like that. | |
// | |
EventEmitter.prototype.off = EventEmitter.prototype.removeListener; | |
EventEmitter.prototype.addListener = EventEmitter.prototype.on; | |
// | |
// Expose the prefix. | |
// | |
EventEmitter.prefixed = prefix; | |
// | |
// Allow `EventEmitter` to be imported as module namespace. | |
// | |
EventEmitter.EventEmitter = EventEmitter; | |
// | |
// Expose the module. | |
// | |
{ | |
module.exports = EventEmitter; | |
} | |
}); | |
// https://github.com/maxogden/websocket-stream/blob/48dc3ddf943e5ada668c31ccd94e9186f02fafbd/ws-fallback.js | |
var ws = null; | |
if (typeof WebSocket !== 'undefined') { | |
ws = WebSocket; | |
} else if (typeof MozWebSocket !== 'undefined') { | |
ws = MozWebSocket; | |
} else if (typeof commonjsGlobal !== 'undefined') { | |
ws = commonjsGlobal.WebSocket || commonjsGlobal.MozWebSocket; | |
} else if (typeof window !== 'undefined') { | |
ws = window.WebSocket || window.MozWebSocket; | |
} else if (typeof self !== 'undefined') { | |
ws = self.WebSocket || self.MozWebSocket; | |
} | |
var browser = ws; | |
var WebSocketOpCode; | |
(function (WebSocketOpCode) { | |
/** | |
* The initial message sent by obs-websocket to newly connected clients. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
WebSocketOpCode[WebSocketOpCode["Hello"] = 0] = "Hello"; | |
/** | |
* The message sent by a newly connected client to obs-websocket in response to a `Hello`. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
WebSocketOpCode[WebSocketOpCode["Identify"] = 1] = "Identify"; | |
/** | |
* The response sent by obs-websocket to a client after it has successfully identified with obs-websocket. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
WebSocketOpCode[WebSocketOpCode["Identified"] = 2] = "Identified"; | |
/** | |
* The message sent by an already-identified client to update identification parameters. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
WebSocketOpCode[WebSocketOpCode["Reidentify"] = 3] = "Reidentify"; | |
/** | |
* The message sent by obs-websocket containing an event payload. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
WebSocketOpCode[WebSocketOpCode["Event"] = 5] = "Event"; | |
/** | |
* The message sent by a client to obs-websocket to perform a request. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
WebSocketOpCode[WebSocketOpCode["Request"] = 6] = "Request"; | |
/** | |
* The message sent by obs-websocket in response to a particular request from a client. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
WebSocketOpCode[WebSocketOpCode["RequestResponse"] = 7] = "RequestResponse"; | |
/** | |
* The message sent by a client to obs-websocket to perform a batch of requests. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
WebSocketOpCode[WebSocketOpCode["RequestBatch"] = 8] = "RequestBatch"; | |
/** | |
* The message sent by obs-websocket in response to a particular batch of requests from a client. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
WebSocketOpCode[WebSocketOpCode["RequestBatchResponse"] = 9] = "RequestBatchResponse"; | |
})(WebSocketOpCode || (WebSocketOpCode = {})); | |
/* eslint-disable no-bitwise, @typescript-eslint/prefer-literal-enum-member */ | |
var EventSubscription; | |
(function (EventSubscription) { | |
/** | |
* Subcription value used to disable all events. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
EventSubscription[EventSubscription["None"] = 0] = "None"; | |
/** | |
* Subscription value to receive events in the `General` category. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
EventSubscription[EventSubscription["General"] = 1] = "General"; | |
/** | |
* Subscription value to receive events in the `Config` category. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
EventSubscription[EventSubscription["Config"] = 2] = "Config"; | |
/** | |
* Subscription value to receive events in the `Scenes` category. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
EventSubscription[EventSubscription["Scenes"] = 4] = "Scenes"; | |
/** | |
* Subscription value to receive events in the `Inputs` category. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
EventSubscription[EventSubscription["Inputs"] = 8] = "Inputs"; | |
/** | |
* Subscription value to receive events in the `Transitions` category. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
EventSubscription[EventSubscription["Transitions"] = 16] = "Transitions"; | |
/** | |
* Subscription value to receive events in the `Filters` category. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
EventSubscription[EventSubscription["Filters"] = 32] = "Filters"; | |
/** | |
* Subscription value to receive events in the `Outputs` category. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
EventSubscription[EventSubscription["Outputs"] = 64] = "Outputs"; | |
/** | |
* Subscription value to receive events in the `SceneItems` category. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
EventSubscription[EventSubscription["SceneItems"] = 128] = "SceneItems"; | |
/** | |
* Subscription value to receive events in the `MediaInputs` category. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
EventSubscription[EventSubscription["MediaInputs"] = 256] = "MediaInputs"; | |
/** | |
* Subscription value to receive the `VendorEvent` event. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
EventSubscription[EventSubscription["Vendors"] = 512] = "Vendors"; | |
/** | |
* Subscription value to receive events in the `Ui` category. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
EventSubscription[EventSubscription["Ui"] = 1024] = "Ui"; | |
/** | |
* Helper to receive all non-high-volume events. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
EventSubscription[EventSubscription["All"] = 1023] = "All"; | |
/** | |
* Subscription value to receive the `InputVolumeMeters` high-volume event. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
EventSubscription[EventSubscription["InputVolumeMeters"] = 65536] = "InputVolumeMeters"; | |
/** | |
* Subscription value to receive the `InputActiveStateChanged` high-volume event. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
EventSubscription[EventSubscription["InputActiveStateChanged"] = 131072] = "InputActiveStateChanged"; | |
/** | |
* Subscription value to receive the `InputShowStateChanged` high-volume event. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
EventSubscription[EventSubscription["InputShowStateChanged"] = 262144] = "InputShowStateChanged"; | |
/** | |
* Subscription value to receive the `SceneItemTransformChanged` high-volume event. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
EventSubscription[EventSubscription["SceneItemTransformChanged"] = 524288] = "SceneItemTransformChanged"; | |
})(EventSubscription || (EventSubscription = {})); | |
/* eslint-enable no-bitwise, @typescript-eslint/prefer-literal-enum-member */ | |
var RequestBatchExecutionType; | |
(function (RequestBatchExecutionType) { | |
/** | |
* Not a request batch. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
RequestBatchExecutionType[RequestBatchExecutionType["None"] = -1] = "None"; | |
/** | |
* A request batch which processes all requests serially, as fast as possible. | |
* | |
* Note: To introduce artificial delay, use the `Sleep` request and the `sleepMillis` request field. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
RequestBatchExecutionType[RequestBatchExecutionType["SerialRealtime"] = 0] = "SerialRealtime"; | |
/** | |
* A request batch type which processes all requests serially, in sync with the graphics thread. Designed to provide high accuracy for animations. | |
* | |
* Note: To introduce artificial delay, use the `Sleep` request and the `sleepFrames` request field. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
RequestBatchExecutionType[RequestBatchExecutionType["SerialFrame"] = 1] = "SerialFrame"; | |
/** | |
* A request batch type which processes all requests using all available threads in the thread pool. | |
* | |
* Note: This is mainly experimental, and only really shows its colors during requests which require lots of | |
* active processing, like `GetSourceScreenshot`. | |
* | |
* Initial OBS Version: 5.0.0 | |
*/ | |
RequestBatchExecutionType[RequestBatchExecutionType["Parallel"] = 2] = "Parallel"; | |
})(RequestBatchExecutionType || (RequestBatchExecutionType = {})); | |
var _nodeResolve_empty = {}; | |
var _nodeResolve_empty$1 = { | |
__proto__: null, | |
'default': _nodeResolve_empty | |
}; | |
var core = createCommonjsModule(function (module, exports) { | |
(function (root, factory) { | |
{ | |
// CommonJS | |
module.exports = factory(); | |
} | |
}(commonjsGlobal, function () { | |
/*globals window, global, require*/ | |
/** | |
* CryptoJS core components. | |
*/ | |
var CryptoJS = CryptoJS || (function (Math, undefined$1) { | |
var crypto; | |
// Native crypto from window (Browser) | |
if (typeof window !== 'undefined' && window.crypto) { | |
crypto = window.crypto; | |
} | |
// Native crypto in web worker (Browser) | |
if (typeof self !== 'undefined' && self.crypto) { | |
crypto = self.crypto; | |
} | |
// Native crypto from worker | |
if (typeof globalThis !== 'undefined' && globalThis.crypto) { | |
crypto = globalThis.crypto; | |
} | |
// Native (experimental IE 11) crypto from window (Browser) | |
if (!crypto && typeof window !== 'undefined' && window.msCrypto) { | |
crypto = window.msCrypto; | |
} | |
// Native crypto from global (NodeJS) | |
if (!crypto && typeof commonjsGlobal !== 'undefined' && commonjsGlobal.crypto) { | |
crypto = commonjsGlobal.crypto; | |
} | |
// Native crypto import via require (NodeJS) | |
if (!crypto && typeof commonjsRequire === 'function') { | |
try { | |
crypto = _nodeResolve_empty$1; | |
} catch (err) {} | |
} | |
/* | |
* Cryptographically secure pseudorandom number generator | |
* | |
* As Math.random() is cryptographically not safe to use | |
*/ | |
var cryptoSecureRandomInt = function () { | |
if (crypto) { | |
// Use getRandomValues method (Browser) | |
if (typeof crypto.getRandomValues === 'function') { | |
try { | |
return crypto.getRandomValues(new Uint32Array(1))[0]; | |
} catch (err) {} | |
} | |
// Use randomBytes method (NodeJS) | |
if (typeof crypto.randomBytes === 'function') { | |
try { | |
return crypto.randomBytes(4).readInt32LE(); | |
} catch (err) {} | |
} | |
} | |
throw new Error('Native crypto module could not be used to get secure random number.'); | |
}; | |
/* | |
* Local polyfill of Object.create | |
*/ | |
var create = Object.create || (function () { | |
function F() {} | |
return function (obj) { | |
var subtype; | |
F.prototype = obj; | |
subtype = new F(); | |
F.prototype = null; | |
return subtype; | |
}; | |
}()); | |
/** | |
* CryptoJS namespace. | |
*/ | |
var C = {}; | |
/** | |
* Library namespace. | |
*/ | |
var C_lib = C.lib = {}; | |
/** | |
* Base object for prototypal inheritance. | |
*/ | |
var Base = C_lib.Base = (function () { | |
return { | |
/** | |
* Creates a new object that inherits from this object. | |
* | |
* @param {Object} overrides Properties to copy into the new object. | |
* | |
* @return {Object} The new object. | |
* | |
* @static | |
* | |
* @example | |
* | |
* var MyType = CryptoJS.lib.Base.extend({ | |
* field: 'value', | |
* | |
* method: function () { | |
* } | |
* }); | |
*/ | |
extend: function (overrides) { | |
// Spawn | |
var subtype = create(this); | |
// Augment | |
if (overrides) { | |
subtype.mixIn(overrides); | |
} | |
// Create default initializer | |
if (!subtype.hasOwnProperty('init') || this.init === subtype.init) { | |
subtype.init = function () { | |
subtype.$super.init.apply(this, arguments); | |
}; | |
} | |
// Initializer's prototype is the subtype object | |
subtype.init.prototype = subtype; | |
// Reference supertype | |
subtype.$super = this; | |
return subtype; | |
}, | |
/** | |
* Extends this object and runs the init method. | |
* Arguments to create() will be passed to init(). | |
* | |
* @return {Object} The new object. | |
* | |
* @static | |
* | |
* @example | |
* | |
* var instance = MyType.create(); | |
*/ | |
create: function () { | |
var instance = this.extend(); | |
instance.init.apply(instance, arguments); | |
return instance; | |
}, | |
/** | |
* Initializes a newly created object. | |
* Override this method to add some logic when your objects are created. | |
* | |
* @example | |
* | |
* var MyType = CryptoJS.lib.Base.extend({ | |
* init: function () { | |
* // ... | |
* } | |
* }); | |
*/ | |
init: function () { | |
}, | |
/** | |
* Copies properties into this object. | |
* | |
* @param {Object} properties The properties to mix in. | |
* | |
* @example | |
* | |
* MyType.mixIn({ | |
* field: 'value' | |
* }); | |
*/ | |
mixIn: function (properties) { | |
for (var propertyName in properties) { | |
if (properties.hasOwnProperty(propertyName)) { | |
this[propertyName] = properties[propertyName]; | |
} | |
} | |
// IE won't copy toString using the loop above | |
if (properties.hasOwnProperty('toString')) { | |
this.toString = properties.toString; | |
} | |
}, | |
/** | |
* Creates a copy of this object. | |
* | |
* @return {Object} The clone. | |
* | |
* @example | |
* | |
* var clone = instance.clone(); | |
*/ | |
clone: function () { | |
return this.init.prototype.extend(this); | |
} | |
}; | |
}()); | |
/** | |
* An array of 32-bit words. | |
* | |
* @property {Array} words The array of 32-bit words. | |
* @property {number} sigBytes The number of significant bytes in this word array. | |
*/ | |
var WordArray = C_lib.WordArray = Base.extend({ | |
/** | |
* Initializes a newly created word array. | |
* | |
* @param {Array} words (Optional) An array of 32-bit words. | |
* @param {number} sigBytes (Optional) The number of significant bytes in the words. | |
* | |
* @example | |
* | |
* var wordArray = CryptoJS.lib.WordArray.create(); | |
* var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]); | |
* var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6); | |
*/ | |
init: function (words, sigBytes) { | |
words = this.words = words || []; | |
if (sigBytes != undefined$1) { | |
this.sigBytes = sigBytes; | |
} else { | |
this.sigBytes = words.length * 4; | |
} | |
}, | |
/** | |
* Converts this word array to a string. | |
* | |
* @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex | |
* | |
* @return {string} The stringified word array. | |
* | |
* @example | |
* | |
* var string = wordArray + ''; | |
* var string = wordArray.toString(); | |
* var string = wordArray.toString(CryptoJS.enc.Utf8); | |
*/ | |
toString: function (encoder) { | |
return (encoder || Hex).stringify(this); | |
}, | |
/** | |
* Concatenates a word array to this word array. | |
* | |
* @param {WordArray} wordArray The word array to append. | |
* | |
* @return {WordArray} This word array. | |
* | |
* @example | |
* | |
* wordArray1.concat(wordArray2); | |
*/ | |
concat: function (wordArray) { | |
// Shortcuts | |
var thisWords = this.words; | |
var thatWords = wordArray.words; | |
var thisSigBytes = this.sigBytes; | |
var thatSigBytes = wordArray.sigBytes; | |
// Clamp excess bits | |
this.clamp(); | |
// Concat | |
if (thisSigBytes % 4) { | |
// Copy one byte at a time | |
for (var i = 0; i < thatSigBytes; i++) { | |
var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; | |
thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8); | |
} | |
} else { | |
// Copy one word at a time | |
for (var j = 0; j < thatSigBytes; j += 4) { | |
thisWords[(thisSigBytes + j) >>> 2] = thatWords[j >>> 2]; | |
} | |
} | |
this.sigBytes += thatSigBytes; | |
// Chainable | |
return this; | |
}, | |
/** | |
* Removes insignificant bits. | |
* | |
* @example | |
* | |
* wordArray.clamp(); | |
*/ | |
clamp: function () { | |
// Shortcuts | |
var words = this.words; | |
var sigBytes = this.sigBytes; | |
// Clamp | |
words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8); | |
words.length = Math.ceil(sigBytes / 4); | |
}, | |
/** | |
* Creates a copy of this word array. | |
* | |
* @return {WordArray} The clone. | |
* | |
* @example | |
* | |
* var clone = wordArray.clone(); | |
*/ | |
clone: function () { | |
var clone = Base.clone.call(this); | |
clone.words = this.words.slice(0); | |
return clone; | |
}, | |
/** | |
* Creates a word array filled with random bytes. | |
* | |
* @param {number} nBytes The number of random bytes to generate. | |
* | |
* @return {WordArray} The random word array. | |
* | |
* @static | |
* | |
* @example | |
* | |
* var wordArray = CryptoJS.lib.WordArray.random(16); | |
*/ | |
random: function (nBytes) { | |
var words = []; | |
for (var i = 0; i < nBytes; i += 4) { | |
words.push(cryptoSecureRandomInt()); | |
} | |
return new WordArray.init(words, nBytes); | |
} | |
}); | |
/** | |
* Encoder namespace. | |
*/ | |
var C_enc = C.enc = {}; | |
/** | |
* Hex encoding strategy. | |
*/ | |
var Hex = C_enc.Hex = { | |
/** | |
* Converts a word array to a hex string. | |
* | |
* @param {WordArray} wordArray The word array. | |
* | |
* @return {string} The hex string. | |
* | |
* @static | |
* | |
* @example | |
* | |
* var hexString = CryptoJS.enc.Hex.stringify(wordArray); | |
*/ | |
stringify: function (wordArray) { | |
// Shortcuts | |
var words = wordArray.words; | |
var sigBytes = wordArray.sigBytes; | |
// Convert | |
var hexChars = []; | |
for (var i = 0; i < sigBytes; i++) { | |
var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; | |
hexChars.push((bite >>> 4).toString(16)); | |
hexChars.push((bite & 0x0f).toString(16)); | |
} | |
return hexChars.join(''); | |
}, | |
/** | |
* Converts a hex string to a word array. | |
* | |
* @param {string} hexStr The hex string. | |
* | |
* @return {WordArray} The word array. | |
* | |
* @static | |
* | |
* @example | |
* | |
* var wordArray = CryptoJS.enc.Hex.parse(hexString); | |
*/ | |
parse: function (hexStr) { | |
// Shortcut | |
var hexStrLength = hexStr.length; | |
// Convert | |
var words = []; | |
for (var i = 0; i < hexStrLength; i += 2) { | |
words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4); | |
} | |
return new WordArray.init(words, hexStrLength / 2); | |
} | |
}; | |
/** | |
* Latin1 encoding strategy. | |
*/ | |
var Latin1 = C_enc.Latin1 = { | |
/** | |
* Converts a word array to a Latin1 string. | |
* | |
* @param {WordArray} wordArray The word array. | |
* | |
* @return {string} The Latin1 string. | |
* | |
* @static | |
* | |
* @example | |
* | |
* var latin1String = CryptoJS.enc.Latin1.stringify(wordArray); | |
*/ | |
stringify: function (wordArray) { | |
// Shortcuts | |
var words = wordArray.words; | |
var sigBytes = wordArray.sigBytes; | |
// Convert | |
var latin1Chars = []; | |
for (var i = 0; i < sigBytes; i++) { | |
var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; | |
latin1Chars.push(String.fromCharCode(bite)); | |
} | |
return latin1Chars.join(''); | |
}, | |
/** | |
* Converts a Latin1 string to a word array. | |
* | |
* @param {string} latin1Str The Latin1 string. | |
* | |
* @return {WordArray} The word array. | |
* | |
* @static | |
* | |
* @example | |
* | |
* var wordArray = CryptoJS.enc.Latin1.parse(latin1String); | |
*/ | |
parse: function (latin1Str) { | |
// Shortcut | |
var latin1StrLength = latin1Str.length; | |
// Convert | |
var words = []; | |
for (var i = 0; i < latin1StrLength; i++) { | |
words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8); | |
} | |
return new WordArray.init(words, latin1StrLength); | |
} | |
}; | |
/** | |
* UTF-8 encoding strategy. | |
*/ | |
var Utf8 = C_enc.Utf8 = { | |
/** | |
* Converts a word array to a UTF-8 string. | |
* | |
* @param {WordArray} wordArray The word array. | |
* | |
* @return {string} The UTF-8 string. | |
* | |
* @static | |
* | |
* @example | |
* | |
* var utf8String = CryptoJS.enc.Utf8.stringify(wordArray); | |
*/ | |
stringify: function (wordArray) { | |
try { | |
return decodeURIComponent(escape(Latin1.stringify(wordArray))); | |
} catch (e) { | |
throw new Error('Malformed UTF-8 data'); | |
} | |
}, | |
/** | |
* Converts a UTF-8 string to a word array. | |
* | |
* @param {string} utf8Str The UTF-8 string. | |
* | |
* @return {WordArray} The word array. | |
* | |
* @static | |
* | |
* @example | |
* | |
* var wordArray = CryptoJS.enc.Utf8.parse(utf8String); | |
*/ | |
parse: function (utf8Str) { | |
return Latin1.parse(unescape(encodeURIComponent(utf8Str))); | |
} | |
}; | |
/** | |
* Abstract buffered block algorithm template. | |
* | |
* The property blockSize must be implemented in a concrete subtype. | |
* | |
* @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0 | |
*/ | |
var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({ | |
/** | |
* Resets this block algorithm's data buffer to its initial state. | |
* | |
* @example | |
* | |
* bufferedBlockAlgorithm.reset(); | |
*/ | |
reset: function () { | |
// Initial values | |
this._data = new WordArray.init(); | |
this._nDataBytes = 0; | |
}, | |
/** | |
* Adds new data to this block algorithm's buffer. | |
* | |
* @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8. | |
* | |
* @example | |
* | |
* bufferedBlockAlgorithm._append('data'); | |
* bufferedBlockAlgorithm._append(wordArray); | |
*/ | |
_append: function (data) { | |
// Convert string to WordArray, else assume WordArray already | |
if (typeof data == 'string') { | |
data = Utf8.parse(data); | |
} | |
// Append | |
this._data.concat(data); | |
this._nDataBytes += data.sigBytes; | |
}, | |
/** | |
* Processes available data blocks. | |
* | |
* This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype. | |
* | |
* @param {boolean} doFlush Whether all blocks and partial blocks should be processed. | |
* | |
* @return {WordArray} The processed data. | |
* | |
* @example | |
* | |
* var processedData = bufferedBlockAlgorithm._process(); | |
* var processedData = bufferedBlockAlgorithm._process(!!'flush'); | |
*/ | |
_process: function (doFlush) { | |
var processedWords; | |
// Shortcuts | |
var data = this._data; | |
var dataWords = data.words; | |
var dataSigBytes = data.sigBytes; | |
var blockSize = this.blockSize; | |
var blockSizeBytes = blockSize * 4; | |
// Count blocks ready | |
var nBlocksReady = dataSigBytes / blockSizeBytes; | |
if (doFlush) { | |
// Round up to include partial blocks | |
nBlocksReady = Math.ceil(nBlocksReady); | |
} else { | |
// Round down to include only full blocks, | |
// less the number of blocks that must remain in the buffer | |
nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0); | |
} | |
// Count words ready | |
var nWordsReady = nBlocksReady * blockSize; | |
// Count bytes ready | |
var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes); | |
// Process blocks | |
if (nWordsReady) { | |
for (var offset = 0; offset < nWordsReady; offset += blockSize) { | |
// Perform concrete-algorithm logic | |
this._doProcessBlock(dataWords, offset); | |
} | |
// Remove processed words | |
processedWords = dataWords.splice(0, nWordsReady); | |
data.sigBytes -= nBytesReady; | |
} | |
// Return processed words | |
return new WordArray.init(processedWords, nBytesReady); | |
}, | |
/** | |
* Creates a copy of this object. | |
* | |
* @return {Object} The clone. | |
* | |
* @example | |
* | |
* var clone = bufferedBlockAlgorithm.clone(); | |
*/ | |
clone: function () { | |
var clone = Base.clone.call(this); | |
clone._data = this._data.clone(); | |
return clone; | |
}, | |
_minBufferSize: 0 | |
}); | |
/** | |
* Abstract hasher template. | |
* | |
* @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits) | |
*/ | |
C_lib.Hasher = BufferedBlockAlgorithm.extend({ | |
/** | |
* Configuration options. | |
*/ | |
cfg: Base.extend(), | |
/** | |
* Initializes a newly created hasher. | |
* | |
* @param {Object} cfg (Optional) The configuration options to use for this hash computation. | |
* | |
* @example | |
* | |
* var hasher = CryptoJS.algo.SHA256.create(); | |
*/ | |
init: function (cfg) { | |
// Apply config defaults | |
this.cfg = this.cfg.extend(cfg); | |
// Set initial values | |
this.reset(); | |
}, | |
/** | |
* Resets this hasher to its initial state. | |
* | |
* @example | |
* | |
* hasher.reset(); | |
*/ | |
reset: function () { | |
// Reset data buffer | |
BufferedBlockAlgorithm.reset.call(this); | |
// Perform concrete-hasher logic | |
this._doReset(); | |
}, | |
/** | |
* Updates this hasher with a message. | |
* | |
* @param {WordArray|string} messageUpdate The message to append. | |
* | |
* @return {Hasher} This hasher. | |
* | |
* @example | |
* | |
* hasher.update('message'); | |
* hasher.update(wordArray); | |
*/ | |
update: function (messageUpdate) { | |
// Append | |
this._append(messageUpdate); | |
// Update the hash | |
this._process(); | |
// Chainable | |
return this; | |
}, | |
/** | |
* Finalizes the hash computation. | |
* Note that the finalize operation is effectively a destructive, read-once operation. | |
* | |
* @param {WordArray|string} messageUpdate (Optional) A final message update. | |
* | |
* @return {WordArray} The hash. | |
* | |
* @example | |
* | |
* var hash = hasher.finalize(); | |
* var hash = hasher.finalize('message'); | |
* var hash = hasher.finalize(wordArray); | |
*/ | |
finalize: function (messageUpdate) { | |
// Final message update | |
if (messageUpdate) { | |
this._append(messageUpdate); | |
} | |
// Perform concrete-hasher logic | |
var hash = this._doFinalize(); | |
return hash; | |
}, | |
blockSize: 512/32, | |
/** | |
* Creates a shortcut function to a hasher's object interface. | |
* | |
* @param {Hasher} hasher The hasher to create a helper for. | |
* | |
* @return {Function} The shortcut function. | |
* | |
* @static | |
* | |
* @example | |
* | |
* var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256); | |
*/ | |
_createHelper: function (hasher) { | |
return function (message, cfg) { | |
return new hasher.init(cfg).finalize(message); | |
}; | |
}, | |
/** | |
* Creates a shortcut function to the HMAC's object interface. | |
* | |
* @param {Hasher} hasher The hasher to use in this HMAC helper. | |
* | |
* @return {Function} The shortcut function. | |
* | |
* @static | |
* | |
* @example | |
* | |
* var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256); | |
*/ | |
_createHmacHelper: function (hasher) { | |
return function (message, key) { | |
return new C_algo.HMAC.init(hasher, key).finalize(message); | |
}; | |
} | |
}); | |
/** | |
* Algorithm namespace. | |
*/ | |
var C_algo = C.algo = {}; | |
return C; | |
}(Math)); | |
return CryptoJS; | |
})); | |
}); | |
var sha256 = createCommonjsModule(function (module, exports) { | |
(function (root, factory) { | |
{ | |
// CommonJS | |
module.exports = factory(core); | |
} | |
}(commonjsGlobal, function (CryptoJS) { | |
(function (Math) { | |
// Shortcuts | |
var C = CryptoJS; | |
var C_lib = C.lib; | |
var WordArray = C_lib.WordArray; | |
var Hasher = C_lib.Hasher; | |
var C_algo = C.algo; | |
// Initialization and round constants tables | |
var H = []; | |
var K = []; | |
// Compute constants | |
(function () { | |
function isPrime(n) { | |
var sqrtN = Math.sqrt(n); | |
for (var factor = 2; factor <= sqrtN; factor++) { | |
if (!(n % factor)) { | |
return false; | |
} | |
} | |
return true; | |
} | |
function getFractionalBits(n) { | |
return ((n - (n | 0)) * 0x100000000) | 0; | |
} | |
var n = 2; | |
var nPrime = 0; | |
while (nPrime < 64) { | |
if (isPrime(n)) { | |
if (nPrime < 8) { | |
H[nPrime] = getFractionalBits(Math.pow(n, 1 / 2)); | |
} | |
K[nPrime] = getFractionalBits(Math.pow(n, 1 / 3)); | |
nPrime++; | |
} | |
n++; | |
} | |
}()); | |
// Reusable object | |
var W = []; | |
/** | |
* SHA-256 hash algorithm. | |
*/ | |
var SHA256 = C_algo.SHA256 = Hasher.extend({ | |
_doReset: function () { | |
this._hash = new WordArray.init(H.slice(0)); | |
}, | |
_doProcessBlock: function (M, offset) { | |
// Shortcut | |
var H = this._hash.words; | |
// Working variables | |
var a = H[0]; | |
var b = H[1]; | |
var c = H[2]; | |
var d = H[3]; | |
var e = H[4]; | |
var f = H[5]; | |
var g = H[6]; | |
var h = H[7]; | |
// Computation | |
for (var i = 0; i < 64; i++) { | |
if (i < 16) { | |
W[i] = M[offset + i] | 0; | |
} else { | |
var gamma0x = W[i - 15]; | |
var gamma0 = ((gamma0x << 25) | (gamma0x >>> 7)) ^ | |
((gamma0x << 14) | (gamma0x >>> 18)) ^ | |
(gamma0x >>> 3); | |
var gamma1x = W[i - 2]; | |
var gamma1 = ((gamma1x << 15) | (gamma1x >>> 17)) ^ | |
((gamma1x << 13) | (gamma1x >>> 19)) ^ | |
(gamma1x >>> 10); | |
W[i] = gamma0 + W[i - 7] + gamma1 + W[i - 16]; | |
} | |
var ch = (e & f) ^ (~e & g); | |
var maj = (a & b) ^ (a & c) ^ (b & c); | |
var sigma0 = ((a << 30) | (a >>> 2)) ^ ((a << 19) | (a >>> 13)) ^ ((a << 10) | (a >>> 22)); | |
var sigma1 = ((e << 26) | (e >>> 6)) ^ ((e << 21) | (e >>> 11)) ^ ((e << 7) | (e >>> 25)); | |
var t1 = h + sigma1 + ch + K[i] + W[i]; | |
var t2 = sigma0 + maj; | |
h = g; | |
g = f; | |
f = e; | |
e = (d + t1) | 0; | |
d = c; | |
c = b; | |
b = a; | |
a = (t1 + t2) | 0; | |
} | |
// Intermediate hash value | |
H[0] = (H[0] + a) | 0; | |
H[1] = (H[1] + b) | 0; | |
H[2] = (H[2] + c) | 0; | |
H[3] = (H[3] + d) | 0; | |
H[4] = (H[4] + e) | 0; | |
H[5] = (H[5] + f) | 0; | |
H[6] = (H[6] + g) | 0; | |
H[7] = (H[7] + h) | 0; | |
}, | |
_doFinalize: function () { | |
// Shortcuts | |
var data = this._data; | |
var dataWords = data.words; | |
var nBitsTotal = this._nDataBytes * 8; | |
var nBitsLeft = data.sigBytes * 8; | |
// Add padding | |
dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32); | |
dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = Math.floor(nBitsTotal / 0x100000000); | |
dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = nBitsTotal; | |
data.sigBytes = dataWords.length * 4; | |
// Hash final blocks | |
this._process(); | |
// Return final computed hash | |
return this._hash; | |
}, | |
clone: function () { | |
var clone = Hasher.clone.call(this); | |
clone._hash = this._hash.clone(); | |
return clone; | |
} | |
}); | |
/** | |
* Shortcut function to the hasher's object interface. | |
* | |
* @param {WordArray|string} message The message to hash. | |
* | |
* @return {WordArray} The hash. | |
* | |
* @static | |
* | |
* @example | |
* | |
* var hash = CryptoJS.SHA256('message'); | |
* var hash = CryptoJS.SHA256(wordArray); | |
*/ | |
C.SHA256 = Hasher._createHelper(SHA256); | |
/** | |
* Shortcut function to the HMAC's object interface. | |
* | |
* @param {WordArray|string} message The message to hash. | |
* @param {WordArray|string} key The secret key. | |
* | |
* @return {WordArray} The HMAC. | |
* | |
* @static | |
* | |
* @example | |
* | |
* var hmac = CryptoJS.HmacSHA256(message, key); | |
*/ | |
C.HmacSHA256 = Hasher._createHmacHelper(SHA256); | |
}(Math)); | |
return CryptoJS.SHA256; | |
})); | |
}); | |
var encBase64 = createCommonjsModule(function (module, exports) { | |
(function (root, factory) { | |
{ | |
// CommonJS | |
module.exports = factory(core); | |
} | |
}(commonjsGlobal, function (CryptoJS) { | |
(function () { | |
// Shortcuts | |
var C = CryptoJS; | |
var C_lib = C.lib; | |
var WordArray = C_lib.WordArray; | |
var C_enc = C.enc; | |
/** | |
* Base64 encoding strategy. | |
*/ | |
C_enc.Base64 = { | |
/** | |
* Converts a word array to a Base64 string. | |
* | |
* @param {WordArray} wordArray The word array. | |
* | |
* @return {string} The Base64 string. | |
* | |
* @static | |
* | |
* @example | |
* | |
* var base64String = CryptoJS.enc.Base64.stringify(wordArray); | |
*/ | |
stringify: function (wordArray) { | |
// Shortcuts | |
var words = wordArray.words; | |
var sigBytes = wordArray.sigBytes; | |
var map = this._map; | |
// Clamp excess bits | |
wordArray.clamp(); | |
// Convert | |
var base64Chars = []; | |
for (var i = 0; i < sigBytes; i += 3) { | |
var byte1 = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff; | |
var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; | |
var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; | |
var triplet = (byte1 << 16) | (byte2 << 8) | byte3; | |
for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) { | |
base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); | |
} | |
} | |
// Add padding | |
var paddingChar = map.charAt(64); | |
if (paddingChar) { | |
while (base64Chars.length % 4) { | |
base64Chars.push(paddingChar); | |
} | |
} | |
return base64Chars.join(''); | |
}, | |
/** | |
* Converts a Base64 string to a word array. | |
* | |
* @param {string} base64Str The Base64 string. | |
* | |
* @return {WordArray} The word array. | |
* | |
* @static | |
* | |
* @example | |
* | |
* var wordArray = CryptoJS.enc.Base64.parse(base64String); | |
*/ | |
parse: function (base64Str) { | |
// Shortcuts | |
var base64StrLength = base64Str.length; | |
var map = this._map; | |
var reverseMap = this._reverseMap; | |
if (!reverseMap) { | |
reverseMap = this._reverseMap = []; | |
for (var j = 0; j < map.length; j++) { | |
reverseMap[map.charCodeAt(j)] = j; | |
} | |
} | |
// Ignore padding | |
var paddingChar = map.charAt(64); | |
if (paddingChar) { | |
var paddingIndex = base64Str.indexOf(paddingChar); | |
if (paddingIndex !== -1) { | |
base64StrLength = paddingIndex; | |
} | |
} | |
// Convert | |
return parseLoop(base64Str, base64StrLength, reverseMap); | |
}, | |
_map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' | |
}; | |
function parseLoop(base64Str, base64StrLength, reverseMap) { | |
var words = []; | |
var nBytes = 0; | |
for (var i = 0; i < base64StrLength; i++) { | |
if (i % 4) { | |
var bits1 = reverseMap[base64Str.charCodeAt(i - 1)] << ((i % 4) * 2); | |
var bits2 = reverseMap[base64Str.charCodeAt(i)] >>> (6 - (i % 4) * 2); | |
var bitsCombined = bits1 | bits2; | |
words[nBytes >>> 2] |= bitsCombined << (24 - (nBytes % 4) * 8); | |
nBytes++; | |
} | |
} | |
return WordArray.create(words, nBytes); | |
} | |
}()); | |
return CryptoJS.enc.Base64; | |
})); | |
}); | |
/** | |
* SHA256 Hashing. | |
* | |
* @param {string} [salt=''] salt. | |
* @param {string} [challenge=''] challenge. | |
* @param {string} msg Message to encode. | |
* @returns {string} sha256 encoded string. | |
*/ | |
function authenticationHashing (salt, challenge, msg) { | |
var hash = encBase64.stringify(sha256(msg + salt)); | |
return encBase64.stringify(sha256(hash + challenge)); | |
} | |
var _excluded = ["authentication", "rpcVersion"]; | |
function _catch(body, recover) { | |
try { | |
var result = body(); | |
} catch (e) { | |
return recover(e); | |
} | |
if (result && result.then) { | |
return result.then(void 0, recover); | |
} | |
return result; | |
} | |
var debug = browser$1('obs-websocket-js'); | |
var OBSWebSocketError = /*#__PURE__*/function (_Error) { | |
_inheritsLoose(OBSWebSocketError, _Error); | |
function OBSWebSocketError(code, message) { | |
var _this; | |
_this = _Error.call(this, message) || this; | |
_this.code = void 0; | |
_this.code = code; | |
return _this; | |
} | |
return OBSWebSocketError; | |
}( /*#__PURE__*/_wrapNativeSuper(Error)); | |
var BaseOBSWebSocket = /*#__PURE__*/function (_EventEmitter) { | |
_inheritsLoose(BaseOBSWebSocket, _EventEmitter); | |
function BaseOBSWebSocket() { | |
var _this2; | |
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | |
args[_key] = arguments[_key]; | |
} | |
_this2 = _EventEmitter.call.apply(_EventEmitter, [this].concat(args)) || this; | |
_this2._identified = false; | |
_this2.internalListeners = new eventemitter3(); | |
_this2.socket = void 0; | |
return _this2; | |
} | |
BaseOBSWebSocket.generateMessageId = function generateMessageId() { | |
return String(BaseOBSWebSocket.requestCounter++); | |
}; | |
var _proto = BaseOBSWebSocket.prototype; | |
/** | |
* Connect to an obs-websocket server | |
* | |
* @param url Websocket server to connect to (including ws:// or wss:// protocol) | |
* @param password Password | |
* @param identificationParams Data for Identify event | |
* @returns Hello & Identified messages data (combined) | |
*/ | |
_proto.connect = function connect(url, password, identificationParams) { | |
if (url === void 0) { | |
url = 'ws://127.0.0.1:4455'; | |
} | |
if (identificationParams === void 0) { | |
identificationParams = {}; | |
} | |
try { | |
var _temp3 = function _temp3() { | |
return _catch(function () { | |
var connectionClosedPromise = _this4.internalEventPromise('ConnectionClosed'); | |
var connectionErrorPromise = _this4.internalEventPromise('ConnectionError'); | |
return Promise.resolve(Promise.race([function () { | |
try { | |
return Promise.resolve(_this4.createConnection(url)).then(function (hello) { | |
_this4.emit('Hello', hello); | |
return _this4.identify(hello, password, identificationParams); | |
}); | |
} catch (e) { | |
return Promise.reject(e); | |
} | |
}(), // Choose the best promise for connection error/close | |
// In browser connection close has close code + reason, | |
// while in node error event has these | |
new Promise(function (resolve, reject) { | |
void connectionErrorPromise.then(function (e) { | |
if (e.message) { | |
reject(e); | |
} | |
}); | |
void connectionClosedPromise.then(function (e) { | |
reject(e); | |
}); | |
})])); | |
}, function (error) { | |
return Promise.resolve(_this4.disconnect()).then(function () { | |
throw error; | |
}); | |
}); | |
}; | |
var _this4 = this; | |
var _temp4 = function () { | |
if (_this4.socket) { | |
return Promise.resolve(_this4.disconnect()).then(function () {}); | |
} | |
}(); | |
return Promise.resolve(_temp4 && _temp4.then ? _temp4.then(_temp3) : _temp3(_temp4)); | |
} catch (e) { | |
return Promise.reject(e); | |
} | |
} | |
/** | |
* Disconnect from obs-websocket server | |
*/ | |
; | |
_proto.disconnect = function disconnect() { | |
try { | |
var _this6 = this; | |
if (!_this6.socket || _this6.socket.readyState === browser.CLOSED) { | |
return Promise.resolve(); | |
} | |
var connectionClosedPromise = _this6.internalEventPromise('ConnectionClosed'); | |
_this6.socket.close(); | |
return Promise.resolve(connectionClosedPromise).then(function () {}); | |
} catch (e) { | |
return Promise.reject(e); | |
} | |
} | |
/** | |
* Update session parameters | |
* | |
* @param data Reidentify data | |
* @returns Identified message data | |
*/ | |
; | |
_proto.reidentify = function reidentify(data) { | |
try { | |
var _this8 = this; | |
var identifiedPromise = _this8.internalEventPromise("op:" + WebSocketOpCode.Identified); | |
return Promise.resolve(_this8.message(WebSocketOpCode.Reidentify, data)).then(function () { | |
return identifiedPromise; | |
}); | |
} catch (e) { | |
return Promise.reject(e); | |
} | |
} | |
/** | |
* Send a request to obs-websocket | |
* | |
* @param requestType Request name | |
* @param requestData Request data | |
* @returns Request response | |
*/ | |
; | |
_proto.call = function call(requestType, requestData) { | |
try { | |
var _this10 = this; | |
var requestId = BaseOBSWebSocket.generateMessageId(); | |
var responsePromise = _this10.internalEventPromise("res:" + requestId); | |
return Promise.resolve(_this10.message(WebSocketOpCode.Request, { | |
requestId: requestId, | |
requestType: requestType, | |
requestData: requestData | |
})).then(function () { | |
return Promise.resolve(responsePromise).then(function (_ref) { | |
var requestStatus = _ref.requestStatus, | |
responseData = _ref.responseData; | |
if (!requestStatus.result) { | |
throw new OBSWebSocketError(requestStatus.code, requestStatus.comment); | |
} | |
return responseData; | |
}); | |
}); | |
} catch (e) { | |
return Promise.reject(e); | |
} | |
} | |
/** | |
* Send a batch request to obs-websocket | |
* | |
* @param requests Array of Request objects (type and data) | |
* @param options A set of options for how the batch will be executed | |
* @param options.executionType The mode of execution obs-websocket will run the batch in | |
* @param options.haltOnFailure Whether obs-websocket should stop executing the batch if one request fails | |
* @returns RequestBatch response | |
*/ | |
; | |
_proto.callBatch = function callBatch(requests, options) { | |
if (options === void 0) { | |
options = {}; | |
} | |
try { | |
var _this12 = this; | |
var requestId = BaseOBSWebSocket.generateMessageId(); | |
var responsePromise = _this12.internalEventPromise("res:" + requestId); | |
return Promise.resolve(_this12.message(WebSocketOpCode.RequestBatch, _extends({ | |
requestId: requestId, | |
requests: requests | |
}, options))).then(function () { | |
return Promise.resolve(responsePromise).then(function (_ref2) { | |
var results = _ref2.results; | |
return results; | |
}); | |
}); | |
} catch (e) { | |
return Promise.reject(e); | |
} | |
} | |
/** | |
* Cleanup from socket disconnection | |
*/ | |
; | |
_proto.cleanup = function cleanup() { | |
if (!this.socket) { | |
return; | |
} | |
this.socket.onopen = null; | |
this.socket.onmessage = null; | |
this.socket.onerror = null; | |
this.socket.onclose = null; | |
this.socket = undefined; | |
this._identified = false; // Cleanup leftovers | |
this.internalListeners.removeAllListeners(); | |
} | |
/** | |
* Create connection to specified obs-websocket server | |
* | |
* @private | |
* @param url Websocket address | |
* @returns Promise for hello data | |
*/ | |
; | |
_proto.createConnection = function createConnection(url) { | |
try { | |
var _this14 = this; | |
var connectionOpenedPromise = _this14.internalEventPromise('ConnectionOpened'); | |
var helloPromise = _this14.internalEventPromise("op:" + WebSocketOpCode.Hello); | |
_this14.socket = new browser(url, _this14.protocol); | |
_this14.socket.onopen = _this14.onOpen.bind(_this14); | |
_this14.socket.onmessage = _this14.onMessage.bind(_this14); | |
_this14.socket.onerror = _this14.onError.bind(_this14); | |
_this14.socket.onclose = _this14.onClose.bind(_this14); | |
return Promise.resolve(connectionOpenedPromise).then(function () { | |
var _this14$socket; | |
var protocol = (_this14$socket = _this14.socket) == null ? void 0 : _this14$socket.protocol; // Browsers don't autoclose on missing/wrong protocol | |
if (!protocol) { | |
throw new OBSWebSocketError(-1, 'Server sent no subprotocol'); | |
} | |
if (protocol !== _this14.protocol) { | |
throw new OBSWebSocketError(-1, 'Server sent an invalid subprotocol'); | |
} | |
return helloPromise; | |
}); | |
} catch (e) { | |
return Promise.reject(e); | |
} | |
} | |
/** | |
* Send identify message | |
* | |
* @private | |
* @param hello Hello message data | |
* @param password Password | |
* @param identificationParams Identification params | |
* @returns Hello & Identified messages data (combined) | |
*/ | |
; | |
_proto.identify = function identify(_ref3, password, identificationParams) { | |
var authentication = _ref3.authentication, | |
rpcVersion = _ref3.rpcVersion, | |
helloRest = _objectWithoutPropertiesLoose(_ref3, _excluded); | |
if (identificationParams === void 0) { | |
identificationParams = {}; | |
} | |
try { | |
var _this16 = this; | |
// Set rpcVersion if unset | |
var data = _extends({ | |
rpcVersion: rpcVersion | |
}, identificationParams); | |
if (authentication && password) { | |
data.authentication = authenticationHashing(authentication.salt, authentication.challenge, password); | |
} | |
var identifiedPromise = _this16.internalEventPromise("op:" + WebSocketOpCode.Identified); | |
return Promise.resolve(_this16.message(WebSocketOpCode.Identify, data)).then(function () { | |
return Promise.resolve(identifiedPromise).then(function (identified) { | |
_this16._identified = true; | |
_this16.emit('Identified', identified); | |
return _extends({ | |
rpcVersion: rpcVersion | |
}, helloRest, identified); | |
}); | |
}); | |
} catch (e) { | |
return Promise.reject(e); | |
} | |
} | |
/** | |
* Send message to obs-websocket | |
* | |
* @private | |
* @param op WebSocketOpCode | |
* @param d Message data | |
*/ | |
; | |
_proto.message = function message(op, d) { | |
try { | |
var _this18 = this; | |
if (!_this18.socket) { | |
throw new Error('Not connected'); | |
} | |
if (!_this18.identified && op !== 1) { | |
throw new Error('Socket not identified'); | |
} | |
return Promise.resolve(_this18.encodeMessage({ | |
op: op, | |
d: d | |
})).then(function (encoded) { | |
_this18.socket.send(encoded); | |
}); | |
} catch (e) { | |
return Promise.reject(e); | |
} | |
} | |
/** | |
* Create a promise to listen for an event on internal listener | |
* (will be cleaned up on disconnect) | |
* | |
* @private | |
* @param event Event to listen to | |
* @returns Event data | |
*/ | |
; | |
_proto.internalEventPromise = function internalEventPromise(event) { | |
try { | |
var _this20 = this; | |
return Promise.resolve(new Promise(function (resolve) { | |
_this20.internalListeners.once(event, resolve); | |
})); | |
} catch (e) { | |
return Promise.reject(e); | |
} | |
} | |
/** | |
* Websocket open event listener | |
* | |
* @private | |
* @param e Event | |
*/ | |
; | |
_proto.onOpen = function onOpen(e) { | |
debug('socket.open'); | |
this.emit('ConnectionOpened'); | |
this.internalListeners.emit('ConnectionOpened', e); | |
} | |
/** | |
* Websocket message event listener | |
* | |
* @private | |
* @param e Event | |
*/ | |
; | |
_proto.onMessage = function onMessage(e) { | |
try { | |
var _this22 = this; | |
return Promise.resolve(_catch(function () { | |
return Promise.resolve(_this22.decodeMessage(e.data)).then(function (_ref4) { | |
var op = _ref4.op, | |
d = _ref4.d; | |
debug('socket.message: %d %j', op, d); | |
if (op === undefined || d === undefined) { | |
return; | |
} | |
switch (op) { | |
case WebSocketOpCode.Event: | |
{ | |
var eventType = d.eventType, | |
eventData = d.eventData; // @ts-expect-error Typescript just doesn't understand it | |
_this22.emit(eventType, eventData); | |
return; | |
} | |
case WebSocketOpCode.RequestResponse: | |
case WebSocketOpCode.RequestBatchResponse: | |
{ | |
var requestId = d.requestId; | |
_this22.internalListeners.emit("res:" + requestId, d); | |
return; | |
} | |
default: | |
_this22.internalListeners.emit("op:" + op, d); | |
} | |
}); | |
}, function (error) { | |
debug('error handling message: %o', error); | |
})); | |
} catch (e) { | |
return Promise.reject(e); | |
} | |
} | |
/** | |
* Websocket error event listener | |
* | |
* @private | |
* @param e ErrorEvent | |
*/ | |
; | |
_proto.onError = function onError(e) { | |
debug('socket.error: %o', e); | |
var error = new OBSWebSocketError(-1, e.message); | |
this.emit('ConnectionError', error); | |
this.internalListeners.emit('ConnectionError', error); | |
} | |
/** | |
* Websocket close event listener | |
* | |
* @private | |
* @param e Event | |
*/ | |
; | |
_proto.onClose = function onClose(e) { | |
debug('socket.close: %s (%d)', e.reason, e.code); | |
var error = new OBSWebSocketError(e.code, e.reason); | |
this.emit('ConnectionClosed', error); | |
this.internalListeners.emit('ConnectionClosed', error); | |
this.cleanup(); | |
}; | |
_createClass(BaseOBSWebSocket, [{ | |
key: "identified", | |
get: function get() { | |
return this._identified; | |
} | |
}]); | |
return BaseOBSWebSocket; | |
}(eventemitter3); // https://github.com/developit/microbundle/issues/531#issuecomment-575473024 | |
// Not using ESM export due to it also being detected and breaking rollup based bundlers (vite) | |
BaseOBSWebSocket.requestCounter = 1; | |
if (typeof exports !== 'undefined') { | |
Object.defineProperty(exports, '__esModule', { | |
value: true | |
}); | |
} | |
var OBSWebSocket$1 = /*#__PURE__*/function (_BaseOBSWebSocket) { | |
_inheritsLoose(OBSWebSocket, _BaseOBSWebSocket); | |
function OBSWebSocket() { | |
var _this; | |
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { | |
args[_key] = arguments[_key]; | |
} | |
_this = _BaseOBSWebSocket.call.apply(_BaseOBSWebSocket, [this].concat(args)) || this; | |
_this.protocol = 'obswebsocket.json'; | |
return _this; | |
} | |
var _proto = OBSWebSocket.prototype; | |
_proto.encodeMessage = function encodeMessage(data) { | |
try { | |
return Promise.resolve(JSON.stringify(data)); | |
} catch (e) { | |
return Promise.reject(e); | |
} | |
}; | |
_proto.decodeMessage = function decodeMessage(data) { | |
try { | |
return Promise.resolve(JSON.parse(data)); | |
} catch (e) { | |
return Promise.reject(e); | |
} | |
}; | |
return OBSWebSocket; | |
}(BaseOBSWebSocket); | |
var OBSWebSocket = /*#__PURE__*/function (_JSONOBSWebSocket) { | |
_inheritsLoose(OBSWebSocket, _JSONOBSWebSocket); | |
function OBSWebSocket() { | |
return _JSONOBSWebSocket.apply(this, arguments) || this; | |
} | |
return OBSWebSocket; | |
}(OBSWebSocket$1); | |
OBSWebSocket.OBSWebSocketError = OBSWebSocketError; | |
OBSWebSocket.WebSocketOpCode = WebSocketOpCode; | |
OBSWebSocket.EventSubscription = EventSubscription; | |
OBSWebSocket.RequestBatchExecutionType = RequestBatchExecutionType; | |
return OBSWebSocket; | |
})(); | |
//# sourceMappingURL=obs-ws.js.map |
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
const { contextBridge, ipcRenderer } = require('electron'); | |
window.addEventListener('DOMContentLoaded', () => { | |
if (window.trustedTypes && window.trustedTypes.createPolicy) { | |
window.trustedTypes.createPolicy('default', { | |
createHTML: (string) => string, | |
createScriptURL: string => string, // warning: this is unsafe! | |
createScript: string => string // warning: this is unsafe! | |
}); | |
} | |
setTimeout(setup, 100); | |
setInterval(deleteBG, 500); | |
keySim("83"); | |
ipcRenderer.on('next-slide', (_event) => { | |
console.log("next slide message received") | |
keySim(39); | |
}) | |
ipcRenderer.on('previous-slide', (_event) => { | |
console.log("next slide message received") | |
keySim(37); | |
}) | |
}) | |
function keySim(k){ | |
document.dispatchEvent( | |
new KeyboardEvent("keydown", { | |
keyCode: k | |
}) | |
); | |
} | |
function setup() { | |
const style = document.createElement('style'); | |
style.innerHTML = ` | |
html { | |
background-color: rgba(0,0,0,0) !important; | |
} | |
body { | |
background-color: rgba(0,0,0,0) !important; | |
} | |
.punch-viewer-content { | |
background: #0000; | |
} | |
:fullscreen { | |
background: #0000; | |
} | |
:fullscreen::backdrop { | |
background: #0000; | |
} | |
`; | |
window.document.body.append(style); | |
} | |
function deleteBG() { | |
const elem = document.querySelectorAll('path[fill="#abcdef"]')[0] | |
if(elem){ | |
console.log(elem) | |
elem.previousElementSibling.remove(); | |
elem.remove(); | |
} | |
} |
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
html, body { | |
margin: 0; | |
padding: 0; | |
} | |
canvas { | |
display: block; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment