Iwara Enhancement

Iwara Enhancement — one-click download with customizable filenames, like ratio display, wide-screen layout, double-click fullscreen, and video player fixes. Supports Tampermonkey and Violentmonkey.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey, Greasemonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

You will need to install an extension such as Tampermonkey to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्क्रिप्ट व्यवस्थापक एक्स्टेंशन इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्क्रिप्ट व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्टाईल व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

// ==UserScript==
// @name         Iwara Enhancement
// @name:en      Iwara Enhancement
// @name:zh-CN   Iwara增强
// @name:ja      Iwara 強化
// @name:ko      Iwara 향상
// @description  Iwara Enhancement — one-click download with customizable filenames, like ratio display, wide-screen layout, double-click fullscreen, and video player fixes. Supports Tampermonkey and Violentmonkey.
// @description:en Iwara Enhancement — one-click download with customizable filenames, like ratio display, wide-screen layout, double-click fullscreen, and video player fixes. Supports Tampermonkey and Violentmonkey.
// @description:zh-CN Iwara增强 — 一键下载与自定义文件名、显示喜爱率、宽屏布局、双击全屏、修复视频播放器等。支持 Tampermonkey 和 Violentmonkey。
// @description:ja Iwara 強化 — カスタムファイル名でのダウンロード、高評価率表示、ワイド画面、ダブルクリック全画面、動画プレイヤー修正など。Tampermonkey・Violentmonkey 対応。
// @description:ko Iwara 향상 — 사용자 정의 파일명 다운로드, 좋아요 비율 표시, 와이드 스크린, 더블클릭 전체화면, 비디오 플레이어 수정 등. Tampermonkey 및 Violentmonkey 지원.
// @noframes
// @grant        unsafeWindow
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_download
// @grant        GM_info
// @require      https://unpkg.com/jquery
// @require      https://unpkg.com/[email protected]
// @require      https://unpkg.com/vue-i18n
// @match        *://*.iwara.tv/*
// @connect      *.iwara.tv
// @namespace    https://github.com/a1156883061/userscripts-iwara-enhancement
// @version      1.5
// @author       a1156883061
// @source       https://github.com/a1156883061/userscripts-iwara-enhancement
// @supportURL   https://github.com/a1156883061/userscripts-iwara-enhancement/issues
// @license MIT
// ==/UserScript==

