Greasy Fork

Greasy Fork is available in English.

Twitter/X Media Batch Downloader

Batch download all images and videos from a Twitter/X account, including withheld accounts, in original quality.

当前为 2025-08-12 提交的版本,查看 最新版本

在您安装前,Greasy Fork 希望您知道此脚本声明其包含了一些负面功能。这些功能也许会使脚本作者获利,而不能给您带来任何直接的金钱收益。

您只有在付费后才能使用脚本的全部功能。Greasy Fork 未参与到支付的流程,因此无法验证您是否获得了有价值的东西,亦无法帮助您申请退款。

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Twitter/X Media Batch Downloader
// @description  Batch download all images and videos from a Twitter/X account, including withheld accounts, in original quality.
// @icon         https://raw.githubusercontent.com/afkarxyz/Twitter-X-Media-Batch-Downloader/refs/heads/main/Archived/icon.svg
// @version      4.5
// @author       afkarxyz
// @namespace    https://github.com/afkarxyz/userscripts/
// @supportURL   https://github.com/afkarxyz/userscripts/issues
// @homepageURL  https://www.patreon.com/exyezed
// @antifeature  payment
// @license      MIT
// @match        https://twitter.com/*
// @match        https://x.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_download
// @connect      api.xbatch.online
// @connect      backup.xbatch.online
// @connect      pbs.twimg.com
// @connect      video.twimg.com
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/jszip.min.js
// ==/UserScript==

