Last active
December 31, 2023 19:02
-
-
Save r3Fuze/5551079c01b1d6e882734bc69561e904 to your computer and use it in GitHub Desktop.
Prusa Connect Live Camera
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Prusa Connect - Custom Live Camera Feed | |
// @namespace https://r3fuze.github.io | |
// @match https://connect.prusa3d.com/* | |
// @run-at document-idle | |
// @grant none | |
// @version 0.5.0 | |
// @author fz | |
// @description Replace the slow camera snapshots in Prusa Connect with a custom live camera feed by using a Raspberry Pi running μStreamer. | |
// ==/UserScript== | |
const PRINTER_GUID = "<printer guid>" | |
const CAMERA_STREAM = "<stream url>" | |
const root = document.getElementById("root") | |
const cameraContainer = document.createElement("div") | |
cameraContainer.classList.add("image-contents", "custom-camera") | |
const cameraFeed = document.createElement("img") | |
cameraFeed.src = CAMERA_STREAM | |
cameraFeed.addEventListener("error", () => { | |
console.error("Failed to load camera stream") | |
}) | |
const reloadButton = document.createElement("button") | |
reloadButton.type = "button" | |
reloadButton.title = "Reload Camera" | |
// Icon from Heroicons (https://heroicons.com/) | |
reloadButton.innerHTML = ` | |
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> | |
<path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99" /> | |
</svg> | |
` | |
const reloadButtonStyle = { | |
position: "absolute", | |
top: "0.5rem", | |
right: "0.5rem", | |
width: "1.5rem", | |
height: "1.5rem", | |
display: "flex", | |
background: "transparent", | |
border: "1px solid white", | |
borderRadius: "0.25rem", | |
padding: "0", | |
} | |
Object.assign(reloadButton.style, reloadButtonStyle) | |
reloadButton.addEventListener("click", (e) => { | |
e.stopPropagation() | |
cameraFeed.src = CAMERA_STREAM + "&t=" + Date.now() | |
}) | |
cameraContainer.appendChild(cameraFeed) | |
cameraContainer.appendChild(reloadButton) | |
const observer = new MutationObserver((mutations) => { | |
if (!location.pathname.includes(PRINTER_GUID)) { | |
return | |
} | |
mutations.forEach((mutation) => { | |
if (mutation.type === "childList") { | |
if (mutation.addedNodes.length > 0) { | |
mutation.addedNodes.forEach((node) => { | |
if (node.classList?.contains("image-contents") || node.querySelector(".image-contents")) { | |
const originalCameraContainer = document.querySelector?.(".image-contents:not(.custom-camera)") | |
if (originalCameraContainer) { | |
originalCameraContainer.parentElement.appendChild(cameraContainer) | |
originalCameraContainer.remove() | |
} | |
return | |
} | |
}) | |
} | |
} | |
}) | |
}) | |
observer.observe(root, { | |
childList: true, | |
subtree: true, | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment