Skip to content
Snippets Groups Projects
bbb.js 6.48 KiB
Newer Older
const puppeteer = require("puppeteer");
const sleep = require("sleep-promise");

module.exports.createFreshPage = async function createFreshPage() {
  const browser = await puppeteer.launch({
Jonas Zohren's avatar
Jonas Zohren committed
    headless: true,
    defaultViewport: {
      width: 1200,
      height: 600,
      isLandscape: true,
    },
  });
  const context = await browser.createIncognitoBrowserContext();
  return context.newPage();
};

module.exports.joinRoom = async function joinRoom(
  page,
  roomUrl,
  displayName = "Puppet"
) {
  await page.goto(roomUrl);
  console.log("joinRoom > Gone to start page for", roomUrl);

  try {
    // Set displayname for program
    await page.type("input.join-form", displayName);
  } catch (error) {
    console.warn("Could not set displayname, probably signed in.");
  try {
    // Join and load room
    await page.click("button#room-join");
  } catch (error) {
    try {
      await page.click('input[value="Join"]');
Jonas Zohren's avatar
Jonas Zohren committed
    } catch (error2) {
      try {
        await page.click('input[value="Start"]');
      } catch (error3) {
        try {
          await page.click('input[value="Starten"]');
        } catch (error4) {
          await page.click('input[value="Teilnehmen"]');
        }
      }

  const dismissButton = await page.waitForSelector(
    'button[aria-describedBy="modalDismissDescription"]'
  );
  console.log("joinRoom > Joined room");
  // Click audio choice panel away
  await dismissButton.click();

  console.log("joinRoom > clicked audio choice away.");
  return page;
};

module.exports.sendChatMessage = async function sendChatMessage(
  page,
  messageText
) {
  const chatInputHandle = await page.$("textarea#message-input");
  const chatSendButtonHandle = await page.$(
    'form > div > button[type="submit"]'
  );

  // Send a text message
  await chatInputHandle.type(messageText);
  await chatSendButtonHandle.click();
  console.log("sendChatMessage > sent Message");
};

module.exports.signIn = async function signIn(
  bbbUrl,
  username,
  password,
  page = null
) {
  // Create page if not done already
  if (page === null) {
    page = await createFreshPage();
  }

  await page.goto(bbbUrl);

  await page.waitForSelector("a.sign-in-button");
  const signInButton = await page.$("a.sign-in-button");
  if (signInButton === null) {
    console.log(
      "SignIn > Can't find sign-in button: User is probably already authenticated."
    );
    return page;
  }

  await page.click("a.sign-in-button");
  await page.waitForNavigation();
  console.log("SignIn > NAVIGATED TO LOGIN PAGE");

  await page.type("input#session_username", username);
  await page.type("input#session_password", password);
  await page.click("input.signin-button");
  console.log("SignIn > entered credentials");

  await page.waitForNavigation();
  console.log("SignIn > Probably logged in.");

  return page;
};

module.exports.screenShotPresentationArea = async function screenShotPresentationArea(
  authenticatedPage,
  path
) {
  const presentationAreaHandle = await authenticatedPage.$("div#container");
  presentationAreaHandle.screenshot({ path, type: "jpeg", quality: 33 });
};

module.exports.getUserCount = async function getUserCount(authenticatedPage) {
  const selector = 'div[role="complementary"] > div > div > h2';
  const h2Handle = (await authenticatedPage.$$(selector))[2];
  return h2Handle.evaluate(
    (node) => node.innerText.split("(")[1].split(")")[0]
  );
};

module.exports.getUserList = async function getUserList(authenticatedPage) {
  const users = [];

  const selector = 'div[class*="userItemContents"]';
  const userHandles = await authenticatedPage.$$(selector);
  for (const userHandle of userHandles) {
    const avatarHandle = await userHandle.$('div[class*="avatar"]');
    const classes = (await avatarHandle.evaluate((node) => node.className))
      .split(" ")
      .map((wholeClass) => wholeClass.split("--")[0])
      .filter((name) => name !== "avatar");
    const userNameHandle = await userHandle.$(
      'span[class*="userNameMain"] > span'
    );
    const userName = await userNameHandle.evaluate((node) => node.innerText);

    users.push({
      classes,
      name: userName,
    });
  }
  return users;
};

module.exports.getRoomName = async function getRoomName(authenticatedPage) {
  const roomNameHandle = await authenticatedPage.$(
    'h1[class*="presentationTitle"]'
  );
  if (roomNameHandle === null) {
    process.send({ eventName: "sessionClosed", data: null });
    await sleep(100);
    process.exit(0);
  }
  return await roomNameHandle.evaluate((node) => node.innerText);
};

module.exports.createRoom = async function createRoom(
  authenticatedPage,
  roomSettings
) {
  const pageUrl = await authenticatedPage.url();
  const urlparts = pageUrl.split("/");
  const url = urlparts[0] + "//" + urlparts[2];
  const authenticityTokenHandle = await authenticatedPage.$(
    'input[name="authenticity_token"]'
  );
  const authenticityToken = await authenticityTokenHandle.evaluate(
    (node) => node.value
  );

  await authenticatedPage.evaluate(
    async (url, authenticityToken, roomSettings) => {
      function urlencodeFormData(fd) {
        var s = "";
        function encode(s) {
          return encodeURIComponent(s).replace(/%20/g, "+");
        }
        for (var pair of fd.entries()) {
          if (typeof pair[1] == "string") {
            s += (s ? "&" : "") + encode(pair[0]) + "=" + encode(pair[1]);
          }
        }
        return s;
      }

      // Prepare form data
      const form = new FormData();
      form.set("utf8", "");
      form.set("authenticity_token", authenticityToken);
      for (const key of Object.keys(roomSettings)) {
        // Maybe fix this, because the POST format is weird
        if (typeof roomSettings[key] === "boolean") {
          form.append("room[" + key + "]", 0);
          if (roomSettings[key]) {
            form.append("room[" + key + "]", 1);
          }
        } else {
          form.set("room[" + key + "]", roomSettings[key]);
        }
      }
      form.set("room[auto_join]", "0");
      form.set("commit", "Create+Room");

      try {
        // Send request to create room
        const response = await fetch(url, {
          method: "POST",
          headers: {
            "Content-Type": "application/x-www-form-urlencoded",
          },
          redirect: "follow", // manual, *follow, error
          body: urlencodeFormData(form),
        });
        return response;
      } catch (error) {
        return error;
      }
    },
    url + "/b",
    authenticityToken,
    roomSettings
  );

  await authenticatedPage.goto(url);
};