production-taskbar-client / src / renderer / utils / desktopCapturer.js
desktopCapturer.js
Raw
import { ipcRenderer } from "electron";
import { once, EventEmitter } from "events";
import log from "electron-log/renderer";

const getFullscreenScreenshots = async (imageFormat = "image/jpeg") => {
  const _handleError = (e) => {
    log.error(`Screenshot error: ${JSON.stringify(e)}`);
  };

  const _handleStream = async (stream) => {
    // Create hidden video tag
    const video = document.createElement("video");
    video.style.cssText = "position:absolute;top:-10000px;left:-10000px;";
    const videoHeight = stream.getVideoTracks()[0].getSettings().height;
    const videoWidth = stream.getVideoTracks()[0].getSettings().width;

    // Set custom emitter to await once instead of callback usage
    const ee = new EventEmitter();
    let screenshot;

    // Event connected to stream
    video.onloadedmetadata = () => {
      video.style.height = `${videoHeight}"px"`;
      video.style.width = `${videoWidth}"px"`;
      video.play();

      // Create canvas
      const canvas = document.createElement("canvas");
      canvas.width = videoWidth;
      canvas.height = videoHeight;
      const ctx = canvas.getContext("2d");
      // Draw video on canvas
      ctx.drawImage(video, 0, 0, canvas.width, canvas.height);

      // Save screenshot to base64
      screenshot = canvas.toDataURL(imageFormat);
      // Remove hidden video tag
      video.remove();
      try {
        // Destroy connect to stream
        stream.getTracks()[0].stop();
      } catch (e) {
        _handleError(e);
      }

      ee.emit("metadata-loaded");
    };

    video.srcObject = stream;
    document.body.appendChild(video);
    await once(ee, "metadata-loaded");
    ee.removeAllListeners(["metadata-loaded"]);
    return screenshot;
  };

  const sources = await ipcRenderer.invoke("main", {
    event: "get-screens",
  });

  let promises = [];
  sources.forEach((source) => {
    if (source.id) {
      try {
        const promise = navigator.mediaDevices.getUserMedia({
          audio: false,
          video: {
            mandatory: {
              chromeMediaSource: "desktop",
              chromeMediaSourceId: source.id,
              minWidth: 1280,
              maxWidth: 2560,
              minHeight: 720,
              maxHeight: 1440,
            },
          },
        });
        promises.push(promise);
      } catch (e) {
        _handleError(e);
      }
    }
  });

  const streams = await Promise.all(promises);
  promises = [];

  streams.forEach((stream) => {
    promises.push(_handleStream(stream));
  });
  return Promise.all(promises);
};

export default getFullscreenScreenshots;