;(() => {
  "use strict"

  $

  const external_Vue_namespaceObject = Vue

  function onClickOutside(el, callback) {
    document.addEventListener("click", handler)

    function handler(e) {
      if (!el.contains(e.target)) {
        document.removeEventListener("click", handler)
        callback(e)
      }
    }
  }

  /**
   * MutationObserver that calls callback with just a single mutation.
   */
  class SimpleMutationObserver extends MutationObserver {
    // since calling `new NodeList()` is illegal, this is the only way to create an empty NodeList
    static emptyNodeList = document.querySelectorAll("#__absolutely_nonexisting")

    constructor(callback) {
      super((mutations) => {
        for (const mutation of mutations) if (this.callback(mutation)) break
      })
      this.callback = callback
    }

    /**
     * @param options.immediate - When observing "childList", immediately trigger a mutation with existing nodes.
     */
    observe(target, options) {
      super.observe(target, options)

      options &&
        options.immediate &&
        options.childList &&
        target.childNodes.length &&
        this.callback({
          target,
          type: "childList",
          addedNodes: target.childNodes,
          removedNodes: SimpleMutationObserver.emptyNodeList,
        })
    }
  }

  function hasClass(node, className) {
    return !!node.classList?.contains(className)
  }

  let log

  setLogger(console.log)

  function setLogger(logger) {
    log = logger.bind(console, `[${GM_info.script.name}]`)
  }

  function clamp(val, min, max) {
    return val < min ? min : val > max ? max : val
  }

  function parseAbbreviatedNumber(str) {
    const units = { k: 1e3, m: 1e6, b: 1e9 }

    let number = parseFloat(str)

    if (!isNaN(number)) {
      const unit = str.trim().slice(-1).toLowerCase()

      return number * (units[unit] || 1)
    }

    return NaN
  }

  function formatDate(date) {
    let delimiter = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "/"
    return [
      date.getFullYear(),
      date.getMonth() + 1,
      date.getDate(),
      date.getHours(),
      date.getMinutes(),
      date.getSeconds(),
    ]
      .map((num) => String(num).padStart(2, "0"))
      .join(delimiter)
  }

  /** 可读的日期时间格式,文件名安全(避免 : / \ 等非法字符) */
  function formatDateReadable(date) {
    let includeTime = !(arguments.length > 1 && arguments[1] !== void 0) || arguments[1]
    const d = [date.getFullYear(), date.getMonth() + 1, date.getDate()]
      .map((num) => String(num).padStart(2, "0"))
      .join("-")

    if (!includeTime) return d

    const t = [date.getHours(), date.getMinutes(), date.getSeconds()]
      .map((num) => String(num).padStart(2, "0"))
      .join("")

    return `${d}T${t}`
  }

  function formatError(e) {
    let fallback = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "Unknown error"
    if (typeof e === "string") return e || fallback

    if (e !== null && typeof e === "object") {
      if (e instanceof Event && e.type === "error") return "Failed to load resource"

      if (e.message) return e.message

      const str = String(e)
      return str === "[object Object]" ? fallback : str
    }

    return fallback
  }

  function adjustHexColor(color, amount) {
    return color.replace(/\w\w/g, (color) =>
      clamp(parseInt(color, 16) + amount, 0, 255)
        .toString(16)
        .padStart(2, "0")
    )
  }

  // written by ChatGPT
  function adjustAlpha(color, alpha) {
    if (alpha < 0 || alpha > 1) throw new Error("Alpha value must be between 0 and 1")

    let r, g, b

    if (color.startsWith("#")) {
      if (color.length !== 7) throw new Error("Invalid color format")

      r = parseInt(color.slice(1, 3), 16)
      g = parseInt(color.slice(3, 5), 16)
      b = parseInt(color.slice(5, 7), 16)
    } else {
      if (!color.startsWith("rgb")) throw new Error("Invalid color format")
      {
        const match = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/)

        if (!match) throw new Error("Invalid color format")

        r = parseInt(match[1], 10)
        g = parseInt(match[2], 10)
        b = parseInt(match[3], 10)
      }
    }

    return `rgba(${r}, ${g}, ${b}, ${alpha})`
  }

  /**
   * Replaces characters that are forbidden in file systems.
   */
  function sanitizePath(path, illegalCharReplacement) {
    let keepDelimiters = !(arguments.length > 2 && arguments[2] !== void 0) || arguments[2]
    path = path.replace(/[*:<>?|]/g, illegalCharReplacement)

    keepDelimiters || (path = path.replace(/[\\/]/g, illegalCharReplacement))

    return path
  }

  const external_VueI18n_namespaceObject = VueI18n

  const en_namespaceObject = JSON.parse(
    '{"language":"English","name":"Iwara Enhancement","description":"Multiple UI enhancements for better experience.","ui":{},"s":{"enabled":"Enabled","extra":"Extra settings","download":{"label":"Download","auto":{"label":"One-click Download","desc":"Automatically starts download when clicking the download button."},"resolution":{"label":"Preferred Resolution for Download"},"filename":{"label":"Filename","desc":"Filename template to use when downloading a video.<br>Each keyword should be surrounded by <b>{\'{ }\'}</b>.","preview":"Preview","key":{"id":"video\'s ID","title":"video\'s title","res":"video\'s resolution","author":"author\'s name","date":"date time when the download starts","up_date":"date time when the video was uploaded","date_ts":"DATE in timestamp format","up_date_ts":"UP_DATE in timestamp format","date_fmt":"current date & time (e.g. 2026-06-10T143000)","up_date_fmt":"upload date & time (e.g. 2026-06-10T143000)"},"replace_illegal_char":"Replace characters that are disallowed in filename with:","tips":["Tips","You can use \\"/\\" in the filename to create subfolders, for example {AUTHOR}/{DATE}-{TITLE}.","If the filename doesn\'t work, check if you have any browser extensions that may interfere with the download, such as the Aria2 extension."]}},"ui":{"label":"UI","like_rate":{"label":"Like rate","desc":"Displays like rates in video/image lists."},"highlight_threshold":{"label":"Highlight threshold","desc":"Highlights video/image items over certain like rate."},"highlight_bg":{"label":"Highlight opacity"},"widen_content":{"label":"Widen content","desc":"Widen the content area in video/image pages.","scale":"Additional scale (%)"},"widen_list":{"label":"Widen list","desc":"Widen image/video lists.","scale":"Scale (%)"}},"script":{"label":"Script","language":{"label":"Language"}}}}'
  )

  const zh_namespaceObject = JSON.parse(
    '{"language":"中文","name":"Iwara增强","description":"多种增强体验的界面优化","s":{"enabled":"启用","extra":"更多选项","download":{"label":"下载","auto":{"label":"一键下载","desc":"点击下载按钮时自动开始下载"},"resolution":{"label":"优先下载的分辨率"},"filename":{"label":"文件名","desc":"下载视频时使用的文件名模板<br>每个关键词必须使用 <b>{\'{ }\'}</b> 来包围","preview":"预览","key":{"id":"视频 ID","title":"视频标题","author":"作者名","res":"视频分辨率","date":"下载开始时的日期和时间","up_date":"视频发布时的日期和时间","date_ts":"DATE 的时间戳格式","up_date_ts":"UP_DATE 的时间戳格式","date_fmt":"当前日期和时间(如 2026-06-10T143000)","up_date_fmt":"视频发布日期和时间(如 2026-06-10T143000)"},"replace_illegal_char":"将文件名中的非法字符替换为:","tips":["提示","可以在文件名里使用\\"/\\"来创建文件夹,例如{AUTHOR}/{DATE}-{TITLE}","如果文件名不起作用,检查一下是否安装了与下载相关的浏览器插件,比如 Aria2 插件"]}},"ui":{"label":"界面","like_rate":{"label":"喜爱率","desc":"在视频和图片列表里显示喜爱率"},"highlight_threshold":{"label":"高亮分界点","desc":"喜爱率高于此值的视频和图片将会被高亮显示"},"highlight_bg":{"label":"高亮透明度"},"widen_content":{"label":"加宽内容区域","desc":"加宽视频页和图片页的内容区域","scale":"额外缩放(%)"},"widen_list":{"label":"加宽列表","desc":"加宽视频列表和图片列表","scale":"缩放(%)"}},"script":{"label":"脚本","language":{"label":"语言"}}}}'
  )

  /* harmony default export */ const i18n = { zh: zh_namespaceObject, en: en_namespaceObject }

  function createStorage(prefix, schema) {
    prefix && (prefix += ".")

    return {
      get(key) {
        return GM_getValue(prefix + key, schema[key])
      },
      set(key, val) {
        typeof val === "function" && (val = val(this.get(key)))

        GM_setValue(prefix + key, val)
      },
    }
  }

  const storage = createStorage("", {
    v: GM_info.script.version,
    locale: navigator.language,
    volume: 0.5,
    auto_down_enabled: true,
    preferred_res: "Source",
    filename: "{DATE} {TITLE} - {AUTHOR} ({ID})",
    illegal_char_replacement: "_",
    dark: false,
    like_rates: true,
    like_rate_highlight: 4,
    like_rate_highlight_opacity: 0.2,
    widen_list: true,
    widen_list_scale:
      window.innerWidth <
      // container-fluid's default max-width is 1200px, leave 100px for tolerance
      1200 + 100
        ? 100
        : ~~(100 * ((window.innerWidth - /* sidebar width */ 250 - /* spacing */ 100) / 1200)),
    widen_content: true,
    widen_content_scale: 100,
  })

  const i18n_i18n = (0, external_VueI18n_namespaceObject.createI18n)({
    locale: storage.get("locale"),
    fallbackLocale: "en",
    messages: i18n,

    // disable warnings - I know what I'm doing!!
    silentFallbackWarn: true,
    silentTranslationWarn: true,
    warnHtmlInMessage: "off",
  })

  function matchLocale(locale) {
    return i18n_i18n.global.availableLocales.includes(locale)
      ? locale
      : i18n_i18n.global.availableLocales.find((loc) => locale.startsWith(loc)) || "en"
  }

  const locale = (0, external_Vue_namespaceObject.ref)(storage.get("locale"))

  ;(0, external_Vue_namespaceObject.watchEffect)(() => {
    i18n_i18n.global.locale = locale.value

    storage.set("locale", locale.value)
  })

  function useConfigSettings() {
    // locale that will actually be used, with fallback applied
    const activeLocale = (0, external_Vue_namespaceObject.computed)(() => matchLocale(locale.value))

    return { locale, activeLocale }
  }

  /* harmony default export */ function mitt(n) {
    return {
      all: (n = n || new Map()),
      on: function (t, e) {
        var i = n.get(t)
        i ? i.push(e) : n.set(t, [e])
      },
      off: function (t, e) {
        var i = n.get(t)
        i && (e ? i.splice(i.indexOf(e) >>> 0, 1) : n.set(t, []))
      },
      emit: function (t, e) {
        var i = n.get(t)
        i &&
          i.slice().map(function (n) {
            n(e)
          }),
          (i = n.get("*")) &&
            i.slice().map(function (n) {
              n(t, e)
            })
      },
    }
  }

  const ready = new Promise((resolve) => {
    document.readyState === "loading"
      ? document.addEventListener("DOMContentLoaded", () => resolve())
      : resolve()
  })

  function once(emitter, event, listener) {
    const fn = (data) => {
      emitter.off(event, fn)
      listener(data)
    }

    emitter.on(event, fn)

    return fn
  }

  function setupPaging() {
    ready.then(() => {
      const appDiv = document.getElementById("app")

      if (!appDiv) {
        log("Missing app div.")
        return
      }

      log("Start observing pages.")

      const appObserver = new SimpleMutationObserver((mutation) => {
        detectPageChange(appDiv, mutation.addedNodes, "pageEnter")
        detectPageChange(appDiv, mutation.removedNodes, "pageLeave")
      })
      appObserver.observe(appDiv, { childList: true, immediate: true })
    })
  }

  const emitter = mitt()

  let currentClassName = ""

  emitter.on("pageEnter", (className) => (currentClassName = className))

  const ALL = "*"

  // page listener for iwara
  function page(id, enter) {
    const match = (() => {
      if (id === ALL) return () => id

      const ids = typeof id === "string" ? [id] : id
      const classes = ids.map((id) => `page-${id}`)

      return (className) => {
        const split = className.split(" ")
        const index = classes.findIndex((cls) => split.includes(cls))

        return ids[index]
      }
    })()

    function callIfMatch(listener) {
      return (className) => {
        const matchedID = match(className)

        if (matchedID !== void 0)
          try {
            listener(matchedID)
          } catch (e) {
            log("Error executing page listener", e)
          }
      }
    }

    const onPageEnter = callIfMatch((matchedID) => {
      enter(matchedID, (onLeave) => {
        once(emitter, "pageLeave", callIfMatch(onLeave))
      })
    })

    emitter.on("pageEnter", onPageEnter)
  }

  function detectPageChange(appDiv, nodes, event) {
    if (nodes.length)
      // a valid class name will be like "page page-videoList", where "videoList" is the ID
      for (const node of nodes)
        if (hasClass(node, "page")) {
          // sometimes there are two (maybe more) "page" elements, and one of them contains only the "page" class,
          // we ignore it in this case
          const hasOtherPageElements =
            $(appDiv)
              .children(".page")
              .filter((_, e) => e !== node && !node.className.includes("page-")).length > 0

          hasOtherPageElements || emitter.emit(event, node.className)
          break
        }
  }

  function cancelOnLeave(onLeave, promise) {
    onLeave(() => promise.cancel())
    return promise
  }

  // cached keys, since there will most likely be only one React instance in the page
  let reactInstanceKey = ""
  let reactEventHandlersKey = ""

  function getReactInstance(element) {
    const reactElement = element

    if (reactInstanceKey) return reactElement[reactInstanceKey]

    for (const key of Object.keys(element))
      if (key.startsWith("__reactFiber$") || key.startsWith("__reactInternalInstance$")) {
        reactInstanceKey = key
        return reactElement[key]
      }
  }

  function getReactEventHandlers(element) {
    const reactElement = element

    if (reactEventHandlersKey) return reactElement[reactEventHandlersKey]

    // 先尝试 React 16/17 的 __reactEventHandlers$
    for (const key of Object.keys(element))
      if (key.startsWith("__reactEventHandlers$")) {
        reactEventHandlersKey = key
        return reactElement[key]
      }
    // 再尝试 React 18 的 __reactProps$
    for (const key of Object.keys(element))
      if (key.startsWith("__reactProps$")) {
        reactEventHandlersKey = key
        return reactElement[key]
      }
    return
  }

  // sometimes I just don't want the script to depend on Lodash...
  function throttle(fn, timeout) {
    let timer = 0

    return function () {
      for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++)
        args[_key] = arguments[_key]
      if (timer) return

      timer = setTimeout(() => {
        fn.apply(null, args)

        timer = 0
      }, timeout)
    }
  }

  /**
   * Periodically calls given function until the return value is truthy.
   * @returns A CancelablePromise that resolves with the function's return value when truthy.
   */
  function until(fn) {
    let interval = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : 0
    !(arguments.length > 2 && arguments[2] !== void 0) || arguments[2]
    let cancelled = false

    const STOP = Symbol()

    const promise = new Promise((resolve, reject) => {
      const run = () => {
        if (cancelled) return STOP

        const result = fn()

        if (result) {
          resolve(result)
          return STOP
        }
      }

      const timerId = setInterval(() => {
        try {
          run() === STOP && clearInterval(timerId)
        } catch (e) {
          reject(e)
          clearInterval(timerId)
        }
      }, interval)
    })
    promise.cancel = () => (cancelled = true)

    return promise
  }

  /**
   * Periodically calls given function until the returned jQuery object is not empty.
   * @returns A CancelablePromise that resolves with the jQuery object.
   */
  function until$(fn) {
    let interval = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : 0
    let cancelOnReload = !(arguments.length > 2 && arguments[2] !== void 0) || arguments[2]
    return until(
      () => {
        const result = fn()

        if (result.length) return result
      },
      interval,
      cancelOnReload
    )
  }

  // a partial structure of the video data defined in iwara's video page,
  // including only the properties we need

  const FILENAME_KEYWORDS = [
    "ID",
    "TITLE",
    "RES",
    "AUTHOR",
    "DATE",
    "UP_DATE",
    "DATE_TS",
    "UP_DATE_TS",
    "DATE_FMT",
    "UP_DATE_FMT",
  ]
  const RESOLUTIONS = ["Source", "540p", "360p"]

  const autoEnabled = (0, external_Vue_namespaceObject.ref)(storage.get("auto_down_enabled"))
  const filenameTemplate = (0, external_Vue_namespaceObject.ref)(storage.get("filename"))
  const illegalCharReplacement = (0, external_Vue_namespaceObject.ref)(
    storage.get("illegal_char_replacement")
  )
  const resolution = (0, external_Vue_namespaceObject.ref)(storage.get("preferred_res"))

  const videoInfo = (0, external_Vue_namespaceObject.reactive)({
    id: "",
    title: "",
    author: "",
    created: 0,
    size: 0,
    error: "",
  })
  const sources = (0, external_Vue_namespaceObject.reactive)([])
  const source = (0, external_Vue_namespaceObject.computed)(
    () =>
      sources.find((_ref) => {
        let { label } = _ref
        return label === resolution.value
      }) || sources[0]
  )

  // indicates whether the sources belong to current page
  const hasFreshSources = (0, external_Vue_namespaceObject.ref)(false)

  const filename = (0, external_Vue_namespaceObject.computed)(() => {
    try {
      if (!source.value) throw "Please open a video"

      return resolveFilename(filenameTemplate.value, source.value)
    } catch (e) {
      return `Unable to resolve filename (${formatError(e)})`
    }
  })

  ;(0, external_Vue_namespaceObject.watchEffect)(() =>
    storage.set("preferred_res", resolution.value)
  )
  ;(0, external_Vue_namespaceObject.watchEffect)(() =>
    storage.set("filename", filenameTemplate.value)
  )
  ;(0, external_Vue_namespaceObject.watchEffect)(() =>
    storage.set("auto_down_enabled", autoEnabled.value)
  )
  ;(0, external_Vue_namespaceObject.watchEffect)(() =>
    convertDownloadDropdown(void 0, autoEnabled.value)
  )

  function useDownloaderSettings() {
    return {
      FILENAME_KEYWORDS,
      RESOLUTIONS,
      autoDownEnabled: autoEnabled,
      resolution,
      filenameTemplate,
      filenamePreview: filename,
      illegalCharReplacement,
    }
  }

  page("video", async (pageID, onLeave) => {
    const videoActions = $(".page-video__actions").get(0)

    if (!videoActions) {
      log("Could not find video actions.")
      return
    }

    onLeave(() => {
      // prevent unexpected downloads
      hasFreshSources.value = false
    })

    const $downloadButton = await cancelOnLeave(
      onLeave,
      until$(() => $(".page-video__actions .downloadButton"))
    )

    updateVideoInfo(videoActions)
    updateSources($downloadButton.closest(".dropdown").get(0))

    autoEnabled.value && convertDownloadDropdown($downloadButton.get(0), true)
  })

  function updateVideoInfo(videoActions) {
    try {
      // FIXME: reading the prop by a path is quite unreliable, any improvement?
      const video =
        findVideoInReactProps(getReactEventHandlers(videoActions)) || findVideoInFiber(videoActions)

      if (!video)
        throw new Error("Cannot extract video info from page (React internal API changed)")

      videoInfo.id = video.id
      videoInfo.title = video.title
      videoInfo.created = new Date(video.createdAt).getTime()
      videoInfo.author = video.user.name
      videoInfo.size = video.file.size
    } catch (e) {
      log(e)
      videoInfo.error = e + ""
    }
  }

  function findVideoInReactProps(props) {
    if (!props) return

    if (props.video) return props.video

    const children = Array.isArray(props.children) ? props.children : [props.children]

    for (const child of children) {
      const video = findVideoInReactProps(child?.props)

      if (video) return video
    }

    return
  }

  function findVideoInFiber(element) {
    let fiber = getReactInstance(element)

    while (fiber) {
      const video = findVideoInReactProps(fiber.memoizedProps)

      if (video) return video

      fiber = fiber.return
    }

    return
  }

  function updateSources(downloadDropdown) {
    const newSources = $(downloadDropdown)
      .find(".dropdown__content a")
      .map(function () {
        const url = this.href
        const label = this.innerText

        return { url, label }
      })
      .get()

    if (!newSources.length) return

    sources.splice(0, sources.length, ...newSources)

    hasFreshSources.value = true
  }

  function convertDownloadDropdown(downloadButton, enabled) {
    const $button = downloadButton ? $(downloadButton) : $(".downloadButton")
    const $dropdown = $button.closest(".dropdown")

    if (!$dropdown.length) return

    const rawButtonText = $button.text().replace(/\s*\(.*\)/, "")

    if (enabled) {
      $dropdown.data("converted") ||
        $dropdown
          .data("converted", true)
          .on("click", function () {
            download(this)
          })
          .children(".dropdown__content")
          .css("display", "none")

      const resolution = source.value?.label

      $button.text(rawButtonText + (resolution ? ` (${resolution})` : ""))
    } else {
      $dropdown
        .data("converted", false)
        .off("click")
        .children(".dropdown__content")
        .css("display", "")
      $button.text(rawButtonText)
    }
  }

  function download(downloadDropdown) {
    try {
      if (!hasFreshSources.value) throw new Error("No sources found in current page.")
      if (!source.value) throw new Error("Missing source.")

      const $downloadButton = $(downloadDropdown).find(".downloadButton")

      const filename = resolveFilename(filenameTemplate.value, source.value)

      log("Downloading:", filename, source.value.url, GM_info.downloadMode)

      if (GM_info.downloadMode === "browser") {
        setDownloadButtonEnabled(false)

        const downloadUrl = resolveDownloadUrl(source.value.url, filename)

        GM_download({
          url: downloadUrl,
          name: filename,
          onload: () => downloadEnded("onload"),
          onerror: (e) => {
            downloadEnded("onerror", e)
            openNativeDownload(downloadUrl, filename)
          },
          ontimeout: () => downloadEnded("ontimeout"),
        })
      } else openNativeDownload(resolveDownloadUrl(source.value.url, filename), filename)

      function setDownloadButtonEnabled(enabled) {
        if (enabled) {
          // TODO: properly disable the button
          $(downloadDropdown).css("pointer-events", "")
          $downloadButton.css("background-color", "")
        } else {
          $(downloadDropdown).css("pointer-events", "none")
          $downloadButton.css("background-color", "var(--primary-dark)")
        }
      }

      function downloadEnded(type, e) {
        setDownloadButtonEnabled(true)

        type === "ontimeout" && (e = { error: "timed_out" })

        if (e && e.error) {
          log(e)
          printDownloadMessage(
            `Download Error (${e.error}): ${(e.details && e.details.current) || "No info"}`
          )
        }
      }
    } catch (e) {
      log(e)
      printDownloadMessage(e + "")
    }
  }

  function resolveFilename(template, source) {
    if (videoInfo.error) throw new Error("Broken video info: " + videoInfo.error)

    const replacements = {
      ID: videoInfo.id,
      TITLE: videoInfo.title,
      RES: source.label,
      AUTHOR: videoInfo.author,
      DATE: formatDate(new Date(), ""),
      DATE_TS: new Date().getTime() + "",
      UP_DATE: formatDate(new Date(videoInfo.created), ""),
      UP_DATE_TS: videoInfo.created + "",
      DATE_FMT: formatDateReadable(new Date()),
      UP_DATE_FMT: formatDateReadable(new Date(videoInfo.created)),
    }

    const wrappedKeywords = FILENAME_KEYWORDS.map((k) => `{${k}}`)
    const regex = new RegExp(`(${wrappedKeywords.join("|")})`, "g")

    const basename = template.replace(regex, (match) => {
      const keyword = match.slice(1, -1)
      const value = replacements[keyword]

      // remove path delimiters in keyword values
      return value.replace(/[/\\]/g, illegalCharReplacement.value)
    })

    const ext = getFilenameExtension(source.url)

    const filename = basename + ext

    return sanitizePath(filename, illegalCharReplacement.value)
  }

  function getFilenameExtension(sourceUrl) {
    try {
      const url = new URL(sourceUrl)
      const queryFilename = url.searchParams.get("filename")
      const path = queryFilename || url.pathname
      const match = path.match(/\.([A-Za-z0-9]+)$/)

      return match ? `.${match[1]}` : ""
    } catch {
      const path = sourceUrl.split(/[?#]/)[0] || sourceUrl
      const match = path.match(/\.([A-Za-z0-9]+)$/)

      return match ? `.${match[1]}` : ""
    }
  }

  function openNativeDownload(url, filename) {
    const a = document.createElement("a")
    a.href = url
    a.download = filename
    a.click()
  }

  function resolveDownloadUrl(sourceUrl, filename) {
    try {
      const url = new URL(sourceUrl)

      url.hostname.endsWith("iwara.tv") &&
        url.searchParams.has("download") &&
        url.searchParams.set("download", getDownloadFilenameLeaf(filename))

      return url.href
    } catch {
      return sourceUrl
    }
  }

  function getDownloadFilenameLeaf(filename) {
    return filename.split(/[\\/]/).pop() || filename
  }

  function printDownloadMessage(msg) {
    $(".page-video__bottom")
      .css("flex-wrap", "wrap")
      .append(`<div style="flex: 100% 0 0">${msg}</div>`)
  }

  const likeRateEnabled = (0, external_Vue_namespaceObject.ref)(storage.get("like_rates"))
  const highlightThreshold = (0, external_Vue_namespaceObject.ref)(
    storage.get("like_rate_highlight")
  )
  const highlightOpacity = (0, external_Vue_namespaceObject.ref)(
    storage.get("like_rate_highlight_opacity")
  )

  const likeRateClass = "enh-like-rate"
  const highlightClass = "enh-highlight"

  ready.then(updateHighlightOpacity)

  ;(0, external_Vue_namespaceObject.watchEffect)(() => {
    storage.set("like_rates", likeRateEnabled.value)

    if (likeRateEnabled.value) {
      document.body.classList.add("enh-show-like-rates")
      $(".videoTeaser, .imageTeaser").each((i, teaser) => processTeaser(teaser))
    } else {
      document.body.classList.remove("enh-show-like-rates")
      $("." + highlightClass).removeClass(highlightClass)
    }
  })

  ;(0, external_Vue_namespaceObject.watchEffect)(() => {
    storage.set("like_rate_highlight", highlightThreshold.value)

    $(".videoTeaser, .imageTeaser").each((i, teaser) => processTeaser(teaser))
  })

  ;(0, external_Vue_namespaceObject.watchEffect)(() => {
    storage.set("like_rate_highlight_opacity", highlightOpacity.value)

    updateHighlightOpacity()
  })

  function useTeaserSettings() {
    return { likeRateEnabled, highlightThreshold, highlightOpacity }
  }

  page(
    ["home", "videoList", "imageList", "subscriptions", "profile", "video", "image"],
    async (pageID, onLeave) => {
      const teaserObserver = new SimpleMutationObserver((mutation) =>
        mutation.addedNodes.forEach(detectColumn)
      )

      onLeave(() => {
        teaserObserver.disconnect()
      })

      const teaserBatcher = new TeaserBatcher()

      if (["home", "profile", "image"].includes(pageID))
        [".videoTeaser", ".imageTeaser"].forEach(async (selector) => {
          const $teasers = await until$(() => $(selector), 200)

          requestProcessTeasers($teasers.toArray())
        })
      else if (pageID === "video") {
        const selectors = [".moreFromUser", ".moreLikeThis"].flatMap((parentCls) =>
          [".videoTeaser", ".imageTeaser"].map((cls) => `${parentCls} ${cls}`)
        )

        selectors.forEach(async (selector) => {
          const $teasers = await until$(() => $(selector), 200)

          requestProcessTeasers($teasers.toArray())
        })
      } else {
        const $teasers = await until$(
          () => $(".videoTeaser:first-of-type, .imageTeaser:first-of-type"),
          200
        )

        detectRow($teasers.closest(".row")[0])
      }

      function detectRow(row) {
        teaserObserver.observe(row, { childList: true, immediate: true })
      }

      function detectColumn(column) {
        const { firstChild } = column

        !firstChild ||
          (!hasClass(firstChild, "videoTeaser") && !hasClass(firstChild, "imageTeaser")) ||
          requestProcessTeasers([firstChild])
      }

      function requestProcessTeasers(teasers) {
        teasers.forEach((teaser) => teaserBatcher.add(teaser))
        teaserBatcher.run(processTeaser)
      }
    }
  )

  class TeaserBatcher {
    teasers = []

    add(teaser) {
      this.teasers.push(teaser)
    }

    run = throttle((callback) => {
      let lastError

      try {
        this.teasers.forEach(callback)
      } catch (e) {
        // only record the last error so the console won't blow up
        lastError = e
      }

      lastError && log("Failed to process teasers", lastError)

      this.teasers.length = 0
    }, 0)
  }

  function processTeaser(teaser) {
    const viewsLabel = $(teaser).find(".views")
    const likesLabel = $(teaser).find(".likes")

    let likePercentage

    const likeRateLabel = viewsLabel.children("." + likeRateClass)

    if (likeRateLabel.length) likePercentage = +likeRateLabel.text().trim().replace("%", "")
    else {
      const views = parseAbbreviatedNumber(viewsLabel.text().trim())
      const likes = parseAbbreviatedNumber(likesLabel.text().trim())

      likePercentage = Math.round((100 * likes) / views)

      const display = Number.isFinite(likePercentage) ? likePercentage + "%" : "/"

      // prettier-ignore
      viewsLabel.children().eq(0).clone().addClass(likeRateClass).text(display).prependTo(viewsLabel)
    }

    likePercentage >= highlightThreshold.value && likeRateEnabled.value
      ? teaser.classList.add(highlightClass)
      : teaser.classList.remove(highlightClass)
  }

  function updateHighlightOpacity() {
    const color = getComputedStyle(document.body).getPropertyValue("--primary").trim()

    // color will be empty before the page is fully loaded
    color &&
      document.body.style.setProperty("--ehg-hl-bg", adjustAlpha(color, highlightOpacity.value))
  }

  const widenListEnabled = (0, external_Vue_namespaceObject.ref)(storage.get("widen_list"))
  const widenListScale = (0, external_Vue_namespaceObject.ref)(storage.get("widen_list_scale"))
  const widenContentEnabled = (0, external_Vue_namespaceObject.ref)(storage.get("widen_content"))
  const widenContentScale = (0, external_Vue_namespaceObject.ref)(
    storage.get("widen_content_scale")
  )

  ;(0, external_Vue_namespaceObject.watch)(widenListEnabled, (enabled) =>
    storage.set("widen_list", enabled)
  )
  ;(0, external_Vue_namespaceObject.watch)(widenListScale, (scale) =>
    storage.set("widen_list_scale", scale)
  )
  ;(0, external_Vue_namespaceObject.watch)(widenContentEnabled, (enabled) =>
    storage.set("widen_content", enabled)
  )
  ;(0, external_Vue_namespaceObject.watch)(widenContentScale, (scale) =>
    storage.set("widen_content_scale", scale)
  )
  ;(0, external_Vue_namespaceObject.watch)(
    [widenListEnabled, widenListScale],
    throttle(updateListScale, 100)
  )

  function useWidenContentSettings() {
    return { widenListEnabled, widenListScale, widenContentEnabled, widenContentScale }
  }

  let widenListStyleEl

  function updateListScale() {
    widenListStyleEl?.remove()
    widenListStyleEl = void 0

    if (widenListEnabled.value) {
      const pageIds = [
        "home",
        "videoList",
        "imageList",
        "subscriptions",
        "profile",
        "video",
        "image",
      ]
      const classes = pageIds.map((pageId) => `.page-${pageId} .container-fluid`)

      widenListStyleEl = GM_addStyle(`${classes.join(",")} {
          max-width: ${1200 * (widenListScale.value / 100)}px;
        }`)
    }
  }

  updateListScale()

  page(["video", "image"], (pageID, onLeave) => {
    const mediaArea = $(".page-video__player, .page-video__slideshow").get(0)

    if (!mediaArea) {
      log(`${pageID === "video" ? "video" : "slideshow"} area not found.`)
      return
    }

    const sidebar = $(".page-video__sidebar").get(0)

    if (!sidebar) {
      log("sidebar not found.")
      return
    }

    const col = $(mediaArea).closest(".col-12").get(0)
    const row = $(mediaArea).closest(".row").get(0)
    const container = $(row).closest(".content").get(0)

    onLeave((0, external_Vue_namespaceObject.watchEffect)(() => updateResize()))

    function updateResize(entries) {
      if (widenContentEnabled.value) {
        let containerWidth = 0
        let rowWidth = 0
        let colWidth = 0
        let mediaHeight = 0

        if (entries)
          for (const entry of entries)
            entry.target === mediaArea
              ? (mediaHeight = entry.contentRect.height)
              : entry.target === col
              ? (colWidth = entry.contentRect.width)
              : entry.target === row
              ? (rowWidth = entry.contentRect.width)
              : entry.target === container && (containerWidth = entry.contentRect.width)
        else {
          containerWidth = container.offsetWidth
          rowWidth = row.offsetWidth
          colWidth = col.offsetWidth
          mediaHeight = mediaArea.offsetHeight
        }

        // iwara uses a polyfilled ResizeObserver, which reports an error when resizing DOMs in the callback immediately,
        // this is so stupid that I have to use setTimeout to avoid the error
        // see: https://github.com/juggle/resize-observer/issues/103
        setTimeout(() => {
          if (containerWidth > 0 && rowWidth > 0 && colWidth > 0) {
            const scale = widenContentScale.value / 100
            const mediaWidth = Math.min(rowWidth * scale, containerWidth)

            mediaArea.style.marginLeft = `${~~((rowWidth - mediaWidth) / 2)}px`
            mediaArea.style.marginRight = `${~~(
              (rowWidth - mediaWidth) / 2 -
              (rowWidth - colWidth)
            )}px`
          }

          mediaHeight > 0 &&
            (sidebar.style.marginTop = `${~~(mediaArea.offsetTop + mediaHeight)}px`)
        }, 0)
      } else {
        mediaArea.style.marginLeft = ""
        mediaArea.style.marginRight = ""
        sidebar.style.marginTop = ""
      }
    }

    const observer = new ResizeObserver(updateResize)

    observer.observe(mediaArea)
    observer.observe(row)
    observer.observe(container)

    onLeave(() => {
      observer.disconnect()
    })
  })

  // extracted by mini-css-extract-plugin
  /* harmony default export */ const Settings_module = {
    switch: "Settings-module__switch--qcsG",
    settings: "Settings-module__settings--alpJ",
    active: "Settings-module__active--iMRv",
    disabled: "Settings-module__disabled--vvjv",
    header: "Settings-module__header--s2Rw",
    title: "Settings-module__title--aDU_",
    view: "Settings-module__view--dY2E",
    sectionHeader: "Settings-module__section-header--Xy_I",
    fieldLabel: "Settings-module__field-label--O5EA",
    labelBlock: "Settings-module__label-block--EYVa",
    labelInline: "Settings-module__label-inline--v3DK",
    panel: "Settings-module__panel--PuCY",
  }

  // recommended vscode plugin for syntax highlighting: https://marketplace.visualstudio.com/items?itemName=Tobermory.es6-string-html
  // language=HTML
  // 由于Iwara的CSP限制,不能运行时渲染Vue模板,需要构建时预编译渲染函数(原模板请参见 git 中的源码)
  function render(_ctx, _cache) {
    return (
      (0, external_Vue_namespaceObject.openBlock)(),
      (0, external_Vue_namespaceObject.createElementBlock)(
        external_Vue_namespaceObject.Fragment,
        null,
        [
          (0, external_Vue_namespaceObject.createElementVNode)(
            "div",
            { class: "text text--text text--bold" },
            "E"
          ),
          _ctx.visible
            ? ((0, external_Vue_namespaceObject.openBlock)(),
              (0, external_Vue_namespaceObject.createElementBlock)(
                "div",
                {
                  key: 0,
                  class: (0, external_Vue_namespaceObject.normalizeClass)(_ctx.css.settings),
                  onClick: (0, external_Vue_namespaceObject.withModifiers)(() => {}, ["stop"]),
                },
                [
                  (0, external_Vue_namespaceObject.createElementVNode)(
                    "header",
                    { class: (0, external_Vue_namespaceObject.normalizeClass)(_ctx.css.header) },
                    [
                      (0, external_Vue_namespaceObject.createElementVNode)(
                        "h2",
                        { class: (0, external_Vue_namespaceObject.normalizeClass)(_ctx.css.title) },
                        (0, external_Vue_namespaceObject.toDisplayString)(_ctx.$t("name")) +
                          " v${GM_info.script.version}",
                        3
                      ),
                    ],
                    2
                  ),
                  (0, external_Vue_namespaceObject.createElementVNode)("nav", null, [
                    (0, external_Vue_namespaceObject.createElementVNode)("ul", null, [
                      ((0, external_Vue_namespaceObject.openBlock)(true),
                      (0, external_Vue_namespaceObject.createElementBlock)(
                        external_Vue_namespaceObject.Fragment,
                        null,
                        (0, external_Vue_namespaceObject.renderList)(
                          _ctx.tabs,
                          (tab, i) => (
                            (0, external_Vue_namespaceObject.openBlock)(),
                            (0, external_Vue_namespaceObject.createElementBlock)(
                              "li",
                              {
                                class: (0, external_Vue_namespaceObject.normalizeClass)({
                                  [_ctx.css.active]: i === _ctx.tabIndex,
                                }),
                                onClick: ($event) => (_ctx.tabIndex = i),
                              },
                              (0, external_Vue_namespaceObject.toDisplayString)(_ctx.$t(tab.name)),
                              11,
                              ["onClick"]
                            )
                          )
                        ),
                        256
                      )),
                    ]),
                  ]),
                  _ctx.tabVal === "ui"
                    ? ((0, external_Vue_namespaceObject.openBlock)(),
                      (0, external_Vue_namespaceObject.createElementBlock)(
                        "div",
                        {
                          key: 0,
                          class: (0, external_Vue_namespaceObject.normalizeClass)(_ctx.css.view),
                        },
                        [
                          (0, external_Vue_namespaceObject.createElementVNode)(
                            "h2",
                            {
                              class: (0, external_Vue_namespaceObject.normalizeClass)(
                                _ctx.css.sectionHeader
                              ),
                            },
                            (0, external_Vue_namespaceObject.toDisplayString)(
                              _ctx.$t("s.ui.label")
                            ),
                            3
                          ),
                          (0, external_Vue_namespaceObject.createElementVNode)(
                            "h3",
                            {
                              class: (0, external_Vue_namespaceObject.normalizeClass)(
                                _ctx.css.fieldLabel
                              ),
                            },
                            (0, external_Vue_namespaceObject.toDisplayString)(
                              _ctx.$t("s.ui.like_rate.label")
                            ),
                            3
                          ),
                          (0, external_Vue_namespaceObject.createElementVNode)(
                            "p",
                            { innerHTML: _ctx.$t("s.ui.like_rate.desc") },
                            null,
                            8,
                            ["innerHTML"]
                          ),
                          (0, external_Vue_namespaceObject.createElementVNode)("p", null, [
                            (0, external_Vue_namespaceObject.createElementVNode)(
                              "label",
                              {
                                class: (0, external_Vue_namespaceObject.normalizeClass)(
                                  _ctx.css.labelBlock
                                ),
                              },
                              [
                                (0, external_Vue_namespaceObject.createTextVNode)(
                                  (0, external_Vue_namespaceObject.toDisplayString)(
                                    _ctx.$t("s.enabled")
                                  ) + " ",
                                  1
                                ),
                                (0, external_Vue_namespaceObject.withDirectives)(
                                  (0, external_Vue_namespaceObject.createElementVNode)(
                                    "input",
                                    {
                                      type: "checkbox",
                                      "onUpdate:modelValue": ($event) =>
                                        (_ctx.likeRateEnabled = $event),
                                    },
                                    null,
                                    8,
                                    ["onUpdate:modelValue"]
                                  ),
                                  [
                                    [
                                      external_Vue_namespaceObject.vModelCheckbox,
                                      _ctx.likeRateEnabled,
                                    ],
                                  ]
                                ),
                              ],
                              2
                            ),
                          ]),
                          (0, external_Vue_namespaceObject.createElementVNode)(
                            "h3",
                            {
                              class: (0, external_Vue_namespaceObject.normalizeClass)(
                                _ctx.css.fieldLabel
                              ),
                            },
                            (0, external_Vue_namespaceObject.toDisplayString)(
                              _ctx.$t("s.ui.highlight_threshold.label")
                            ),
                            3
                          ),
                          (0, external_Vue_namespaceObject.createElementVNode)(
                            "p",
                            { innerHTML: _ctx.$t("s.ui.highlight_threshold.desc") },
                            null,
                            8,
                            ["innerHTML"]
                          ),
                          (0, external_Vue_namespaceObject.createElementVNode)("p", null, [
                            (0, external_Vue_namespaceObject.withDirectives)(
                              (0, external_Vue_namespaceObject.createElementVNode)(
                                "input",
                                {
                                  type: "number",
                                  step: "0.1",
                                  min: "0",
                                  max: "100",
                                  "onUpdate:modelValue": ($event) =>
                                    (_ctx.highlightThreshold = $event),
                                },
                                null,
                                8,
                                ["onUpdate:modelValue"]
                              ),
                              [[external_Vue_namespaceObject.vModelText, _ctx.highlightThreshold]]
                            ),
                          ]),
                          (0, external_Vue_namespaceObject.createElementVNode)(
                            "h3",
                            {
                              class: (0, external_Vue_namespaceObject.normalizeClass)(
                                _ctx.css.fieldLabel
                              ),
                            },
                            (0, external_Vue_namespaceObject.toDisplayString)(
                              _ctx.$t("s.ui.highlight_bg.label")
                            ),
                            3
                          ),
                          (0, external_Vue_namespaceObject.createElementVNode)("p", null, [
                            (0, external_Vue_namespaceObject.withDirectives)(
                              (0, external_Vue_namespaceObject.createElementVNode)(
                                "input",
                                {
                                  type: "range",
                                  min: "0",
                                  max: "1",
                                  step: "0.01",
                                  "onUpdate:modelValue": ($event) =>
                                    (_ctx.highlightOpacity = $event),
                                },
                                null,
                                8,
                                ["onUpdate:modelValue"]
                              ),
                              [[external_Vue_namespaceObject.vModelText, _ctx.highlightOpacity]]
                            ),
                          ]),
                          (0, external_Vue_namespaceObject.createElementVNode)(
                            "h3",
                            {
                              class: (0, external_Vue_namespaceObject.normalizeClass)(
                                _ctx.css.fieldLabel
                              ),
                            },
                            (0, external_Vue_namespaceObject.toDisplayString)(
                              _ctx.$t("s.ui.widen_content.label")
                            ),
                            3
                          ),
                          (0, external_Vue_namespaceObject.createElementVNode)(
                            "p",
                            { innerHTML: _ctx.$t("s.ui.widen_content.desc") },
                            null,
                            8,
                            ["innerHTML"]
                          ),
                          (0, external_Vue_namespaceObject.createElementVNode)("p", null, [
                            (0, external_Vue_namespaceObject.createElementVNode)(
                              "label",
                              {
                                class: (0, external_Vue_namespaceObject.normalizeClass)(
                                  _ctx.css.labelBlock
                                ),
                              },
                              [
                                (0, external_Vue_namespaceObject.createTextVNode)(
                                  (0, external_Vue_namespaceObject.toDisplayString)(
                                    _ctx.$t("s.enabled")
                                  ) + " ",
                                  1
                                ),
                                (0, external_Vue_namespaceObject.withDirectives)(
                                  (0, external_Vue_namespaceObject.createElementVNode)(
                                    "input",
                                    {
                                      type: "checkbox",
                                      "onUpdate:modelValue": ($event) =>
                                        (_ctx.widenContentEnabled = $event),
                                    },
                                    null,
                                    8,
                                    ["onUpdate:modelValue"]
                                  ),
                                  [
                                    [
                                      external_Vue_namespaceObject.vModelCheckbox,
                                      _ctx.widenContentEnabled,
                                    ],
                                  ]
                                ),
                              ],
                              2
                            ),
                          ]),
                          (0, external_Vue_namespaceObject.createElementVNode)("p", null, [
                            (0, external_Vue_namespaceObject.createElementVNode)(
                              "label",
                              {
                                class: (0, external_Vue_namespaceObject.normalizeClass)(
                                  _ctx.css.labelBlock
                                ),
                              },
                              [
                                (0, external_Vue_namespaceObject.createTextVNode)(
                                  (0, external_Vue_namespaceObject.toDisplayString)(
                                    _ctx.$t("s.ui.widen_content.scale")
                                  ) + " ",
                                  1
                                ),
                                (0, external_Vue_namespaceObject.createElementVNode)(
                                  "input",
                                  {
                                    type: "number",
                                    step: "1",
                                    min: "10",
                                    max: "500",
                                    value: _ctx.widenContentScale,
                                    onChange: ($event) =>
                                      (_ctx.widenContentScale = Math.round($event.target.value)),
                                  },
                                  null,
                                  40,
                                  ["value", "onChange"]
                                ),
                              ],
                              2
                            ),
                          ]),
                          (0, external_Vue_namespaceObject.createElementVNode)(
                            "h3",
                            {
                              class: (0, external_Vue_namespaceObject.normalizeClass)(
                                _ctx.css.fieldLabel
                              ),
                            },
                            (0, external_Vue_namespaceObject.toDisplayString)(
                              _ctx.$t("s.ui.widen_list.label")
                            ),
                            3
                          ),
                          (0, external_Vue_namespaceObject.createElementVNode)(
                            "p",
                            { innerHTML: _ctx.$t("s.ui.widen_list.desc") },
                            null,
                            8,
                            ["innerHTML"]
                          ),
                          (0, external_Vue_namespaceObject.createElementVNode)("p", null, [
                            (0, external_Vue_namespaceObject.createElementVNode)(
                              "label",
                              {
                                class: (0, external_Vue_namespaceObject.normalizeClass)(
                                  _ctx.css.labelBlock
                                ),
                              },
                              [
                                (0, external_Vue_namespaceObject.createTextVNode)(
                                  (0, external_Vue_namespaceObject.toDisplayString)(
                                    _ctx.$t("s.enabled")
                                  ) + " ",
                                  1
                                ),
                                (0, external_Vue_namespaceObject.withDirectives)(
                                  (0, external_Vue_namespaceObject.createElementVNode)(
                                    "input",
                                    {
                                      type: "checkbox",
                                      "onUpdate:modelValue": ($event) =>
                                        (_ctx.widenListEnabled = $event),
                                    },
                                    null,
                                    8,
                                    ["onUpdate:modelValue"]
                                  ),
                                  [
                                    [
                                      external_Vue_namespaceObject.vModelCheckbox,
                                      _ctx.widenListEnabled,
                                    ],
                                  ]
                                ),
                              ],
                              2
                            ),
                          ]),
                          (0, external_Vue_namespaceObject.createElementVNode)("p", null, [
                            (0, external_Vue_namespaceObject.createElementVNode)(
                              "label",
                              {
                                class: (0, external_Vue_namespaceObject.normalizeClass)(
                                  _ctx.css.labelBlock
                                ),
                              },
                              [
                                (0, external_Vue_namespaceObject.createTextVNode)(
                                  (0, external_Vue_namespaceObject.toDisplayString)(
                                    _ctx.$t("s.ui.widen_list.scale")
                                  ) + " ",
                                  1
                                ),
                                (0, external_Vue_namespaceObject.createElementVNode)(
                                  "input",
                                  {
                                    type: "number",
                                    step: "1",
                                    min: "10",
                                    max: "500",
                                    value: _ctx.widenListScale,
                                    onChange: ($event) =>
                                      (_ctx.widenListScale = Math.round($event.target.value)),
                                  },
                                  null,
                                  40,
                                  ["value", "onChange"]
                                ),
                              ],
                              2
                            ),
                          ]),
                        ],
                        2
                      ))
                    : _ctx.tabVal === "download"
                    ? ((0, external_Vue_namespaceObject.openBlock)(),
                      (0, external_Vue_namespaceObject.createElementBlock)(
                        "div",
                        {
                          key: 1,
                          class: (0, external_Vue_namespaceObject.normalizeClass)(_ctx.css.view),
                        },
                        [
                          (0, external_Vue_namespaceObject.createElementVNode)(
                            "h2",
                            {
                              class: (0, external_Vue_namespaceObject.normalizeClass)(
                                _ctx.css.sectionHeader
                              ),
                            },
                            (0, external_Vue_namespaceObject.toDisplayString)(
                              _ctx.$t("s.download.label")
                            ),
                            3
                          ),
                          (0, external_Vue_namespaceObject.createElementVNode)(
                            "h3",
                            {
                              class: (0, external_Vue_namespaceObject.normalizeClass)(
                                _ctx.css.fieldLabel
                              ),
                            },
                            (0, external_Vue_namespaceObject.toDisplayString)(
                              _ctx.$t("s.download.auto.label")
                            ),
                            3
                          ),
                          (0, external_Vue_namespaceObject.createElementVNode)(
                            "p",
                            { innerHTML: _ctx.$t("s.download.auto.desc") },
                            null,
                            8,
                            ["innerHTML"]
                          ),
                          (0, external_Vue_namespaceObject.createElementVNode)("p", null, [
                            (0, external_Vue_namespaceObject.createElementVNode)(
                              "label",
                              {
                                class: (0, external_Vue_namespaceObject.normalizeClass)(
                                  _ctx.css.labelBlock
                                ),
                              },
                              [
                                (0, external_Vue_namespaceObject.createTextVNode)(
                                  (0, external_Vue_namespaceObject.toDisplayString)(
                                    _ctx.$t("s.enabled")
                                  ) + " ",
                                  1
                                ),
                                (0, external_Vue_namespaceObject.withDirectives)(
                                  (0, external_Vue_namespaceObject.createElementVNode)(
                                    "input",
                                    {
                                      type: "checkbox",
                                      "onUpdate:modelValue": ($event) =>
                                        (_ctx.autoDownEnabled = $event),
                                    },
                                    null,
                                    8,
                                    ["onUpdate:modelValue"]
                                  ),
                                  [
                                    [
                                      external_Vue_namespaceObject.vModelCheckbox,
                                      _ctx.autoDownEnabled,
                                    ],
                                  ]
                                ),
                              ],
                              2
                            ),
                          ]),
                          (0, external_Vue_namespaceObject.createElementVNode)(
                            "h3",
                            {
                              class: (0, external_Vue_namespaceObject.normalizeClass)(
                                _ctx.css.fieldLabel
                              ),
                            },
                            (0, external_Vue_namespaceObject.toDisplayString)(
                              _ctx.$t("s.download.resolution.label")
                            ),
                            3
                          ),
                          (0, external_Vue_namespaceObject.createElementVNode)("p", null, [
                            ((0, external_Vue_namespaceObject.openBlock)(true),
                            (0, external_Vue_namespaceObject.createElementBlock)(
                              external_Vue_namespaceObject.Fragment,
                              null,
                              (0, external_Vue_namespaceObject.renderList)(
                                _ctx.RESOLUTIONS,
                                (res) => (
                                  (0, external_Vue_namespaceObject.openBlock)(),
                                  (0, external_Vue_namespaceObject.createElementBlock)(
                                    "label",
                                    {
                                      class: (0, external_Vue_namespaceObject.normalizeClass)(
                                        _ctx.css.labelInline
                                      ),
                                    },
                                    [
                                      (0, external_Vue_namespaceObject.withDirectives)(
                                        (0, external_Vue_namespaceObject.createElementVNode)(
                                          "input",
                                          {
                                            type: "radio",
                                            name: "res",
                                            value: res,
                                            "onUpdate:modelValue": ($event) =>
                                              (_ctx.resolution = $event),
                                          },
                                          null,
                                          8,
                                          ["value", "onUpdate:modelValue"]
                                        ),
                                        [
                                          [
                                            external_Vue_namespaceObject.vModelRadio,
                                            _ctx.resolution,
                                          ],
                                        ]
                                      ),
                                      (0, external_Vue_namespaceObject.createTextVNode)(
                                        " " +
                                          (0, external_Vue_namespaceObject.toDisplayString)(res),
                                        1
                                      ),
                                    ],
                                    2
                                  )
                                )
                              ),
                              256
                            )),
                          ]),
                          (0, external_Vue_namespaceObject.createElementVNode)(
                            "h3",
                            {
                              class: (0, external_Vue_namespaceObject.normalizeClass)(
                                _ctx.css.fieldLabel
                              ),
                            },
                            (0, external_Vue_namespaceObject.toDisplayString)(
                              _ctx.$t("s.download.filename.label")
                            ),
                            3
                          ),
                          (0, external_Vue_namespaceObject.createElementVNode)(
                            "p",
                            { innerHTML: _ctx.$t("s.download.filename.desc") },
                            null,
                            8,
                            ["innerHTML"]
                          ),
                          (0, external_Vue_namespaceObject.createElementVNode)(
                            "div",
                            {
                              class: (0, external_Vue_namespaceObject.normalizeClass)(
                                _ctx.css.keywords
                              ),
                            },
                            [
                              (0, external_Vue_namespaceObject.createElementVNode)(
                                "table",
                                {
                                  class: (0, external_Vue_namespaceObject.normalizeClass)(
                                    _ctx.css.keywordTable
                                  ),
                                },
                                [
                                  ((0, external_Vue_namespaceObject.openBlock)(true),
                                  (0, external_Vue_namespaceObject.createElementBlock)(
                                    external_Vue_namespaceObject.Fragment,
                                    null,
                                    (0, external_Vue_namespaceObject.renderList)(
                                      _ctx.FILENAME_KEYWORDS,
                                      (kw) => (
                                        (0, external_Vue_namespaceObject.openBlock)(),
                                        (0, external_Vue_namespaceObject.createElementBlock)(
                                          "tr",
                                          null,
                                          [
                                            (0, external_Vue_namespaceObject.createElementVNode)(
                                              "th",
                                              null,
                                              (0, external_Vue_namespaceObject.toDisplayString)(kw),
                                              1
                                            ),
                                            (0, external_Vue_namespaceObject.createElementVNode)(
                                              "td",
                                              null,
                                              (0, external_Vue_namespaceObject.toDisplayString)(
                                                _ctx.$t(
                                                  "s.download.filename.key." + kw.toLowerCase()
                                                )
                                              ),
                                              1
                                            ),
                                          ]
                                        )
                                      )
                                    ),
                                    256
                                  )),
                                ],
                                2
                              ),
                            ],
                            2
                          ),
                          (0, external_Vue_namespaceObject.createElementVNode)("details", null, [
                            (0, external_Vue_namespaceObject.createElementVNode)(
                              "summary",
                              null,
                              (0, external_Vue_namespaceObject.toDisplayString)(_ctx.$t("s.extra")),
                              1
                            ),
                            (0, external_Vue_namespaceObject.createElementVNode)("p", null, [
                              (0, external_Vue_namespaceObject.createTextVNode)(
                                (0, external_Vue_namespaceObject.toDisplayString)(
                                  _ctx.$t("s.download.filename.replace_illegal_char")
                                ) + " ",
                                1
                              ),
                              (0, external_Vue_namespaceObject.withDirectives)(
                                (0, external_Vue_namespaceObject.createElementVNode)(
                                  "input",
                                  {
                                    type: "text",
                                    "onUpdate:modelValue": ($event) =>
                                      (_ctx.illegalCharReplacement = $event),
                                  },
                                  null,
                                  8,
                                  ["onUpdate:modelValue"]
                                ),
                                [
                                  [
                                    external_Vue_namespaceObject.vModelText,
                                    _ctx.illegalCharReplacement,
                                  ],
                                ]
                              ),
                              (0, external_Vue_namespaceObject.createTextVNode)(
                                " " +
                                  (0, external_Vue_namespaceObject.toDisplayString)(
                                    "*miku*miku:dance??.mp4 -> "
                                  ) +
                                  " " +
                                  (0, external_Vue_namespaceObject.toDisplayString)(
                                    _ctx.sanitizePath(
                                      "*miku*miku:dance??.mp4",
                                      _ctx.illegalCharReplacement
                                    )
                                  ),
                                1
                              ),
                            ]),
                          ]),
                          (0, external_Vue_namespaceObject.withDirectives)(
                            (0, external_Vue_namespaceObject.createElementVNode)(
                              "input",
                              {
                                type: "text",
                                "onUpdate:modelValue": ($event) => (_ctx.filenameTemplate = $event),
                              },
                              null,
                              8,
                              ["onUpdate:modelValue"]
                            ),
                            [[external_Vue_namespaceObject.vModelText, _ctx.filenameTemplate]]
                          ),
                          (0, external_Vue_namespaceObject.createElementVNode)(
                            "p",
                            null,
                            (0, external_Vue_namespaceObject.toDisplayString)(
                              _ctx.$t("s.download.filename.preview") + ": " + _ctx.filenamePreview
                            ),
                            1
                          ),
                          (0, external_Vue_namespaceObject.createElementVNode)(
                            "div",
                            {
                              class: (0, external_Vue_namespaceObject.normalizeClass)(
                                _ctx.css.panel
                              ),
                            },
                            [
                              (0, external_Vue_namespaceObject.createElementVNode)("p", null, [
                                (0, external_Vue_namespaceObject.createElementVNode)(
                                  "b",
                                  null,
                                  (0, external_Vue_namespaceObject.toDisplayString)(
                                    _ctx.$tm("s.download.filename.tips")[0]
                                  ),
                                  1
                                ),
                              ]),
                              (0, external_Vue_namespaceObject.createElementVNode)("ul", null, [
                                ((0, external_Vue_namespaceObject.openBlock)(true),
                                (0, external_Vue_namespaceObject.createElementBlock)(
                                  external_Vue_namespaceObject.Fragment,
                                  null,
                                  (0, external_Vue_namespaceObject.renderList)(
                                    _ctx.$tm("s.download.filename.tips").slice(1),
                                    (tip) => (
                                      (0, external_Vue_namespaceObject.openBlock)(),
                                      (0, external_Vue_namespaceObject.createElementBlock)(
                                        "li",
                                        null,
                                        [
                                          (0, external_Vue_namespaceObject.createElementVNode)(
                                            "p",
                                            { innerHTML: tip },
                                            null,
                                            8,
                                            ["innerHTML"]
                                          ),
                                        ]
                                      )
                                    )
                                  ),
                                  256
                                )),
                              ]),
                            ],
                            2
                          ),
                        ],
                        2
                      ))
                    : (0, external_Vue_namespaceObject.createCommentVNode)("v-if", true),
                  _ctx.tabVal === "script"
                    ? ((0, external_Vue_namespaceObject.openBlock)(),
                      (0, external_Vue_namespaceObject.createElementBlock)(
                        "div",
                        {
                          key: 2,
                          class: (0, external_Vue_namespaceObject.normalizeClass)(_ctx.css.view),
                        },
                        [
                          (0, external_Vue_namespaceObject.createElementVNode)(
                            "h2",
                            {
                              class: (0, external_Vue_namespaceObject.normalizeClass)(
                                _ctx.css.sectionHeader
                              ),
                            },
                            (0, external_Vue_namespaceObject.toDisplayString)(
                              _ctx.$t("s.script.label")
                            ),
                            3
                          ),
                          (0, external_Vue_namespaceObject.createElementVNode)(
                            "h3",
                            {
                              class: (0, external_Vue_namespaceObject.normalizeClass)(
                                _ctx.css.fieldLabel
                              ),
                            },
                            (0, external_Vue_namespaceObject.toDisplayString)(
                              _ctx.$t("s.script.language.label")
                            ),
                            3
                          ),
                          (0, external_Vue_namespaceObject.createElementVNode)("p", null, [
                            ((0, external_Vue_namespaceObject.openBlock)(true),
                            (0, external_Vue_namespaceObject.createElementBlock)(
                              external_Vue_namespaceObject.Fragment,
                              null,
                              (0, external_Vue_namespaceObject.renderList)(
                                _ctx.$i18n.availableLocales,
                                (loc) => (
                                  (0, external_Vue_namespaceObject.openBlock)(),
                                  (0, external_Vue_namespaceObject.createElementBlock)(
                                    "label",
                                    {
                                      class: (0, external_Vue_namespaceObject.normalizeClass)(
                                        _ctx.css.labelInline
                                      ),
                                    },
                                    [
                                      (0, external_Vue_namespaceObject.createElementVNode)(
                                        "input",
                                        {
                                          type: "radio",
                                          name: "loc",
                                          value: loc,
                                          checked: _ctx.activeLocale === loc,
                                          onChange: ($event) => (_ctx.locale = loc),
                                        },
                                        null,
                                        40,
                                        ["value", "checked", "onChange"]
                                      ),
                                      (0, external_Vue_namespaceObject.createTextVNode)(
                                        " " +
                                          (0, external_Vue_namespaceObject.toDisplayString)(
                                            _ctx.localeName(loc)
                                          ),
                                        1
                                      ),
                                    ],
                                    2
                                  )
                                )
                              ),
                              256
                            )),
                          ]),
                        ],
                        2
                      ))
                    : (0, external_Vue_namespaceObject.createCommentVNode)("v-if", true),
                ],
                10,
                ["onClick"]
              ))
            : (0, external_Vue_namespaceObject.createCommentVNode)("v-if", true),
        ],
        64
      )
    )
  }

  function setup() {
    const tabs = [
      { name: "s.ui.label", val: "ui" },
      { name: "s.download.label", val: "download" },
      { name: "s.script.label", val: "script" },
    ]
    const tabIndex = (0, external_Vue_namespaceObject.ref)(0)
    const tabVal = (0, external_Vue_namespaceObject.computed)(
      () => tabs[tabIndex.value] && tabs[tabIndex.value].val
    )
    const visible = (0, external_Vue_namespaceObject.ref)(false)

    const onClickContainer = () => {
      visible.value = !visible.value

      visible.value && onClickOutside(settingsContainer, () => (visible.value = false))
    }

    settingsContainer.addEventListener("click", onClickContainer)

    ;(0, external_Vue_namespaceObject.onBeforeUnmount)(() => {
      settingsContainer.removeEventListener("click", onClickContainer)
    })

    function localeName(loc) {
      const msg = i18n_i18n.global.getLocaleMessage(loc)
      return msg?.language || loc
    }

    return {
      css: Settings_module,
      tabs,
      tabIndex,
      tabVal,
      visible,
      downloadMode: GM_info.downloadMode,
      sanitizePath,
      localeName,
      ...useDownloaderSettings(),
      ...useConfigSettings(),
      ...useTeaserSettings(),
      ...useWidenContentSettings(),
    }
  }

  const SETTINGS_ID = "enh-settings"

  const settingsContainer = $(
    `<div id="${SETTINGS_ID}" class='header__link ${Settings_module.switch}'></div>`
  )[0]

  let app

  page(ALL, (pageID, onLeave) => {
    const destination = $(".page .dropdown--bottomLeft, a[href='/register']")[0]

    if (destination) {
      // destination element will be destroyed everytime the page changes,
      // so we need to insert the container after every page change
      destination.before(settingsContainer)

      // lazy-init the app
      if (!app)
        try {
          app = (0, external_Vue_namespaceObject.createApp)({ render, setup })

          app.use(i18n_i18n)

          true &&
            // pending fix https://github.com/vuejs/core/pull/5197
            // @ts-ignore
            (unsafeWindow.Vue = Vue)

          app.mount(settingsContainer)

          log("Settings view initialized")
        } catch (e) {
          log("Settings view init failed: " + (e?.message || e))
          app = void 0
          settingsContainer.textContent = "E"
        }
    } else log("Could not insert settings view: container not found.")
  })

  // prevent Sentry from tracking the logging
  setLogger(console.log.__sentry_original__ || console.log)

  const patchedFlag = "__enhPatched"

  page(["video"], async (pageID, onLeave) => {
    const timerPromise = until(() => {
      const player = getPlayer()

      if (player) {
        fixResolution(player)

        if (!(patchedFlag in player)) {
          player[patchedFlag] = true
          preventVolumeScrolling(player)
        }
      }
    }, 500)

    onLeave(() => timerPromise.cancel())

    function getPlayer() {
      return $(".page-video__player .video-js").get(0)?.player
    }

    function preventVolumeScrolling(player) {
      const originalGet = WeakMap.prototype.get

      // hook WeakMap.get() to get the event data
      // https://github.com/videojs/video.js/blob/2b0df25df332dceaab375327887f0721ca8d21d0/src/js/utils/events.js#L271
      WeakMap.prototype.get = function (key) {
        const value = originalGet.call(this, key)

        try {
          const data = value

          if (data?.handlers?.mousewheel) {
            log(`removing ${data.handlers.mousewheel.length} mousewheel handler(s) from Player`)

            // the listeners are bound functions and cannot be checked with toString(),
            // so we have to remove all mousewheel handlers
            delete data.handlers.mousewheel
          }
        } catch (e) {
          log("error:", e)
        } finally {
          return value
        }
      }

      // trigger the hook by adding an arbitrary event listener
      player.on("__dummy", () => {})
      player.off("__dummy")

      WeakMap.prototype.get = originalGet

      const originalOn = player.on

      // prevent adding new mousewheel listeners
      player.on = function (targetOrType) {
        if (targetOrType === "mousewheel") {
          log("prevented adding mousewheel listener")
          return
        }

        for (
          var _len = arguments.length, rest = new Array(_len > 1 ? _len - 1 : 0), _key = 1;
          _key < _len;
          _key++
        )
          rest[_key - 1] = arguments[_key]
        return originalOn.call(this, targetOrType, ...rest)
      }
    }

    function fixResolution(player) {
      const targetSource = getTargetSource(player)

      if (targetSource && targetSource.src !== player.src()) {
        log(`setting resolution to ${targetSource.name}: ${targetSource.src}`)
        player.src(targetSource)
      }
    }

    function getTargetSource(player) {
      const sources = player.currentSources()

      if (!sources.length) return

      const selectedResName = localStorage.getItem("player-resolution")
      const source = sources.find((s) => s.name === selectedResName)

      if (source) return source

      log(`error: source not found for ${selectedResName}`)

      return
    }
  })

  // this "bg" is covering the video player and preventing player from entering fullscreen mode by double-clicks
  GM_addStyle(`
.videoPlayer__bg {
  pointer-events: none;
}
`)

  const state = (0, external_Vue_namespaceObject.reactive)({ theme: "light" })

  setInterval(() => {
    state.theme = localStorage.theme
  }, 1e3)

  ;(0, external_Vue_namespaceObject.watchEffect)(updateTheme)

  function updateTheme() {
    const theme = state.theme
    const adjustmentSign = theme === "light" ? -1 : 1
    const bodyColor = getComputedStyle(document.body).getPropertyValue("--body")

    document.body.style.setProperty(
      "--enh-body-focus",
      adjustHexColor(bodyColor, adjustmentSign * 15)
    )
    document.body.style.setProperty(
      "--enh-body-highlight",
      adjustHexColor(bodyColor, adjustmentSign * 30)
    )

    const darkClass = "enh-dark"

    theme === "dark"
      ? document.body.classList.add(darkClass)
      : document.body.classList.remove(darkClass)
  }

  async function main() {
    document.body.classList.add("enh-body")

    setupPaging()
  }

  main()
})()

