Embed URL

A user script that adds a corresponding embed such as an image or video to a URL.

Versión del día 1/1/2023. Echa un vistazo a la versión más reciente.

// ==UserScript==
// @name            Embed URL
// @name:ja         埋め込みを追加する
// @description     A user script that adds a corresponding embed such as an image or video to a URL.
// @description:ja  URLに画像や動画などの対応する埋め込みを追加するユーザースクリプトです。
// @version         1.0.0
// @icon            data:image/png;base64,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
// @match           *://*/*
// @connect         imgur.com
// @connect         i.imgur.com
// @connect         publish.twitter.com
// @namespace       https://github.com/sqrtox/userscript-embed-url
// @author          sqrtox
// @license         MIT
// @grant           GM.xmlHttpRequest
// ==/UserScript==
"use strict";
(() => {
  var __defProp = Object.defineProperty;
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
  var __publicField = (obj, key, value) => {
    __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
    return value;
  };
  var __accessCheck = (obj, member, msg) => {
    if (!member.has(obj))
      throw TypeError("Cannot " + msg);
  };
  var __privateGet = (obj, member, getter) => {
    __accessCheck(obj, member, "read from private field");
    return getter ? getter.call(obj) : member.get(obj);
  };
  var __privateAdd = (obj, member, value) => {
    if (member.has(obj))
      throw TypeError("Cannot add the same private member more than once");
    member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
  };
  var __privateSet = (obj, member, value, setter) => {
    __accessCheck(obj, member, "write to private field");
    setter ? setter.call(obj, value) : member.set(obj, value);
    return value;
  };
  var __privateMethod = (obj, member, method) => {
    __accessCheck(obj, member, "access private method");
    return method;
  };

  // src/utils/objectKeys.ts
  var objectKeys = (obj) => Object.keys(obj);

  // src/utils/findElement.ts
  var findElement = function* (tagName, context = document) {
    if (!(context instanceof Document) && context instanceof document.createElement(tagName).constructor) {
      yield context;
    }
    yield* context.getElementsByTagName(tagName);
  };

  // src/utils/observeAnchor.ts
  var ObserveAnchorRecordTypes = {
    Found: "found",
    Added: "added",
    Removed: "removed",
    Appeared: "appeared",
    Disappeared: "disappeared",
    Changed: "changed"
  };
  var observeAnchor = (callback, {
    filter,
    signal
  } = {}) => {
    signal?.addEventListener("abort", () => {
      intersectionObserver?.disconnect();
      intersectionObserver = void 0;
      mutationObserver?.disconnect();
      mutationObserver = void 0;
    }, { once: true });
    const filterSet = filter && new Set(filter);
    const flush = (creator) => {
      const records = [];
      for (const record of creator()) {
        if (!record.targets.length) {
          continue;
        }
        if (filterSet && !filterSet.has(record.type)) {
          continue;
        }
        records.push(record);
      }
      if (!records.length) {
        return;
      }
      callback(records);
    };
    let intersectionObserver = new IntersectionObserver((records) => {
      flush(function* () {
        const appearedTargets = [];
        const disappearedTargets = [];
        for (const { isIntersecting, target } of records) {
          if (!(target instanceof HTMLAnchorElement)) {
            continue;
          }
          if (isIntersecting) {
            appearedTargets.push(target);
          } else {
            disappearedTargets.push(target);
          }
        }
        yield {
          type: ObserveAnchorRecordTypes.Appeared,
          targets: appearedTargets
        };
        yield {
          type: ObserveAnchorRecordTypes.Disappeared,
          targets: disappearedTargets
        };
      });
    });
    let mutationObserver = new MutationObserver((records) => {
      flush(function* () {
        const changedTargets = [];
        const addedTargets = [];
        const removedTargets = [];
        for (const {
          type,
          target,
          addedNodes,
          removedNodes,
          attributeName,
          oldValue
        } of records) {
          switch (type) {
            case "attributes": {
              if (!(target instanceof HTMLAnchorElement)) {
                break;
              }
              if (attributeName !== "href") {
                break;
              }
              if (target.href === oldValue) {
                break;
              }
              changedTargets.push(target);
              break;
            }
            case "childList": {
              for (const n of addedNodes) {
                if (!(n instanceof Element)) {
                  continue;
                }
                for (const e of findElement("a", n)) {
                  addedTargets.push(e);
                  intersectionObserver?.observe(e);
                }
              }
              for (const n of removedNodes) {
                if (!(n instanceof Element)) {
                  continue;
                }
                for (const e of findElement("a", n)) {
                  removedTargets.push(e);
                  intersectionObserver?.unobserve(e);
                }
              }
              break;
            }
          }
        }
        yield {
          type: ObserveAnchorRecordTypes.Changed,
          targets: changedTargets
        };
        yield {
          type: ObserveAnchorRecordTypes.Added,
          targets: addedTargets
        };
        yield {
          type: ObserveAnchorRecordTypes.Removed,
          targets: removedTargets
        };
      });
    });
    mutationObserver.observe(document, {
      childList: true,
      subtree: true,
      attributes: true,
      attributeOldValue: true,
      attributeFilter: ["href"]
    });
    flush(function* () {
      const targets = [];
      for (const e of findElement("a")) {
        targets.push(e);
        intersectionObserver?.observe(e);
      }
      yield {
        type: ObserveAnchorRecordTypes.Found,
        targets
      };
    });
  };

  // src/utils/AnchorEmbed.ts
  var _rules, _resolvers, _excludes, _abortControllersMap, _createAbortController, createAbortController_fn, _resolve, resolve_fn, _appliedRulesMap, _isAppliedRule, isAppliedRule_fn, _observeAnchorController, _testFilter, testFilter_fn;
  var _AnchorEmbed = class {
    constructor({
      rules,
      resolvers = []
    }) {
      __privateAdd(this, _createAbortController);
      __privateAdd(this, _resolve);
      __privateAdd(this, _isAppliedRule);
      __publicField(this, "constructor", _AnchorEmbed);
      __privateAdd(this, _rules, void 0);
      __privateAdd(this, _resolvers, void 0);
      __privateAdd(this, _excludes, /* @__PURE__ */ new WeakSet());
      __privateAdd(this, _abortControllersMap, /* @__PURE__ */ new WeakMap());
      __privateAdd(this, _appliedRulesMap, /* @__PURE__ */ new WeakMap());
      __privateAdd(this, _observeAnchorController, void 0);
      __privateSet(this, _rules, rules);
      __privateSet(this, _resolvers, resolvers);
    }
    exclude(target) {
      __privateGet(this, _excludes).add(target);
    }
    include(target) {
      __privateGet(this, _excludes).delete(target);
    }
    applyRule(target, asHref = target.href) {
      var _a;
      if (__privateGet(this, _excludes).has(target)) {
        return;
      }
      if (!asHref) {
        return;
      }
      const url = __privateMethod(this, _resolve, resolve_fn).call(this, new URL(asHref));
      const appliedRulesMap = __privateGet(this, _appliedRulesMap);
      for (const rule of __privateGet(this, _rules)) {
        if (!__privateMethod(_a = this.constructor, _testFilter, testFilter_fn).call(_a, url, rule)) {
          continue;
        }
        if (__privateMethod(this, _isAppliedRule, isAppliedRule_fn).call(this, target, rule)) {
          continue;
        }
        rule.effect({
          anchorEmbed: this,
          rule,
          url,
          target,
          onAbort: (listener) => {
            const { signal } = __privateMethod(this, _createAbortController, createAbortController_fn).call(this, target);
            signal.addEventListener("abort", () => listener());
          }
        });
        const appliedRules = appliedRulesMap.get(target) ?? /* @__PURE__ */ new Set();
        if (!appliedRulesMap.has(target)) {
          appliedRulesMap.set(target, appliedRules);
        }
        appliedRules.add(rule);
      }
    }
    destroyRule(target) {
      const abortControllersMap = __privateGet(this, _abortControllersMap);
      const controllers = abortControllersMap.get(target);
      if (controllers) {
        for (const controller of controllers) {
          controller.abort();
          controllers.delete(controller);
        }
        if (!controllers.size) {
          abortControllersMap.delete(target);
        }
      }
      __privateGet(this, _appliedRulesMap).delete(target);
    }
    apply() {
      const observeAnchorController = __privateSet(this, _observeAnchorController, new AbortController());
      observeAnchor((records) => {
        for (const { type, targets } of records) {
          for (const target of targets) {
            switch (type) {
              case ObserveAnchorRecordTypes.Appeared: {
                this.applyRule(target);
                break;
              }
              case ObserveAnchorRecordTypes.Changed: {
                this.destroyRule(target);
                this.applyRule(target);
                break;
              }
              case ObserveAnchorRecordTypes.Removed: {
                this.destroyRule(target);
                break;
              }
            }
          }
        }
      }, {
        signal: observeAnchorController.signal,
        filter: [
          ObserveAnchorRecordTypes.Appeared,
          ObserveAnchorRecordTypes.Changed,
          ObserveAnchorRecordTypes.Removed
        ]
      });
    }
    destroy() {
      for (const e of findElement("a")) {
        this.destroyRule(e);
      }
      __privateGet(this, _observeAnchorController)?.abort();
      __privateSet(this, _observeAnchorController, void 0);
    }
  };
  var AnchorEmbed = _AnchorEmbed;
  _rules = new WeakMap();
  _resolvers = new WeakMap();
  _excludes = new WeakMap();
  _abortControllersMap = new WeakMap();
  _createAbortController = new WeakSet();
  createAbortController_fn = function(target) {
    const controller = new AbortController();
    const controllersMap = __privateGet(this, _abortControllersMap);
    const controllers = controllersMap.get(target) ?? /* @__PURE__ */ new Set();
    if (!controllersMap.has(target)) {
      controllersMap.set(target, controllers);
    }
    controllers.add(controller);
    return controller;
  };
  _resolve = new WeakSet();
  resolve_fn = function(url) {
    const resolvers = __privateGet(this, _resolvers).filter((v) => {
      var _a;
      return __privateMethod(_a = this.constructor, _testFilter, testFilter_fn).call(_a, url, v);
    });
    if (!resolvers.length) {
      return url;
    }
    let current = resolvers[0].effect(url) ?? url;
    const len = resolvers.length;
    for (let i = 1; i < len; i++) {
      const resolved = resolvers[i].effect(current);
      if (resolved) {
        current = resolved;
      }
    }
    return current;
  };
  _appliedRulesMap = new WeakMap();
  _isAppliedRule = new WeakSet();
  isAppliedRule_fn = function(target, rule) {
    const appliedRules = __privateGet(this, _appliedRulesMap).get(target);
    if (!appliedRules) {
      return false;
    }
    return appliedRules.has(rule);
  };
  _observeAnchorController = new WeakMap();
  _testFilter = new WeakSet();
  testFilter_fn = function(url, filter) {
    const { test } = filter;
    if (test instanceof RegExp) {
      return test.test(url.href);
    }
    if (test instanceof Array) {
      return test.length ? test.some((v) => v.test(url.href)) : false;
    }
    const testMethod = "testMethod" in filter && filter.testMethod || "every";
    const keys = objectKeys(test);
    if (!keys.length) {
      return false;
    }
    return keys[testMethod]((k) => {
      const r = test[k];
      if (!r) {
        return false;
      }
      if (r instanceof RegExp) {
        return r.test(url[k]);
      }
      return r.length ? r.some((v) => v.test(url[k])) : false;
    });
  };
  __privateAdd(AnchorEmbed, _testFilter);

  // node_modules/tslib/tslib.es6.js
  /*! *****************************************************************************
  Copyright (c) Microsoft Corporation.
  
  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted.
  
  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  PERFORMANCE OF THIS SOFTWARE.
  ***************************************************************************** */
  var __assign = function() {
    __assign = Object.assign || function __assign2(t) {
      for (var s2, i = 1, n = arguments.length; i < n; i++) {
        s2 = arguments[i];
        for (var p in s2)
          if (Object.prototype.hasOwnProperty.call(s2, p))
            t[p] = s2[p];
      }
      return t;
    };
    return __assign.apply(this, arguments);
  };

  // node_modules/lower-case/dist.es2015/index.js
  function lowerCase(str) {
    return str.toLowerCase();
  }

  // node_modules/no-case/dist.es2015/index.js
  var DEFAULT_SPLIT_REGEXP = [/([a-z0-9])([A-Z])/g, /([A-Z])([A-Z][a-z])/g];
  var DEFAULT_STRIP_REGEXP = /[^A-Z0-9]+/gi;
  function noCase(input, options) {
    if (options === void 0) {
      options = {};
    }
    var _a = options.splitRegexp, splitRegexp = _a === void 0 ? DEFAULT_SPLIT_REGEXP : _a, _b = options.stripRegexp, stripRegexp = _b === void 0 ? DEFAULT_STRIP_REGEXP : _b, _c = options.transform, transform = _c === void 0 ? lowerCase : _c, _d = options.delimiter, delimiter = _d === void 0 ? " " : _d;
    var result = replace(replace(input, splitRegexp, "$1\0$2"), stripRegexp, "\0");
    var start = 0;
    var end = result.length;
    while (result.charAt(start) === "\0")
      start++;
    while (result.charAt(end - 1) === "\0")
      end--;
    return result.slice(start, end).split("\0").map(transform).join(delimiter);
  }
  function replace(input, re, value) {
    if (re instanceof RegExp)
      return input.replace(re, value);
    return re.reduce(function(input2, re2) {
      return input2.replace(re2, value);
    }, input);
  }

  // node_modules/dot-case/dist.es2015/index.js
  function dotCase(input, options) {
    if (options === void 0) {
      options = {};
    }
    return noCase(input, __assign({ delimiter: "." }, options));
  }

  // node_modules/param-case/dist.es2015/index.js
  function paramCase(input, options) {
    if (options === void 0) {
      options = {};
    }
    return dotCase(input, __assign({ delimiter: "-" }, options));
  }

  // src/utils/createStyles.ts
  var s = document.createElement("style");
  document.head.append(s);
  var randomClassName = () => `css-${Math.random().toString(36).slice(2)}`;
  var createStyles = (stylesList) => {
    const classNames6 = {};
    let css = "";
    for (const k of objectKeys(stylesList)) {
      const className = classNames6[k] = randomClassName();
      const styles = stylesList[k];
      for (const k2 in styles) {
        css += `.${className}${k2}{`;
        const style = styles[k2];
        for (const k3 in style) {
          css += `${paramCase(k3)}:${style[k3]};`;
        }
        css += "}";
      }
    }
    s.innerHTML += css;
    return classNames6;
  };

  // src/utils/createElement.ts
  var createElement = (tagName, {
    attributes = {}
  } = {}, ...children) => {
    const e = document.createElement(tagName);
    for (const k in attributes) {
      const v = attributes[k];
      if (!v) {
        continue;
      }
      e[k] = v;
    }
    for (const child of children) {
      e.append(child);
    }
    return e;
  };

  // src/utils/createThumbnail.ts
  var classNames = createStyles({
    cover: {
      "": {
        display: "flex",
        justifyContent: "center",
        alignItems: "center",
        position: "fixed",
        top: "0px",
        left: "0px",
        width: "100vw",
        height: "100vh",
        zIndex: "999999",
        backgroundColor: "rgba(0, 0, 0, 0.75)"
      }
    },
    coverHidden: {
      "": {
        display: "none"
      }
    },
    noScroll: {
      "": {
        overflow: "hidden !important"
      }
    },
    coverImg: {
      "": {
        maxWidth: "50vw"
      }
    }
  });
  var cover = createElement("div", {
    attributes: {
      className: `${classNames.cover} ${classNames.coverHidden}`
    }
  });
  cover.addEventListener("click", () => {
    document.documentElement.classList.remove(classNames.noScroll);
    cover.classList.add(classNames.coverHidden);
  });
  document.body.append(cover);
  var createThumbnail = (src) => {
    const img = createElement("img", {
      attributes: {
        src
      }
    });
    img.addEventListener("click", (ev) => {
      ev.stopPropagation();
      document.documentElement.classList.add(classNames.noScroll);
      cover.classList.remove(classNames.coverHidden);
      while (cover.firstChild) {
        cover.firstChild.remove();
      }
      const coverImg = createElement("img", {
        attributes: {
          src: img.src,
          className: classNames.coverImg
        }
      });
      cover.append(coverImg);
    });
    return img;
  };

  // src/utils/exoticFetch.ts
  var exoticFetch = (url, {
    method = "GET",
    responseType = "blob"
  } = {}) => new Promise((resolve, reject) => {
    GM.xmlHttpRequest({
      method,
      url,
      responseType,
      onload: (res) => {
        resolve({
          response: res.response,
          finalUrl: res.finalUrl
        });
      },
      onerror: (err) => reject(err)
    });
  });

  // src/utils/insertAfter.ts
  var insertAfter = (target, element) => {
    const { parentNode, nextSibling } = target;
    if (!parentNode) {
      throw new Error("No parent node");
    }
    if (nextSibling) {
      parentNode.insertBefore(element, nextSibling);
    } else {
      parentNode.append(element);
    }
  };

  // src/utils/createSpoiler.ts
  var classNames2 = createStyles({
    hiddenSpoilerButton: {
      "": {
        display: "none"
      }
    },
    spoilerButton: {
      "": {
        backgroundColor: "#000",
        color: "#fff",
        padding: "0.5rem",
        cursor: "pointer"
      }
    }
  });
  var createSpoiler = ({
    target,
    onAbort,
    rule
  }, factory) => {
    const spoiler = createElement("div");
    const openSpoilerButton = createElement(
      "div",
      {
        attributes: {
          className: classNames2.spoilerButton
        }
      },
      `「${rule.name}」を表示する`
    );
    const closeSpoilerButton = createElement(
      "div",
      {
        attributes: {
          className: `${classNames2.spoilerButton} ${classNames2.hiddenSpoilerButton}`
        }
      },
      `「${rule.name}」を非表示にする`
    );
    const container = document.createElement("div");
    spoiler.append(openSpoilerButton);
    spoiler.append(closeSpoilerButton);
    spoiler.append(container);
    let controller;
    openSpoilerButton.addEventListener("click", (ev) => {
      ev.stopPropagation();
      openSpoilerButton.classList.add(classNames2.hiddenSpoilerButton);
      closeSpoilerButton.classList.remove(classNames2.hiddenSpoilerButton);
      factory({
        container,
        onAbort: (listener) => {
          controller = new AbortController();
          controller.signal.addEventListener("abort", () => listener());
        }
      });
    });
    closeSpoilerButton.addEventListener("click", (ev) => {
      ev.stopPropagation();
      closeSpoilerButton.classList.add(classNames2.hiddenSpoilerButton);
      openSpoilerButton.classList.remove(classNames2.hiddenSpoilerButton);
      controller?.abort();
      controller = void 0;
    });
    onAbort(() => {
      spoiler.remove();
    });
    insertAfter(target, spoiler);
  };

  // src/rules/imgur.ts
  var classNames3 = createStyles({
    img: {
      "": {
        maxWidth: "90%"
      }
    },
    video: {
      "": {
        maxWidth: "100%"
      }
    }
  });
  var imgur_default = () => ({
    name: "Imgur",
    test: {
      hostname: /^i\.imgur\.com$/
    },
    effect: async (ctx) => {
      const { target, onAbort, url, anchorEmbed: anchorEmbed2 } = ctx;
      const { response } = await exoticFetch(url.href);
      const container = document.createElement("div");
      switch (response.type.replace(/\/.+$/, "")) {
        case "image": {
          const img = createThumbnail(url.href);
          img.classList.add(classNames3.img);
          container.append(img);
          break;
        }
        case "video": {
          createSpoiler(ctx, ({ onAbort: onAbort2, container: container2 }) => {
            const video = createElement("video", {
              attributes: {
                src: url.href,
                controls: true,
                className: classNames3.video
              }
            });
            container2.append(video);
            onAbort2(() => video.remove());
          });
          break;
        }
        default: {
          if (response.type !== "text/html") {
            break;
          }
          const text = await response.text();
          const m = text.match(/<meta\s+property="og:image"\s+data-react-helmet="true"\s+content="(.+?)">/);
          if (!m) {
            break;
          }
          const url2 = new URL(m[1]);
          url2.search = "";
          anchorEmbed2.destroyRule(target);
          anchorEmbed2.applyRule(target, url2.href);
          break;
        }
      }
      if (container.children.length) {
        insertAfter(target, container);
        onAbort(() => container.remove());
      }
    }
  });

  // src/resolvers/feeder-jump-page.ts
  var feeder_jump_page_default = () => ({
    name: "Feeder jump page",
    test: {
      hostname: /^www[12]\.x-feeder\.info$/,
      pathname: /^\/jump\.php$/
    },
    effect: ({ searchParams }) => {
      const href = searchParams.get("url");
      if (typeof href !== "string") {
        return;
      }
      return new URL(href);
    }
  });

  // src/utils/option.ts
  var option = (func) => {
    try {
      return func();
    } catch {
      return;
    }
  };

  // src/utils/resolveYoutubeId.ts
  var resolveYoutubeId = ({
    hostname,
    searchParams,
    pathname
  }) => {
    switch (hostname) {
      case "m.youtube.com":
      case "www.youtube.com": {
        if (pathname !== "/watch") {
          throw new Error("Unsupported pathname");
        }
        const id = searchParams.get("v");
        if (typeof id !== "string") {
          throw new Error("Could not retrieve id");
        }
        return id;
      }
      case "youtu.be": {
        return pathname;
      }
      default: {
        throw new Error("Unsupported hostname");
      }
    }
  };

  // src/rules/youtube.ts
  var classNames4 = createStyles({
    iframe: {
      "": {
        border: "none",
        maxWidth: "100%"
      }
    },
    container: {
      "": {
        display: "flex",
        justifyContent: "center",
        backgroundColor: "#000"
      }
    }
  });
  var youtube_default = () => ({
    name: "YouTube",
    test: {
      hostname: /^(?:www|m)\.youtube\.com|youtu\.be$/
    },
    effect: (ctx) => {
      const { url } = ctx;
      const id = option(() => resolveYoutubeId(url));
      if (!id) {
        return;
      }
      const src = `https://www.youtube-nocookie.com/embed/${id}`;
      createSpoiler(ctx, ({ onAbort, container }) => {
        container.classList.add(classNames4.container);
        const ifr = createElement("iframe", {
          attributes: {
            src,
            title: "YouTube video player",
            allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",
            allowFullscreen: true,
            className: classNames4.iframe,
            width: "560",
            height: "315"
          }
        });
        container.append(ifr);
        onAbort(() => ifr.remove());
      });
    }
  });

  // src/rules/nicovideo.ts
  var classNames5 = createStyles({
    iframe: {
      "": {
        border: "none",
        maxWidth: "100%"
      }
    },
    container: {
      "": {
        display: "flex",
        justifyContent: "center",
        backgroundColor: "#000"
      }
    }
  });
  var nicovideo_default = () => ({
    name: "ニコニコ動画",
    test: {
      hostname: /^(?:www|sp)\.nicovideo\.jp$/,
      pathname: /^\/watch\/sm\d+$/
    },
    effect: (ctx) => {
      const src = `https://embed.nicovideo.jp${ctx.url.pathname}`;
      createSpoiler(ctx, ({ onAbort, container }) => {
        container.classList.add(classNames5.container);
        const ifr = createElement("iframe", {
          attributes: {
            src,
            allowFullscreen: true,
            className: classNames5.iframe
          }
        });
        container.append(ifr);
        onAbort(() => ifr.remove());
      });
    }
  });

  // src/utils/wakeScriptTag.ts
  var wakeScriptTag = (root) => {
    for (const e of findElement("script", root)) {
      const s2 = createElement("script", {
        attributes: {
          src: e.src,
          charset: e.charset,
          async: e.async,
          defer: e.defer,
          type: e.type
        }
      });
      e.parentNode?.insertBefore(s2, e);
      e.remove();
    }
  };

  // src/rules/twitter.ts
  var twitter_default = () => ({
    name: "Twitter",
    test: {
      hostname: /^twitter\.com$/,
      pathname: /^\/[^/]+\/status\/\d+/
    },
    effect: async (ctx) => {
      const { url, anchorEmbed: anchorEmbed2 } = ctx;
      createSpoiler(ctx, async ({ onAbort, container }) => {
        const wrapper = createElement("div");
        onAbort(() => wrapper.remove());
        const { response } = await exoticFetch(
          `https://publish.twitter.com/oembed?url=${url.href}`,
          {
            responseType: "json"
          }
        );
        wrapper.innerHTML = response.html;
        for (const e of findElement("a", wrapper)) {
          anchorEmbed2.exclude(e);
        }
        container.append(wrapper);
        wakeScriptTag(wrapper);
      });
    }
  });

  // src/index.ts
  var anchorEmbed = new AnchorEmbed({
    rules: [
      imgur_default(),
      youtube_default(),
      nicovideo_default(),
      twitter_default()
    ],
    resolvers: [
      feeder_jump_page_default()
    ]
  });
  anchorEmbed.apply();
})();