/**
 * @name PremiumScreenShare
 * @author Ahlawat
 * @authorId 1025214794766221384
 * @version 2.3.1
 * @invite SgKSKyh9gY
 * @description Make the screen sharing experience PREMIUM.
 * @website https://tharki-god.github.io/
 * @source https://github.com/Tharki-God/BetterDiscordPlugins/blob/master/PremiumScreenShare
 * @updateUrl https://tharki-god.github.io/BetterDiscordPlugins/PremiumScreenShare.plugin.js
 */
/*@cc_on
@if (@_jscript)
var shell = WScript.CreateObject("WScript.Shell");
var fs = new ActiveXObject("Scripting.FileSystemObject");
var pathPlugins = shell.ExpandEnvironmentStrings("%APPDATA%\\BetterDiscord\\plugins");
var pathSelf = WScript.ScriptFullName;
shell.Popup("It looks like you've mistakenly tried to run me directly. \n(Don't do that!)", 0, "I'm a plugin for BetterDiscord", 0x30);
if (fs.GetParentFolderName(pathSelf) === fs.GetAbsolutePathName(pathPlugins)) {
shell.Popup("I'm in the correct folder already.", 0, "I'm already installed", 0x40);
} else if (!fs.FolderExists(pathPlugins)) {
shell.Popup("I can't find the BetterDiscord plugins folder.\nAre you sure it's even installed?", 0, "Can't install myself", 0x10);
} else if (shell.Popup("Should I move myself to BetterDiscord's plugins folder for you?", 0, "Do you need some help?", 0x34) === 6) {
fs.MoveFile(pathSelf, fs.BuildPath(pathPlugins, fs.GetFileName(pathSelf)));
shell.Exec("explorer " + pathPlugins);
shell.Popup("I'm installed!", 0, "Successfully installed", 0x40);
}
WScript.Quit();
@else@*/
module.exports = (() => {
  const config = {
    info: {
      name: "PremiumScreenShare",
      authors: [
        {
          name: "Ahlawat",
          discord_id: "1025214794766221384",
          github_username: "Tharki-God",
        },
      ],
      version: "2.3.1",
      description: "Make the screen sharing experience PREMIUM.",
      github: "https://github.com/Tharki-God/BetterDiscordPlugins",
      github_raw:
        "https://tharki-god.github.io/BetterDiscordPlugins/PremiumScreenShare.plugin.js",
    },
    changelog: [
      {
        title: "v0.0.1",
        items: ["Idea in mind"],
      },
      {
        title: "v0.0.5",
        items: ["Base Model"],
      },
      {
        title: "Initial Release v1.0.0",
        items: [
          "This is the initial release of the plugin :)",
          "Stream those tiddies real nice (╹ڡ╹ )",
        ],
      },
      {
        title: "v1.0.1",
        items: ["Library Handler"],
      },
      {
        title: "v1.0.3",
        items: ["Refractor"],
      },
      {
        title: "v1.0.4",
        items: ["Module Name"],
      },
      {
        title: "v1.0.5",
        items: ["Added option for more fps"],
      },
      {
        title: "v2.0.0",
        items: ["Truely premium and cotains feature which nitro don't"],
      },
      {
        title: "v2.0.1",
        items: ["removed useless code"],
      },
      {
        title: "v2.0.2",
        items: ["optimization"],
      },
      {
        title: "v2.0.6",
        items: ["Replaced Dropdowns with RadioGroup because Zlib Broken"],
      },
      {
        title: "v2.2.1",
        items: ["Refractor and fixed some bugs"],
      },
      {
        title: "v2.2.3",
        items: ["Corrected text."],
      },
    ],
    main: "PremiumScreenShare.plugin.js",
  };
  const RequiredLibs = [{
    window: "ZeresPluginLibrary",
    filename: "0PluginLibrary.plugin.js",
    external: "https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js",
    downloadUrl: "https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js"
  },
  {
    window: "BunnyLib",
    filename: "1BunnyLib.plugin.js",
    external: "https://github.com/Tharki-God/BetterDiscordPlugins",
    downloadUrl: "https://tharki-god.github.io/BetterDiscordPlugins/1BunnyLib.plugin.js"
  },
  ];
  class handleMissingLibrarys {
    load() {
      for (const Lib of RequiredLibs.filter(lib => !window.hasOwnProperty(lib.window)))
        BdApi.showConfirmationModal(
          "Library Missing",
          `The library plugin (${Lib.window}) needed for ${config.info.name} is missing. Please click Download Now to install it.`,
          {
            confirmText: "Download Now",
            cancelText: "Cancel",
            onConfirm: () => this.downloadLib(Lib),
          }
        );
    }
    async downloadLib(Lib) {
      const fs = require("fs");
      const path = require("path");
      const { Plugins } = BdApi;
      const LibFetch = await fetch(
        Lib.downloadUrl
      );
      if (!LibFetch.ok) return this.errorDownloadLib(Lib);
      const LibContent = await LibFetch.text();
      try {
        await fs.writeFile(
          path.join(Plugins.folder, Lib.filename),
          LibContent,
          (err) => {
            if (err) return this.errorDownloadLib(Lib);
          }
        );
      } catch (err) {
        return this.errorDownloadLib(Lib);
      }
    }
    errorDownloadZLib(Lib) {
      const { shell } = require("electron");
      BdApi.showConfirmationModal(
        "Error Downloading",
        [
          `${Lib.window} download failed. Manually install plugin library from the link below.`,
        ],
        {
          confirmText: "Download",
          cancelText: "Cancel",
          onConfirm: () => {
            shell.openExternal(
              Lib.external
            );
          },
        }
      );
    }
    start() { }
    stop() { }
  }
  return RequiredLibs.some(m => !window.hasOwnProperty(m.window))
    ? handleMissingLibrarys
    : (([Plugin, ZLibrary]) => {
      const {
        PluginUpdater,
        Logger,
        Utilities,
        Patcher,
        Settings: {
          SettingPanel,
          SettingGroup,
          RadioGroup,
          Dropdown, //scrolling issues
        },
      } = ZLibrary;
      const {
        LibraryUtils,
        LibraryModules: {
          ApplicationStreamingOptionStore,
          WebRTCUtils,
          TextTags
        }
      } = BunnyLib.build(config);
      const fpsOptions = [
        {
          name: "5 FPS",
          value: 5,
        },
        {
          name: "10 FPS",
          value: 10,
        },
        {
          name: "15 FPS",
          value: 15,
        },
        {
          name: "30 FPS",
          value: 30,
        },
        {
          name: "45 FPS",
          value: 45,
        },
        {
          name: "60 FPS",
          value: 60,
        },
        {
          name: "120 FPS",
          value: 120,
        },
        {
          name: "144 FPS",
          value: 144,
        },
        {
          name: "240 FPS",
          value: 240,
        },
        {
          name: "360 FPS",
          value: 360,
        },
      ];
      const resoOptions = [
        {
          name: "144p",
          value: 144,
        },
        {
          name: "240p",
          value: 240,
        },
        {
          name: "360p",
          value: 360,
        },
        {
          name: "480p",
          value: 480,
        },
        {
          name: "720p",
          value: 720,
        },
        {
          name: "1080p",
          value: 1080,
        },
        {
          name: "1440p",
          value: 1440,
        },
        {
          name: "2160p",
          value: 2160,
        },
      ];
      const resoWithSource = [
        {
          name: "Source",
          value: 0,
        },
        ...resoOptions,
      ];
      const defaultSettings = {
        fps: {
          1: 15,
          2: 30,
          3: 60,
        },
        resolution: {
          1: 480,
          2: 720,
          3: 1080,
        },
        smoothVideo: {
          resolution: 720,
          fps: 60,
        },
        betterReadability: {
          resolution: 0,
          fps: 60,
        },
      };
      return class PremiumScreenShare extends Plugin {
        constructor() {
          super();
          this.settings = Utilities.loadData(
            config.info.name,
            "settings",
            defaultSettings
          );
        }
        checkForUpdates() {
          try {
            PluginUpdater.checkForUpdate(
              config.info.name,
              config.info.version,
              config.info.github_raw
            );
          } catch (err) {
            Logger.err("Plugin Updater could not be reached.", err);
          }
        }
        start() {
          this.checkForUpdates();
          this.saveDefault();
          this.initialize();
          this.patchQualityStore();
          this.fixBetterReadablityText();
        }
        saveDefault() {
          if (!this.defaultParameters)
            this.defaultParameters = Object.freeze({
              LY: Object.freeze(Object.assign({}, ApplicationStreamingOptionStore?.LY)),
              ND: Object.freeze(
                ApplicationStreamingOptionStore?.ND?.map((n) => Object.freeze(n))
              ),
              WC: Object.freeze(
                ApplicationStreamingOptionStore?.WC?.map((n) => Object.freeze(n))
              ),
              af: Object.freeze(
                ApplicationStreamingOptionStore?.af?.map((n) => Object.freeze(n))
              ),
              k0: Object.freeze(
                ApplicationStreamingOptionStore?.k0?.map((n) => Object.freeze(n))
              ),
              km: Object.freeze(
                ApplicationStreamingOptionStore?.km?.map((n) => Object.freeze(n))
              ),
              no: Object.freeze(Object.assign({}, ApplicationStreamingOptionStore?.no)),
              ws: Object.freeze(Object.assign({}, ApplicationStreamingOptionStore?.ws)),
            });
        }

        initialize() {
          this.constants = {
            settings: this.settings,
            get fps() {
              return Object.values(this.settings["fps"])
                .sort(LibraryUtils.ascending)
                .filter((item, pos, self) => LibraryUtils.removeDuplicate(item, pos, self));
            },
            get fpsWithPresets() {
              return [
                this.settings["betterReadability"].fps,
                this.settings["smoothVideo"].fps,
                ...this.fps,
              ];
            },
            get resolution() {
              return [
                ...Object.values(this.settings["resolution"])
                  .sort(LibraryUtils.ascending)
                  .filter((item, pos, self) => LibraryUtils.removeDuplicate(item, pos, self)),
                0,
              ];
            },
            get resolutionWithPresets() {
              return [
                this.settings["smoothVideo"].resolution,
                this.settings["betterReadability"].resolution,
                ...this.resolution,
              ];
            }
          };
          const customParameters = {
            LY: Object.assign(
              {},
              ...this.constants["resolution"].map((resolution) => {
                const label = `RESOLUTION_${resolution == 0 ? "SOURCE" : resolution}`;
                return { [resolution]: label, [label]: resolution };
              })
            ),
            ND: this.constants["resolutionWithPresets"].map(
              (resolution) => this.constants["fpsWithPresets"].map(
                (fps) => ({ resolution, fps })
              )
            ).flat(Infinity),
            WC: this.constants["resolution"]
              .filter((resolution) => resolution !== this.settings["resolution"][1])
              .map((resolution) => ({ value: resolution, label: resolution == 0 ? "Source" : resolution })),
            af: this.constants["fps"].map(
              (fps) => ({ value: fps, label: `${fps} FPS` })
            ),
            k0: this.constants["fps"].map(
              (fps) => ({ value: fps, label: fps })
            ),
            km: this.constants["resolution"].map(
              (res) => ({ value: res, label: res == 0 ? "Source" : `${res}p` })
            ),
            no: {
              1: [this.settings["smoothVideo"]],
              2: [this.settings["betterReadability"]],
              3: [],
            },
            ws: Object.assign(
              {},
              ...this.constants["fps"].map((res) => {
                const label = `FPS_${res}`;
                return { [res]: label, [label]: res };
              })
            ),
          };
          this.setStreamParameters(customParameters);
        }
        patchQualityStore() {
          const maxResolution = Math.max(
            ...this.constants["resolutionWithPresets"]
          );
          const maxFPS = Math.max(
            ...this.constants["fpsWithPresets"]
          );
          const maxVideoQuality = Object.freeze({
            width: maxResolution * (16 / 9),
            height: maxResolution,
            framerate: maxFPS,
          });
          Patcher.before(
            WebRTCUtils,
            "updateVideoQuality",
            (instance, args) => {
              instance.videoQualityManager.options.videoBudget =
                maxVideoQuality;
              instance.videoQualityManager.options.videoCapture =
                maxVideoQuality;
              for (const ladder in instance.videoQualityManager.ladder
                .ladder) {
                instance.videoQualityManager.ladder.ladder[ladder].framerate =
                  maxVideoQuality.framerate;
                instance.videoQualityManager.ladder.ladder[
                  ladder
                ].mutedFramerate = maxVideoQuality.framerate / 2;
              }
              for (const ladder of instance.videoQualityManager.ladder
                .orderedLadder) {
                ladder.framerate = maxVideoQuality.framerate;
                ladder.mutedFramerate = maxVideoQuality.framerate / 2;
              }
            }
          );
        }
        fixBetterReadablityText() {
          Patcher.before(TextTags, "render", (_, [args]) => {
            if (args?.title !== "Resolution" || !args?.children?.props?.children) return;
            const {
              children: { props },
            } = args;
            if (props?.children)
              props.children = props.children.replace(
                "(Source)",
                `(${this.settings["betterReadability"].resolution == 0
                  ? "Source"
                  : `${this.settings["betterReadability"].resolution}P`
                })`
              );
          });
        }
        setStreamParameters(Parameters) {
          for (const key in Parameters) {
            Object.defineProperty(ApplicationStreamingOptionStore, key, {
              value: Parameters[key],
              writable: true,
            });
          }
        }
        onStop() {
          this.setStreamParameters(this.defaultParameters);
          Patcher.unpatchAll();
        }
        getSettingsPanel() {
          return SettingPanel.build(
            this.saveSettings.bind(this),
            new SettingGroup("FPS (Depends on your screen FPS)", {
              collapsible: true,
              shown: false,
            }).append(
              new RadioGroup(
                "15 FPS",
                "Replace 15 FPS with custom FPS",
                this.settings["fps"][1],
                fpsOptions,
                (e) => {
                  this.settings["fps"][1] = e;
                }
              ),
              new RadioGroup(
                "30 FPS",
                "Replace 30 FPS with custom FPS",
                this.settings["fps"][2],
                fpsOptions,
                (e) => {
                  this.settings["fps"][2] = e;
                }
              ),
              new RadioGroup(
                "60 FPS",
                "Replace 60 FPS with custom FPS",
                this.settings["fps"][3],
                fpsOptions,
                (e) => {
                  this.settings["fps"][3] = e;
                }
              )
            ),
            new SettingGroup(
              "Resolution (Depends on your screen resolution)",
              {
                collapsible: true,
                shown: false,
              }
            ).append(
              new RadioGroup(
                "480p",
                "Replace 480p with custom resolution",
                this.settings["resolution"][1],
                resoOptions,
                (e) => {
                  this.settings["resolution"][1] = e;
                }
              ),
              new RadioGroup(
                "720p",
                "Replace 720p with custom resolution",
                this.settings["resolution"][2],
                resoOptions,
                (e) => {
                  this.settings["resolution"][2] = e;
                }
              ),
              new RadioGroup(
                "1080p",
                "Replace 1080p with custom resolution",
                this.settings["resolution"][3],
                resoOptions,
                (e) => {
                  this.settings["resolution"][3] = e;
                }
              )
            ),
            new SettingGroup("Preset Smoother Video", {
              collapsible: true,
              shown: false,
            }).append(
              new RadioGroup(
                "Resolution",
                "Change Smoother Video preset resolution",
                this.settings["smoothVideo"]["resolution"],
                resoWithSource,
                (e) => {
                  this.settings["smoothVideo"]["resolution"] = e;
                }
              ),
              new RadioGroup(
                "FPS",
                "Change smoother video preset FPS",
                this.settings["smoothVideo"]["fps"],
                fpsOptions,
                (e) => {
                  this.settings["smoothVideo"]["fps"] = e;
                }
              )
            ),
            new SettingGroup("Preset Better Readability", {
              collapsible: true,
              shown: false,
            }).append(
              new RadioGroup(
                "Resolution",
                "Change Better Readability preset resolution",
                this.settings["betterReadability"]["resolution"],
                resoWithSource,
                (e) => {
                  this.settings["betterReadability"]["resolution"] = e;
                }
              ),
              new RadioGroup(
                "FPS",
                "Change Better Readability preset FPS",
                this.settings["betterReadability"]["fps"],
                fpsOptions,
                (e) => {
                  this.settings["betterReadability"]["fps"] = e;
                }
              )
            )
          );
        }
        saveSettings() {
          Utilities.saveData(config.info.name, "settings", this.settings);
          this.initialize();
        }
      };
    })(ZLibrary.buildPlugin(config));
})();
/*@end@*/