GM_addStyle(`
.Settings-module__switch--qcsG {
  cursor: pointer;
}

.Settings-module__settings--alpJ {
  position: absolute;
  z-index: 1000;
  top: 100%;
  right: 0;
  width: 400px;
  max-height: calc(100vh - 65px);
  overflow: auto;
  background: var(--body);
  font-size: 14px;
  border: 2px solid var(--primary);
  border-top: none;
  cursor: default;
}

.Settings-module__settings--alpJ nav {
    padding: 0 16px;
    border-bottom: 1px solid var(--enh-body-highlight);
  }

.Settings-module__settings--alpJ nav ul {
      margin: 0;
      padding: 0;
      display: flex;
      flex-wrap: wrap;
    }

.Settings-module__settings--alpJ nav li {
      padding: 8px 16px;
      list-style-type: none;
      cursor: pointer;
    }

.Settings-module__settings--alpJ nav li:hover {
        background: var(--enh-body-focus);
      }

.Settings-module__settings--alpJ nav li.Settings-module__active--iMRv {
        background: var(--enh-body-highlight);
      }

.Settings-module__settings--alpJ details {
    border: 1px solid var(--enh-body-highlight);
  }

.Settings-module__settings--alpJ details > * {
      padding: 0 8px;
    }

.Settings-module__settings--alpJ p,
  .Settings-module__settings--alpJ summary {
    color: var(--muted);
  }

.Settings-module__settings--alpJ p {
    margin-top: 0;
    margin-bottom: 8px;
  }

.Settings-module__settings--alpJ a {
    font-weight: bold;
    cursor: pointer;
  }

.Settings-module__settings--alpJ ol,
  .Settings-module__settings--alpJ ul {
    padding-left: 20px;
  }

.Settings-module__settings--alpJ table {
    margin: 8px 0;
    width: 100%;
    background: var(--enh-body-focus);
    border: 1px solid var(--enh-body-highlight);
    border-collapse: collapse;
  }

.Settings-module__settings--alpJ th {
    text-align: right;
  }

.Settings-module__settings--alpJ th,
  .Settings-module__settings--alpJ td {
    padding: 4px 8px;
    border: 1px solid var(--enh-body-highlight);
  }

.Settings-module__settings--alpJ label,
  .Settings-module__settings--alpJ summary {
    cursor: pointer;
  }

.Settings-module__settings--alpJ label:hover, .Settings-module__settings--alpJ summary:hover {
      background: var(--enh-body-focus);
    }

.Settings-module__settings--alpJ label input, .Settings-module__settings--alpJ summary input {
      cursor: pointer;
    }

.Settings-module__settings--alpJ label.Settings-module__disabled--vvjv, .Settings-module__settings--alpJ summary.Settings-module__disabled--vvjv {
      cursor: not-allowed;
    }

.Settings-module__settings--alpJ label.Settings-module__disabled--vvjv input, .Settings-module__settings--alpJ summary.Settings-module__disabled--vvjv input {
        cursor: not-allowed;
      }

.Settings-module__settings--alpJ input[type="text"] {
    outline: none !important;
  }

.Settings-module__settings--alpJ input[type="text"] {
    margin: 8px 0;
    width: 100%;
    padding: 8px;
    background: var(--enh-body-focus);
    color: var(--text);
    border: 2px solid var(--enh-body-highlight);
    border-radius: 3px;
  }

.Settings-module__settings--alpJ input[type="text"]:hover,
    .Settings-module__settings--alpJ input[type="text"]:focus {
      background: var(--enh-body-highlight);
    }

.Settings-module__header--s2Rw {
  padding: 0 16px;
}

.Settings-module__title--aDU_ {
  margin-top: 4px;
}

.Settings-module__view--dY2E {
  padding: 16px;
}

.Settings-module__section-header--Xy_I {
  margin-bottom: 16px;
}

.Settings-module__field-label--O5EA {
  position: relative;
  margin: 16px 0;
  padding-top: 16px;
}

.Settings-module__field-label--O5EA:not(:first-of-type) {
    border-top: 1px solid var(--enh-body-highlight);
  }

.Settings-module__label-block--EYVa {
  display: flex;
  padding: 8px 8px 8px 0;
}

.Settings-module__label-block--EYVa input {
    margin-left: auto;
  }

.Settings-module__label-inline--v3DK {
  display: inline-flex;
  padding: 8px 8px 8px 0;
}

.Settings-module__label-inline--v3DK:not(:first-child) {
    padding-left: 8px;
  }

.Settings-module__label-inline--v3DK:not(:last-child) {
    margin-right: 8px;
  }

.Settings-module__panel--PuCY {
  margin-bottom: 8px;
  padding: 8px;
  background: var(--enh-body-focus);
}


.enh-body {
  --ehg-hl-bg: rbga(0, 0, 0, 0);
}

#enh-settings {
  position: relative;
}

#enh-settings * {
    box-sizing: border-box;
  }

.enh-like-rate {
  display: none;
}

.enh-show-like-rates .videoTeaser .views, .enh-show-like-rates .imageTeaser .views {
    }

.enh-show-like-rates .videoTeaser .enh-like-rate, .enh-show-like-rates .imageTeaser .enh-like-rate {
      display: block;
    }

.enh-show-like-rates .videoTeaser .enh-like-rate + .text, .enh-show-like-rates .imageTeaser .enh-like-rate + .text {
        display: none;
      }

.enh-show-like-rates .page-start__subscriptions,
  .enh-show-like-rates .page-start__videos,
  .enh-show-like-rates .page-start__images {
    position: relative;
    z-index: 0;
  }

/* for all the affected pages, check out process-teaser.ts */
.enh-highlight:before {
    content: "";
    position: absolute;
    z-index: -1;
    top: -8px;
    bottom: 7px;
    left: 7px;
    right: 7px;
    background: var(--ehg-hl-bg);
  }
.page-video .enh-highlight:before,
    .page-image .enh-highlight:before {
      content: none;
    }
.page-profile .enh-highlight,
  .page-subscriptions .enh-highlight {
    position: relative;
  }
.page-profile .enh-highlight:before, .page-subscriptions .enh-highlight:before {
      top: -6px;
      bottom: -6px;
      left: -6px;
      right: -6px;
    }
.page-video .enh-highlight,
  .page-image .enh-highlight {
    background: var(--ehg-hl-bg);
  }

`)