Epix Auto Friend

Automatically adds all the Epix friends links from the gamescom discord server

当前为 2024-08-13 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        Epix Auto Friend
// @namespace   Violentmonkey Scripts
// @match       https://discord.com/channels/574865170694799400/1259933715409145966*
// @inject-into content
// @grant       GM_addStyle
// @grant       GM_getValue
// @grant       GM_setValue
// @version     1.0
// @author      UpDownLeftDie
// @license     MIT
// @description Automatically adds all the Epix friends links from the gamescom discord server

// ==/UserScript==

let EPIX_IDS = [];
let DISCORD_TOKEN = '';
let EPIX_FRIENDS = [];

function main() {
  EPIX_FRIENDS = GM_getValue('epixFriends') || [];
  EPIX_IDS = GM_getValue('epixIds') || [];
  DISCORD_TOKEN = localStorage.getItem("token")?.replaceAll('\"', '');
  console.log({EPIX_FRIENDS, EPIX_IDS, DISCORD_TOKEN: !!DISCORD_TOKEN});

  const epixButton = document.createElement('button');
  epixButton.setAttribute('id', 'epixButton');
  epixButton.setAttribute('type', 'button');
  epixButton.innerHTML = 'Run Epix Friend Adder';
  document.querySelector('h1').appendChild(epixButton);

  document.getElementById("epixButton").addEventListener("click", handleButton, false);
}

async function handleButton(event) {
  await getEpixIds();

  const epixButton = document.getElementById('epixButton');
  epixButton.setAttribute('disabled', true);
  epixButton.innerHTML = 'Running...';


  let messages = [];
  do {
    const minId = GM_getValue('discordMinId');
    console.log({minId});
    messages = await getDiscordMessages(minId);
    const codes = getEpixCodes(messages);
    console.log({messages, codes});
    if (codes.length <= 0 && messages.length > 0) {
       GM_setValue('discordMinId', messages[messages.length - 1][0].id);
    }
    for(let i in codes) {
      const promises = EPIX_IDS.map(epixId => connectRequest(epixId, codes[i].code));
      let responses = await Promise.all(promises);
      let json = await responses[0].json();
      const status = json?.data?.status.toUpperCase();
      updateFriends(status, codes[i]);
    }
  } while(messages.length >= 25);

  epixButton.innerHTML = 'Done!';
}

async function getEpixIds() {
  return new Promise((resolve, reject) => {
    const inputValue = EPIX_IDS?.length ? EPIX_IDS.join(',') : '';
    const dialog = document.createElement('dialog');
    dialog.setAttribute('open', true);
    dialog.setAttribute('id', 'epixIdsDialog')
    dialog.innerHTML = `
      <p>Enter your Epix user id(s) (<strong>NOT the same as your invite id!</strong>)</p>
      To get this go to your <a href="https://www.gamescom.global/en/epix" target="_blank">profile</a>:
        <ol>
          <li>open dev tools</li>
          <li>refresh the page</li>
          <li>look at network requests for "user?userId=XXXXXXX"</li>
        </ol>
      <form method="dialog">
        <input id="epixIds" placeholder="b5629b160f555ab4b08ef8e49568b7dd, a49f9b160f555vd4b08ef8e49568b7a2" value="${inputValue}" />
        <button id="epixIdAddButton">START</button>
      </form>
    `;
    document.body.appendChild(dialog);
    document.getElementById("epixIdAddButton").addEventListener("click", ()=> {
      const idStr = document.getElementById("epixIds").value;
      const ids = idStr.split(',').reduce((acc, curr) => {
        const id = curr.replace(/\W/gi, '');
        if (!id) return acc;
        acc.push(id);
        return acc;
      }, []);
      EPIX_IDS = ids;
      GM_setValue('epixIds', EPIX_IDS);
      dialog.parentNode.removeChild(dialog);
      resolve();
    }, false);
  });
}

function getEpixCodes(discordMessages) {
  const codes = discordMessages.reduce((acc, curr) => {
    const message = curr[0]
    const match = message.content.match(/epix-connect=([\w\d]{7})/i);
    if (match?.[1] && !EPIX_FRIENDS.includes(match[1])) {
      acc.push({code: match[1], messageId: message.id});
    }
    return acc;
  }, [])

  return codes;
}


function updateFriends(status, code) {
  if (status === "CONNECTION_SUCCESSFUL" || status === "ALREADY_MATCHED") {
    EPIX_FRIENDS.push(code.code);
    GM_setValue('epixFriends', EPIX_FRIENDS);
    GM_setValue('discordMinId', code.messageId);
  }

}



//--- Style our newly added elements using CSS.
GM_addStyle (`
  #epixButton {
    margin-left: 10px;
  }

  #epixIdsDialog {
    margin-top: 5rem;
  }
  #epixIdsDialog ol {
    list-style: auto;
    padding-left: 35px;
    margin-bottom: 10px;
  }
  #epixIdsDialog input {
    width: 100%;
  }
  #epixIdsDialog button {
    margin: 5px auto;
    display: block;
    font-size: large;
    background: greenyellow;
    padding: 2px 10px;
  }
`);


async function connectRequest(userId, profileId) {
  return fetch("https://wfppjum4x2.execute-api.eu-central-1.amazonaws.com/production/connection-request", {
    "referrer": "https://www.gamescom.global/",
    "referrerPolicy": "strict-origin-when-cross-origin",
    "body": `{"userId":"${userId}","profileId":"${profileId}"}`,
    "method": "POST",
    "mode": "cors",
    "credentials": "omit"
  });
}


async function getDiscordMessages(minId) {
  const params = queryString([
    ['limit', 25],
    ['channel_id', '1259933715409145966'],
    ['min_id', minId],
    ['sort_by', 'timestamp'],
    ['sort_order', 'asc'],
    ['has','link'],
  ]);
  const res = await fetch(`https://discord.com/api/v9/guilds/574865170694799400/messages/search?${params}`, {
    "headers": {
      "accept": "*/*",
      "authorization": DISCORD_TOKEN
    },
    "referrer": "https://discord.com/channels/574865170694799400/1259933715409145966",
    "referrerPolicy": "strict-origin-when-cross-origin",
    "method": "GET",
    "mode": "cors",
    "credentials": "include"
  });
  if (!res.ok) {
    console.error({ERROR: res.error});
    return;
  }

  const data = await res.json();
  return data.messages;
}


const queryString = params => params.filter(p => p[1] !== undefined).map(p => p[0] + '=' + encodeURIComponent(p[1])).join('&');

(new MutationObserver(check)).observe(document, {childList: true, subtree: true});
function check(changes, observer) {
  if(document.querySelector('h1')) {
    observer.disconnect();
    main();
  }
}