(() => {
  const JSZip = window.JSZip;

  const API_URLS = {
    DEFAULT: "https://api.xbatch.online",
    BACKUP: "https://backup.xbatch.online",
  };

  const ICONS = {
    PREV: `<svg style="width: 12px; height: 12px; margin-right: 6px; display: inline-block; vertical-align: middle;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
      <path fill="currentColor" d="M9.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l192 192c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256 246.6 86.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-192 192z"/>
    </svg>`,
    NEXT: `<svg style="width: 12px; height: 12px; margin-left: 6px; display: inline-block; vertical-align: middle;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
      <path fill="currentColor" d="M310.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-192 192c-12.5 12.5-32.8 12.5-45.3 0s-12.5-32.8 0-45.3L242.7 256 73.4 86.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l192 192z"/>
    </svg>`,
    AUTO: `<svg style="width: 12px; height: 12px; margin-right: 6px; display: inline-block; vertical-align: middle;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
      <path fill="currentColor" d="M327.5 85.2c-4.5 1.7-7.5 6-7.5 10.8s3 9.1 7.5 10.8L384 128l21.2 56.5c1.7 4.5 6 7.5 10.8 7.5s9.1-3 10.8-7.5L448 128l56.5-21.2c4.5-1.7 7.5-6 7.5-10.8s-3-9.1-7.5-10.8L448 64 426.8 7.5C425.1 3 420.8 0 416 0s-9.1 3-10.8 7.5L384 64 327.5 85.2zM205.1 73.3c-2.6-5.7-8.3-9.3-14.5-9.3s-11.9 3.6-14.5 9.3L123.3 187.3 9.3 240C3.6 242.6 0 248.3 0 254.6s3.6 11.9 9.3 14.5l114.1 52.7L176 435.8c2.6 5.7 8.3 9.3 14.5 9.3s11.9-3.6 14.5-9.3l52.7-114.1 114.1-52.7c5.7-2.6 9.3-8.3 9.3-14.5s-3.6-11.9-9.3-14.5L257.8 187.4 205.1 73.3zM384 384l-56.5 21.2c-4.5 1.7-7.5 6-7.5 10.8s3 9.1 7.5 10.8L384 448l21.2 56.5c1.7 4.5 6 7.5 10.8 7.5s9.1-3 10.8-7.5L448 448l56.5-21.2c4.5-1.7 7.5-6 7.5-10.8s-3-9.1-7.5-10.8L448 384l-21.2-56.5c-1.7-4.5-6-7.5-10.8-7.5s-9.1 3-10.8 7.5L384 384z"/>
    </svg>`,
    STOP: `<svg style="width: 12px; height: 12px; margin-right: 6px; display: inline-block; vertical-align: middle;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512">
      <path fill="currentColor" d="M0 128C0 92.7 28.7 64 64 64H320c35.3 0 64 28.7 64 64V384c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V128z"/>
    </svg>`,
    CLEAR: {
      PATH: "M135.2 17.7C140.6 6.8 151.7 0 163.8 0L284.2 0c12.1 0 23.2 6.8 28.6 17.7L320 32l96 0c17.7 0 32 14.3 32 32s-14.3 32-32 32L32 96C14.3 96 0 81.7 0 64S14.3 32 32 32l96 0 7.2-14.3zM32 128l384 0 0 320c0 35.3-28.7 64-64 64L96 512c-35.3 0-64-28.7-64-64l0-320zm96 64c-8.8 0-16 7.2-16 16l0 224c0 8.8 7.2 16 16 16s16-7.2 16-16l0-224c0-8.8-7.2-16-16-16zm96 0c-8.8 0-16 7.2-16 16l0 224c0 8.8 7.2 16 16 16s16-7.2 16-16l0-224c0-8.8-7.2-16-16-16zm96 0c-8.8 0-16 7.2-16 16l0 224c0 8.8 7.2 16 16 16s16-7.2 16-16l0-224c0-8.8-7.2-16-16-16z",
      VIEWBOX: "0 0 448 512",
    },
    RESET: {
      PATH: "M463.5 224l8.5 0c13.3 0 24-10.7 24-24l0-128c0-9.7-5.8-18.5-14.8-22.2s-19.3-1.7-26.2 5.2L413.4 96.6c-87.6-86.5-228.7-86.2-315.8 1c-87.5 87.5-87.5 229.3 0 316.8s229.3 87.5 316.8 0c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0c-62.5 62.5-163.8 62.5-226.3 0s-62.5-163.8 0-226.3c62.2-62.2 162.7-62.5 225.3-1L327 183c-6.9 6.9-8.9 17.2-5.2 26.2s12.5 14.8 22.2 14.8l119.5 0z",
      VIEWBOX: "0 0 512 512",
    },
    PATREON: {
      PATH: "M489.7 153.8c-.1-65.4-51-119-110.7-138.3C304.8-8.5 207-5 136.1 28.4C50.3 68.9 23.3 157.7 22.3 246.2C21.5 319 28.7 510.6 136.9 512c80.3 1 92.3-102.5 129.5-152.3c26.4-35.5 60.5-45.5 102.4-55.9c72-17.8 121.1-74.7 121-150z",
      VIEWBOX: "0 0 512 512",
    },
    INFO: {
      PATH: "M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM216 336c-13.3 0-24 10.7-24 24s10.7 24 24 24l80 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-8 0 0-88c0-13.3-10.7-24-24-24l-48 0c-13.3 0-24 10.7-24 24s10.7 24 24 24l24 0 0 64-24 0zm40-144a32 32 0 1 0 0-64 32 32 0 1 0 0 64z",
      VIEWBOX: "0 0 512 512",
    },
    DOWNLOAD: {
      SECONDARY_PATH:
        "M0 256C0 397.4 114.6 512 256 512s256-114.6 256-256c0-17.7-14.3-32-32-32s-32 14.3-32 32c0 106-86 192-192 192S64 362 64 256c0-17.7-14.3-32-32-32s-32 14.3-32 32z",
      PRIMARY_PATH:
        "M390.6 185.4c12.5 12.5 12.5 32.8 0 45.3l-112 112c-12.5 12.5-32.8 12.5-45.3 0l-112-112c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L224 242.7 224 32c0-17.7 14.3-32 32-32s32 14.3 32 32l0 210.7 57.4-57.4c12.5-12.5 32.8-12.5 45.3 0z",
      VIEWBOX: "0 0 512 512",
    },
    FETCH: {
      PATH: "M374.6 214.6l-128 128c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L192 242.7 192 32c0-17.7 14.3-32 32-32s32 14.3 32 32l0 210.7 73.4-73.4c12.5-12.5 32.8-12.5 45.3 0s12.5 32.8 0 45.3zM64 352l0 64c0 17.7 14.3 32 32 32l256 0c17.7 0 32-14.3 32-32l0-64c0-17.7 14.3-32 32-32s32 14.3 32 32l0 64c0 53-43 96-96 96L96 512c-53 0-96-43-96-96l0-64c0-17.7 14.3-32 32-32s32 14.3 32 32z",
      VIEWBOX: "0 0 448 512",
    },
    ACCOUNT: {
      PATH: "M412.1 416.6C398.1 361.1 347.9 320 288 320l-64 0c-59.9 0-110.1 41.1-124.1 96.6C58 375.9 32 319 32 256C32 132.3 132.3 32 256 32s224 100.3 224 224c0 63-26 119.9-67.9 160.6zm-28.5 23.4C347.5 465.2 303.5 480 256 480s-91.5-14.8-127.7-39.9c4-49.3 45.3-88.1 95.7-88.1l64 0c50.4 0 91.6 38.8 95.7 88.1zM256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zm0-256a48 48 0 1 1 0-96 48 48 0 1 1 0 96zm-80-48a80 80 0 1 0 160 0 80 80 0 1 0 -160 0z",
      VIEWBOX: "0 0 512 512",
    },
    TOTAL: {
      PATH: "M320 464c8.8 0 16-7.2 16-16l0-288-80 0c-17.7 0-32-14.3-32-32l0-80L64 48c-8.8 0-16 7.2-16 16l0 384c0 8.8 7.2 16 16 16l256 0zM0 64C0 28.7 28.7 0 64 0L229.5 0c17 0 33.3 6.7 45.3 18.7l90.5 90.5c12 12 18.7 28.3 18.7 45.3L384 448c0 35.3-28.7 64-64 64L64 512c-35.3 0-64-28.7-64-64L0 64z",
      VIEWBOX: "0 0 384 512",
    },
    BATCH: {
      PATH: "M48 272L48 64c0-8.8 7.2-16 16-16l160 0 0 80c0 17.7 14.3 32 32 32l80 0 0 112L48 272zm288 48l16 0 32 0 0-165.5c0-17-6.7-33.3-18.7-45.3L274.7 18.7C262.7 6.7 246.5 0 229.5 0L64 0C28.7 0 0 28.7 0 64L0 320l32 0 16 0 288 0zM0 352l0 64 48 0 0-64L0 352zM64 512l0-48c-8.8 0-16-7.2-16-16L0 448c0 35.3 28.7 64 64 64zm256-48l0 48c35.3 0 64-28.7 64-64l-48 0c0 8.8-7.2 16-16 16zm64-112l-48 0 0 64 48 0 0-64zM96 464l0 48 80 0 0-48-80 0zm112 0l0 48 80 0 0-48-80 0z",
      VIEWBOX: "0 0 384 512",
    },
    ZIP: {
      PATH: "M64 464c-8.8 0-16-7.2-16-16L48 64c0-8.8 7.2-16 16-16l48 0c0 8.8 7.2 16 16 16l32 0c8.8 0 16-7.2 16-16l48 0 0 80c0 17.7 14.3 32 32 32l80 0 0 288c0 8.8-7.2 16-16 16L64 464zM64 0C28.7 0 0 28.7 0 64L0 448c0 35.3 28.7 64 64 64l256 0c35.3 0 64-28.7 64-64l0-293.5c0-17-6.7-33.3-18.7-45.3L274.7 18.7C262.7 6.7 246.5 0 229.5 0L64 0zm48 112c0 8.8 7.2 16 16 16l32 0c8.8 0 16-7.2 16-16s-7.2-16-16-16l-32 0c-8.8 0-16 7.2-16 16zm0 64c0 8.8 7.2 16 16 16l32 0c8.8 0 16-7.2 16-16s-7.2-16-16-16l-32 0c-8.8 0-16 7.2-16 16zm-6.3 71.8L82.1 335.9c-1.4 5.4-2.1 10.9-2.1 16.4c0 35.2 28.8 63.7 64 63.7s64-28.5 64-63.7c0-5.5-.7-11.1-2.1-16.4l-23.5-88.2c-3.7-14-16.4-23.8-30.9-23.8l-14.8 0c-14.5 0-27.2 9.7-30.9 23.8zM128 336l32 0c8.8 0 16 7.2 16 16s-7.2 16-16 16l-32 0c-8.8 0-16-7.2-16-16s7.2-16 16-16z",
      VIEWBOX: "0 0 384 512",
    },
    MEDIA_TYPE: {
      ALL: {
        PATH: "M256 48c-8.8 0-16 7.2-16 16l0 224c0 8.7 6.9 15.8 15.6 16l69.1-94.2c4.5-6.2 11.7-9.8 19.4-9.8s14.8 3.6 19.4 9.8L380 232.4l56-85.6c4.4-6.8 12-10.9 20.1-10.9s15.7 4.1 20.1 10.9L578.7 303.8c7.6-1.3 13.3-7.9 13.3-15.8l0-224c0-8.8-7.2-16-16-16L256 48zM192 64c0-35.3 28.7-64 64-64L576 0c35.3 0 64 28.7 64 64l0 224c0 35.3-28.7 64-64 64l-320 0c-35.3 0-64-28.7-64-64l0-224zm-56 64l24 0 0 48 0 88 0 112 0 8 0 80 192 0 0-80 48 0 0 80 48 0c8.8 0 16-7.2 16-16l0-64 48 0 0 64c0 35.3-28.7 64-64 64l-48 0-24 0-24 0-192 0-24 0-24 0-48 0c-35.3 0-64-28.7-64-64L0 192c0-35.3 28.7-64 64-64l48 0 24 0zm-24 48l-48 0c-8.8 0-16 7.2-16 16l0 48 64 0 0-64zm0 288l0-64-64 0 0 48c0 8.8 7.2 16 16 16l48 0zM48 352l64 0 0-64-64 0 0 64zM304 80a32 32 0 1 1 0 64 32 32 0 1 1 0-64z",
        VIEWBOX: "0 0 640 512",
      },
      IMAGE: {
        PATH: "M448 80c8.8 0 16 7.2 16 16l0 319.8-5-6.5-136-176c-4.5-5.9-11.6-9.3-19-9.3s-14.4 3.4-19 9.3L202 340.7l-30.5-42.7C167 291.7 159.8 288 152 288s-15 3.7-19.5 10.1l-80 112L48 416.3l0-.3L48 96c0-8.8 7.2-16 16-16l384 0zM64 32C28.7 32 0 60.7 0 96L0 416c0 35.3 28.7 64 64 64l384 0c35.3 0 64-28.7 64-64l0-320c0-35.3-28.7-64-64-64L64 32zm80 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z",
        VIEWBOX: "0 0 512 512",
      },
      VIDEO: {
        PATH: "M352 432l-192 0 0-112 0-40 192 0 0 40 0 112zm0-200l-192 0 0-40 0-112 192 0 0 112 0 40zM64 80l48 0 0 88-64 0 0-72c0-8.8 7.2-16 16-16zM48 216l64 0 0 80-64 0 0-80zm64 216l-48 0c-8.8 0-16-7.2-16-16l0-72 64 0 0 88zM400 168l0-88 48 0c8.8 0 16 7.2 16 16l0 72-64 0zm0 48l64 0 0 80-64 0 0-80zm0 128l64 0 0 72c0 8.8-7.2 16-16 16l-48 0 0-88zM448 32L64 32C28.7 32 0 60.7 0 96L0 416c0 35.3 28.7 64 64 64l384 0c35.3 0 64-28.7 64-64l0-320c0-35.3-28.7-64-64-64z",
        VIEWBOX: "0 0 512 512",
      },
      GIF: {
        PATH: "M512 80c8.8 0 16 7.2 16 16l0 320c0 8.8-7.2 16-16 16L64 432c-8.8 0-16-7.2-16-16L48 96c0-8.8 7.2-16 16-16l448 0zM64 32C28.7 32 0 60.7 0 96L0 416c0 35.3 28.7 64 64 64l448 0c35.3 0 64-28.7 64-64l0-320c0-35.3-28.7-64-64-64L64 32zM296 160c-13.3 0-24 10.7-24 24l0 144c0 13.3 10.7 24 24 24s24-10.7 24-24l0-144c0-13.3-10.7-24-24-24zm56 24l0 80 0 64c0 13.3 10.7 24 24 24s24-10.7 24-24l0-40 40 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-40 0 0-32 64 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-88 0c-13.3 0-24 10.7-24 24zM128 256c0-26.5 21.5-48 48-48c8 0 15.4 1.9 22 5.3c11.8 6.1 26.3 1.5 32.3-10.3s1.5-26.3-10.3-32.3c-13.2-6.8-28.2-10.7-44-10.7c-53 0-96 43-96 96s43 96 96 96c19.6 0 37.5-6.1 52.8-15.8c7-4.4 11.2-12.1 11.2-20.3l0-51.9c0-13.3-10.7-24-24-24l-32 0c-13.3 0-24 10.7-24 24s10.7 24 24 24l8 0 0 13.1c-5.3 1.9-10.6 2.9-16 2.9c-26.5 0-48-21.5-48-48z",
        VIEWBOX: "0 0 576 512",
      },
      MEDIA: {
        PATH: "M160 80l352 0c8.8 0 16 7.2 16 16l0 224c0 8.8-7.2 16-16 16l-21.2 0L388.1 178.9c-4.4-6.8-12-10.9-20.1-10.9s-15.7 4.1-20.1 10.9l-52.2 79.8-12.4-16.9c-4.5-6.2-11.7-9.8-19.4-9.8s-14.8 3.6-19.4 9.8L175.6 336 160 336c-8.8 0-16-7.2-16-16l0-224c0-8.8 7.2-16 16-16zM96 96l0 224c0 35.3 28.7 64 64 64l352 0c35.3 0 64-28.7 64-64l0-224c0-35.3-28.7-64-64-64L160 32c-35.3 0-64 28.7-64 64zM48 120c0-13.3-10.7-24-24-24S0 106.7 0 120L0 344c0 75.1 60.9 136 136 136l320 0c13.3 0 24-10.7 24-24s-10.7-24-24-24l-320 0c-48.6 0-88-39.4-88-88l0-224zm208 24a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z",
        VIEWBOX: "0 0 576 512",
      },
      POST: {
        PATH: "M168 80c-13.3 0-24 10.7-24 24l0 304c0 8.4-1.4 16.5-4.1 24L440 432c13.3 0 24-10.7 24-24l0-304c0-13.3-10.7-24-24-24L168 80zM72 480c-39.8 0-72-32.2-72-72L0 112C0 98.7 10.7 88 24 88s24 10.7 24 24l0 296c0 13.3 10.7 24 24 24s24-10.7 24-24l0-304c0-39.8 32.2-72 72-72l272 0c39.8 0 72 32.2 72 72l0 304c0 39.8-32.2 72-72 72L72 480zM176 136c0-13.3 10.7-24 24-24l96 0c13.3 0 24 10.7 24 24l0 80c0 13.3-10.7 24-24 24l-96 0c-13.3 0-24-10.7-24-24l0-80zm200-24l32 0c13.3 0 24 10.7 24 24s-10.7 24-24 24l-32 0c-13.3 0-24-10.7-24-24s10.7-24 24-24zm0 80l32 0c13.3 0 24 10.7 24 24s-10.7 24-24 24l-32 0c-13.3 0-24-10.7-24-24s10.7-24 24-24zM200 272l208 0c13.3 0 24 10.7 24 24s-10.7 24-24 24l-208 0c-13.3 0-24-10.7-24-24s10.7-24 24-24zm0 80l208 0c13.3 0 24 10.7 24 24s-10.7 24-24 24l-208 0c-13.3 0-24-10.7-24-24s10.7-24 24-24z",
        VIEWBOX: "0 0 512 512",
      },
      TWEETS: {
        PATH: "M88.2 309.1c9.8-18.3 6.8-40.8-7.5-55.8C59.4 230.9 48 204 48 176c0-63.5 63.8-128 160-128s160 64.5 160 128s-63.8 128-160 128c-13.1 0-25.8-1.3-37.8-3.6c-10.4-2-21.2-.6-30.7 4.2c-4.1 2.1-8.3 4.1-12.6 6c-16 7.2-32.9 13.5-49.9 18c2.8-4.6 5.4-9.1 7.9-13.6c1.1-1.9 2.2-3.9 3.2-5.9zM208 352c114.9 0 208-78.8 208-176S322.9 0 208 0S0 78.8 0 176c0 41.8 17.2 80.1 45.9 110.3c-.9 1.7-1.9 3.5-2.8 5.1c-10.3 18.4-22.3 36.5-36.6 52.1c-6.6 7-8.3 17.2-4.6 25.9C5.8 378.3 14.4 384 24 384c43 0 86.5-13.3 122.7-29.7c4.8-2.2 9.6-4.5 14.2-6.8c15.1 3 30.9 4.5 47.1 4.5zM432 480c16.2 0 31.9-1.6 47.1-4.5c4.6 2.3 9.4 4.6 14.2 6.8C529.5 498.7 573 512 616 512c9.6 0 18.2-5.7 22-14.5c3.8-8.8 2-19-4.6-25.9c-14.2-15.6-26.2-33.7-36.6-52.1c-.9-1.7-1.9-3.4-2.8-5.1C622.8 384.1 640 345.8 640 304c0-94.4-87.9-171.5-198.2-175.8c4.1 15.2 6.2 31.2 6.2 47.8l0 .6c87.2 6.7 144 67.5 144 127.4c0 28-11.4 54.9-32.7 77.2c-14.3 15-17.3 37.6-7.5 55.8c1.1 2 2.2 4 3.2 5.9c2.5 4.5 5.2 9 7.9 13.6c-17-4.5-33.9-10.7-49.9-18c-4.3-1.9-8.5-3.9-12.6-6c-9.5-4.8-20.3-6.2-30.7-4.2c-12.1 2.4-24.8 3.6-37.8 3.6c-61.7 0-110-26.5-136.8-62.3c-16 5.4-32.8 9.4-50 11.8C279 439.8 350 480 432 480z",
        VIEWBOX: "0 0 640 512",
      },
      REPLIES: {
        PATH: "M224 240l96 0c66.2 0 122 44.7 138.8 105.5c3.3-12.4 5.2-26.2 5.2-41.5c0-70.7-57.3-128-128-128l-112 0-24 0c-13.3 0-24-10.7-24-24l0-24 0-28.1L55.9 208 176 316.1l0-28.1 0-24c0-13.3 10.7-24 24-24l24 0zm0 48l0 48 0 16c0 12.6-7.4 24.1-19 29.2s-25 3-34.4-5.4l-160-144C3.9 225.7 0 217.1 0 208s3.9-17.7 10.6-23.8l160-144c9.4-8.5 22.9-10.6 34.4-5.4s19 16.6 19 29.2l0 16 0 48 48 0 64 0c97.2 0 176 78.8 176 176c0 78-38.6 126.2-68.7 152.1c-4.1 3.5-8.1 6.6-11.7 9.3c-3.2 2.4-6.2 4.4-8.9 6.2c-4.5 3-8.3 5.1-10.8 6.5c-2.5 1.4-5.3 1.9-8.1 1.9c-10.9 0-19.7-8.9-19.7-19.7c0-6.8 3.6-13.2 8.3-18.1c.5-.5 .9-.9 1.4-1.4c2.4-2.3 5.1-5.1 7.7-8.6c1.7-2.3 3.4-5 5-7.9c5.3-9.7 9.5-22.9 9.5-40.2c0-53-43-96-96-96l-48 0-48 0z",
        VIEWBOX: "0 0 512 512",
      },
    },
  };

  const defaultSettings = {
    patreonAuth: "",
    authToken: "",
    batchEnabled: false,
    autoBatchEnabled: false,
    batchSize: 100,
    startingBatch: 0,
    timelineType: "media",
    mediaType: "all",
    concurrentDownloads: 50,
    cacheDuration: 360,
    apiServer: "default",
    darkTheme: false,
  };
  const batchSizes = [25, 50, 100, 200];
  const cacheDurations = [60, 120, 180, 240, 300, 360, 720, 1440];

  function getSettings() {
    return {
      patreonAuth: GM_getValue("patreonAuth", defaultSettings.patreonAuth),
      authToken: GM_getValue("authToken", defaultSettings.authToken),
      batchEnabled: GM_getValue("batchEnabled", defaultSettings.batchEnabled),
      autoBatchEnabled: GM_getValue(
        "autoBatchEnabled",
        defaultSettings.autoBatchEnabled
      ),
      batchSize: GM_getValue("batchSize", defaultSettings.batchSize),
      startingBatch: GM_getValue(
        "startingBatch",
        defaultSettings.startingBatch
      ),
      timelineType: GM_getValue("timelineType", defaultSettings.timelineType),
      mediaType: GM_getValue("mediaType", defaultSettings.mediaType),
      concurrentDownloads: GM_getValue(
        "concurrentDownloads",
        defaultSettings.concurrentDownloads
      ),
      cacheDuration: GM_getValue(
        "cacheDuration",
        defaultSettings.cacheDuration
      ),
      apiServer: GM_getValue("apiServer", defaultSettings.apiServer),
      darkTheme: GM_getValue("darkTheme", defaultSettings.darkTheme),
    };
  }

  function saveSettings(settings) {
    GM_setValue("patreonAuth", settings.patreonAuth);
    GM_setValue("authToken", settings.authToken);
    GM_setValue("batchEnabled", settings.batchEnabled);
    GM_setValue("autoBatchEnabled", settings.autoBatchEnabled);
    GM_setValue("batchSize", settings.batchSize);
    GM_setValue("startingBatch", settings.startingBatch);
    GM_setValue("timelineType", settings.timelineType);
    GM_setValue("mediaType", settings.mediaType);
    GM_setValue("concurrentDownloads", settings.concurrentDownloads);
    GM_setValue("cacheDuration", settings.cacheDuration);
    GM_setValue("apiServer", settings.apiServer);
    GM_setValue("darkTheme", settings.darkTheme);
  }

  function getServiceBaseUrl() {
    const settings = getSettings();
    return settings.apiServer === "default"
      ? API_URLS.DEFAULT
      : API_URLS.BACKUP;
  }

  function formatNumber(num) {
    return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  }

  const cacheManager = {
    set: (key, data, success = true) => {
      if (!success) return;

      const settings = getSettings();
      const cacheItem = {
        data: data,
        timestamp: Date.now(),
        expiry: Date.now() + settings.cacheDuration * 60 * 1000,
      };
      localStorage.setItem(`twitter_dl_${key}`, JSON.stringify(cacheItem));
    },

    get: (key) => {
      const cacheItem = localStorage.getItem(`twitter_dl_${key}`);
      if (!cacheItem) return null;

      try {
        const parsed = JSON.parse(cacheItem);
        if (Date.now() > parsed.expiry) {
          localStorage.removeItem(`twitter_dl_${key}`);
          return null;
        }
        return parsed.data;
      } catch (e) {
        localStorage.removeItem(`twitter_dl_${key}`);
        return null;
      }
    },

    clear: () => {
      const keysToRemove = [];
      for (let i = 0; i < localStorage.length; i++) {
        const key = localStorage.key(i);
        if (key.startsWith("twitter_dl_")) {
          keysToRemove.push(key);
        }
      }

      keysToRemove.forEach((key) => localStorage.removeItem(key));
    },
  };

  function createDownloadIcon() {
    const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    svg.setAttribute("viewBox", ICONS.DOWNLOAD.VIEWBOX);
    svg.setAttribute("width", "18");
    svg.setAttribute("height", "18");
    svg.style.verticalAlign = "middle";
    svg.style.cursor = "pointer";

    const defs = document.createElementNS("http://www.w3.org/2000/svg", "defs");
    const style = document.createElementNS(
      "http://www.w3.org/2000/svg",
      "style"
    );
    style.textContent = ".fa-secondary{opacity:.4}";
    defs.appendChild(style);
    svg.appendChild(defs);

    const secondaryPath = document.createElementNS(
      "http://www.w3.org/2000/svg",
      "path"
    );
    secondaryPath.setAttribute("class", "fa-secondary");
    secondaryPath.setAttribute("fill", "currentColor");
    secondaryPath.setAttribute("d", ICONS.DOWNLOAD.SECONDARY_PATH);
    svg.appendChild(secondaryPath);

    const primaryPath = document.createElementNS(
      "http://www.w3.org/2000/svg",
      "path"
    );
    primaryPath.setAttribute("class", "fa-primary");
    primaryPath.setAttribute("fill", "currentColor");
    primaryPath.setAttribute("d", ICONS.DOWNLOAD.PRIMARY_PATH);
    svg.appendChild(primaryPath);

    return svg;
  }

  function createPatreonIcon() {
    const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    svg.setAttribute("viewBox", ICONS.PATREON.VIEWBOX);
    svg.setAttribute("width", "18");
    svg.setAttribute("height", "18");
    svg.style.verticalAlign = "middle";
    svg.style.marginRight = "8px";

    const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
    path.setAttribute("fill", "currentColor");
    path.setAttribute("d", ICONS.PATREON.PATH);
    svg.appendChild(path);

    return svg;
  }

  function createInfoIcon() {
    const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    svg.setAttribute("viewBox", ICONS.INFO.VIEWBOX);
    svg.setAttribute("width", "16");
    svg.setAttribute("height", "16");
    svg.style.marginLeft = "8px";
    svg.style.cursor = "pointer";
    svg.style.color = "#64748b";
    svg.style.transition = "color 0.2s ease";

    const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
    path.setAttribute("fill", "currentColor");
    path.setAttribute("d", ICONS.INFO.PATH);
    svg.appendChild(path);

    svg.addEventListener("mouseenter", () => {
      svg.style.color = "#0ea5e9";
    });

    svg.addEventListener("mouseleave", () => {
      svg.style.color = "#64748b";
    });

    return svg;
  }

  function createInfoTooltip(message) {
    let activeTooltip = null;

    function showTooltip(e) {
      if (activeTooltip) {
        document.body.removeChild(activeTooltip);
      }

      const tooltip = document.createElement("div");
      tooltip.textContent = message;
      tooltip.style.cssText = `
        position: fixed;
        background-color: #1f2937;
        color: white;
        padding: 8px 12px;
        border-radius: 6px;
        font-size: 12px;
        line-height: 1.4;
        max-width: 300px;
        z-index: 10003;
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
        pointer-events: none;
        white-space: normal;
        word-wrap: break-word;
      `;

      document.body.appendChild(tooltip);
      activeTooltip = tooltip;

      const rect = e.target.getBoundingClientRect();
      const tooltipRect = tooltip.getBoundingClientRect();

      let top = rect.bottom + 8;
      let left = rect.left + rect.width / 2 - tooltipRect.width / 2;

      if (left < 8) left = 8;
      if (left + tooltipRect.width > window.innerWidth - 8) {
        left = window.innerWidth - tooltipRect.width - 8;
      }
      if (top + tooltipRect.height > window.innerHeight - 8) {
        top = rect.top - tooltipRect.height - 8;
      }

      tooltip.style.top = top + "px";
      tooltip.style.left = left + "px";
    }

    function hideTooltip() {
      if (activeTooltip) {
        document.body.removeChild(activeTooltip);
        activeTooltip = null;
      }
    }

    return { showTooltip, hideTooltip };
  }

  function createAccountIcon(isDarkTheme = false) {
    const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    svg.setAttribute("viewBox", ICONS.ACCOUNT.VIEWBOX);
    svg.setAttribute("width", "12");
    svg.setAttribute("height", "12");
    svg.style.marginRight = "6px";
    svg.style.color = isDarkTheme ? "#ffffff" : "#64748b";
    svg.style.verticalAlign = "middle";
    svg.style.display = "inline-block";

    const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
    path.setAttribute("fill", "currentColor");
    path.setAttribute("d", ICONS.ACCOUNT.PATH);
    svg.appendChild(path);

    return svg;
  }

  function createTotalItemsIcon(isDarkTheme = false) {
    const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    svg.setAttribute("viewBox", ICONS.TOTAL.VIEWBOX);
    svg.setAttribute("width", "12");
    svg.setAttribute("height", "12");
    svg.style.marginRight = "6px";
    svg.style.color = isDarkTheme ? "#ffffff" : "#64748b";
    svg.style.verticalAlign = "middle";
    svg.style.display = "inline-block";

    const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
    path.setAttribute("fill", "currentColor");
    path.setAttribute("d", ICONS.TOTAL.PATH);
    svg.appendChild(path);

    return svg;
  }

  function createCurrentBatchIcon(isDarkTheme = false) {
    const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    svg.setAttribute("viewBox", ICONS.BATCH.VIEWBOX);
    svg.setAttribute("width", "12");
    svg.setAttribute("height", "12");
    svg.style.marginRight = "6px";
    svg.style.color = isDarkTheme ? "#ffffff" : "#64748b";
    svg.style.verticalAlign = "middle";
    svg.style.display = "inline-block";

    const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
    path.setAttribute("fill", "currentColor");
    path.setAttribute("d", ICONS.BATCH.PATH);
    svg.appendChild(path);

    return svg;
  }

  function createTotalZipIcon(isDarkTheme = false) {
    const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    svg.setAttribute("viewBox", ICONS.ZIP.VIEWBOX);
    svg.setAttribute("width", "12");
    svg.setAttribute("height", "12");
    svg.style.marginRight = "6px";
    svg.style.color = isDarkTheme ? "#ffffff" : "#64748b";
    svg.style.verticalAlign = "middle";
    svg.style.display = "inline-block";

    const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
    path.setAttribute("fill", "currentColor");
    path.setAttribute("d", ICONS.ZIP.PATH);
    svg.appendChild(path);

    return svg;
  }

  function createMediaTypeIcon(mediaType, isDarkTheme = false) {
    let iconData;
    switch (mediaType) {
      case "image":
        iconData = ICONS.MEDIA_TYPE.IMAGE;
        break;
      case "video":
        iconData = ICONS.MEDIA_TYPE.VIDEO;
        break;
      case "gif":
        iconData = ICONS.MEDIA_TYPE.GIF;
        break;
      default:
        iconData = ICONS.MEDIA_TYPE.ALL;
    }

    const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    svg.setAttribute("viewBox", iconData.VIEWBOX);
    svg.setAttribute("width", "12");
    svg.setAttribute("height", "12");
    svg.style.marginRight = "6px";
    svg.style.color = isDarkTheme ? "#ffffff" : "#64748b";
    svg.style.verticalAlign = "middle";
    svg.style.display = "inline-block";

    const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
    path.setAttribute("fill", "currentColor");
    path.setAttribute("d", iconData.PATH);
    svg.appendChild(path);

    return svg;
  }

  function createTimelineTypeIcon(timelineType, isDarkTheme = false) {
    let iconData;
    switch (timelineType) {
      case "media":
        iconData = ICONS.MEDIA_TYPE.MEDIA;
        break;
      case "timeline":
        iconData = ICONS.MEDIA_TYPE.POST;
        break;
      case "tweets":
        iconData = ICONS.MEDIA_TYPE.TWEETS;
        break;
      case "with_replies":
        iconData = ICONS.MEDIA_TYPE.REPLIES;
        break;
      default:
        iconData = ICONS.MEDIA_TYPE.MEDIA;
    }

    const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    svg.setAttribute("viewBox", iconData.VIEWBOX);
    svg.setAttribute("width", "16");
    svg.setAttribute("height", "16");
    svg.style.marginRight = "6px";
    svg.style.color = isDarkTheme ? "#ffffff" : "#64748b";
    svg.style.verticalAlign = "middle";
    svg.style.display = "inline-block";

    const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
    path.setAttribute("fill", "currentColor");
    path.setAttribute("d", iconData.PATH);
    svg.appendChild(path);

    return svg;
  }

  function createAuthTokenPopup() {
    const settings = getSettings();
    const overlay = document.createElement("div");
    overlay.style.cssText = `
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-color: rgba(0, 0, 0, 0.35);
        backdrop-filter: blur(2.5px);
        display: flex;
        justify-content: center;
        align-items: center;
        z-index: 10001;
        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    `;

    const popup = document.createElement("div");
    popup.style.cssText = `
        background-color: ${settings.darkTheme ? "#1f2937" : "#ffffff"};
        color: ${settings.darkTheme ? "#f1f5f9" : "#0f172a"};
        border-radius: 16px;
        width: 300px;
        max-width: 90%;
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
        overflow: hidden;
    `;

    const header = document.createElement("div");
    header.style.cssText = `
        padding: 16px;
        border-bottom: 1px solid ${settings.darkTheme ? "#374151" : "#e2e8f0"};
        font-weight: bold;
        font-size: 16px;
        text-align: center;
        background-color: ${settings.darkTheme ? "#374151" : "#f8fafc"};
    `;
    header.textContent = "Authentication Required";

    const content = document.createElement("div");
    content.style.cssText = `
        padding: 16px;
        text-align: center;
    `;

    const authLink = document.createElement("a");
    authLink.href = "https://www.patreon.com/posts/127206894";
    authLink.target = "_blank";
    authLink.textContent = "How to Obtain Auth Token";
    authLink.style.cssText = `
        color: #0ea5e9;
        text-decoration: none;
        cursor: pointer;
    `;
    content.appendChild(authLink);

    const buttonContainer = document.createElement("div");
    buttonContainer.style.cssText = `
        padding: 16px;
        display: flex;
        justify-content: center;
        border-top: 1px solid ${settings.darkTheme ? "#374151" : "#e2e8f0"};
    `;

    const okButton = document.createElement("button");
    okButton.style.cssText = `
        background-color: #0ea5e9;
        color: white;
        border: none;
        border-radius: 6px;
        padding: 8px 24px;
        font-weight: bold;
        cursor: pointer;
        transition: background-color 0.2s;
    `;
    okButton.textContent = "OK";
    okButton.addEventListener("mouseenter", () => {
      okButton.style.backgroundColor = "#0284c7";
    });
    okButton.addEventListener("mouseleave", () => {
      okButton.style.backgroundColor = "#0ea5e9";
    });
    okButton.onclick = () => {
      document.body.removeChild(overlay);
    };

    buttonContainer.appendChild(okButton);
    popup.appendChild(header);
    popup.appendChild(content);
    popup.appendChild(buttonContainer);
    overlay.appendChild(popup);
    document.body.appendChild(overlay);
    return overlay;
  }

  function createPatreonAuthPopup() {
    const settings = getSettings();
    const overlay = document.createElement("div");
    overlay.style.cssText = `
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-color: rgba(0, 0, 0, 0.35);
        backdrop-filter: blur(2.5px);
        display: flex;
        justify-content: center;
        align-items: center;
        z-index: 10001;
        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    `;

    const popup = document.createElement("div");
    popup.style.cssText = `
        background-color: ${settings.darkTheme ? "#1f2937" : "#ffffff"};
        color: ${settings.darkTheme ? "#f1f5f9" : "#0f172a"};
        border-radius: 16px;
        width: 320px;
        max-width: 90%;
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
        overflow: hidden;
    `;

    const header = document.createElement("div");
    header.style.cssText = `
        padding: 16px;
        border-bottom: 1px solid ${settings.darkTheme ? "#374151" : "#e2e8f0"};
        font-weight: bold;
        font-size: 16px;
        text-align: center;
        background-color: ${settings.darkTheme ? "#374151" : "#f8fafc"};
    `;
    header.textContent = "Patreon Authentication Required";

    const content = document.createElement("div");
    content.style.cssText = `
        padding: 16px;
        text-align: center;
    `;

    const message = document.createElement("p");
    message.style.cssText = `
        margin-bottom: 16px;
        line-height: 1.5;
    `;
    message.textContent =
      "Please enter your Patreon authentication code. This feature requires a paid membership to access.";
    content.appendChild(message);

    const patreonButton = document.createElement("a");
    patreonButton.href = "https://www.patreon.com/exyezed";
    patreonButton.target = "_blank";
    patreonButton.style.cssText = `
        display: flex;
        align-items: center;
        justify-content: center;
        background-color: ${settings.darkTheme ? "#374151" : "#f1f5f9"};
        color: ${settings.darkTheme ? "#f1f5f9" : "#0f172a"};
        text-decoration: none;
        padding: 10px 16px;
        border-radius: 8px;
        margin-top: 8px;
        transition: background-color 0.2s;
    `;
    patreonButton.innerHTML =
      createPatreonIcon().outerHTML + "Join Patreon Membership";
    patreonButton.addEventListener("mouseenter", () => {
      patreonButton.style.backgroundColor = settings.darkTheme
        ? "#4b5563"
        : "#e2e8f0";
    });
    patreonButton.addEventListener("mouseleave", () => {
      patreonButton.style.backgroundColor = settings.darkTheme
        ? "#374151"
        : "#f1f5f9";
    });
    content.appendChild(patreonButton);

    const buttonContainer = document.createElement("div");
    buttonContainer.style.cssText = `
        padding: 16px;
        display: flex;
        justify-content: center;
        border-top: 1px solid ${settings.darkTheme ? "#374151" : "#e2e8f0"};
    `;

    const okButton = document.createElement("button");
    okButton.style.cssText = `
        background-color: #0ea5e9;
        color: white;
        border: none;
        border-radius: 6px;
        padding: 8px 24px;
        font-weight: bold;
        cursor: pointer;
        transition: background-color 0.2s;
    `;
    okButton.textContent = "OK";
    okButton.addEventListener("mouseenter", () => {
      okButton.style.backgroundColor = "#0284c7";
    });
    okButton.addEventListener("mouseleave", () => {
      okButton.style.backgroundColor = "#0ea5e9";
    });
    okButton.onclick = () => {
      document.body.removeChild(overlay);
    };

    buttonContainer.appendChild(okButton);
    popup.appendChild(header);
    popup.appendChild(content);
    popup.appendChild(buttonContainer);
    overlay.appendChild(popup);

    document.body.appendChild(overlay);
    return overlay;
  }

  function createInfoDialog(message, title = "Information") {
    const settings = getSettings();
    const overlay = document.createElement("div");
    overlay.style.cssText = `
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-color: rgba(0, 0, 0, 0.35);
        backdrop-filter: blur(2.5px);
        display: flex;
        justify-content: center;
        align-items: center;
        z-index: 10001;
        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    `;

    const dialog = document.createElement("div");
    dialog.style.cssText = `
        background-color: ${settings.darkTheme ? "#1f2937" : "#ffffff"};
        color: ${settings.darkTheme ? "#f1f5f9" : "#334155"};
        border-radius: 16px;
        width: 300px;
        max-width: 90%;
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
        overflow: hidden;
    `;

    const header = document.createElement("div");
    header.style.cssText = `
        padding: 16px;
        border-bottom: 1px solid ${settings.darkTheme ? "#374151" : "#e2e8f0"};
        font-weight: bold;
        font-size: 16px;
        text-align: center;
        background-color: ${settings.darkTheme ? "#374151" : "#f8fafc"};
    `;
    header.textContent = title;

    const content = document.createElement("div");
    content.style.cssText = `
        padding: 20px 16px;
        text-align: center;
        line-height: 1.5;
    `;
    content.textContent = message;

    const buttonContainer = document.createElement("div");
    buttonContainer.style.cssText = `
        padding: 16px;
        display: flex;
        justify-content: center;
        border-top: 1px solid ${settings.darkTheme ? "#374151" : "#e2e8f0"};
    `;

    const okButton = document.createElement("button");
    okButton.style.cssText = `
        background-color: #22c55e;
        color: white;
        border: none;
        border-radius: 6px;
        padding: 8px 24px;
        font-weight: bold;
        cursor: pointer;
        transition: background-color 0.2s;
    `;
    okButton.textContent = "OK";
    okButton.addEventListener("mouseenter", () => {
      okButton.style.backgroundColor = "#16a34a";
    });
    okButton.addEventListener("mouseleave", () => {
      okButton.style.backgroundColor = "#22c55e";
    });
    okButton.onclick = () => {
      document.body.removeChild(overlay);
    };

    buttonContainer.appendChild(okButton);
    dialog.appendChild(header);
    dialog.appendChild(content);
    dialog.appendChild(buttonContainer);
    overlay.appendChild(dialog);

    document.body.appendChild(overlay);
    return overlay;
  }

  function createConfirmDialog(message, onConfirm, onCancel) {
    const settings = getSettings();
    const overlay = document.createElement("div");
    overlay.style.cssText = `
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-color: rgba(0, 0, 0, 0.35);
        backdrop-filter: blur(2.5px);
        display: flex;
        justify-content: center;
        align-items: center;
        z-index: 10001;
        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    `;

    const dialog = document.createElement("div");
    dialog.style.cssText = `
        background-color: ${settings.darkTheme ? "#1f2937" : "#ffffff"};
        color: ${settings.darkTheme ? "#f1f5f9" : "#334155"};
        border-radius: 16px;
        width: 300px;
        max-width: 90%;
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
        overflow: hidden;
    `;

    const header = document.createElement("div");
    header.style.cssText = `
        padding: 16px;
        border-bottom: 1px solid ${settings.darkTheme ? "#374151" : "#e2e8f0"};
        font-weight: bold;
        font-size: 16px;
        text-align: center;
        background-color: ${settings.darkTheme ? "#374151" : "#f8fafc"};
    `;
    header.textContent = "Confirmation";

    const content = document.createElement("div");
    content.style.cssText = `
        padding: 16px;
        text-align: center;
    `;
    content.textContent = message;

    const buttons = document.createElement("div");
    buttons.style.cssText = `
        display: flex;
        padding: 16px;
        border-top: 1px solid ${settings.darkTheme ? "#374151" : "#e2e8f0"};
    `;

    const cancelButton = document.createElement("button");
    cancelButton.style.cssText = `
        flex: 1;
        background-color: ${settings.darkTheme ? "#374151" : "#94a3b8"};
        color: white;
        border: none;
        border-radius: 6px;
        padding: 8px 16px;
        margin-right: 8px;
        font-weight: bold;
        cursor: pointer;
        text-align: center;
        transition: background-color 0.2s;
    `;
    cancelButton.textContent = "No";
    cancelButton.addEventListener("mouseenter", () => {
      cancelButton.style.backgroundColor = settings.darkTheme
        ? "#4b5563"
        : "#64748b";
    });
    cancelButton.addEventListener("mouseleave", () => {
      cancelButton.style.backgroundColor = settings.darkTheme
        ? "#374151"
        : "#94a3b8";
    });
    cancelButton.onclick = () => {
      document.body.removeChild(overlay);
      if (onCancel) onCancel();
    };

    const confirmButton = document.createElement("button");
    confirmButton.style.cssText = `
        flex: 1;
        background-color: #ef4444;
        color: white;
        border: none;
        border-radius: 6px;
        padding: 8px 16px;
        font-weight: bold;
        cursor: pointer;
        text-align: center;
        transition: background-color 0.2s;
    `;
    confirmButton.textContent = "Yes";
    confirmButton.addEventListener("mouseenter", () => {
      confirmButton.style.backgroundColor = "#dc2626";
    });
    confirmButton.addEventListener("mouseleave", () => {
      confirmButton.style.backgroundColor = "#ef4444";
    });
    confirmButton.onclick = () => {
      document.body.removeChild(overlay);
      if (onConfirm) onConfirm();
    };

    buttons.appendChild(cancelButton);
    buttons.appendChild(confirmButton);

    dialog.appendChild(header);
    dialog.appendChild(content);
    dialog.appendChild(buttons);
    overlay.appendChild(dialog);

    document.body.appendChild(overlay);
  }

  function formatDate(dateString) {
    const date = new Date(dateString);
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");
    const hours = String(date.getHours()).padStart(2, "0");
    const minutes = String(date.getMinutes()).padStart(2, "0");
    const seconds = String(date.getSeconds()).padStart(2, "0");

    return `${year}${month}${day}_${hours}${minutes}${seconds}`;
  }

  function getCurrentTimestamp() {
    const now = new Date();
    const year = now.getFullYear();
    const month = String(now.getMonth() + 1).padStart(2, "0");
    const day = String(now.getDate()).padStart(2, "0");
    const hours = String(now.getHours()).padStart(2, "0");
    const minutes = String(now.getMinutes()).padStart(2, "0");
    const seconds = String(now.getSeconds()).padStart(2, "0");

    return `${year}${month}${day}_${hours}${minutes}${seconds}`;
  }

  function fetchData(url) {
    return new Promise((resolve, reject) => {
      GM_xmlhttpRequest({
        method: "GET",
        url: url,
        responseType: "json",
        onload: (response) => {
          if (response.status >= 200 && response.status < 300) {
            resolve(response.response);
          } else {
            reject(new Error(`Request failed with status ${response.status}`));
          }
        },
        onerror: (error) => {
          reject(
            new Error(`Network error: ${error?.message || "Unknown error"}`)
          );
        },
        ontimeout: () => {
          reject(new Error("Request timed out"));
        },
      });
    });
  }

  function fetchBinary(url) {
    return new Promise((resolve, reject) => {
      GM_xmlhttpRequest({
        method: "GET",
        url: url,
        responseType: "blob",
        onload: (response) => {
          if (response.status >= 200 && response.status < 300) {
            resolve(response.response);
          } else {
            reject(new Error(`Request failed with status ${response.status}`));
          }
        },
        onerror: () => {
          reject(new Error("Network error"));
        },
      });
    });
  }

  function getMediaTypeLabel(mediaType) {
    switch (mediaType) {
      case "image":
        return "Image";
      case "video":
        return "Video";
      case "gif":
        return "GIF";
      default:
        return "Media";
    }
  }

  function createToggleSwitch(options, selectedValue, onChange) {
    const settings = getSettings();
    const toggleWrapper = document.createElement("div");
    toggleWrapper.style.cssText = `
      position: relative;
      height: 40px;
      background-color: ${settings.darkTheme ? "#374151" : "#f1f5f9"};
      border-radius: 8px;
      padding: 0;
      cursor: pointer;
      width: 100%;
      margin-bottom: 16px;
      overflow: hidden;
    `;

    const toggleSlider = document.createElement("div");
    toggleSlider.style.cssText = `
      position: absolute;
      height: 100%;
      background-color: #0ea5e9;
      border-radius: 8px;
      transition: transform 0.3s ease, width 0.3s ease;
      z-index: 1;
    `;

    const optionsContainer = document.createElement("div");
    optionsContainer.style.cssText = `
      position: relative;
      display: flex;
      height: 100%;
      z-index: 2;
      width: 100%;
    `;

    const selectedIndex = options.findIndex(
      (option) => option.value === selectedValue
    );
    const optionWidth = 100 / options.length;
    toggleSlider.style.width = `${optionWidth}%`;
    toggleSlider.style.transform = `translateX(${selectedIndex * 100}%)`;
    options.forEach((option, index) => {
      const optionElement = document.createElement("div");
      optionElement.style.cssText = `
        flex: 1;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 14px;
        transition: color 0.3s ease;
        color: ${option.value === selectedValue ? "white" : "#64748b"};
        cursor: pointer;
        user-select: none;
        text-align: center;
        height: 100%;
        padding: 0 4px;
      `;

      if (option.icon) {
        const iconContainer = document.createElement("span");
        iconContainer.style.cssText = `
          display: flex;
          align-items: center;
          justify-content: center;
          margin-right: 6px;
        `;

        const iconClone = option.icon.cloneNode(true);

        const paths = iconClone.querySelectorAll("path");
        paths.forEach((path) => {
          path.setAttribute(
            "fill",
            option.value === selectedValue ? "white" : "#64748b"
          );
        });

        iconContainer.appendChild(iconClone);
        optionElement.appendChild(iconContainer);
      }

      const text = document.createElement("span");
      text.textContent = option.label;
      text.style.cssText = `
        display: inline-block;
        text-align: center;
      `;
      optionElement.appendChild(text);

      optionElement.addEventListener("click", (e) => {
        e.stopPropagation();
        onChange(option.value);

        toggleSlider.style.transform = `translateX(${index * 100}%)`;

        optionsContainer.querySelectorAll("div").forEach((opt, i) => {
          opt.style.color = i === index ? "white" : "#64748b";

          const optIcon = opt.querySelector("svg");
          if (optIcon) {
            const optPaths = optIcon.querySelectorAll("path");
            optPaths.forEach((path) => {
              path.setAttribute("fill", i === index ? "white" : "#64748b");
            });
          }
        });
      });

      optionsContainer.appendChild(optionElement);
    });

    toggleWrapper.appendChild(toggleSlider);
    toggleWrapper.appendChild(optionsContainer);

    return toggleWrapper;
  }

  function createMediaTypeIcons() {
    const allIcon = document.createElementNS(
      "http://www.w3.org/2000/svg",
      "svg"
    );
    allIcon.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    allIcon.setAttribute("viewBox", ICONS.MEDIA_TYPE.ALL.VIEWBOX);
    allIcon.setAttribute("width", "16");
    allIcon.setAttribute("height", "16");
    allIcon.style.verticalAlign = "middle";

    const allPath = document.createElementNS(
      "http://www.w3.org/2000/svg",
      "path"
    );
    allPath.setAttribute("fill", "#64748b");
    allPath.setAttribute("d", ICONS.MEDIA_TYPE.ALL.PATH);
    allIcon.appendChild(allPath);

    const imageIcon = document.createElementNS(
      "http://www.w3.org/2000/svg",
      "svg"
    );
    imageIcon.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    imageIcon.setAttribute("viewBox", ICONS.MEDIA_TYPE.IMAGE.VIEWBOX);
    imageIcon.setAttribute("width", "16");
    imageIcon.setAttribute("height", "16");
    imageIcon.style.verticalAlign = "middle";

    const imagePath = document.createElementNS(
      "http://www.w3.org/2000/svg",
      "path"
    );
    imagePath.setAttribute("fill", "#64748b");
    imagePath.setAttribute("d", ICONS.MEDIA_TYPE.IMAGE.PATH);
    imageIcon.appendChild(imagePath);

    const videoIcon = document.createElementNS(
      "http://www.w3.org/2000/svg",
      "svg"
    );
    videoIcon.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    videoIcon.setAttribute("viewBox", ICONS.MEDIA_TYPE.VIDEO.VIEWBOX);
    videoIcon.setAttribute("width", "16");
    videoIcon.setAttribute("height", "16");
    videoIcon.style.verticalAlign = "middle";

    const videoPath = document.createElementNS(
      "http://www.w3.org/2000/svg",
      "path"
    );
    videoPath.setAttribute("fill", "#64748b");
    videoPath.setAttribute("d", ICONS.MEDIA_TYPE.VIDEO.PATH);
    videoIcon.appendChild(videoPath);

    const gifIcon = document.createElementNS(
      "http://www.w3.org/2000/svg",
      "svg"
    );
    gifIcon.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    gifIcon.setAttribute("viewBox", ICONS.MEDIA_TYPE.GIF.VIEWBOX);
    gifIcon.setAttribute("width", "16");
    gifIcon.setAttribute("height", "16");
    gifIcon.style.verticalAlign = "middle";

    const gifPath = document.createElementNS(
      "http://www.w3.org/2000/svg",
      "path"
    );
    gifPath.setAttribute("fill", "#64748b");
    gifPath.setAttribute("d", ICONS.MEDIA_TYPE.GIF.PATH);
    gifIcon.appendChild(gifPath);

    return {
      all: allIcon,
      image: imageIcon,
      video: videoIcon,
      gif: gifIcon,
    };
  }

  function createSlider(options, selectedValue, onChange) {
    const toggleOptions = options.map((option) => {
      let label = option.toString();
      if (typeof option === "number" && option >= 60 && option % 60 === 0) {
        label = `${option / 60}h`;
      }
      return { value: option, label: label };
    });

    return createToggleSwitch(toggleOptions, selectedValue, onChange);
  }

  function createModal(username) {
    let autoBatchStarted = false;
    let autoBatchCancelled = false;
    const existingModal = document.getElementById("media-downloader-modal");
    if (existingModal) {
      existingModal.remove();
    }

    const settings = getSettings();

    const modal = document.createElement("div");
    modal.id = "media-downloader-modal";
    modal.style.cssText = `
        position: fixed;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background-color: rgba(0, 0, 0, 0.35);
        backdrop-filter: blur(2.5px);
        display: flex;
        justify-content: center;
        align-items: center;
        z-index: 10000;
        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    `;

    const modalContent = document.createElement("div");
    modalContent.style.cssText = `
    background-color: ${settings.darkTheme ? "#1f2937" : "#ffffff"};
    color: ${settings.darkTheme ? "#f1f5f9" : "#334155"};
    border-radius: 16px;
    width: 500px;
    max-width: 90%;
    max-height: 90vh;
    overflow-y: auto;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    `;

    const header = document.createElement("div");
    header.style.cssText = `
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 16px;
        border-bottom: 1px solid ${settings.darkTheme ? "#374151" : "#e2e8f0"};
    `;

    const title = document.createElement("h2");
    title.innerHTML = `Download ${getMediaTypeLabel(
      settings.mediaType
    )}: <span style="color: #0ea5e9">${username}</span>`;
    title.style.cssText = `
    margin: 0;
    font-size: 18px;
    font-weight: bold;
    color: ${settings.darkTheme ? "#f1f5f9" : "#334155"};
    `;

    const closeButton = document.createElement("button");
    closeButton.innerHTML = "&times;";
    closeButton.style.cssText = `
        background: none;
        border: none;
        color: ${settings.darkTheme ? "#f1f5f9" : "#0f172a"};
        font-size: 24px;
        cursor: pointer;
        padding: 0;
        line-height: 1;
        transition: color 0.2s;
    `;
    closeButton.addEventListener("mouseenter", () => {
      closeButton.style.color = "#0ea5e9";
    });
    closeButton.addEventListener("mouseleave", () => {
      closeButton.style.color = settings.darkTheme ? "#f1f5f9" : "#0f172a";
    });
    closeButton.onclick = () => modal.remove();

    header.appendChild(title);
    header.appendChild(closeButton);

    const tabs = document.createElement("div");
    tabs.style.cssText = `
        display: flex;
        border-bottom: 1px solid ${settings.darkTheme ? "#374151" : "#e2e8f0"};
    `;

    const mainTab = document.createElement("div");
    mainTab.textContent = "Main";
    mainTab.className = "active-tab";
    mainTab.style.cssText = `
        padding: 12px 16px;
        cursor: pointer;
        flex: 1;
        text-align: center;
        border-bottom: 2px solid #0ea5e9;
        color: ${settings.darkTheme ? "#f1f5f9" : "#0f172a"};
    `;

    const settingsTab = document.createElement("div");
    settingsTab.textContent = "Settings";
    settingsTab.style.cssText = `
        padding: 12px 16px;
        cursor: pointer;
        flex: 1;
        text-align: center;
        color: #64748b;
    `;

    tabs.appendChild(mainTab);
    tabs.appendChild(settingsTab);

    const mainContent = document.createElement("div");
    mainContent.style.cssText = `
    padding: 16px;
    `;

    const settingsContent = document.createElement("div");
    settingsContent.style.cssText = `
    padding: 16px;
    display: none;
    `;

    const fetchButton = document.createElement("button");
    const mediaTypeLabelText = getMediaTypeLabel(
      settings.mediaType
    ).toLowerCase();
    const fetchIcon = document.createElementNS(
      "http://www.w3.org/2000/svg",
      "svg"
    );
    fetchIcon.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    fetchIcon.setAttribute("viewBox", ICONS.FETCH.VIEWBOX);
    fetchIcon.setAttribute("width", "16");
    fetchIcon.setAttribute("height", "16");
    fetchIcon.style.marginRight = "8px";

    const fetchPath = document.createElementNS(
      "http://www.w3.org/2000/svg",
      "path"
    );
    fetchPath.setAttribute("fill", "currentColor");
    fetchPath.setAttribute("d", ICONS.FETCH.PATH);
    fetchIcon.appendChild(fetchPath);

    const fetchButtonText = document.createElement("span");
    fetchButtonText.textContent = settings.autoBatchEnabled
      ? "Auto Fetch"
      : settings.mediaType === "all"
      ? "Fetch Media"
      : `Fetch ${
          mediaTypeLabelText === "gif"
            ? "GIF"
            : mediaTypeLabelText.charAt(0).toUpperCase() +
              mediaTypeLabelText.slice(1)
        }`;

    fetchButton.innerHTML = "";
    fetchButton.appendChild(fetchIcon);
    fetchButton.appendChild(fetchButtonText);
    fetchButton.style.cssText = `
        background-color: #22c55e;
        color: white;
        border: none;
        border-radius: 6px;
        padding: 8px 16px;
        font-weight: bold;
        cursor: pointer;
        margin: 0;
        width: 48%;
        display: flex;
        justify-content: center;
        align-items: center;
        text-align: center;
        transition: background-color 0.2s;
    `;
    fetchButton.addEventListener("mouseenter", () => {
      fetchButton.style.backgroundColor = "#16a34a";
    });

    fetchButton.addEventListener("mouseleave", () => {
      fetchButton.style.backgroundColor = "#22c55e";
    });
    const infoContainer = document.createElement("div");
    infoContainer.style.cssText = `
        background-color: ${settings.darkTheme ? "#374151" : "#f1f5f9"};
        border-radius: 8px;
        padding: 12px;
        margin-bottom: 16px;
        display: none;
    `;

    const buttonContainer = document.createElement("div");
    buttonContainer.style.cssText = `
        display: none;
        gap: 8px;
        margin-bottom: 16px;
    `;
    const batchNavContainer = document.createElement("div");
    batchNavContainer.style.cssText = `
        display: none;
        flex-direction: column;
        gap: 8px;
        margin-bottom: 16px;
    `;

    const prevBatchButton = document.createElement("button");
    prevBatchButton.innerHTML = `<span style="display: flex; align-items: center; justify-content: center; gap: 6px; white-space: nowrap;">${ICONS.PREV}<span>Prev Batch</span></span>`;
    prevBatchButton.style.cssText = `
        background-color: #6366f1;
        color: white;
        border: none;
        border-radius: 6px;
        padding: 8px 16px;
        font-weight: bold;
        cursor: pointer;
        width: 40%;
        display: flex;
        align-items: center;
        justify-content: center;
        text-align: center;
        transition: background-color 0.2s;
    `;

    prevBatchButton.addEventListener("mouseenter", () => {
      prevBatchButton.style.backgroundColor = "#4f46e5";
    });
    prevBatchButton.addEventListener("mouseleave", () => {
      prevBatchButton.style.backgroundColor = "#6366f1";
    });

    const nextBatchButton = document.createElement("button");
    nextBatchButton.innerHTML = `<span style="display: flex; align-items: center; justify-content: center; gap: 6px; white-space: nowrap;"><span>Next Batch</span>${ICONS.NEXT}</span>`;
    nextBatchButton.style.cssText = `
        background-color: #6366f1;
        color: white;
        border: none;
        border-radius: 6px;
        padding: 8px 16px;
        font-weight: bold;
        cursor: pointer;
        width: 40%;
        display: flex;
        align-items: center;
        justify-content: center;
        text-align: center;
        transition: background-color 0.2s;
    `;

    nextBatchButton.addEventListener("mouseenter", () => {
      nextBatchButton.style.backgroundColor = "#4f46e5";
    });
    nextBatchButton.addEventListener("mouseleave", () => {
      nextBatchButton.style.backgroundColor = "#6366f1";
    });

    const buttonWrapper = document.createElement("div");
    buttonWrapper.style.cssText = `
        display: flex;
        gap: 8px;
        justify-content: center;
        width: 100%;
    `;

    buttonWrapper.appendChild(prevBatchButton);
    buttonWrapper.appendChild(nextBatchButton);
    batchNavContainer.appendChild(buttonWrapper);

    const stopFetchButton = document.createElement("button");
    stopFetchButton.innerHTML = `<span style="display: flex; align-items: center; justify-content: center; gap: 6px; white-space: nowrap;">${ICONS.STOP}<span>Stop Fetch</span></span>`;

    stopFetchButton.style.cssText = `
        background-color: #ef4444;
        color: white;
        border: none;
        border-radius: 6px;
        padding: 8px 16px;
        font-weight: bold;
        cursor: pointer;
        width: 140px; /* Fixed width instead of percentage */
        display: none;
        align-items: center;
        justify-content: center;
        text-align: center;
        transition: background-color 0.2s;
    `;

    stopFetchButton.addEventListener("mouseenter", () => {
      stopFetchButton.style.backgroundColor = "#dc2626";
    });
    stopFetchButton.addEventListener("mouseleave", () => {
      stopFetchButton.style.backgroundColor = "#ef4444";
    });
    stopFetchButton.addEventListener("click", () => {
      autoBatchCancelled = true;
      autoBatchStarted = false;
      batchNavContainer.style.display = "flex";
      prevBatchButton.style.display =
        mediaData.currentPage > getSettings().startingBatch ? "block" : "none";
      nextBatchButton.style.display = mediaData.hasMore ? "block" : "none";
      stopFetchButton.style.display = "none";
      batchInfoContainer.style.display = "flex";
      infoContainer.style.display = "block";
      fetchButtonText.textContent = "Auto Fetch";
    });

    const stopFetchWrapper = document.createElement("div");
    stopFetchWrapper.style.cssText = `
        display: flex;
        justify-content: center;
        width: 100%;
        margin-top: 8px; /* Add spacing between button rows */
    `;
    stopFetchWrapper.appendChild(stopFetchButton);
    batchNavContainer.appendChild(stopFetchWrapper);

    const batchInfoContainer = document.createElement("div");
    batchInfoContainer.style.cssText = `
        display: none;
        flex-direction: column;
        gap: 8px;
        margin-bottom: 16px;
        padding: 12px;
        background-color: ${settings.darkTheme ? "#374151" : "#f8fafc"};
        border-radius: 8px;
        border: 1px solid ${settings.darkTheme ? "#4b5563" : "#e2e8f0"};
    `;

    const batchStatsRow = document.createElement("div");
    batchStatsRow.style.cssText = `
        display: flex;
        justify-content: space-between;
        align-items: center;
    `;

    const currentBatchLabel = document.createElement("div");
    currentBatchLabel.style.cssText = `
        font-size: 14px;
        color: ${settings.darkTheme ? "#ffffff" : "#475569"};
    `;

    const totalBatchLabel = document.createElement("div");
    totalBatchLabel.style.cssText = `
        font-size: 14px;
        color: ${settings.darkTheme ? "#ffffff" : "#475569"};
    `;

    batchStatsRow.appendChild(currentBatchLabel);
    batchStatsRow.appendChild(totalBatchLabel);

    const downloadButtonsRow = document.createElement("div");
    downloadButtonsRow.style.cssText = `
        display: flex;
        gap: 8px;
        justify-content: center;
    `;

    const downloadCurrentButton = document.createElement("button");
    downloadCurrentButton.innerHTML = "";
    const currentIcon = createDownloadIcon();
    currentIcon.style.width = "12px";
    currentIcon.style.height = "12px";
    currentIcon.style.marginRight = "4px";
    const currentText = document.createElement("span");
    currentText.textContent = "Download Current";
    downloadCurrentButton.appendChild(currentIcon);
    downloadCurrentButton.appendChild(currentText);
    downloadCurrentButton.style.cssText = `
        background-color: #0ea5e9;
        color: white;
        border: none;
        border-radius: 6px;
        padding: 6px 12px;
        font-weight: bold;
        cursor: pointer;
        font-size: 12px;
        transition: background-color 0.2s;
        flex: 1;
        display: flex;
        align-items: center;
        justify-content: center;
    `;
    downloadCurrentButton.addEventListener("mouseenter", () => {
      downloadCurrentButton.style.backgroundColor = "#0284c7";
    });
    downloadCurrentButton.addEventListener("mouseleave", () => {
      downloadCurrentButton.style.backgroundColor = "#0ea5e9";
    });

    const downloadAllButton = document.createElement("button");
    downloadAllButton.innerHTML = "";
    const allIcon = createDownloadIcon();
    allIcon.style.width = "12px";
    allIcon.style.height = "12px";
    allIcon.style.marginRight = "4px";
    const allText = document.createElement("span");
    allText.textContent = "Download All";
    downloadAllButton.appendChild(allIcon);
    downloadAllButton.appendChild(allText);
    downloadAllButton.style.cssText = `
        background-color: #0ea5e9;
        color: white;
        border: none;
        border-radius: 6px;
        padding: 6px 12px;
        font-weight: bold;
        cursor: pointer;
        font-size: 12px;
        transition: background-color 0.2s;
        flex: 1;
        display: flex;
        align-items: center;
        justify-content: center;
    `;
    downloadAllButton.addEventListener("mouseenter", () => {
      downloadAllButton.style.backgroundColor = "#0284c7";
    });
    downloadAllButton.addEventListener("mouseleave", () => {
      downloadAllButton.style.backgroundColor = "#0ea5e9";
    });

    downloadButtonsRow.appendChild(downloadCurrentButton);
    downloadButtonsRow.appendChild(downloadAllButton);

    batchInfoContainer.appendChild(batchStatsRow);
    batchInfoContainer.appendChild(downloadButtonsRow);

    const downloadButton = document.createElement("button");
    const downloadIcon = createDownloadIcon();
    downloadIcon.style.width = "16px";
    downloadIcon.style.height = "16px";
    downloadIcon.style.marginRight = "8px";

    downloadButton.innerHTML = "";
    downloadButton.appendChild(downloadIcon);
    downloadButton.appendChild(document.createTextNode("Download"));
    downloadButton.style.cssText = `
        background-color: #0ea5e9;
        color: white;
        border: none;
        border-radius: 6px;
        padding: 8px 16px;
        font-weight: bold;
        cursor: pointer;
        width: 50%;
        margin-left: auto;
        margin-right: auto;
        display: flex;
        align-items: center;
        justify-content: center;
        text-align: center;
        transition: background-color 0.2s;
    `;
    downloadButton.addEventListener("mouseenter", () => {
      downloadButton.style.backgroundColor = "#0284c7";
    });
    downloadButton.addEventListener("mouseleave", () => {
      downloadButton.style.backgroundColor = "#0ea5e9";
    });
    downloadButton.onclick = () => downloadMedia(false);

    if (settings.batchEnabled) {
      buttonContainer.style.display = "none";
    } else {
      buttonContainer.appendChild(downloadButton);
    }
    const batchButtonsContainer = document.createElement("div");
    batchButtonsContainer.style.cssText = `
        display: none;
        gap: 8px;
        margin-bottom: 16px;
    `;

    const progressContainer = document.createElement("div");
    progressContainer.style.cssText = `
        margin-top: 16px;
        display: none;
    `;

    const progressText = document.createElement("div");
    progressText.style.cssText = `
        margin-bottom: 8px;
        font-size: 14px;
        text-align: center;
    `;
    progressText.textContent = "Downloading...";

    const progressBar = document.createElement("div");
    progressBar.style.cssText = `
        width: 100%;
        height: 8px;
        background-color: ${settings.darkTheme ? "#374151" : "#f1f5f9"};
        border-radius: 4px;
        overflow: hidden;
    `;

    const progressFill = document.createElement("div");
    progressFill.style.cssText = `
        height: 100%;
        width: 0%;
        background-color: #0ea5e9;
        transition: width 0.3s ease-in-out;
        will-change: width;
    `;

    progressBar.appendChild(progressFill);
    progressContainer.appendChild(progressText);
    progressContainer.appendChild(progressBar);
    const convertGifButton = document.createElement("button");
    const convertGifIcon = document.createElementNS(
      "http://www.w3.org/2000/svg",
      "svg"
    );
    convertGifIcon.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    convertGifIcon.setAttribute("viewBox", ICONS.MEDIA_TYPE.GIF.VIEWBOX);
    convertGifIcon.setAttribute("width", "16");
    convertGifIcon.setAttribute("height", "16");
    convertGifIcon.style.marginRight = "8px";

    const convertGifPath = document.createElementNS(
      "http://www.w3.org/2000/svg",
      "path"
    );
    convertGifPath.setAttribute("fill", "currentColor");
    convertGifPath.setAttribute("d", ICONS.MEDIA_TYPE.GIF.PATH);
    convertGifIcon.appendChild(convertGifPath);

    const convertGifButtonText = document.createElement("span");
    convertGifButtonText.textContent = "Convert GIF";

    convertGifButton.innerHTML = "";
    convertGifButton.appendChild(convertGifIcon);
    convertGifButton.appendChild(convertGifButtonText);
    convertGifButton.style.cssText = `
        background-color: #3b82f6;
        color: white;
        border: none;
        border-radius: 6px;
        padding: 8px 16px;
        font-weight: bold;
        cursor: pointer;
        margin: 0;
        width: 48%;
        display: flex;
        justify-content: center;
        align-items: center;
        text-align: center;
        transition: background-color 0.2s;
    `;

    convertGifButton.addEventListener("mouseenter", () => {
      convertGifButton.style.backgroundColor = "#2563eb";
    });

    convertGifButton.addEventListener("mouseleave", () => {
      convertGifButton.style.backgroundColor = "#3b82f6";
    });
    convertGifButton.addEventListener("click", () => {
      const convertUrl = `https://convert.xbatch.online/${username}`;
      window.open(convertUrl, "_blank");
    });

    const mainButtonsContainer = document.createElement("div");
    mainButtonsContainer.style.cssText = `
        display: flex;
        gap: 4%;
        margin: 16px 0;
        width: 100%;
    `;

    mainButtonsContainer.appendChild(fetchButton);
    mainButtonsContainer.appendChild(convertGifButton);

    mainContent.appendChild(mainButtonsContainer);
    mainContent.appendChild(infoContainer);
    mainContent.appendChild(batchInfoContainer);
    mainContent.appendChild(batchNavContainer);
    mainContent.appendChild(buttonContainer);
    mainContent.appendChild(batchButtonsContainer);
    mainContent.appendChild(progressContainer);

    const settingsTabs = document.createElement("div");
    settingsTabs.style.cssText = `
        display: flex;
        border-bottom: 1px solid ${settings.darkTheme ? "#374151" : "#e2e8f0"};
        margin-bottom: 16px;
        width: 100%;
    `;

    const fetchTab = document.createElement("button");
    fetchTab.textContent = "Fetch";
    fetchTab.style.cssText = `
        background: none;
        border: none;
        padding: 12px 16px;
        cursor: pointer;
        color: ${settings.darkTheme ? "#f1f5f9" : "#0f172a"};
        border-bottom: 2px solid #0ea5e9;
        font-weight: bold;
        font-size: 14px;
        flex: 1;
        text-align: center;
    `;

    const authTab = document.createElement("button");
    authTab.textContent = "Auth";
    authTab.style.cssText = `
        background: none;
        border: none;
        padding: 12px 16px;
        cursor: pointer;
        color: #64748b;
        border-bottom: none;
        font-weight: bold;
        font-size: 14px;
        flex: 1;
        text-align: center;
    `;

    const advancedTab = document.createElement("button");
    advancedTab.textContent = "Advanced";
    advancedTab.style.cssText = `
        background: none;
        border: none;
        padding: 12px 16px;
        cursor: pointer;
        color: #64748b;
        border-bottom: none;
        font-weight: bold;
        font-size: 14px;
        flex: 1;
        text-align: center;
    `;

    settingsTabs.appendChild(fetchTab);
    settingsTabs.appendChild(authTab);
    settingsTabs.appendChild(advancedTab);
    const fetchTabContent = document.createElement("div");
    fetchTabContent.style.cssText = `
        display: flex;
        flex-direction: column;
        gap: ${settings.batchEnabled ? "16px" : "8px"};
    `;

    const downloadTabContent = document.createElement("div");
    downloadTabContent.style.cssText = `
        display: none;
        flex-direction: column;
        gap: 16px;
    `;

    const authTabContent = document.createElement("div");
    authTabContent.style.cssText = `
        display: none;
        flex-direction: column;
        gap: 16px;
    `;

    const advancedTabContent = document.createElement("div");
    advancedTabContent.style.cssText = `
        display: none;
        flex-direction: column;
        gap: 0px;
    `;

    const patreonAuthGroup = document.createElement("div");
    patreonAuthGroup.style.cssText = `
        display: flex;
        flex-direction: column;
        gap: 8px;
    `;

    const patreonAuthLabel = document.createElement("label");
    patreonAuthLabel.textContent = "Patreon Auth:";
    patreonAuthLabel.style.cssText = `
        font-size: 14px;
        font-weight: bold;
        color: ${settings.darkTheme ? "#f1f5f9" : "#334155"};
    `;

    const patreonAuthInputContainer = document.createElement("div");
    patreonAuthInputContainer.style.cssText = `
        position: relative;
        display: flex;
        align-items: center;
    `;

    const patreonAuthInput = document.createElement("input");
    patreonAuthInput.type = "text";
    patreonAuthInput.value = settings.patreonAuth;
    patreonAuthInput.style.cssText = `
    background-color: ${settings.darkTheme ? "#374151" : "#f1f5f9"};
    border: 1px solid transparent;
    border-radius: 4px;
    padding: 8px 12px;
    color: ${settings.darkTheme ? "#cbd5e1" : "#64748b"};
    width: 100%;
    box-sizing: border-box;
    transition: all 0.2s ease;
    `;

    patreonAuthInput.addEventListener("focus", () => {
      patreonAuthInput.style.border = "1px solid #0ea5e9";
      patreonAuthInput.style.outline = "none";
    });
    patreonAuthInput.addEventListener("blur", () => {
      patreonAuthInput.style.border = "1px solid transparent";
    });

    patreonAuthInput.addEventListener("input", () => {
      const newSettings = getSettings();
      newSettings.patreonAuth = patreonAuthInput.value;
      saveSettings(newSettings);
      patreonAuthClearButton.style.display = patreonAuthInput.value
        ? "block"
        : "none";
    });

    const patreonAuthClearButton = document.createElement("button");
    patreonAuthClearButton.innerHTML = "&times;";
    patreonAuthClearButton.style.cssText = `
        position: absolute;
        right: 8px;
        background: none;
        border: none;
        color: #64748b;
        font-size: 18px;
        cursor: pointer;
        padding: 0;
        display: ${settings.patreonAuth ? "block" : "none"};
    `;
    patreonAuthClearButton.addEventListener("click", () => {
      patreonAuthInput.value = "";
      const newSettings = getSettings();
      newSettings.patreonAuth = "";
      saveSettings(newSettings);
      patreonAuthClearButton.style.display = "none";
    });

    patreonAuthInputContainer.appendChild(patreonAuthInput);
    patreonAuthInputContainer.appendChild(patreonAuthClearButton);
    patreonAuthGroup.appendChild(patreonAuthLabel);
    patreonAuthGroup.appendChild(patreonAuthInputContainer);

    const tokenGroup = document.createElement("div");
    tokenGroup.style.cssText = `
        display: flex;
        flex-direction: column;
        gap: 8px;
    `;

    const tokenLabel = document.createElement("label");
    tokenLabel.textContent = "Auth Token:";
    tokenLabel.style.cssText = `
        font-size: 14px;
        font-weight: bold;
        color: ${settings.darkTheme ? "#f1f5f9" : "#334155"};
    `;

    const tokenInputContainer = document.createElement("div");
    tokenInputContainer.style.cssText = `
        position: relative;
        display: flex;
        align-items: center;
    `;

    const tokenInput = document.createElement("input");
    tokenInput.type = "text";
    tokenInput.value = settings.authToken;
    tokenInput.style.cssText = `
    background-color: ${settings.darkTheme ? "#374151" : "#f1f5f9"};
    border: 1px solid transparent;
    border-radius: 4px;
    padding: 8px 12px;
    color: ${settings.darkTheme ? "#cbd5e1" : "#64748b"};
    width: 100%;
    box-sizing: border-box;
    transition: all 0.2s ease;
    `;
    tokenInput.addEventListener("focus", () => {
      tokenInput.style.border = "1px solid #0ea5e9";
      tokenInput.style.outline = "none";
    });
    tokenInput.addEventListener("blur", () => {
      tokenInput.style.border = "1px solid transparent";
    });

    tokenInput.addEventListener("input", () => {
      const newSettings = getSettings();
      newSettings.authToken = tokenInput.value;
      saveSettings(newSettings);
      tokenClearButton.style.display = tokenInput.value ? "block" : "none";
    });

    const tokenClearButton = document.createElement("button");
    tokenClearButton.innerHTML = "&times;";
    tokenClearButton.style.cssText = `
        position: absolute;
        right: 8px;
        background: none;
        border: none;
        color: #64748b;
        font-size: 18px;
        cursor: pointer;
        padding: 0;
        display: ${settings.authToken ? "block" : "none"};
    `;
    tokenClearButton.addEventListener("click", () => {
      tokenInput.value = "";
      const newSettings = getSettings();
      newSettings.authToken = "";
      saveSettings(newSettings);
      tokenClearButton.style.display = "none";
    });

    tokenInputContainer.appendChild(tokenInput);
    tokenInputContainer.appendChild(tokenClearButton);
    tokenGroup.appendChild(tokenLabel);
    tokenGroup.appendChild(tokenInputContainer);

    const apiServerGroup = document.createElement("div");
    apiServerGroup.style.cssText = `
        display: flex;
        flex-direction: column;
        gap: 8px;
    `;

    const apiServerLabel = document.createElement("label");
    apiServerLabel.textContent = "Service:";
    apiServerLabel.style.cssText = `
        font-size: 14px;
        font-weight: bold;
        color: ${settings.darkTheme ? "#f1f5f9" : "#334155"};
    `;

    const apiServerOptions = [
      { value: "default", label: "Default" },
      { value: "backup", label: "Backup" },
    ];

    const apiServerToggle = createToggleSwitch(
      apiServerOptions,
      settings.apiServer,
      (value) => {
        const newSettings = getSettings();
        newSettings.apiServer = value;
        saveSettings(newSettings);
        settings.apiServer = value;
      }
    );

    apiServerGroup.appendChild(apiServerLabel);
    apiServerGroup.appendChild(apiServerToggle);

    const batchGroup = document.createElement("div");
    batchGroup.style.cssText = `
        display: flex;
        align-items: center;
        gap: 8px;
    `;
    const batchLabel = document.createElement("label");
    batchLabel.style.cssText = `
        font-size: 14px;
        font-weight: bold;
        color: ${settings.darkTheme ? "#f1f5f9" : "#334155"};
        flex: 1;
        display: flex;
        align-items: center;
    `;
    const batchLabelText = document.createElement("span");
    batchLabelText.textContent = "Batch:";
    batchLabel.appendChild(batchLabelText);

    const batchInfoIcon = createInfoIcon();
    const batchTooltip = createInfoTooltip(
      "When enabled, the media fetching process is performed in batches"
    );
    batchInfoIcon.addEventListener("mouseenter", batchTooltip.showTooltip);
    batchInfoIcon.addEventListener("mouseleave", batchTooltip.hideTooltip);
    batchLabel.appendChild(batchInfoIcon);

    const batchToggle = document.createElement("div");
    batchToggle.style.cssText = `
        position: relative;
        width: 50px;
        height: 24px;
        background-color: ${settings.batchEnabled ? "#22c55e" : "#cbd5e1"};
        border-radius: 12px;
        cursor: pointer;
        transition: background-color 0.3s;
    `;

    const batchToggleHandle = document.createElement("div");
    batchToggleHandle.style.cssText = `
        position: absolute;
        top: 2px;
        left: ${settings.batchEnabled ? "28px" : "2px"};
        width: 20px;
        height: 20px;
        background-color: white;
        border-radius: 50%;
        transition: left 0.3s;
    `;

    batchToggle.appendChild(batchToggleHandle);
    batchToggle.addEventListener("click", () => {
      const newSettings = getSettings();
      newSettings.batchEnabled = !newSettings.batchEnabled;
      saveSettings(newSettings);
      batchToggle.style.backgroundColor = newSettings.batchEnabled
        ? "#22c55e"
        : "#cbd5e1";
      batchToggleHandle.style.left = newSettings.batchEnabled ? "28px" : "2px";
      autoBatchGroup.style.display = newSettings.batchEnabled ? "flex" : "none";
      batchSizeGroup.style.display = newSettings.batchEnabled ? "flex" : "none";
      startingBatchGroup.style.display = newSettings.batchEnabled
        ? "flex"
        : "none";

      if (!newSettings.batchEnabled) {
        fetchTabContent.style.gap = "8px";
        newSettings.autoBatchEnabled = false;
        saveSettings(newSettings);
        autoBatchToggle.style.backgroundColor = "#cbd5e1";
        autoBatchHandle.style.left = "2px";
        const mt = getSettings().mediaType;
        const mtLabel = getMediaTypeLabel(mt).toLowerCase();
        const labelText =
          mt === "all"
            ? "Fetch Media"
            : `Fetch ${
                mtLabel === "gif"
                  ? "GIF"
                  : mtLabel.charAt(0).toUpperCase() + mtLabel.slice(1)
              }`;

        fetchButtonText.textContent = labelText;
        fetchButton.innerHTML = "";
        let updatedFetchIcon = fetchIcon.cloneNode(true);
        fetchButton.appendChild(updatedFetchIcon);
        fetchButton.appendChild(fetchButtonText);
        if (typeof stopFetchButton !== "undefined")
          stopFetchButton.style.display = "none";
        if (typeof prevBatchButton !== "undefined")
          prevBatchButton.style.display = "block";
        if (typeof nextBatchButton !== "undefined")
          nextBatchButton.style.display = "block";
      } else {
        fetchTabContent.style.gap = "16px";
      }
    });

    batchGroup.appendChild(batchLabel);
    batchGroup.appendChild(batchToggle);

    const autoBatchGroup = document.createElement("div");
    autoBatchGroup.style.cssText = `
        display: ${settings.batchEnabled ? "flex" : "none"};
        align-items: center;
        gap: 8px;
    `;
    const autoBatchLabel = document.createElement("label");
    autoBatchLabel.style.cssText = `
        font-size: 14px;
        font-weight: bold;
        color: ${settings.darkTheme ? "#f1f5f9" : "#334155"};
        flex: 1;
        display: flex;
        align-items: center;
    `;
    autoBatchLabel.textContent = "Auto Fetch";
    const autoBatchToggle = document.createElement("div");
    autoBatchToggle.style.cssText = `
        position: relative;
        width: 50px;
        height: 24px;
        background-color: ${settings.autoBatchEnabled ? "#22c55e" : "#cbd5e1"};
        border-radius: 12px;
        cursor: pointer;
        transition: background-color 0.3s;
    `;
    const autoBatchHandle = document.createElement("div");
    autoBatchHandle.style.cssText = `
        position: absolute;
        top: 2px;
        left: ${settings.autoBatchEnabled ? "28px" : "2px"};
        width: 20px;
        height: 20px;
        background-color: white;
        border-radius: 50%;
        transition: left 0.3s;
    `;
    autoBatchToggle.appendChild(autoBatchHandle);
    autoBatchToggle.addEventListener("click", () => {
      const newSettings = getSettings();
      const willEnable = !newSettings.autoBatchEnabled;
      newSettings.autoBatchEnabled = willEnable;
      saveSettings(newSettings);
      autoBatchCancelled = false;
      autoBatchStarted = false;
      autoBatchToggle.style.backgroundColor = willEnable
        ? "#22c55e"
        : "#cbd5e1";
      autoBatchHandle.style.left = willEnable ? "28px" : "2px";
      const label = willEnable
        ? "Auto Fetch"
        : newSettings.mediaType === "all"
        ? "Fetch Media"
        : newSettings.mediaType === "image"
        ? "Fetch Photos"
        : "Fetch Videos";
      fetchButtonText.textContent = label;

      if (willEnable) {
        const keyPrefix = `twitter_dl_${newSettings.timelineType}_${newSettings.mediaType}_${username}_`;
        const keySuffix = `_${newSettings.batchSize}_batch_true`;
        for (let i = 0; i < localStorage.length; i++) {
          const key = localStorage.key(i);
          if (key.startsWith(keyPrefix) && key.endsWith(keySuffix)) {
            const pageNum = parseInt(
              key.slice(keyPrefix.length, key.length - keySuffix.length),
              10
            );
            if (!isNaN(pageNum)) {
              const cachedData = cacheManager.get(key);
              if (cachedData && cachedData.timeline) {
                mediaData.batchData[pageNum] = cachedData.timeline;
              }
            }
          }
        }
        const batchNums = Object.keys(mediaData.batchData).map(Number);
        mediaData.currentPage =
          batchNums.length > 0 ? Math.max(...batchNums) + 1 : 0;
        fetchButtonText.textContent = "Auto Fetch";
      } else {
        const mt = newSettings.mediaType;
        const label =
          mt === "all"
            ? "Fetch Media"
            : `Fetch ${getMediaTypeLabel(mt).toUpperCase()}`;
        fetchButtonText.textContent = label;
      }
    });
    autoBatchGroup.appendChild(autoBatchLabel);
    autoBatchGroup.appendChild(autoBatchToggle);

    const batchSizeGroup = document.createElement("div");
    batchSizeGroup.style.cssText = `
    display: ${settings.batchEnabled ? "flex" : "none"};
    flex-direction: column;
    gap: 8px;
    `;

    const batchSizeLabel = document.createElement("label");
    batchSizeLabel.style.cssText = `
        font-size: 14px;
        font-weight: bold;
        color: ${settings.darkTheme ? "#f1f5f9" : "#334155"};
        display: flex;
        align-items: center;
    `;
    const batchSizeLabelText = document.createElement("span");
    batchSizeLabelText.textContent = "Batch Size:";
    batchSizeLabel.appendChild(batchSizeLabelText);

    const batchSizeInfoIcon = createInfoIcon();
    const batchSizeTooltip = createInfoTooltip(
      "Number of media items fetched in a single request"
    );
    batchSizeInfoIcon.addEventListener(
      "mouseenter",
      batchSizeTooltip.showTooltip
    );
    batchSizeInfoIcon.addEventListener(
      "mouseleave",
      batchSizeTooltip.hideTooltip
    );
    batchSizeLabel.appendChild(batchSizeInfoIcon);

    const batchSizeToggle = createSlider(
      batchSizes,
      settings.batchSize,
      (value) => {
        const newSettings = getSettings();
        newSettings.batchSize = value;
        saveSettings(newSettings);
        settings.batchSize = value;
      }
    );

    batchSizeGroup.appendChild(batchSizeLabel);
    batchSizeGroup.appendChild(batchSizeToggle);

    const startingBatchGroup = document.createElement("div");
    startingBatchGroup.style.cssText = `
    display: ${settings.batchEnabled ? "flex" : "none"};
    flex-direction: column;
    gap: 8px;
    `;

    const startingBatchLabel = document.createElement("label");
    startingBatchLabel.style.cssText = `
        font-size: 14px;
        font-weight: bold;
        color: ${settings.darkTheme ? "#f1f5f9" : "#334155"};
        display: flex;
        align-items: center;
    `;
    const startingBatchLabelText = document.createElement("span");
    startingBatchLabelText.textContent = "Starting Batch:";
    startingBatchLabel.appendChild(startingBatchLabelText);

    const startingBatchInfoIcon = createInfoIcon();
    const startingBatchTooltip = createInfoTooltip(
      "Determines which batch number to start fetching from"
    );
    startingBatchInfoIcon.addEventListener(
      "mouseenter",
      startingBatchTooltip.showTooltip
    );
    startingBatchInfoIcon.addEventListener(
      "mouseleave",
      startingBatchTooltip.hideTooltip
    );
    startingBatchLabel.appendChild(startingBatchInfoIcon);

    const startingBatchInput = document.createElement("input");
    startingBatchInput.type = "number";
    startingBatchInput.value = settings.startingBatch;
    startingBatchInput.min = "0";
    startingBatchInput.style.cssText = `
        background-color: ${settings.darkTheme ? "#374151" : "#f1f5f9"};
        border: 1px solid transparent;
        border-radius: 4px;
        padding: 8px 12px;
        color: ${settings.darkTheme ? "#cbd5e1" : "#64748b"};
        width: 100%;
        box-sizing: border-box;
        transition: all 0.2s ease;
    `;
    startingBatchInput.addEventListener("focus", () => {
      startingBatchInput.style.border = "1px solid #0ea5e9";
      startingBatchInput.style.outline = "none";
    });
    startingBatchInput.addEventListener("blur", () => {
      startingBatchInput.style.border = "1px solid transparent";
    });

    startingBatchInput.addEventListener("input", () => {
      const newSettings = getSettings();
      newSettings.startingBatch = parseInt(startingBatchInput.value) || 0;
      saveSettings(newSettings);
      settings.startingBatch = newSettings.startingBatch;
    });

    startingBatchGroup.appendChild(startingBatchLabel);
    startingBatchGroup.appendChild(startingBatchInput);

    const timelineTypeGroup = document.createElement("div");
    timelineTypeGroup.style.cssText = `
    display: flex;
    flex-direction: column;
    gap: 8px;
    `;

    const timelineTypeLabel = document.createElement("label");
    timelineTypeLabel.textContent = "Timeline Type:";
    timelineTypeLabel.style.cssText = `
        font-size: 14px;
        font-weight: bold;
        color: ${settings.darkTheme ? "#f1f5f9" : "#334155"};
    `;

    const timelineTypeOptions = [
      { value: "media", label: "Media", icon: createTimelineTypeIcon("media") },
      {
        value: "timeline",
        label: "Post",
        icon: createTimelineTypeIcon("timeline"),
      },
      {
        value: "tweets",
        label: "Tweets",
        icon: createTimelineTypeIcon("tweets"),
      },
      {
        value: "with_replies",
        label: "Replies",
        icon: createTimelineTypeIcon("with_replies"),
      },
    ];

    const timelineTypeToggle = createToggleSwitch(
      timelineTypeOptions,
      settings.timelineType,
      (value) => {
        const newSettings = getSettings();
        newSettings.timelineType = value;
        saveSettings(newSettings);
        settings.timelineType = value;
      }
    );

    timelineTypeGroup.appendChild(timelineTypeLabel);
    timelineTypeGroup.appendChild(timelineTypeToggle);

    const mediaTypeGroup = document.createElement("div");
    mediaTypeGroup.style.cssText = `
    display: flex;
    flex-direction: column;
    gap: 8px;
    `;

    const mediaTypeLabel = document.createElement("label");
    mediaTypeLabel.textContent = "Media Type:";
    mediaTypeLabel.style.cssText = `
        font-size: 14px;
        font-weight: bold;
        color: ${settings.darkTheme ? "#f1f5f9" : "#334155"};
    `;

    const mediaTypeIcons = createMediaTypeIcons();
    const mediaTypeOptions = [
      { value: "all", label: "All", icon: mediaTypeIcons.all },
      { value: "image", label: "Image", icon: mediaTypeIcons.image },
      { value: "video", label: "Video", icon: mediaTypeIcons.video },
      { value: "gif", label: "GIF", icon: mediaTypeIcons.gif },
    ];

    const mediaTypeToggle = createToggleSwitch(
      mediaTypeOptions,
      settings.mediaType,
      (value) => {
        const newSettings = getSettings();
        newSettings.mediaType = value;
        saveSettings(newSettings);
        settings.mediaType = value;

        const newMediaTypeLabel = getMediaTypeLabel(value).toLowerCase();
        const newFetchButtonText =
          value === "all"
            ? "Fetch Media"
            : `Fetch ${
                newMediaTypeLabel === "gif"
                  ? "GIF"
                  : newMediaTypeLabel.charAt(0).toUpperCase() +
                    newMediaTypeLabel.slice(1)
              }`;

        fetchButton.innerHTML = "";
        const newFetchIcon = fetchIcon.cloneNode(true);
        fetchButton.appendChild(newFetchIcon);
        fetchButton.appendChild(document.createTextNode(newFetchButtonText));

        title.innerHTML = `Download ${getMediaTypeLabel(
          value
        )}: <span style="color: #0ea5e9">${username}</span>`;
      }
    );

    mediaTypeGroup.appendChild(mediaTypeLabel);
    mediaTypeGroup.appendChild(mediaTypeToggle);

    const concurrentGroup = document.createElement("div");
    concurrentGroup.style.cssText = `
    display: flex;
    flex-direction: column;
    gap: 8px;
    `;

    const concurrentLabel = document.createElement("label");
    concurrentLabel.style.cssText = `
        font-size: 14px;
        font-weight: bold;
        color: ${settings.darkTheme ? "#f1f5f9" : "#334155"};
        display: flex;
        align-items: center;
    `;

    const concurrentLabelText = document.createElement("span");
    concurrentLabelText.textContent = "Batch Download Items:";
    concurrentLabel.appendChild(concurrentLabelText);

    const concurrentInfoIcon = createInfoIcon();
    const concurrentTooltip = createInfoTooltip(
      "Total item that are downloaded in a single request"
    );
    concurrentInfoIcon.addEventListener(
      "mouseenter",
      concurrentTooltip.showTooltip
    );
    concurrentInfoIcon.addEventListener(
      "mouseleave",
      concurrentTooltip.hideTooltip
    );
    concurrentLabel.appendChild(concurrentInfoIcon);

    const concurrentToggle = document.createElement("div");
    concurrentToggle.textContent = "Fixed to 50 concurrent downloads";
    concurrentToggle.style.cssText = `
        padding: 10px;
        background-color: ${settings.darkTheme ? "#374151" : "#f1f5f9"};
        color: ${settings.darkTheme ? "#f1f5f9" : "#334155"};
        border-radius: 8px;
        text-align: center;
    `;

    concurrentGroup.appendChild(concurrentLabel);
    concurrentGroup.appendChild(concurrentToggle);

    const cacheDurationGroup = document.createElement("div");
    cacheDurationGroup.style.cssText = `
    display: flex;
    flex-direction: column;
    gap: 8px;
    `;

    const cacheDurationLabel = document.createElement("label");
    cacheDurationLabel.textContent = "Cache Duration:";
    cacheDurationLabel.style.cssText = `
        font-size: 14px;
        font-weight: bold;
        color: ${settings.darkTheme ? "#f1f5f9" : "#334155"};
    `;

    const cacheDurationOptions = cacheDurations.map((duration) => {
      let label = duration.toString() + "m";
      if (duration >= 60 && duration % 60 === 0) {
        label = `${duration / 60}h`;
      }
      return { value: duration, label: label };
    });

    const cacheDurationToggle = createToggleSwitch(
      cacheDurationOptions,
      settings.cacheDuration,
      (value) => {
        const newSettings = getSettings();
        newSettings.cacheDuration = value;
        saveSettings(newSettings);
        settings.cacheDuration = value;
      }
    );
    cacheDurationGroup.appendChild(cacheDurationLabel);
    cacheDurationGroup.appendChild(cacheDurationToggle);

    const darkThemeGroup = document.createElement("div");
    darkThemeGroup.style.cssText = `
        display: flex;
        align-items: center;
        gap: 8px;
    `;
    const darkThemeLabel = document.createElement("label");
    darkThemeLabel.style.cssText = `
        font-size: 14px;
        font-weight: bold;
        color: ${settings.darkTheme ? "#f1f5f9" : "#334155"};
        flex: 1;
        display: flex;
        align-items: center;
    `;
    const darkThemeLabelText = document.createElement("span");
    darkThemeLabelText.textContent = "Dark Theme:";
    darkThemeLabel.appendChild(darkThemeLabelText);

    const darkThemeToggle = document.createElement("div");
    darkThemeToggle.style.cssText = `
        position: relative;
        width: 50px;
        height: 24px;
        background-color: ${settings.darkTheme ? "#22c55e" : "#cbd5e1"};
        border-radius: 12px;
        cursor: pointer;
        transition: background-color 0.3s;
    `;

    const darkThemeToggleHandle = document.createElement("div");
    darkThemeToggleHandle.style.cssText = `
        position: absolute;
        top: 2px;
        left: ${settings.darkTheme ? "28px" : "2px"};
        width: 20px;
        height: 20px;
        background-color: white;
        border-radius: 50%;
        transition: left 0.3s;
    `;

    darkThemeToggle.appendChild(darkThemeToggleHandle);
    darkThemeToggle.addEventListener("click", () => {
      const newSettings = getSettings();
      newSettings.darkTheme = !newSettings.darkTheme;
      saveSettings(newSettings);
      settings.darkTheme = newSettings.darkTheme;
      darkThemeToggle.style.backgroundColor = newSettings.darkTheme
        ? "#22c55e"
        : "#cbd5e1";
      darkThemeToggleHandle.style.left = newSettings.darkTheme ? "28px" : "2px";
      updateTheme();
    });

    darkThemeGroup.appendChild(darkThemeLabel);
    darkThemeGroup.appendChild(darkThemeToggle);

    const buttonsContainer = document.createElement("div");
    buttonsContainer.style.cssText = `
    display: flex;
    gap: 16px;
    margin-top: 16px;
    width: 100%;
    justify-content: center;
    align-items: center;
    `;

    const clearCacheButton = document.createElement("button");
    const trashIcon = document.createElementNS(
      "http://www.w3.org/2000/svg",
      "svg"
    );
    trashIcon.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    trashIcon.setAttribute("viewBox", ICONS.CLEAR.VIEWBOX);
    trashIcon.setAttribute("width", "16");
    trashIcon.setAttribute("height", "16");
    trashIcon.style.marginRight = "8px";

    const trashPath = document.createElementNS(
      "http://www.w3.org/2000/svg",
      "path"
    );
    trashPath.setAttribute("fill", "currentColor");
    trashPath.setAttribute("d", ICONS.CLEAR.PATH);
    trashIcon.appendChild(trashPath);
    clearCacheButton.appendChild(trashIcon);
    clearCacheButton.appendChild(document.createTextNode("Clear Cache"));
    clearCacheButton.style.cssText = `
    background-color: #ef4444;
    color: white;
    border: none;
    border-radius: 6px;
    padding: 8px 16px;
    font-weight: bold;
    cursor: pointer;
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    transition: background-color 0.2s;
    `;

    const resetDefaultButton = document.createElement("button");
    const resetIcon = document.createElementNS(
      "http://www.w3.org/2000/svg",
      "svg"
    );
    resetIcon.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    resetIcon.setAttribute("viewBox", ICONS.RESET.VIEWBOX);
    resetIcon.setAttribute("width", "16");
    resetIcon.setAttribute("height", "16");
    resetIcon.style.marginRight = "8px";

    const resetPath = document.createElementNS(
      "http://www.w3.org/2000/svg",
      "path"
    );
    resetPath.setAttribute("fill", "currentColor");
    resetPath.setAttribute("d", ICONS.RESET.PATH);
    resetIcon.appendChild(resetPath);

    resetDefaultButton.appendChild(resetIcon);
    resetDefaultButton.appendChild(document.createTextNode("Reset Default"));
    resetDefaultButton.style.cssText = `
    background-color: #6366f1;
    color: white;
    border: none;
    border-radius: 6px;
    padding: 8px 16px;
    font-weight: bold;
    cursor: pointer;
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    transition: background-color 0.2s;
    `;
    buttonsContainer.appendChild(clearCacheButton);
    buttonsContainer.appendChild(resetDefaultButton);

    clearCacheButton.addEventListener("mouseenter", () => {
      clearCacheButton.style.backgroundColor = "#dc2626";
    });
    clearCacheButton.addEventListener("mouseleave", () => {
      clearCacheButton.style.backgroundColor = "#ef4444";
    });

    resetDefaultButton.addEventListener("mouseenter", () => {
      resetDefaultButton.style.backgroundColor = "#5b56f4";
    });
    resetDefaultButton.addEventListener("mouseleave", () => {
      resetDefaultButton.style.backgroundColor = "#6366f1";
    });
    clearCacheButton.addEventListener("click", () => {
      createConfirmDialog("Are you sure about clearing the cache?", () => {
        cacheManager.clear();

        createInfoDialog(
          "Cache has been successfully cleared.",
          "Clear Successful"
        );
      });
    });

    resetDefaultButton.addEventListener("click", () => {
      createConfirmDialog(
        "Are you sure you want to reset all settings to default values?",
        () => {
          const currentSettings = getSettings();
          const preservedPatreonAuth = currentSettings.patreonAuth;
          const preservedAuthToken = currentSettings.authToken;

          const resetSettings = { ...defaultSettings };
          resetSettings.patreonAuth = preservedPatreonAuth;
          resetSettings.authToken = preservedAuthToken;
          saveSettings(resetSettings);

          startingBatchInput.value = defaultSettings.startingBatch;

          batchToggle.style.backgroundColor = defaultSettings.batchEnabled
            ? "#22c55e"
            : "#cbd5e1";
          batchToggleHandle.style.left = defaultSettings.batchEnabled
            ? "28px"
            : "2px";

          batchSizeGroup.style.display = defaultSettings.batchEnabled
            ? "flex"
            : "none";
          startingBatchGroup.style.display = defaultSettings.batchEnabled
            ? "flex"
            : "none";
          autoBatchGroup.style.display = defaultSettings.batchEnabled
            ? "flex"
            : "none";

          patreonAuthClearButton.style.display = preservedPatreonAuth
            ? "block"
            : "none";
          tokenClearButton.style.display = preservedAuthToken
            ? "block"
            : "none";

          const timelineTypeOptions = [
            "media",
            "timeline",
            "tweets",
            "with_replies",
          ];
          const timelineTypeIndex = timelineTypeOptions.indexOf(
            defaultSettings.timelineType
          );
          const timelineTypeSlider =
            timelineTypeToggle.querySelector("div:first-child");
          const timelineTypeContainer =
            timelineTypeToggle.querySelector("div:last-child");

          if (
            timelineTypeSlider &&
            timelineTypeContainer &&
            timelineTypeIndex !== -1
          ) {
            timelineTypeSlider.style.transform = `translateX(${
              timelineTypeIndex * 100
            }%)`;
            timelineTypeContainer.querySelectorAll("div").forEach((opt, i) => {
              opt.style.color = i === timelineTypeIndex ? "white" : "#64748b";
              const optIcon = opt.querySelector("svg");
              if (optIcon) {
                const optPaths = optIcon.querySelectorAll("path");
                optPaths.forEach((path) => {
                  path.setAttribute(
                    "fill",
                    i === timelineTypeIndex ? "white" : "#64748b"
                  );
                });
              }
            });
          }

          const mediaTypeOptions = ["all", "image", "video", "gif"];
          const mediaTypeIndex = mediaTypeOptions.indexOf(
            defaultSettings.mediaType
          );
          const mediaTypeSlider =
            mediaTypeToggle.querySelector("div:first-child");
          const mediaTypeContainer =
            mediaTypeToggle.querySelector("div:last-child");

          if (mediaTypeSlider && mediaTypeContainer && mediaTypeIndex !== -1) {
            mediaTypeSlider.style.transform = `translateX(${
              mediaTypeIndex * 100
            }%)`;
            mediaTypeContainer.querySelectorAll("div").forEach((opt, i) => {
              opt.style.color = i === mediaTypeIndex ? "white" : "#64748b";
              const optIcon = opt.querySelector("svg");
              if (optIcon) {
                const optPaths = optIcon.querySelectorAll("path");
                optPaths.forEach((path) => {
                  path.setAttribute(
                    "fill",
                    i === mediaTypeIndex ? "white" : "#64748b"
                  );
                });
              }
            });
          }

          const batchSizeIndex = batchSizes.indexOf(defaultSettings.batchSize);
          const batchSizeSlider =
            batchSizeToggle.querySelector("div:first-child");
          const batchSizeContainer =
            batchSizeToggle.querySelector("div:last-child");

          if (batchSizeSlider && batchSizeContainer && batchSizeIndex !== -1) {
            batchSizeSlider.style.transform = `translateX(${
              batchSizeIndex * 100
            }%)`;
            batchSizeContainer.querySelectorAll("div").forEach((opt, i) => {
              opt.style.color = i === batchSizeIndex ? "white" : "#64748b";
              const optIcon = opt.querySelector("svg");
              if (optIcon) {
                const optPaths = optIcon.querySelectorAll("path");
                optPaths.forEach((path) => {
                  path.setAttribute(
                    "fill",
                    i === batchSizeIndex ? "white" : "#64748b"
                  );
                });
              }
            });
          }

          const cacheDurationIndex = cacheDurations.indexOf(
            defaultSettings.cacheDuration
          );
          const cacheDurationSlider =
            cacheDurationToggle.querySelector("div:first-child");
          const cacheDurationContainer =
            cacheDurationToggle.querySelector("div:last-child");

          if (
            cacheDurationSlider &&
            cacheDurationContainer &&
            cacheDurationIndex !== -1
          ) {
            cacheDurationSlider.style.transform = `translateX(${
              cacheDurationIndex * 100
            }%)`;
            cacheDurationContainer.querySelectorAll("div").forEach((opt, i) => {
              opt.style.color = i === cacheDurationIndex ? "white" : "#64748b";
              const optIcon = opt.querySelector("svg");
              if (optIcon) {
                const optPaths = optIcon.querySelectorAll("path");
                optPaths.forEach((path) => {
                  path.setAttribute(
                    "fill",
                    i === cacheDurationIndex ? "white" : "#64748b"
                  );
                });
              }
            });
          }
          const apiServerOptions = ["default", "backup"];
          const apiServerIndex = apiServerOptions.indexOf(
            defaultSettings.apiServer
          );
          const apiServerSlider =
            apiServerToggle.querySelector("div:first-child");
          const apiServerContainer =
            apiServerToggle.querySelector("div:last-child");

          if (apiServerSlider && apiServerContainer && apiServerIndex !== -1) {
            apiServerSlider.style.transform = `translateX(${
              apiServerIndex * 100
            }%)`;
            apiServerContainer.querySelectorAll("div").forEach((opt, i) => {
              opt.style.color = i === apiServerIndex ? "white" : "#64748b";
              const optIcon = opt.querySelector("svg");
              if (optIcon) {
                const optPaths = optIcon.querySelectorAll("path");
                optPaths.forEach((path) => {
                  path.setAttribute(
                    "fill",
                    i === apiServerIndex ? "white" : "#64748b"
                  );
                });
              }
            });
          }

          darkThemeToggle.style.backgroundColor = defaultSettings.darkTheme
            ? "#22c55e"
            : "#cbd5e1";
          darkThemeToggleHandle.style.left = defaultSettings.darkTheme
            ? "28px"
            : "2px";
          settings.darkTheme = defaultSettings.darkTheme;
          updateTheme();

          const newMediaTypeLabel = getMediaTypeLabel(
            defaultSettings.mediaType
          ).toLowerCase();
          const newFetchButtonText =
            defaultSettings.mediaType === "all"
              ? "Fetch Media"
              : `Fetch ${
                  newMediaTypeLabel === "gif"
                    ? "GIF"
                    : newMediaTypeLabel.charAt(0).toUpperCase() +
                      newMediaTypeLabel.slice(1)
                }`;
          fetchButton.innerHTML = "";
          const newFetchIcon = fetchIcon.cloneNode(true);
          fetchButton.appendChild(newFetchIcon);
          fetchButton.appendChild(document.createTextNode(newFetchButtonText));
          title.innerHTML = `Download ${getMediaTypeLabel(
            defaultSettings.mediaType
          )}: <span style="color: #0ea5e9">${username}</span>`;

          setTimeout(() => {
            createInfoDialog(
              "Settings have been successfully reset to default values.",
              "Reset Successful"
            );
          }, 100);
        }
      );
    });

    const patreonLink = document.createElement("a");
    patreonLink.href = "https://www.patreon.com/exyezed";
    patreonLink.target = "_blank";
    patreonLink.style.cssText = `
        display: flex;
        align-items: center;
        justify-content: center;
        color: #64748b;
        text-decoration: none;
        margin-top: 16px;
        padding: 8px;
        border-radius: 8px;
        transition: background-color 0.2s, color 0.2s;
    `;
    patreonLink.innerHTML =
      createPatreonIcon().outerHTML + "Patreon Authentication";
    patreonLink.addEventListener("mouseenter", () => {
      patreonLink.style.backgroundColor = settings.darkTheme
        ? "#374151"
        : "#f1f5f9";
      patreonLink.style.color = "#0ea5e9";
    });
    patreonLink.addEventListener("mouseleave", () => {
      patreonLink.style.backgroundColor = "transparent";
      patreonLink.style.color = "#64748b";
    });

    const batchSizeStartingContainer = document.createElement("div");
    batchSizeStartingContainer.style.cssText = `
        display: flex;
        flex-direction: column;
        gap: 0px;
    `;
    batchSizeStartingContainer.appendChild(batchSizeGroup);
    batchSizeStartingContainer.appendChild(startingBatchGroup);

    const mediaTimelineContainer = document.createElement("div");
    mediaTimelineContainer.style.cssText = `
        display: flex;
        flex-direction: column;
        gap: 0px;
    `;
    mediaTimelineContainer.appendChild(mediaTypeGroup);
    mediaTimelineContainer.appendChild(timelineTypeGroup);

    fetchTabContent.appendChild(batchGroup);
    fetchTabContent.appendChild(autoBatchGroup);
    fetchTabContent.appendChild(batchSizeStartingContainer);
    fetchTabContent.appendChild(mediaTimelineContainer);

    authTabContent.appendChild(patreonAuthGroup);
    authTabContent.appendChild(tokenGroup);
    authTabContent.appendChild(patreonLink);

    advancedTabContent.appendChild(darkThemeGroup);

    apiServerGroup.style.marginTop = "16px";
    advancedTabContent.appendChild(apiServerGroup);

    cacheDurationGroup.style.marginTop = "0px";
    advancedTabContent.appendChild(cacheDurationGroup);

    buttonsContainer.style.marginTop = "16px";
    advancedTabContent.appendChild(buttonsContainer);

    function switchTab(activeTab, activeContent) {
      const allTabs = [fetchTab, authTab, advancedTab];
      const allContents = [fetchTabContent, authTabContent, advancedTabContent];

      allTabs.forEach((tab) => {
        if (tab && tab.style) {
          tab.style.color = "#64748b";
          tab.style.borderBottom = "none";
        }
      });

      allContents.forEach((content) => {
        if (content && content.style) {
          content.style.display = "none";
        }
      });

      if (activeTab && activeTab.style) {
        activeTab.style.color = settings.darkTheme ? "#f1f5f9" : "#0f172a";
        activeTab.style.borderBottom = "2px solid #0ea5e9";
      }
      if (activeContent && activeContent.style) {
        activeContent.style.display = "flex";
      }
    }
    fetchTab.addEventListener("click", function () {
      switchTab(fetchTab, fetchTabContent);
    });
    authTab.addEventListener("click", function () {
      switchTab(authTab, authTabContent);
    });
    advancedTab.addEventListener("click", function () {
      switchTab(advancedTab, advancedTabContent);
    });

    const settingsForm = document.createElement("div");
    settingsForm.style.cssText = `
        display: flex;
        flex-direction: column;
    `;

    settingsForm.appendChild(settingsTabs);
    settingsForm.appendChild(fetchTabContent);
    settingsForm.appendChild(authTabContent);
    settingsForm.appendChild(advancedTabContent);

    settingsContent.appendChild(settingsForm);

    mainTab.addEventListener("click", function () {
      mainTab.style.borderBottom = "2px solid #0ea5e9";
      mainTab.style.color = settings.darkTheme ? "#f1f5f9" : "#0f172a";
      settingsTab.style.borderBottom = "none";
      settingsTab.style.color = "#64748b";
      mainContent.style.display = "block";
      settingsContent.style.display = "none";
    });

    settingsTab.addEventListener("click", function () {
      settingsTab.style.borderBottom = "2px solid #0ea5e9";
      settingsTab.style.color = settings.darkTheme ? "#f1f5f9" : "#0f172a";
      mainTab.style.borderBottom = "none";
      mainTab.style.color = "#64748b";
      settingsContent.style.display = "block";
      mainContent.style.display = "none";

      switchTab(fetchTab, fetchTabContent);
    });

    modalContent.appendChild(header);
    modalContent.appendChild(tabs);
    modalContent.appendChild(mainContent);
    modalContent.appendChild(settingsContent);
    modal.appendChild(modalContent);

    const mediaData = {
      username: username,
      currentPage: getSettings().startingBatch,
      mediaItems: [],
      allMediaItems: [],
      batchData: {},
      hasMore: false,
      downloading: false,
      totalDownloaded: 0,
      totalToDownload: 0,
      totalItems: 0,
      nextBatchClicked: false,
    };

    function refreshInfoDisplays() {
      const isDark = getSettings().darkTheme;

      if (infoContainer.innerHTML && mediaData.totalItems > 0) {
        const settings = getSettings();
        const mediaTypeLabel = getMediaTypeLabel(settings.mediaType);

        if (
          settings.batchEnabled &&
          mediaData.mediaItems &&
          mediaData.mediaItems.length > 0
        ) {
          const accountIconHtml = createAccountIcon(isDark).outerHTML;
          const mediaIconHtml = createMediaTypeIcon(
            settings.mediaType,
            isDark
          ).outerHTML;
          const totalItemsIconHtml = createTotalItemsIcon(isDark).outerHTML;

          infoContainer.innerHTML = `
            <div style="margin-bottom: 8px; display: flex; align-items: center;">${accountIconHtml}<strong style="margin-right: 6px;">Account:</strong><span>${
            mediaData.username
          }</span></div>
            <div style="margin-bottom: 8px; display: flex; align-items: center;">${mediaIconHtml}<strong style="margin-right: 6px;">${mediaTypeLabel} Found:</strong><span>${formatNumber(
            mediaData.totalItems
          )}</span></div>
            <div style="margin-bottom: 8px; display: flex; align-items: center;">${totalItemsIconHtml}<strong style="margin-right: 6px;">Total Items:</strong><span>${formatNumber(
            mediaData.allMediaItems.length
          )}</span></div>
          `;
        } else if (
          mediaData.allMediaItems &&
          mediaData.allMediaItems.length > 0
        ) {
          const accountIconHtml = createAccountIcon(isDark).outerHTML;
          const mediaIconHtml = createMediaTypeIcon(
            settings.mediaType,
            isDark
          ).outerHTML;
          const totalZipIconHtml = createTotalZipIcon(isDark).outerHTML;
          const currentPart =
            Math.floor(mediaData.allMediaItems.length / 500) + 1;

          infoContainer.innerHTML = `
            <div style="margin-bottom: 8px; display: flex; align-items: center;">${accountIconHtml}<strong style="margin-right: 6px;">Account:</strong><span>${
            mediaData.username
          }</span></div>
            <div style="margin-bottom: 8px; display: flex; align-items: center;">${mediaIconHtml}<strong style="margin-right: 6px;">${mediaTypeLabel} Found:</strong><span>${formatNumber(
            mediaData.totalItems
          )}</span></div>
            <div style="margin-top: 8px; display: flex; align-items: center;">${totalZipIconHtml}<strong style="margin-right: 6px;">Total ZIP ${
            currentPart === 1 ? "File" : "Files"
          }:</strong><span>${currentPart}</span></div>
          `;
        }
      }

      if (infoContainer.innerHTML) {
        const accountIcons = infoContainer.querySelectorAll(
          'svg[viewBox="0 0 24 24"]'
        );
        accountIcons.forEach((icon) => {
          icon.style.color = isDark ? "#ffffff" : "#64748b";
        });

        const mediaIcons = infoContainer.querySelectorAll(
          'svg[viewBox="0 0 576 512"], svg[viewBox="0 0 512 512"], svg[viewBox="0 0 640 512"]'
        );
        mediaIcons.forEach((icon) => {
          icon.style.color = isDark ? "#ffffff" : "#64748b";
        });

        const totalIcons = infoContainer.querySelectorAll(
          'svg[viewBox="0 0 448 512"]'
        );
        totalIcons.forEach((icon) => {
          icon.style.color = isDark ? "#ffffff" : "#64748b";
        });
      }
    }

    function updateBatchLabels() {
      const isDark = getSettings().darkTheme;
      const settings = getSettings();

      if (currentBatchLabel && currentBatchLabel.innerHTML) {
        const currentBatchIconHtml = createCurrentBatchIcon(isDark).outerHTML;
        currentBatchLabel.innerHTML = `<div style="display: flex; align-items: center;">${currentBatchIconHtml}<strong style="margin-right: 6px; color: ${
          settings.darkTheme ? "#ffffff" : "#475569"
        };">Current Batch:</strong><span style="color: ${
          settings.darkTheme ? "#ffffff" : "#475569"
        };">${mediaData.currentPage + 1}</span></div>`;
      }

      if (
        totalBatchLabel &&
        totalBatchLabel.innerHTML &&
        mediaData.totalItems > 0
      ) {
        const totalBatches = Math.ceil(
          mediaData.totalItems / settings.batchSize
        );
        const totalZipIconHtml = createTotalZipIcon(isDark).outerHTML;
        totalBatchLabel.innerHTML = `<div style="display: flex; align-items: center;">${totalZipIconHtml}<strong style="margin-right: 6px; color: ${
          settings.darkTheme ? "#ffffff" : "#475569"
        };">Total ZIP ${
          totalBatches === 1 ? "File" : "Files"
        }:</strong><span style="color: ${
          settings.darkTheme ? "#ffffff" : "#475569"
        };">${totalBatches}</span></div>`;
      }

      if (currentBatchLabel && currentBatchLabel.innerHTML) {
        const batchIcons = currentBatchLabel.querySelectorAll("svg");
        batchIcons.forEach((icon) => {
          icon.style.color = isDark ? "#ffffff" : "#64748b";
        });
      }

      if (totalBatchLabel && totalBatchLabel.innerHTML) {
        const zipIcons = totalBatchLabel.querySelectorAll("svg");
        zipIcons.forEach((icon) => {
          icon.style.color = isDark ? "#ffffff" : "#64748b";
        });
      }
    }

    function updateTheme() {
      const isDark = getSettings().darkTheme;
      modalContent.style.backgroundColor = isDark ? "#1f2937" : "#ffffff";
      modalContent.style.color = isDark ? "#f1f5f9" : "#334155";
      header.style.borderBottom = `1px solid ${isDark ? "#374151" : "#e2e8f0"}`;
      title.style.color = isDark ? "#f1f5f9" : "#334155";
      closeButton.style.color = isDark ? "#f1f5f9" : "#0f172a";
      tabs.style.borderBottom = `1px solid ${isDark ? "#374151" : "#e2e8f0"}`;
      mainTab.style.color =
        mainContent.style.display === "block"
          ? isDark
            ? "#f1f5f9"
            : "#0f172a"
          : "#64748b";
      settingsTab.style.color =
        settingsContent.style.display === "block"
          ? isDark
            ? "#f1f5f9"
            : "#0f172a"
          : "#64748b";
      infoContainer.style.backgroundColor = isDark ? "#374151" : "#f1f5f9";
      batchInfoContainer.style.backgroundColor = isDark ? "#374151" : "#f8fafc";
      batchInfoContainer.style.border = `1px solid ${
        isDark ? "#4b5563" : "#e2e8f0"
      }`;
      settingsTabs.style.borderBottom = `1px solid ${
        isDark ? "#374151" : "#e2e8f0"
      }`;

      const allSettingTabs = [fetchTab, authTab, advancedTab];
      allSettingTabs.forEach((tab) => {
        if (tab.style.borderBottom.includes("solid")) {
          tab.style.color = isDark ? "#f1f5f9" : "#0f172a";
        }
      });
      patreonAuthLabel.style.color = isDark ? "#f1f5f9" : "#334155";
      patreonAuthInput.style.backgroundColor = isDark ? "#374151" : "#f1f5f9";
      autoBatchLabel.style.color = isDark ? "#f1f5f9" : "#334155";
      patreonAuthInput.style.color = isDark ? "#cbd5e1" : "#64748b";
      tokenLabel.style.color = isDark ? "#f1f5f9" : "#334155";
      tokenInput.style.backgroundColor = isDark ? "#374151" : "#f1f5f9";
      tokenInput.style.color = isDark ? "#cbd5e1" : "#64748b";
      apiServerLabel.style.color = isDark ? "#f1f5f9" : "#334155";
      batchLabel.style.color = isDark ? "#f1f5f9" : "#334155";
      batchSizeLabel.style.color = isDark ? "#f1f5f9" : "#334155";
      startingBatchLabel.style.color = isDark ? "#f1f5f9" : "#334155";
      startingBatchInput.style.backgroundColor = isDark ? "#374151" : "#f1f5f9";
      startingBatchInput.style.color = isDark ? "#cbd5e1" : "#64748b";
      timelineTypeLabel.style.color = isDark ? "#f1f5f9" : "#334155";
      mediaTypeLabel.style.color = isDark ? "#f1f5f9" : "#334155";
      concurrentLabel.style.color = isDark ? "#f1f5f9" : "#334155";
      cacheDurationLabel.style.color = isDark ? "#f1f5f9" : "#334155";
      darkThemeLabel.style.color = isDark ? "#f1f5f9" : "#334155";
      const toggleSwitches = [
        timelineTypeToggle,
        mediaTypeToggle,
        batchSizeToggle,
        concurrentToggle,
        cacheDurationToggle,
        apiServerToggle,
      ];
      toggleSwitches.forEach((toggle) => {
        if (toggle) {
          toggle.style.backgroundColor = isDark ? "#374151" : "#f1f5f9";
        }
      });

      if (progressBar) {
        progressBar.style.backgroundColor = isDark ? "#374151" : "#f1f5f9";
      }

      if (currentBatchLabel) {
        currentBatchLabel.style.color = isDark ? "#ffffff" : "#475569";
      }
      if (totalBatchLabel) {
        totalBatchLabel.style.color = isDark ? "#ffffff" : "#475569";
      }

      refreshInfoDisplays();

      updateBatchLabels();
    }

    fetchButton.addEventListener("click", async () => {
      const settings = getSettings();
      if (!settings.authToken) {
        createAuthTokenPopup();
        return;
      }
      if (!settings.patreonAuth) {
        createPatreonAuthPopup();
        return;
      }
      if (settings.autoBatchEnabled && !autoBatchStarted) {
        autoBatchCancelled = false;
        autoBatchStarted = true;
        const batchNums = Object.keys(mediaData.batchData).map(Number);
        mediaData.currentPage =
          batchNums.length > 0 ? Math.max(...batchNums) + 1 : 0;
      }
      if (
        !settings.autoBatchEnabled ||
        (settings.autoBatchEnabled &&
          !autoBatchStarted &&
          Object.keys(mediaData.batchData).length === 0)
      ) {
        infoContainer.style.display = "none";
        buttonContainer.style.display = "none";
        nextBatchButton.style.display = "none";
        prevBatchButton.style.display = "none";
        progressContainer.style.display = "none";
        if (settings.autoBatchEnabled) {
          autoBatchStarted = true;
          mediaData.currentPage = 0;
        }
      }
      fetchButton.disabled = true;
      fetchButton.innerHTML = "";
      fetchButton.appendChild(document.createTextNode("Fetching..."));

      try {
        const cacheKey = `${settings.timelineType}_${settings.mediaType}_${username}_${mediaData.currentPage}_${settings.batchSize}_batch_${settings.batchEnabled}`;
        let data = cacheManager.get(cacheKey);

        if (!data) {
          let url;
          if (settings.batchEnabled) {
            url = `${getServiceBaseUrl()}/metadata/${settings.timelineType}/${
              settings.batchSize
            }/${mediaData.currentPage}/${settings.mediaType}/${username}/${
              settings.authToken
            }/${settings.patreonAuth || ""}`;
          } else {
            url = `${getServiceBaseUrl()}/metadata/${settings.timelineType}/${
              settings.mediaType
            }/${username}/${settings.authToken}/${settings.patreonAuth || ""}`;
          }

          data = await fetchData(url);
          if (data && data.timeline && data.timeline.length > 0) {
            cacheManager.set(cacheKey, data, true);
          }
        }
        if (data.timeline && data.timeline.length > 0) {
          mediaData.mediaItems = data.timeline;
          mediaData.hasMore = data.metadata.has_more;
          mediaData.totalItems = data.total_urls;

          mediaData.batchData[mediaData.currentPage] = [...data.timeline];

          const currentBatchKeys = Object.keys(mediaData.batchData).map(Number);
          for (const batchNum of currentBatchKeys) {
            if (batchNum > mediaData.currentPage) {
              delete mediaData.batchData[batchNum];
            }
          }
          mediaData.allMediaItems = [];
          const maxBatch = Math.max(
            ...Object.keys(mediaData.batchData).map(Number)
          );
          for (let i = 0; i <= maxBatch; i++) {
            if (mediaData.batchData[i]) {
              mediaData.allMediaItems = [
                ...mediaData.allMediaItems,
                ...mediaData.batchData[i],
              ];
            }
          }

          const mediaTypeLabel = getMediaTypeLabel(settings.mediaType);

          if (settings.batchEnabled) {
            const accountIconHtml = createAccountIcon(
              settings.darkTheme
            ).outerHTML;
            const mediaIconHtml = createMediaTypeIcon(
              settings.mediaType,
              settings.darkTheme
            ).outerHTML;
            const totalItemsIconHtml = createTotalItemsIcon(
              settings.darkTheme
            ).outerHTML;
            infoContainer.innerHTML = `
              <div style="margin-bottom: 8px; display: flex; align-items: center;">${accountIconHtml}<strong style="margin-right: 6px;">Account:</strong><span>${
              data.account_info.name
            }</span></div>
              <div style="margin-bottom: 8px; display: flex; align-items: center;">${mediaIconHtml}<strong style="margin-right: 6px;">${mediaTypeLabel} Found:</strong><span>${formatNumber(
              data.total_urls
            )}</span></div>
              <div style="margin-bottom: 8px; display: flex; align-items: center;">${totalItemsIconHtml}<strong style="margin-right: 6px;">Total Items:</strong><span>${formatNumber(
              mediaData.allMediaItems.length
            )}</span></div>
            `;
            const currentBatchIconHtml = createCurrentBatchIcon(
              settings.darkTheme
            ).outerHTML;
            currentBatchLabel.innerHTML = `<div style="display: flex; align-items: center;">${currentBatchIconHtml}<strong style="margin-right: 6px; color: ${
              settings.darkTheme ? "#ffffff" : "#475569"
            };">Current Batch:</strong><span style="color: ${
              settings.darkTheme ? "#ffffff" : "#475569"
            };">${mediaData.currentPage + 1}</span></div>`;

            const totalBatches = Math.ceil(
              data.total_urls / settings.batchSize
            );
            const totalZipIconHtml = createTotalZipIcon(
              settings.darkTheme
            ).outerHTML;
            totalBatchLabel.innerHTML = `<div style="display: flex; align-items: center;">${totalZipIconHtml}<strong style="margin-right: 6px; color: ${
              settings.darkTheme ? "#ffffff" : "#475569"
            };">Total ZIP ${
              totalBatches === 1 ? "File" : "Files"
            }:</strong><span style="color: ${
              settings.darkTheme ? "#ffffff" : "#475569"
            };">${totalBatches}</span></div>`;
            batchInfoContainer.style.display = "flex";
            batchNavContainer.style.display = "flex";
          } else {
            const currentPart =
              Math.floor(mediaData.allMediaItems.length / 500) + 1;
            const accountIconHtml = createAccountIcon(
              settings.darkTheme
            ).outerHTML;
            const mediaIconHtml = createMediaTypeIcon(
              settings.mediaType,
              settings.darkTheme
            ).outerHTML;
            const totalZipIconHtml = createTotalZipIcon(
              settings.darkTheme
            ).outerHTML;
            infoContainer.innerHTML = `
              <div style="margin-bottom: 8px; display: flex; align-items: center;">${accountIconHtml}<strong style="margin-right: 6px;">Account:</strong><span>${
              data.account_info.name
            }</span></div>
              <div style="margin-bottom: 8px; display: flex; align-items: center;">${mediaIconHtml}<strong style="margin-right: 6px;">${mediaTypeLabel} Found:</strong><span>${formatNumber(
              data.total_urls
            )}</span></div>
              <div style="margin-top: 8px; display: flex; align-items: center;">${totalZipIconHtml}<strong style="margin-right: 6px;">Total ZIP ${
              currentPart === 1 ? "File" : "Files"
            }:</strong><span>${currentPart}</span></div>
            `;

            batchInfoContainer.style.display = "none";
            batchNavContainer.style.display = "none";
          }

          infoContainer.style.display = "block";

          if (settings.batchEnabled) {
            buttonContainer.style.display = "none";
          } else {
            buttonContainer.innerHTML = "";
            buttonContainer.appendChild(downloadButton);
            buttonContainer.style.display = "block";
          }
          if (settings.batchEnabled && mediaData.hasMore) {
            nextBatchButton.style.display = "block";
          }
          if (
            settings.batchEnabled &&
            mediaData.currentPage > getSettings().startingBatch
          ) {
            prevBatchButton.style.display = "block";
          }

          reassignDownloadHandlers();

          fetchButton.disabled = false;
          const currentMediaTypeLabel = getMediaTypeLabel(
            settings.mediaType
          ).toLowerCase();

          const updatedFetchButtonText = settings.autoBatchEnabled
            ? "Auto Fetch"
            : settings.mediaType === "all"
            ? "Fetch Media"
            : `Fetch ${
                currentMediaTypeLabel === "gif"
                  ? "GIF"
                  : currentMediaTypeLabel.charAt(0).toUpperCase() +
                    currentMediaTypeLabel.slice(1)
              }`;

          fetchButton.innerHTML = "";
          let updatedFetchIcon1 = fetchIcon.cloneNode(true);
          fetchButton.appendChild(updatedFetchIcon1);
          fetchButton.appendChild(
            document.createTextNode(updatedFetchButtonText)
          );

          console.log("Fetch success - Next Batch Debug:", {
            hasMore: mediaData.hasMore,
            nextBatchClicked: mediaData.nextBatchClicked,
            shouldShowPopup: !mediaData.hasMore && mediaData.nextBatchClicked,
            autoBatchEnabled: settings.autoBatchEnabled,
          });

          if (
            !mediaData.hasMore &&
            mediaData.nextBatchClicked &&
            !settings.autoBatchEnabled
          ) {
            console.log(
              "Showing next batch completion popup after successful fetch"
            );
            createInfoDialog(
              "Next batch has completed! All available batches have been fetched."
            );
          }

          if (mediaData.nextBatchClicked) {
            console.log(
              "Resetting nextBatchClicked flag after successful fetch"
            );
            mediaData.nextBatchClicked = false;
          }

          if (settings.autoBatchEnabled && !autoBatchCancelled) {
            prevBatchButton.style.display = "none";
            nextBatchButton.style.display = "none";
            stopFetchButton.style.display = "block";
            if (mediaData.hasMore) {
              setTimeout(() => {
                if (settings.autoBatchEnabled && !autoBatchCancelled) {
                  mediaData.currentPage++;
                  fetchButton.click();
                }
              }, 1000);
            } else {
              stopFetchButton.style.display = "none";
              prevBatchButton.style.display =
                mediaData.currentPage > 0 ? "block" : "none";
              nextBatchButton.style.display = "none";
              autoBatchStarted = false;

              createInfoDialog(
                "Auto fetch has completed! All available batches have been fetched."
              );
            }
          }
        } else {
          console.log("No media found branch:", {
            nextBatchClicked: mediaData.nextBatchClicked,
          });

          if (mediaData.nextBatchClicked) {
            console.log(
              "Showing next batch completion popup from no media found branch"
            );
            createInfoDialog(
              "Next batch has completed! All available batches have been fetched."
            );
            mediaData.nextBatchClicked = false;
          }

          infoContainer.innerHTML =
            '<div style="color: #ef4444;">No media found, invalid token, or invalid Patreon authentication.</div>';
          infoContainer.style.display = "block";
          fetchButton.disabled = false;
          const currentMediaTypeLabel = getMediaTypeLabel(
            settings.mediaType
          ).toLowerCase();
          const updatedFetchButtonText =
            settings.mediaType === "all"
              ? "Fetch Media"
              : `Fetch ${
                  currentMediaTypeLabel === "gif"
                    ? "GIF"
                    : currentMediaTypeLabel.charAt(0).toUpperCase() +
                      currentMediaTypeLabel.slice(1)
                }`;

          fetchButton.innerHTML = "";
          let updatedFetchIcon2 = fetchIcon.cloneNode(true);
          fetchButton.appendChild(updatedFetchIcon2);
          fetchButton.appendChild(
            document.createTextNode(updatedFetchButtonText)
          );
        }
      } catch (error) {
        infoContainer.innerHTML = `<div style="color: #ef4444;">Error: ${error.message}</div>`;
        infoContainer.style.display = "block";
        fetchButton.disabled = false;

        if (mediaData.currentPage > getSettings().startingBatch) {
          prevBatchButton.style.display = "block";
        }

        const currentMediaTypeLabel = getMediaTypeLabel(
          settings.mediaType
        ).toLowerCase();

        const updatedFetchButtonText =
          settings.mediaType === "all"
            ? "Fetch Media"
            : `Fetch ${
                currentMediaTypeLabel === "gif"
                  ? "GIF"
                  : currentMediaTypeLabel.charAt(0).toUpperCase() +
                    currentMediaTypeLabel.slice(1)
              }`;

        fetchButton.innerHTML = "";
        let updatedFetchIcon3 = fetchIcon.cloneNode(true);
        fetchButton.appendChild(updatedFetchIcon3);
        fetchButton.appendChild(
          document.createTextNode(updatedFetchButtonText)
        );
      }
    });

    nextBatchButton.addEventListener("click", () => {
      console.log("Next Batch Button clicked, setting flag to true");
      mediaData.nextBatchClicked = true;
      mediaData.currentPage++;

      autoBatchCancelled = true;
      autoBatchStarted = false;

      const settings = getSettings();
      const cacheKey = `${settings.timelineType}_${settings.mediaType}_${username}_${mediaData.currentPage}_${settings.batchSize}_batch_${settings.batchEnabled}`;
      const cachedData = cacheManager.get(cacheKey);

      if (cachedData && cachedData.timeline && cachedData.timeline.length > 0) {
        mediaData.mediaItems = cachedData.timeline;
        mediaData.hasMore = cachedData.metadata.has_more;
        mediaData.totalItems = cachedData.total_urls;

        mediaData.batchData[mediaData.currentPage] = [...cachedData.timeline];

        mediaData.allMediaItems = [];
        const maxBatch = Math.max(
          ...Object.keys(mediaData.batchData).map(Number)
        );
        for (let i = 0; i <= maxBatch; i++) {
          if (mediaData.batchData[i]) {
            mediaData.allMediaItems = [
              ...mediaData.allMediaItems,
              ...mediaData.batchData[i],
            ];
          }
        }

        refreshInfoDisplays();

        if (settings.batchEnabled) {
          prevBatchButton.style.display =
            mediaData.currentPage > 0 ? "block" : "none";
          nextBatchButton.style.display = mediaData.hasMore ? "block" : "none";
          infoContainer.style.display = "block";
          buttonContainer.style.display = "none";
          batchInfoContainer.style.display = "flex";
          batchNavContainer.style.display = "flex";
        }

        const currentBatchIconHtml = createCurrentBatchIcon(
          settings.darkTheme
        ).outerHTML;
        currentBatchLabel.innerHTML = `<div style="display: flex; align-items: center;">${currentBatchIconHtml}<strong style="margin-right: 6px; color: ${
          settings.darkTheme ? "#ffffff" : "#475569"
        };">Current Batch:</strong><span style="color: ${
          settings.darkTheme ? "#ffffff" : "#475569"
        };">${mediaData.currentPage + 1}</span></div>`;
        const totalBatches = Math.ceil(
          cachedData.total_urls / settings.batchSize
        );
        const totalZipIconHtml = createTotalZipIcon(
          settings.darkTheme
        ).outerHTML;
        totalBatchLabel.innerHTML = `<div style="display: flex; align-items: center;">${totalZipIconHtml}<strong style="margin-right: 6px; color: ${
          settings.darkTheme ? "#ffffff" : "#475569"
        };">Total ZIP ${
          totalBatches === 1 ? "File" : "Files"
        }:</strong><span style="color: ${
          settings.darkTheme ? "#ffffff" : "#475569"
        };">${totalBatches}</span></div>`;
        console.log("Next Batch Debug:", {
          hasMore: mediaData.hasMore,
          nextBatchClicked: mediaData.nextBatchClicked,
          shouldShowPopup: !mediaData.hasMore && mediaData.nextBatchClicked,
        });

        if (!mediaData.hasMore && mediaData.nextBatchClicked) {
          console.log("Showing next batch completion popup");
          createInfoDialog(
            "Next batch has completed! All available batches have been fetched."
          );
        }
        console.log("Resetting nextBatchClicked flag to false");
        mediaData.nextBatchClicked = false;

        reassignDownloadHandlers();
      } else {
        const wasAutoBatchEnabled = getSettings().autoBatchEnabled;

        if (wasAutoBatchEnabled) {
          const newSettings = getSettings();
          newSettings.autoBatchEnabled = false;
          saveSettings(newSettings);
        }

        fetchButton.click();

        if (wasAutoBatchEnabled) {
          setTimeout(() => {
            const newSettings = getSettings();
            newSettings.autoBatchEnabled = true;
            saveSettings(newSettings);

            autoBatchCancelled = true;
            autoBatchStarted = false;
          }, 100);
        }
      }
    });

    prevBatchButton.addEventListener("click", () => {
      if (mediaData.currentPage > 0) {
        mediaData.currentPage--;

        autoBatchCancelled = true;
        autoBatchStarted = false;

        const settings = getSettings();
        const cacheKey = `${settings.timelineType}_${settings.mediaType}_${username}_${mediaData.currentPage}_${settings.batchSize}_batch_${settings.batchEnabled}`;
        let data = cacheManager.get(cacheKey);

        if (data && data.timeline && data.timeline.length > 0) {
          mediaData.mediaItems = data.timeline;
          mediaData.hasMore = data.metadata.has_more;
          mediaData.totalItems = data.total_urls;

          mediaData.batchData[mediaData.currentPage] = [...data.timeline];

          const currentBatchKeys = Object.keys(mediaData.batchData).map(Number);
          for (const batchNum of currentBatchKeys) {
            if (batchNum > mediaData.currentPage) {
              delete mediaData.batchData[batchNum];
            }
          }
          mediaData.allMediaItems = [];
          const maxBatch = Math.max(
            ...Object.keys(mediaData.batchData).map(Number)
          );
          for (let i = 0; i <= maxBatch; i++) {
            if (mediaData.batchData[i]) {
              mediaData.allMediaItems = [
                ...mediaData.allMediaItems,
                ...mediaData.batchData[i],
              ];
            }
          }

          const mediaTypeLabel = getMediaTypeLabel(settings.mediaType);

          if (settings.batchEnabled) {
            const accountIconHtml = createAccountIcon(
              settings.darkTheme
            ).outerHTML;
            const mediaIconHtml = createMediaTypeIcon(
              settings.mediaType,
              settings.darkTheme
            ).outerHTML;
            const totalItemsIconHtml = createTotalItemsIcon(
              settings.darkTheme
            ).outerHTML;
            infoContainer.innerHTML = `
              <div style="margin-bottom: 8px; display: flex; align-items: center;">${accountIconHtml}<strong style="margin-right: 6px;">Account:</strong><span>${
              data.account_info.name
            }</span></div>
              <div style="margin-bottom: 8px; display: flex; align-items: center;">${mediaIconHtml}<strong style="margin-right: 6px;">${mediaTypeLabel} Found:</strong><span>${formatNumber(
              data.total_urls
            )}</span></div>
              <div style="margin-bottom: 8px; display: flex; align-items: center;">${totalItemsIconHtml}<strong style="margin-right: 6px;">Total Items:</strong><span>${formatNumber(
              mediaData.allMediaItems.length
            )}</span></div>
            `;

            const currentBatchIconHtml = createCurrentBatchIcon(
              settings.darkTheme
            ).outerHTML;
            currentBatchLabel.innerHTML = `<div style="display: flex; align-items: center;">${currentBatchIconHtml}<strong style="margin-right: 6px; color: ${
              settings.darkTheme ? "#ffffff" : "#475569"
            };">Current Batch:</strong><span style="color: ${
              settings.darkTheme ? "#ffffff" : "#475569"
            };">${mediaData.currentPage + 1}</span></div>`;

            const totalBatches = Math.ceil(
              data.total_urls / settings.batchSize
            );
            const totalZipIconHtml = createTotalZipIcon(
              settings.darkTheme
            ).outerHTML;
            totalBatchLabel.innerHTML = `<div style="display: flex; align-items: center;">${totalZipIconHtml}<strong style="margin-right: 6px; color: ${
              settings.darkTheme ? "#ffffff" : "#475569"
            };">Total ZIP ${
              totalBatches === 1 ? "File" : "Files"
            }:</strong><span style="color: ${
              settings.darkTheme ? "#ffffff" : "#475569"
            };">${totalBatches}</span></div>`;
            batchInfoContainer.style.display = "flex";
            batchNavContainer.style.display = "flex";
          }

          infoContainer.style.display = "block";

          if (settings.batchEnabled) {
            buttonContainer.style.display = "none";
          } else {
            buttonContainer.innerHTML = "";
            buttonContainer.appendChild(downloadButton);
            buttonContainer.style.display = "block";
          }
          if (settings.batchEnabled && mediaData.hasMore) {
            nextBatchButton.style.display = "block";
          }
          if (settings.batchEnabled && mediaData.currentPage > 0) {
            prevBatchButton.style.display = "block";
          }
          reassignDownloadHandlers();
        } else {
          fetchButton.click();
        }
      }
    });

    function chunkMediaItems(items) {
      const chunks = [];
      for (let i = 0; i < items.length; i += 500) {
        chunks.push(items.slice(i, i + 500));
      }
      return chunks;
    }

    function reassignDownloadHandlers() {
      const settings = getSettings();
      if (settings.batchEnabled) {
        downloadCurrentButton.onclick = () => downloadMedia(false);
        downloadAllButton.onclick = () => downloadMedia(true);
      }
    }

    async function downloadMedia(downloadAll) {
      if (mediaData.downloading) return;

      mediaData.downloading = true;

      const settings = getSettings();
      const timestamp = getCurrentTimestamp();

      let itemsToDownload;
      if (downloadAll) {
        itemsToDownload = mediaData.allMediaItems;
      } else {
        itemsToDownload = mediaData.mediaItems;
      }

      mediaData.totalToDownload = itemsToDownload.length;
      mediaData.totalDownloaded = 0;

      progressText.textContent = `Downloading 0/${formatNumber(
        mediaData.totalToDownload
      )}`;
      progressFill.style.width = "0%";
      progressContainer.style.display = "block";

      fetchButton.disabled = true;
      if (settings.batchEnabled) {
        downloadCurrentButton.disabled = true;
        downloadAllButton.disabled = true;
      } else {
        downloadButton.disabled = true;
      }
      nextBatchButton.disabled = true;

      const chunks = chunkMediaItems(itemsToDownload);

      for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) {
        const chunk = chunks[chunkIndex];

        if (chunk.length === 1 && chunks.length === 1) {
          try {
            const item = chunk[0];
            const formattedDate = formatDate(item.date);
            const baseFilename = `${username}_${formattedDate}_${item.tweet_id}`;
            const fileExtension = item.type === "photo" ? "jpg" : "mp4";

            const filename = `${baseFilename}.${fileExtension}`;

            progressText.textContent = `Downloading 0/1`;

            const blob = await fetchBinary(item.url);

            const downloadLink = document.createElement("a");
            downloadLink.href = URL.createObjectURL(blob);
            downloadLink.download = filename;
            document.body.appendChild(downloadLink);
            downloadLink.click();
            document.body.removeChild(downloadLink);

            mediaData.totalDownloaded = 1;
            progressText.textContent = `Downloading 1/1`;
            progressFill.style.width = "100%";

            continue;
          } catch (error) {}
        }

        const zip = new JSZip();

        const hasImages = chunk.some((item) => item.type === "photo");
        const hasVideos = chunk.some((item) => item.type === "video");
        const hasGifs = chunk.some((item) => item.type === "gif");

        let imageFolder, videoFolder, gifFolder;
        if (settings.mediaType === "all") {
          if (hasImages) imageFolder = zip.folder("image");
          if (hasVideos) videoFolder = zip.folder("video");
          if (hasGifs) gifFolder = zip.folder("gif");
        }

        const filenameMap = {};

        const downloadInBatches = async (items, batchSize) => {
          for (let i = 0; i < items.length; i += batchSize) {
            const batch = items.slice(i, i + batchSize);

            const downloadPromises = batch.map(async (item) => {
              try {
                const formattedDate = formatDate(item.date);
                let baseFilename = `${username}_${formattedDate}_${item.tweet_id}`;

                if (filenameMap[baseFilename] !== undefined) {
                  filenameMap[baseFilename]++;
                  baseFilename = `${baseFilename}_${String(
                    filenameMap[baseFilename]
                  ).padStart(2, "0")}`;
                } else {
                  filenameMap[baseFilename] = 0;
                }

                const fileExtension = item.type === "photo" ? "jpg" : "mp4";
                const filename = `${baseFilename}.${fileExtension}`;

                const blob = await fetchBinary(item.url);

                if (settings.mediaType === "all") {
                  if (item.type === "photo") {
                    imageFolder.file(filename, blob);
                  } else if (item.type === "video") {
                    videoFolder.file(filename, blob);
                  } else if (item.type === "gif") {
                    gifFolder.file(filename, blob);
                  }
                } else {
                  zip.file(filename, blob);
                }

                mediaData.totalDownloaded++;
                const completedCount = mediaData.totalDownloaded;
                progressText.textContent = `Downloading ${formatNumber(
                  completedCount
                )}/${formatNumber(mediaData.totalToDownload)}`;
                progressFill.style.width = `${
                  (completedCount / mediaData.totalToDownload) * 100
                }%`;
              } catch (error) {
                console.error("Error downloading item:", error);
                mediaData.totalDownloaded++;
              }
            });

            await Promise.all(downloadPromises);
          }
        };

        await downloadInBatches(chunk, settings.concurrentDownloads);

        progressText.textContent = `Creating ZIP file ${chunkIndex + 1}/${
          chunks.length
        }...`;

        try {
          const zipBlob = await zip.generateAsync({ type: "blob" });

          let zipFilename;
          if (chunks.length === 1 && chunk.length < 500) {
            zipFilename = `${username}_${timestamp}.zip`;
          } else if (settings.batchEnabled && !downloadAll) {
            zipFilename = `${username}_${timestamp}_part_${String(
              mediaData.currentPage + 1
            ).padStart(2, "0")}.zip`;
          } else {
            zipFilename = `${username}_${timestamp}_part_${String(
              chunkIndex + 1
            ).padStart(2, "0")}.zip`;
          }

          const downloadLink = document.createElement("a");
          downloadLink.href = URL.createObjectURL(zipBlob);
          downloadLink.download = zipFilename;
          document.body.appendChild(downloadLink);
          downloadLink.click();
          document.body.removeChild(downloadLink);
        } catch (error) {
          progressText.textContent = `Error creating ZIP ${chunkIndex + 1}: ${
            error.message
          }`;
        }
      }
      mediaData.downloading = false;
      progressContainer.style.display = "none";
      fetchButton.disabled = false;
      if (settings.batchEnabled) {
        downloadCurrentButton.disabled = false;
        downloadAllButton.disabled = false;
        reassignDownloadHandlers();
      } else {
        downloadButton.disabled = false;
      }
      nextBatchButton.disabled = false;
      createInfoDialog(
        "All media downloaded successfully.",
        "Download Complete"
      );
      return;
    }

    document.body.appendChild(modal);
  }

  function extractUsername() {
    const pathParts = window.location.pathname
      .split("/")
      .filter((part) => part);
    if (pathParts.length > 0) {
      return pathParts[0];
    }
    return null;
  }

  function insertDownloadIconOnWithheld() {
    const withheldHeaders = document.querySelectorAll(
      '[data-testid="empty_state_header_text"]'
    );

    withheldHeaders.forEach((headerDiv) => {
      if (!headerDiv.querySelector(".download-icon-withheld")) {
        const accountWithheldSpan = headerDiv.querySelector("span");
        if (
          accountWithheldSpan &&
          accountWithheldSpan.textContent.includes("Account Withheld")
        ) {
          const username = extractUsername();
          if (!username) return;

          const downloadIcon = createDownloadIcon();

          const iconDiv = document.createElement("div");
          iconDiv.className =
            "download-icon-withheld css-175oi2r r-1awozwy r-xoduu5";
          iconDiv.style.cssText = `
                    display: inline-flex;
                    align-items: center;
                    margin-left: 12px;
                    gap: 6px;
                    padding: 0 3px;
                    transition: transform 0.2s, color 0.2s;
                `;
          iconDiv.appendChild(downloadIcon);

          iconDiv.addEventListener("mouseenter", () => {
            iconDiv.style.transform = "scale(1.1)";
            iconDiv.style.color = "#0ea5e9";
          });

          iconDiv.addEventListener("mouseleave", () => {
            iconDiv.style.transform = "scale(1)";
            iconDiv.style.color = "";
          });

          iconDiv.addEventListener("click", (e) => {
            e.stopPropagation();
            createModal(username);
          });

          headerDiv.appendChild(iconDiv);
        }
      }
    });
  }

  function insertDownloadIcon() {
    const usernameDivs = document.querySelectorAll('[data-testid="UserName"]');

    usernameDivs.forEach((usernameDiv) => {
      if (!usernameDiv.querySelector(".download-icon")) {
        const username = extractUsername();
        if (!username) return;

        const verifiedButton = usernameDiv
          .querySelector('[aria-label*="verified"], [aria-label*="Verified"]')
          ?.closest("button");

        const targetElement = verifiedButton
          ? verifiedButton.parentElement
          : usernameDiv.querySelector(".css-1jxf684")?.closest("span");

        if (targetElement) {
          const downloadIcon = createDownloadIcon();

          const iconDiv = document.createElement("div");
          iconDiv.className = "download-icon css-175oi2r r-1awozwy r-xoduu5";
          iconDiv.style.cssText = `
                    display: inline-flex;
                    align-items: center;
                    margin-left: 6px;
                    margin-right: 6px;
                    gap: 6px;
                    padding: 0 3px;
                    transition: transform 0.2s, color 0.2s;
                `;
          iconDiv.appendChild(downloadIcon);

          iconDiv.addEventListener("mouseenter", () => {
            iconDiv.style.transform = "scale(1.1)";
            iconDiv.style.color = "#0ea5e9";
          });

          iconDiv.addEventListener("mouseleave", () => {
            iconDiv.style.transform = "scale(1)";
            iconDiv.style.color = "";
          });

          iconDiv.addEventListener("click", (e) => {
            e.stopPropagation();
            createModal(username);
          });

          const wrapperDiv = document.createElement("div");
          wrapperDiv.style.cssText = `
                    display: inline-flex;
                    align-items: center;
                    gap: 4px;
                `;
          wrapperDiv.appendChild(iconDiv);
          targetElement.parentNode.insertBefore(
            wrapperDiv,
            targetElement.nextSibling
          );
        }
      }
    });
  }

  insertDownloadIcon();
  insertDownloadIconOnWithheld();

  function checkForUserNameElement() {
    const usernameDivs = document.querySelectorAll('[data-testid="UserName"]');
    if (usernameDivs.length > 0) {
      insertDownloadIcon();
    }

    const withheldHeaders = document.querySelectorAll(
      '[data-testid="empty_state_header_text"]'
    );
    if (withheldHeaders.length > 0) {
      insertDownloadIconOnWithheld();
    }
  }

  setInterval(checkForUserNameElement, 100);

  let lastUrl = location.href;
  let lastUsername = extractUsername();

  function checkForChanges() {
    const currentUrl = location.href;
    const currentUsername = extractUsername();

    if (currentUrl !== lastUrl || currentUsername !== lastUsername) {
      lastUrl = currentUrl;
      lastUsername = currentUsername;

      document.querySelectorAll(".download-icon").forEach((icon) => {
        const wrapper = icon.closest("div[style*='display: inline-flex']");
        if (wrapper) {
          wrapper.remove();
        }
      });

      document.querySelectorAll(".download-icon-withheld").forEach((icon) => {
        icon.remove();
      });

      setTimeout(() => {
        insertDownloadIcon();
        insertDownloadIconOnWithheld();
      }, 50);
    }
  }

  const observer = new MutationObserver(() => {
    checkForChanges();
    checkForUserNameElement();
  });

  observer.observe(document.body, {
    childList: true,
    subtree: true,
    attributes: true,
    characterData: true,
  });

  setInterval(checkForChanges, 300);

  const originalPushState = history.pushState;
  const originalReplaceState = history.replaceState;

  history.pushState = function () {
    originalPushState.apply(this, arguments);
    checkForChanges();
    insertDownloadIcon();
    insertDownloadIconOnWithheld();
  };

  history.replaceState = function () {
    originalReplaceState.apply(this, arguments);
    checkForChanges();
    insertDownloadIcon();
    insertDownloadIconOnWithheld();
  };

  window.addEventListener("popstate", () => {
    checkForChanges();
    insertDownloadIcon();
    insertDownloadIconOnWithheld();
  });
})();