Greasy Fork is available in English.

falinks-teambuilder-helper

A UserScript helps import teams to a Falinks Teambuilder room

질문, 리뷰하거나, 이 스크립트를 신고하세요.
// ==UserScript==
// @name          falinks-teambuilder-helper
// @description   A UserScript helps import teams to a Falinks Teambuilder room
// @namespace     http://tampermonkey.net/
// @version       1.1.0
// @author        txfs19260817
// @icon          https://www.falinks-teambuilder.com/favicon.ico
// @source        https://github.com/txfs19260817/falinks-teambuilder-helper
// @license       WTFPL
// @match         http*://play.pokemonshowdown.com/*
// @match         http*://*.psim.us/*
// @match         http*://pokepast.es/*
// @match         http*://play.limitlesstcg.com/*
// @require       https://unpkg.com/@pkmn/sets/build/index.min.js
// @connect       www.falinks-teambuilder.com
// @run-at        document-end
// ==/UserScript==

/******/ (() => { // webpackBootstrap
/******/ 	"use strict";
var __webpack_exports__ = {};

;// CONCATENATED MODULE: external "window"
const external_window_namespaceObject = window;
;// CONCATENATED MODULE: ./src/utils.ts
// Random 4-letter string
function S4() {
    return ((1 + Math.random()) * 0x10000 | 0).toString(16).substring(1);
}
// Button building
const buttonStyles = (/* unused pure expression or super */ null && ([
    "ps",
    "limitless"
]));
const createRoomButtonId = "falinks-new-room-btn";
const showdownBtnStyle = {
    outline: "none",
    cursor: "pointer",
    textAlign: "center",
    textDecoration: "none",
    boxShadow: "0 1px 2px rgba(0,0,0,.2),inset 0 -1px 2px #fff",
    borderRadius: "5px",
    fontFamily: "Verdana,Helvetica,Arial,sans-serif",
    display: "inline-block",
    color: "#222",
    textShadow: "0 1px 0 #fff",
    border: "1px solid #aaa",
    background: "linear-gradient(to bottom,#f6f6f6,#e3e3e3)",
    fontSize: "9pt",
    padding: "3px 8px",
    marginLeft: "6px",
    marginBottom: "3px"
};
const buildPSButton = function(eid, text, onclick) {
    let style = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : "ps";
    const submitBtn = document.createElement("button");
    submitBtn.id = eid;
    submitBtn.textContent = text;
    submitBtn.type = "button";
    submitBtn.onclick = onclick;
    // pokepast.es potentially erased all css, including button. So add it back
    if (style === "ps") {
        Object.assign(submitBtn.style, showdownBtnStyle);
    } else if (style === "limitless") {
        submitBtn.classList.add("export"); // reuse the "export" button style
        submitBtn.style.marginLeft = "6px"; // add some margin to the left
    }
    return submitBtn;
};
// URL stuff
const pokepasteURL = "pokepast.es";
const falinksTeambuilderURL = "falinks-teambuilder.com";
const showdownURL = "play.pokemonshowdown.com";
const limitlesstcgURL = "play.limitlesstcg.com";
const safeReferrers = [
    pokepasteURL,
    falinksTeambuilderURL,
    limitlesstcgURL
];
function isSafeReferrer(s) {
    return safeReferrers.some((r)=>s.includes(r));
}
function isLimitlessTeamlistURL(url) {
    const { hostname , pathname  } = new URL(url);
    return hostname === limitlesstcgURL && (pathname.endsWith("teamlist") || pathname.endsWith("teamlist/"));
}
function falinksRoomEndpoint(packed) {
    // packed team will be passed as a query param
    return `//www.${falinksTeambuilderURL}/room/room_${S4()}${S4()}/?protocol=WebSocket&packed=${encodeURIComponent(packed)}`;
}
function showdownTeambuilderEndpoint(packed) {
    // packed team will be in the URL hash
    return `https://${showdownURL}/teambuilder#${packed}`;
}

;// CONCATENATED MODULE: ./src/index.ts


function pasteToPacked(paste) {
    var _pkmnSets_pkmn_sets_Teams_importTeam;
    // see: https://github.com/pkmn/ps/blob/main/sets/README.md#browser
    //@ts-ignore
    return ((_pkmnSets_pkmn_sets_Teams_importTeam = external_window_namespaceObject.pkmn.sets.Teams.importTeam(paste)) === null || _pkmnSets_pkmn_sets_Teams_importTeam === void 0 ? void 0 : _pkmnSets_pkmn_sets_Teams_importTeam.pack()) ?? '';
}
function createRoomButton(packedTeam) {
    let style = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "ps";
    return buildPSButton("falinks-new-room-btn", "🤝 Open in a Falinks Teambuilder room", ()=>{
        window.open(falinksRoomEndpoint(packedTeam));
    }, style);
}
function createToPSButton(packedTeam) {
    let format = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "gen9", name = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : `Falinks Team ${S4()}`, style = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : "ps";
    // seems `Team.pack()` does not add format and team name to the packed team, we do it manually
    const packedWithFormat = `${format}]${name}|${packedTeam}`;
    return buildPSButton("falinks-add-team-btn", "🚀 Add to your Showdown teams", ()=>{
        window.open(showdownTeambuilderEndpoint(packedWithFormat));
    }, style);
}
function getPasteAtPokepaste() {
    var _document_querySelector, _notes_match, _document_querySelector1;
    // get format from notes
    const notes = ((_document_querySelector = document.querySelector("body > aside > p")) === null || _document_querySelector === void 0 ? void 0 : _document_querySelector.textContent) ?? '';
    const format = ((_notes_match = notes.match(/Format: (.*)/)) === null || _notes_match === void 0 ? void 0 : _notes_match[1]) ?? '';
    // get name from title
    const name = (_document_querySelector1 = document.querySelector("body > aside > h1")) === null || _document_querySelector1 === void 0 ? void 0 : _document_querySelector1.textContent;
    // get team from textarea
    const paste = [
        1,
        2,
        3,
        4,
        5,
        6
    ].map((i)=>{
        var _document_querySelector;
        return ((_document_querySelector = document.querySelector(`body > article:nth-child(${i}) > pre`)) === null || _document_querySelector === void 0 ? void 0 : _document_querySelector.textContent) ?? '';
    }).join('');
    return {
        format,
        name,
        paste
    };
}
function getPackedAtShowdown() {
    var _unsafeWindow_room, _unsafeWindow_room_curTeam;
    // @ts-ignore
    return ((_unsafeWindow_room = unsafeWindow.room) === null || _unsafeWindow_room === void 0 ? void 0 : (_unsafeWindow_room_curTeam = _unsafeWindow_room.curTeam) === null || _unsafeWindow_room_curTeam === void 0 ? void 0 : _unsafeWindow_room_curTeam.team) ?? '';
}
function addPackedToLocalStorage(packedTeam) {
    const updatedShowdownTeams = packedTeam + "\n" + localStorage.getItem("showdown_teams");
    localStorage.setItem("showdown_teams", updatedShowdownTeams);
}
function main() {
    const { host , hash , href  } = window.location;
    if (host === pokepasteURL) {
        // parse the DOM of pokepast.es
        const { paste , format , name  } = getPasteAtPokepaste();
        // pack the team
        const packed = pasteToPacked(paste);
        // add both Create Room and Add To PS buttons to Pokepaste aside
        document.querySelector("body > aside").append(createRoomButton(packed), createToPSButton(packed, format, name));
    } else if (isLimitlessTeamlistURL(href)) {
        // @ts-ignore
        const paste = teamlist; // teamlist is a global variable defined in this page
        console.log(paste);
        const packed = pasteToPacked(paste);
        const title = document.querySelector("body > div.pre-content > div > div > div > div").textContent;
        const author = document.querySelector("body > div.main > div > div.infobox > div.heading").textContent;
        const name = `${author} @ ${title}`;
        document.querySelector("body > div.main > div > div.teamlist > div.buttons").append(createRoomButton(packed, "limitless"), createToPSButton(packed, "gen9vgc2023series2", name, "limitless") // use gen9vgc2023series2 as format atm
        );
    } else {
        // add the Create Room button to Showdown Teambuilder, next to "Upload to PokePaste" button
        const observer = new MutationObserver(function() {
            const pokepasteForm = document.getElementById("pokepasteForm");
            if (pokepasteForm && !document.getElementById(createRoomButtonId)) {
                const packed = getPackedAtShowdown();
                const btn = createRoomButton(packed);
                pokepasteForm.appendChild(btn);
            }
        });
        observer.observe(document.querySelector("body"), {
            subtree: true,
            childList: true
        });
        // check both referer and hash to find if a packed team sent from trusted sources
        if (hash && isSafeReferrer(document.referrer)) {
            const packedTeam = decodeURIComponent(document.location.hash.slice(1));
            // reset the URL to avoid re-importing the team
            history.replaceState(null, document.title, location.pathname + location.search);
            // ask the user to import the team
            const doAdd = confirm(`Would you like to add this team from ${document.referrer} to your teams?\n${packedTeam}`);
            if (doAdd) {
                addPackedToLocalStorage(packedTeam);
                window.location.reload();
            }
        }
    }
}
main();

/******/ })()
;