var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __knownSymbol = (name, symbol) => {
  return (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
};
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
  for (var prop in b || (b = {}))
    if (__hasOwnProp.call(b, prop))
      __defNormalProp(a, prop, b[prop]);
  if (__getOwnPropSymbols)
    for (var prop of __getOwnPropSymbols(b)) {
      if (__propIsEnum.call(b, prop))
        __defNormalProp(a, prop, b[prop]);
    }
  return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __async = (__this, __arguments, generator) => {
  return new Promise((resolve, reject) => {
    var fulfilled = (value) => {
      try {
        step(generator.next(value));
      } catch (e) {
        reject(e);
      }
    };
    var rejected = (value) => {
      try {
        step(generator.throw(value));
      } catch (e) {
        reject(e);
      }
    };
    var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
    step((generator = generator.apply(__this, __arguments)).next());
  });
};
var __await = function(promise, isYieldStar) {
  this[0] = promise;
  this[1] = isYieldStar;
};
var __yieldStar = (value) => {
  var obj = value[__knownSymbol("asyncIterator")];
  var isAwait = false;
  var method;
  var it = {};
  if (obj == null) {
    obj = value[__knownSymbol("iterator")]();
    method = (k) => it[k] = (x) => obj[k](x);
  } else {
    obj = obj.call(value);
    method = (k) => it[k] = (v) => {
      if (isAwait) {
        isAwait = false;
        if (k === "throw")
          throw v;
        return v;
      }
      isAwait = true;
      return {
        done: false,
        value: new __await(new Promise((resolve) => {
          var x = obj[k](v);
          if (!(x instanceof Object))
            throw TypeError("Object expected");
          resolve(x);
        }), 1)
      };
    };
  }
  return it[__knownSymbol("iterator")] = () => it, method("next"), "throw" in obj ? method("throw") : it.throw = (x) => {
    throw x;
  }, "return" in obj && method("return"), it;
};

// src/formatter.ts
var _Formatter = class _Formatter {
  constructor() {
    return _Formatter;
  }
  static formatSearchResult(details, options = {
    limit: 100,
    type: "all"
  }) {
    const results = [];
    for (let i = 0; i < details.length; i++) {
      if (typeof options.limit === "number" && options.limit > 0 && results.length >= options.limit)
        break;
      let data = details[i];
      let res;
      if (options.type === "all") {
        if (!!data.videoRenderer)
          options.type = "video";
        else if (!!data.channelRenderer)
          options.type = "channel";
        else if (!!data.playlistRenderer)
          options.type = "playlist";
        else
          continue;
      }
      if (options.type === "video" || options.type === "film") {
        const parsed = Util_default.parseVideo(data);
        if (!parsed)
          continue;
        res = parsed;
      } else if (options.type === "channel") {
        const parsed = Util_default.parseChannel(data);
        if (!parsed)
          continue;
        res = parsed;
      } else if (options.type === "playlist") {
        const parsed = Util_default.parsePlaylist(data);
        if (!parsed)
          continue;
        res = parsed;
      }
      results.push(res);
    }
    return results;
  }
};
__name(_Formatter, "Formatter");
var Formatter = _Formatter;

// src/Structures/Channel.ts
var _Channel = class _Channel {
  constructor(data) {
    if (!data)
      throw new Error(`Cannot instantiate the ${this.constructor.name} class without data!`);
    this._patch(data);
  }
  /**
   * Patch raw data
   * @private
   * @ignore
   */
  _patch(data) {
    var _a;
    if (!data)
      data = {};
    this.name = data.name || null;
    this.verified = !!data.verified || false;
    this.id = data.id || null;
    this.url = data.url || null;
    this.icon = data.icon || { url: null, width: 0, height: 0 };
    this.subscribers = data.subscribers || null;
    if ((_a = this.icon.url) == null ? void 0 : _a.startsWith("//"))
      this.icon.url = `https:${this.icon.url}`;
  }
  /**
   * Returns channel icon url
   * @param {object} options Icon options
   * @param {number} [options.size=0] Icon size. **Default is 0**
   */
  iconURL(options = { size: 0 }) {
    if (typeof options.size !== "number" || options.size < 0)
      throw new Error("invalid icon size");
    if (!this.icon.url)
      return null;
    const def = this.icon.url.split("=s")[1].split("-c")[0];
    return this.icon.url.replace(`=s${def}-c`, `=s${options.size}-c`);
  }
  get type() {
    return "channel";
  }
  toString() {
    return this.name || "";
  }
  toJSON() {
    return {
      name: this.name,
      verified: this.verified,
      id: this.id,
      url: this.url,
      iconURL: this.iconURL(),
      type: this.type,
      subscribers: this.subscribers
    };
  }
};
__name(_Channel, "Channel");
var Channel = _Channel;

// src/Structures/Thumbnail.ts
var _Thumbnail = class _Thumbnail {
  /**
   * Thumbnail constructor
   * @param data Thumbnail constructor params
   */
  constructor(data) {
    if (!data)
      throw new Error(`Cannot instantiate the ${this.constructor.name} class without data!`);
    this._patch(data);
  }
  /**
   * Patch raw data
   * @param data Raw Data
   * @private
   * @ignore
   */
  _patch(data) {
    if (!data)
      data = {};
    this.id = data.id || null;
    this.width = data.width || 0;
    this.height = data.height || 0;
    this.url = data.url || null;
  }
  /**
   * Returns thumbnail url
   * @param {"default"|"hqdefault"|"mqdefault"|"sddefault"|"maxresdefault"|"ultrares"} thumbnailType Thumbnail type
   */
  displayThumbnailURL(thumbnailType = "ultrares") {
    if (!["default", "hqdefault", "mqdefault", "sddefault", "maxresdefault", "ultrares"].includes(thumbnailType))
      throw new Error(`Invalid thumbnail type "${thumbnailType}"!`);
    if (thumbnailType === "ultrares")
      return this.url;
    return `https://i3.ytimg.com/vi/${this.id}/${thumbnailType}.jpg`;
  }
  /**
   * Returns default thumbnail
   * @param {"0"|"1"|"2"|"3"|"4"} id Thumbnail id. **4 returns thumbnail placeholder.**
   */
  defaultThumbnailURL(id) {
    if (!id)
      id = "0";
    if (!["0", "1", "2", "3", "4"].includes(id))
      throw new Error(`Invalid thumbnail id "${id}"!`);
    return `https://i3.ytimg.com/vi/${this.id}/${id}.jpg`;
  }
  toString() {
    return this.url ? `${this.url}` : "";
  }
  toJSON() {
    return {
      id: this.id,
      width: this.width,
      height: this.height,
      url: this.url
    };
  }
};
__name(_Thumbnail, "Thumbnail");
var Thumbnail = _Thumbnail;

// src/Structures/Playlist.ts
var BASE_API = "https://www.youtube.com/youtubei/v1/browse?key=";
var _Playlist = class _Playlist {
  constructor(data = {}, searchResult = false) {
    this.fake = false;
    this._continuation = {};
    if (!data)
      throw new Error(`Cannot instantiate the ${this.constructor.name} class without data!`);
    Object.defineProperty(this, "_continuation", { enumerable: false, configurable: true, writable: true });
    if (!!searchResult)
      this._patchSearch(data);
    else
      this._patch(data);
  }
  _patch(data) {
    var _a, _b, _c, _d, _e, _f;
    this.id = data.id || null;
    this.title = data.title || null;
    this.videoCount = data.videoCount || 0;
    this.lastUpdate = data.lastUpdate || null;
    this.views = data.views || 0;
    this.url = data.url || data.link || this.id ? `https://www.youtube.com/playlist?list=${this.id}` : null;
    this.link = data.link || data.url || null;
    this.channel = data.author || null;
    this.thumbnail = new Thumbnail(data.thumbnail || {});
    this.videos = data.videos || [];
    this._continuation.api = (_b = (_a = data.continuation) == null ? void 0 : _a.api) != null ? _b : null;
    this._continuation.token = (_d = (_c = data.continuation) == null ? void 0 : _c.token) != null ? _d : null;
    this._continuation.clientVersion = (_f = (_e = data.continuation) == null ? void 0 : _e.clientVersion) != null ? _f : "<important data>";
    this.mix = data.mix || false;
    this.fake = Boolean(data.fake);
  }
  _patchSearch(data) {
    var _a;
    this.id = data.id || null;
    this.title = data.title || null;
    this.thumbnail = new Thumbnail(data.thumbnail || {});
    this.channel = data.channel || null;
    this.videos = data.videos || [];
    this.videoCount = ((_a = data.videos) == null ? void 0 : _a.length) || 0;
    this.url = data.url || data.link || this.id ? `https://www.youtube.com/playlist?list=${this.id}` : null;
    this.link = data.link || data.url || null;
    this.lastUpdate = null;
    this.views = 0;
    this.mix = data.mix || false;
    this.fake = Boolean(data.fake);
  }
  /**
   * @param limit Max items to parse from current chunk
   */
  next(limit = Infinity) {
    return __async(this, null, function* () {
      var _a, _b, _c;
      if (!this._continuation || !this._continuation.token)
        return [];
      const nextPage = yield Util_default.getHTML(`${BASE_API}${this._continuation.api}`, {
        method: "POST",
        body: JSON.stringify({
          continuation: this._continuation.token,
          context: {
            client: {
              utcOffsetMinutes: 0,
              gl: "US",
              hl: "en",
              clientName: "WEB",
              clientVersion: this._continuation.clientVersion
            },
            user: {},
            request: {}
          }
        })
      });
      const contents = (_c = (_b = (_a = Util_default.json(nextPage)) == null ? void 0 : _a.onResponseReceivedActions[0]) == null ? void 0 : _b.appendContinuationItemsAction) == null ? void 0 : _c.continuationItems;
      if (!contents)
        return [];
      const partial = Util_default.getPlaylistVideos(contents, limit);
      this._continuation.token = Util_default.getContinuationToken(contents);
      this.videos = [...this.videos, ...partial];
      return partial;
    });
  }
  fetch(max = Infinity) {
    return __async(this, null, function* () {
      const ctn = this._continuation.token;
      if (!ctn)
        return this;
      if (max < 1)
        max = Infinity;
      while (typeof this._continuation.token === "string" && this._continuation.token.length) {
        if (this.videos.length >= max)
          break;
        const res = yield this.next();
        if (!res.length)
          break;
      }
      return this;
    });
  }
  get type() {
    return "playlist";
  }
  *[Symbol.iterator]() {
    yield* __yieldStar(this.videos);
  }
  toJSON() {
    var _a, _b, _c;
    return {
      id: this.id,
      title: this.title,
      thumbnail: ((_a = this.thumbnail) == null ? void 0 : _a.toJSON()) || null,
      channel: {
        name: this.channel.name,
        id: this.channel.id,
        icon: (_c = (_b = this.channel) == null ? void 0 : _b.iconURL) == null ? void 0 : _c.call(_b)
      },
      mix: this.mix,
      url: this.url,
      videos: this.videos
    };
  }
};
__name(_Playlist, "Playlist");
var Playlist = _Playlist;

// src/Structures/Video.ts
var _Video = class _Video {
  constructor(data) {
    this.nsfw = false;
    this.shorts = false;
    this.unlisted = false;
    if (!data)
      throw new Error(`Cannot instantiate the ${this.constructor.name} class without data!`);
    this._patch(data);
  }
  /**
   * Patch raw data
   * @private
   * @ignore
   */
  _patch(data) {
    var _a, _b;
    if (!data)
      data = {};
    this.id = data.id || null;
    this.title = data.title || null;
    this.description = data.description || null;
    this.durationFormatted = data.duration_raw || "0:00";
    this.duration = (data.duration < 0 ? 0 : data.duration) || 0;
    this.uploadedAt = data.uploadedAt || null;
    this.views = parseInt(data.views) || 0;
    this.thumbnail = new Thumbnail(data.thumbnail || {});
    this.channel = new Channel(data.channel || {});
    this.likes = ((_a = data.ratings) == null ? void 0 : _a.likes) || 0;
    this.dislikes = ((_b = data.ratings) == null ? void 0 : _b.dislikes) || 0;
    this.live = !!data.live;
    this.private = !!data.private;
    this.tags = data.tags || [];
    this.nsfw = Boolean(data.nsfw);
    this.unlisted = Boolean(data.unlisted);
    this.shorts = Boolean(data.shorts);
    this.music = data.music;
    Object.defineProperty(this, "streamingData", {
      enumerable: false,
      configurable: true,
      writable: true,
      value: data.streamingData || null
    });
    Object.defineProperty(this, "videos", {
      enumerable: false,
      configurable: true,
      writable: true,
      value: data.videos || []
    });
  }
  get formats() {
    var _a;
    return ((_a = this.streamingData) == null ? void 0 : _a.formats) || [];
  }
  get adaptiveFormats() {
    var _a;
    return ((_a = this.streamingData) == null ? void 0 : _a.adaptiveFormats) || [];
  }
  get url() {
    if (!this.id)
      return null;
    return `https://www.youtube.com/watch?v=${this.id}`;
  }
  get shortsURL() {
    if (!this.shorts)
      return this.url;
    return `https://www.youtube.com/shorts/${this.id}`;
  }
  /**
   * YouTube video embed html
   * @param {object} options Options
   * @param {string} [options.id] DOM element id
   * @param {number} [options.width] Iframe width
   * @param {number} [options.height] Iframe height
   */
  embedHTML(options = { id: "ytplayer", width: 640, height: 360 }) {
    if (!this.id)
      return null;
    return `<iframe title="__youtube_sr_frame__" id="${options.id || "ytplayer"}" type="text/html" width="${options.width || 640}" height="${options.height || 360}" src="${this.embedURL}" frameborder="0"></iframe>`;
  }
  /**
   * Creates mix playlist url from this video
   */
  createMixURL() {
    return `${this.url}&list=RD${this.id}`;
  }
  /**
   * YouTube video embed url
   */
  get embedURL() {
    if (!this.id)
      return null;
    return `https://www.youtube.com/embed/${this.id}`;
  }
  get type() {
    return "video";
  }
  toString() {
    return this.url || "";
  }
  toJSON() {
    const res = {
      id: this.id,
      url: this.url,
      shorts_url: this.shortsURL,
      title: this.title,
      description: this.description,
      duration: this.duration,
      duration_formatted: this.durationFormatted,
      uploadedAt: this.uploadedAt,
      unlisted: this.unlisted,
      nsfw: this.nsfw,
      thumbnail: this.thumbnail.toJSON(),
      channel: {
        name: this.channel.name,
        id: this.channel.id,
        icon: this.channel.iconURL()
      },
      views: this.views,
      type: this.type,
      tags: this.tags,
      ratings: {
        likes: this.likes,
        dislikes: this.dislikes
      },
      shorts: this.shorts,
      live: this.live,
      private: this.private,
      music: this.music
    };
    return res;
  }
};
__name(_Video, "Video");
var Video = _Video;

// src/Util.ts
var PLAYLIST_REGEX = /^https?:\/\/(www.)?youtube.com\/playlist\?list=((PL|FL|UU|LL|RD|OL)[a-zA-Z0-9-_]{16,41})$/;
var PLAYLIST_ID = /(PL|FL|UU|LL|RD|OL)[a-zA-Z0-9-_]{11,41}/;
var ALBUM_REGEX = /(RDC|O)LAK5uy_[a-zA-Z0-9-_]{33}/;
var VIDEO_URL = /^((?:https?:)?\/\/)?((?:www|m)\.)?((?:youtube\.com|youtu.be))(\/(?:[\w\-]+\?v=|embed\/|v\/)?)([\w\-]+)(\S+)?$/;
var VIDEO_ID = /^[a-zA-Z0-9-_]{11}$/;
var DEFAULT_INNERTUBE_KEY = "AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8";
var innertubeCache = null;
var __fetch;
var isNode = typeof process !== "undefined" && "node" in (process.versions || {});
var FETCH_LIBS = ["node-fetch", "cross-fetch", "undici"];
function getFetch() {
  return __async(this, null, function* () {
    if (typeof __fetch === "function")
      return __fetch;
    if (typeof window !== "undefined" && "fetch" in window)
      return window.fetch;
    if ("fetch" in globalThis)
      return globalThis.fetch;
    for (const fetchLib of FETCH_LIBS) {
      try {
        const pkg = yield import(fetchLib);
        const mod = pkg.fetch || pkg.default || pkg;
        if (mod)
          return __fetch = mod;
      } catch (e) {
      }
    }
    if (isNode)
      throw new Error(`Could not resolve fetch library. Install one of ${FETCH_LIBS.map((m) => `"${m}"`).join(", ")} or define "fetch" in global scope!`);
    throw new Error("Could not resolve fetch in global scope");
  });
}
__name(getFetch, "getFetch");
var _Util = class _Util {
  constructor() {
    return _Util;
  }
  static innertubeKey() {
    return __async(this, null, function* () {
      if (innertubeCache)
        return innertubeCache;
      return yield _Util.fetchInnerTubeKey();
    });
  }
  static get VideoRegex() {
    return VIDEO_URL;
  }
  static get VideoIDRegex() {
    return VIDEO_ID;
  }
  static get AlbumRegex() {
    return ALBUM_REGEX;
  }
  /**
   * YouTube playlist URL Regex
   * @type {RegExp}
   */
  static get PlaylistURLRegex() {
    return PLAYLIST_REGEX;
  }
  /**
   * YouTube Playlist ID regex
   * @type {RegExp}
   */
  static get PlaylistIDRegex() {
    return PLAYLIST_ID;
  }
  static fetchInnerTubeKey() {
    return __async(this, null, function* () {
      var _a, _b, _c;
      const html = yield _Util.getHTML("https://www.youtube.com?hl=en");
      const key = (_c = (_a = html.split('INNERTUBE_API_KEY":"')[1]) == null ? void 0 : _a.split('"')[0]) != null ? _c : (_b = html.split('innertubeApiKey":"')[1]) == null ? void 0 : _b.split('"')[0];
      if (key)
        innertubeCache = key;
      return key != null ? key : DEFAULT_INNERTUBE_KEY;
    });
  }
  /**
   * Parse HTML
   * @param {string} url Website URL
   * @param {RequestInit} [requestOptions] Request Options
   * @returns {Promise<string>}
   */
  static getHTML(url, requestOptions = {}) {
    requestOptions = Object.assign(
      {},
      {
        headers: Object.assign(
          {},
          {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0"
          },
          (requestOptions == null ? void 0 : requestOptions.headers) || {}
        )
      },
      requestOptions || {}
    );
    return new Promise((resolve, reject) => __async(this, null, function* () {
      if (!__fetch)
        __fetch = yield getFetch();
      __fetch(url, requestOptions).then((res) => {
        if (!res.ok)
          throw new Error(`Rejected with status code: ${res.status}`);
        return res.text();
      }).then((html) => resolve(html)).catch((e) => reject(e));
    }));
  }
  /**
   * Returns duration in ms
   * @param {string} duration Duration to parse
   */
  static parseDuration(duration) {
    duration != null ? duration : duration = "0:00";
    const args = duration.split(":");
    let dur = 0;
    switch (args.length) {
      case 3:
        dur = parseInt(args[0]) * 60 * 60 * 1e3 + parseInt(args[1]) * 60 * 1e3 + parseInt(args[2]) * 1e3;
        break;
      case 2:
        dur = parseInt(args[0]) * 60 * 1e3 + parseInt(args[1]) * 1e3;
        break;
      default:
        dur = parseInt(args[0]) * 1e3;
    }
    return dur;
  }
  /**
   * Parse items from html
   * @param {string} html HTML
   * @param options Options
   */
  static parseSearchResult(html, options) {
    if (!html)
      throw new Error("Invalid raw data");
    if (!options)
      options = { type: "video", limit: 0 };
    if (!options.type)
      options.type = "video";
    let details = [];
    let fetched = false;
    try {
      let data = html.split("ytInitialData = JSON.parse('")[1].split("');</script>")[0];
      html = data.replace(/\\x([0-9A-F]{2})/gi, (...items) => {
        return String.fromCharCode(parseInt(items[1], 16));
      });
    } catch (e) {
    }
    try {
      details = JSON.parse(html.split('{"itemSectionRenderer":{"contents":')[html.split('{"itemSectionRenderer":{"contents":').length - 1].split(',"continuations":[{')[0]);
      fetched = true;
    } catch (e) {
    }
    if (!fetched) {
      try {
        details = JSON.parse(html.split('{"itemSectionRenderer":')[html.split('{"itemSectionRenderer":').length - 1].split('},{"continuationItemRenderer":{')[0]).contents;
        fetched = true;
      } catch (e) {
      }
    }
    if (!fetched)
      return [];
    return Formatter.formatSearchResult(details, options);
  }
  /**
   * Parse channel from raw data
   * @param {object} data Raw data to parse video from
   */
  static parseChannel(data) {
    if (!data || !data.channelRenderer)
      return;
    const badges = data.channelRenderer.ownerBadges;
    let url = `https://www.youtube.com${data.channelRenderer.navigationEndpoint.browseEndpoint.canonicalBaseUrl || data.channelRenderer.navigationEndpoint.commandMetadata.webCommandMetadata.url}`;
    let res = new Channel({
      id: data.channelRenderer.channelId,
      name: data.channelRenderer.title.simpleText,
      icon: data.channelRenderer.thumbnail.thumbnails[data.channelRenderer.thumbnail.thumbnails.length - 1],
      url,
      verified: !(badges == null ? void 0 : badges.length) ? false : badges.some((badge) => {
        var _a, _b;
        return badge["verifiedBadge"] || ((_b = (_a = badge == null ? void 0 : badge.metadataBadgeRenderer) == null ? void 0 : _a.style) == null ? void 0 : _b.toLowerCase().includes("verified"));
      }),
      subscribers: data.channelRenderer.subscriberCountText.simpleText
    });
    return res;
  }
  /**
   * Parse video from raw data
   * @param {object} data Raw data to parse video from
   */
  static parseVideo(data) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E;
    if (!data || !data.videoRenderer)
      return;
    const badge = data.videoRenderer.ownerBadges && data.videoRenderer.ownerBadges[0];
    let res = new Video({
      id: data.videoRenderer.videoId,
      url: `https://www.youtube.com/watch?v=${data.videoRenderer.videoId}`,
      title: data.videoRenderer.title.runs[0].text,
      description: data.videoRenderer.descriptionSnippet && data.videoRenderer.descriptionSnippet.runs[0] ? data.videoRenderer.descriptionSnippet.runs[0].text : "",
      duration: data.videoRenderer.lengthText ? _Util.parseDuration(data.videoRenderer.lengthText.simpleText) : 0,
      duration_raw: data.videoRenderer.lengthText ? data.videoRenderer.lengthText.simpleText : null,
      thumbnail: {
        id: data.videoRenderer.videoId,
        url: data.videoRenderer.thumbnail.thumbnails[data.videoRenderer.thumbnail.thumbnails.length - 1].url,
        height: data.videoRenderer.thumbnail.thumbnails[data.videoRenderer.thumbnail.thumbnails.length - 1].height,
        width: data.videoRenderer.thumbnail.thumbnails[data.videoRenderer.thumbnail.thumbnails.length - 1].width
      },
      channel: {
        id: data.videoRenderer.ownerText.runs[0].navigationEndpoint.browseEndpoint.browseId || null,
        name: data.videoRenderer.ownerText.runs[0].text || null,
        url: `https://www.youtube.com${data.videoRenderer.ownerText.runs[0].navigationEndpoint.browseEndpoint.canonicalBaseUrl || data.videoRenderer.ownerText.runs[0].navigationEndpoint.commandMetadata.webCommandMetadata.url}`,
        icon: {
          url: ((_c = (_b = (_a = data.videoRenderer.channelThumbnail) == null ? void 0 : _a.thumbnails) == null ? void 0 : _b[0]) == null ? void 0 : _c.url) || ((_h = (_g = (_f = (_e = (_d = data.videoRenderer.channelThumbnailSupportedRenderers) == null ? void 0 : _d.channelThumbnailWithLinkRenderer) == null ? void 0 : _e.thumbnail) == null ? void 0 : _f.thumbnails) == null ? void 0 : _g[0]) == null ? void 0 : _h.url),
          width: ((_k = (_j = (_i = data.videoRenderer.channelThumbnail) == null ? void 0 : _i.thumbnails) == null ? void 0 : _j[0]) == null ? void 0 : _k.width) || ((_p = (_o = (_n = (_m = (_l = data.videoRenderer.channelThumbnailSupportedRenderers) == null ? void 0 : _l.channelThumbnailWithLinkRenderer) == null ? void 0 : _m.thumbnail) == null ? void 0 : _n.thumbnails) == null ? void 0 : _o[0]) == null ? void 0 : _p.width),
          height: ((_s = (_r = (_q = data.videoRenderer.channelThumbnail) == null ? void 0 : _q.thumbnails) == null ? void 0 : _r[0]) == null ? void 0 : _s.height) || ((_x = (_w = (_v = (_u = (_t = data.videoRenderer.channelThumbnailSupportedRenderers) == null ? void 0 : _t.channelThumbnailWithLinkRenderer) == null ? void 0 : _u.thumbnail) == null ? void 0 : _v.thumbnails) == null ? void 0 : _w[0]) == null ? void 0 : _x.height)
        },
        verified: Boolean((_z = (_y = badge == null ? void 0 : badge.metadataBadgeRenderer) == null ? void 0 : _y.style) == null ? void 0 : _z.toLowerCase().includes("verified"))
      },
      uploadedAt: (_B = (_A = data.videoRenderer.publishedTimeText) == null ? void 0 : _A.simpleText) != null ? _B : null,
      views: (_E = (_D = (_C = data.videoRenderer.viewCountText) == null ? void 0 : _C.simpleText) == null ? void 0 : _D.replace(/[^0-9]/g, "")) != null ? _E : 0
    });
    return res;
  }
  static parsePlaylist(data) {
    var _a, _b, _c;
    if (!data.playlistRenderer)
      return;
    const res = new Playlist(
      {
        id: data.playlistRenderer.playlistId,
        title: data.playlistRenderer.title.simpleText,
        thumbnail: {
          id: data.playlistRenderer.playlistId,
          url: data.playlistRenderer.thumbnails[0].thumbnails[data.playlistRenderer.thumbnails[0].thumbnails.length - 1].url,
          height: data.playlistRenderer.thumbnails[0].thumbnails[data.playlistRenderer.thumbnails[0].thumbnails.length - 1].height,
          width: data.playlistRenderer.thumbnails[0].thumbnails[data.playlistRenderer.thumbnails[0].thumbnails.length - 1].width
        },
        channel: {
          id: data.playlistRenderer.shortBylineText.runs[0].navigationEndpoint.browseEndpoint.browseId,
          name: data.playlistRenderer.shortBylineText.runs[0].text,
          url: `https://www.youtube.com${((_a = data.playlistRenderer.shortBylineText.runs[0].navigationEndpoint.browseEndpoint) == null ? void 0 : _a.canonicalBaseUrl) || ((_c = (_b = data.playlistRenderer.shortBylineText.runs[0].navigationEndpoint.commandMetadata) == null ? void 0 : _b.webCommandMetadata) == null ? void 0 : _c.url)}`
        },
        videos: parseInt(data.playlistRenderer.videoCount.replace(/[^0-9]/g, ""))
      },
      true
    );
    return res;
  }
  static getPlaylistVideos(data, limit = Infinity) {
    var _a, _b, _c, _d;
    const videos = [];
    for (let i = 0; i < data.length; i++) {
      if (limit === videos.length)
        break;
      const info = data[i].playlistVideoRenderer;
      if (!info || !info.shortBylineText)
        continue;
      videos.push(
        new Video({
          id: info.videoId,
          index: parseInt((_a = info.index) == null ? void 0 : _a.simpleText) || 0,
          duration: _Util.parseDuration((_b = info.lengthText) == null ? void 0 : _b.simpleText) || 0,
          duration_raw: (_d = (_c = info.lengthText) == null ? void 0 : _c.simpleText) != null ? _d : "0:00",
          thumbnail: {
            id: info.videoId,
            url: info.thumbnail.thumbnails[info.thumbnail.thumbnails.length - 1].url,
            height: info.thumbnail.thumbnails[info.thumbnail.thumbnails.length - 1].height,
            width: info.thumbnail.thumbnails[info.thumbnail.thumbnails.length - 1].width
          },
          title: info.title.runs[0].text,
          channel: {
            id: info.shortBylineText.runs[0].navigationEndpoint.browseEndpoint.browseId || null,
            name: info.shortBylineText.runs[0].text || null,
            url: `https://www.youtube.com${info.shortBylineText.runs[0].navigationEndpoint.browseEndpoint.canonicalBaseUrl || info.shortBylineText.runs[0].navigationEndpoint.commandMetadata.webCommandMetadata.url}`,
            icon: null
          }
        })
      );
    }
    return videos;
  }
  static getPlaylist(html, limit) {
    var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
    if (!limit || typeof limit !== "number")
      limit = 100;
    if (limit <= 0)
      limit = Infinity;
    let parsed;
    let playlistDetails;
    try {
      const rawJSON = `${html.split('{"playlistVideoListRenderer":{"contents":')[1].split('}],"playlistId"')[0]}}]`;
      parsed = JSON.parse(rawJSON);
      playlistDetails = JSON.parse(html.split('{"playlistSidebarRenderer":')[1].split("}};</script>")[0]).items;
    } catch (e) {
      return null;
    }
    const API_KEY = (_d = (_c = (_a = html.split('INNERTUBE_API_KEY":"')[1]) == null ? void 0 : _a.split('"')[0]) != null ? _c : (_b = html.split('innertubeApiKey":"')[1]) == null ? void 0 : _b.split('"')[0]) != null ? _d : DEFAULT_INNERTUBE_KEY;
    const videos = _Util.getPlaylistVideos(parsed, limit);
    const data = playlistDetails[0].playlistSidebarPrimaryInfoRenderer;
    if (!data.title.runs || !data.title.runs.length)
      return null;
    const author = (_e = playlistDetails[1]) == null ? void 0 : _e.playlistSidebarSecondaryInfoRenderer.videoOwner;
    const views = data.stats.length === 3 ? data.stats[1].simpleText.replace(/[^0-9]/g, "") : 0;
    const lastUpdate = (_h = (_g = (_f = data.stats.find((x) => "runs" in x && x["runs"].find((y) => y.text.toLowerCase().includes("last update")))) == null ? void 0 : _f.runs.pop()) == null ? void 0 : _g.text) != null ? _h : null;
    const videosCount = data.stats[0].runs[0].text.replace(/[^0-9]/g, "") || 0;
    const res = new Playlist({
      continuation: {
        api: API_KEY,
        token: _Util.getContinuationToken(parsed),
        clientVersion: (_l = (_k = (_i = html.split('"INNERTUBE_CONTEXT_CLIENT_VERSION":"')[1]) == null ? void 0 : _i.split('"')[0]) != null ? _k : (_j = html.split('"innertube_context_client_version":"')[1]) == null ? void 0 : _j.split('"')[0]) != null ? _l : "<some version>"
      },
      id: data.title.runs[0].navigationEndpoint.watchEndpoint.playlistId,
      title: data.title.runs[0].text,
      videoCount: parseInt(videosCount) || 0,
      lastUpdate,
      views: parseInt(views) || 0,
      videos,
      url: `https://www.youtube.com/playlist?list=${data.title.runs[0].navigationEndpoint.watchEndpoint.playlistId}`,
      link: `https://www.youtube.com${data.title.runs[0].navigationEndpoint.commandMetadata.webCommandMetadata.url}`,
      author: author ? {
        name: author.videoOwnerRenderer.title.runs[0].text,
        id: author.videoOwnerRenderer.title.runs[0].navigationEndpoint.browseEndpoint.browseId,
        url: `https://www.youtube.com${author.videoOwnerRenderer.navigationEndpoint.commandMetadata.webCommandMetadata.url || author.videoOwnerRenderer.navigationEndpoint.browseEndpoint.canonicalBaseUrl}`,
        icon: author.videoOwnerRenderer.thumbnail.thumbnails.length ? (_m = author.videoOwnerRenderer.thumbnail.thumbnails.pop()) == null ? void 0 : _m.url : null
      } : {},
      thumbnail: ((_n = data.thumbnailRenderer.playlistVideoThumbnailRenderer) == null ? void 0 : _n.thumbnail.thumbnails.length) ? data.thumbnailRenderer.playlistVideoThumbnailRenderer.thumbnail.thumbnails.pop() : null
    });
    return res;
  }
  static getContinuationToken(ctx) {
    var _a, _b, _c;
    const continuationToken = (_c = (_b = (_a = ctx.find((x) => Object.keys(x)[0] === "continuationItemRenderer")) == null ? void 0 : _a.continuationItemRenderer.continuationEndpoint) == null ? void 0 : _b.continuationCommand) == null ? void 0 : _c.token;
    return continuationToken;
  }
  static getVideo(html) {
    var _a, _b, _c, _d, _e, _f, _g, _h;
    let data, nextData = {};
    try {
      const parsed = JSON.parse(html.split("var ytInitialData = ")[1].split(";</script>")[0]);
      data = parsed.contents.twoColumnWatchNextResults.results.results.contents;
      try {
        nextData = parsed.contents.twoColumnWatchNextResults.secondaryResults.secondaryResults.results;
      } catch (e) {
      }
    } catch (e) {
      throw new Error("Could not parse video metadata!");
    }
    const raw = {
      primary: ((_a = data == null ? void 0 : data.find((section) => "videoPrimaryInfoRenderer" in section)) == null ? void 0 : _a.videoPrimaryInfoRenderer) || {},
      secondary: ((_b = data == null ? void 0 : data.find((section) => "videoSecondaryInfoRenderer" in section)) == null ? void 0 : _b.videoSecondaryInfoRenderer) || {}
    };
    let info;
    try {
      info = JSON.parse(html.split("var ytInitialPlayerResponse = ")[1].split(";</script>")[0]);
    } catch (e) {
      info = JSON.parse(html.split("var ytInitialPlayerResponse = ")[1].split(";var")[0]);
    }
    if (!(info == null ? void 0 : info.videoDetails))
      return null;
    info = __spreadProps(__spreadValues(__spreadValues({}, raw.primary), raw.secondary), {
      info
    });
    let musicInfo = [];
    try {
      const jsonData = html.split('{"horizontalCardListRenderer":')[1].split(',{"reelShelfRenderer"')[0];
      musicInfo = JSON.parse('{"horizontalCardListRenderer":' + jsonData).horizontalCardListRenderer.cards.map((val) => {
        return {
          title: val.videoAttributeViewModel.title,
          cover: val.videoAttributeViewModel.image.sources[0].url,
          artist: val.videoAttributeViewModel.subtitle,
          album: val.videoAttributeViewModel.secondarySubtitle.content
        };
      });
    } catch (e) {
      musicInfo = [];
    }
    const payload = new Video({
      id: info.info.videoDetails.videoId,
      title: info.info.videoDetails.title,
      views: parseInt(info.info.videoDetails.viewCount) || 0,
      tags: info.info.videoDetails.keywords,
      private: info.info.videoDetails.isPrivate,
      unlisted: !!((_d = (_c = info.info.microformat) == null ? void 0 : _c.playerMicroformatRenderer) == null ? void 0 : _d.isUnlisted),
      nsfw: ((_f = (_e = info.info.microformat) == null ? void 0 : _e.playerMicroformatRenderer) == null ? void 0 : _f.isFamilySafe) === false,
      live: info.info.videoDetails.isLiveContent,
      duration: parseInt(info.info.videoDetails.lengthSeconds) * 1e3,
      shorts: [`{"webCommandMetadata":{"url":"/shorts/${info.info.videoDetails.videoId}"`, `{window['ytPageType'] = "shorts";`, `"/hashtag/shorts"`].some((r) => html.includes(r)),
      duration_raw: _Util.durationString(_Util.parseMS(parseInt(info.info.videoDetails.lengthSeconds) * 1e3 || 0)),
      channel: {
        name: info.info.videoDetails.author,
        id: info.info.videoDetails.channelId,
        url: `https://www.youtube.com${info.owner.videoOwnerRenderer.title.runs[0].navigationEndpoint.browseEndpoint.canonicalBaseUrl}`,
        icon: info.owner.videoOwnerRenderer.thumbnail.thumbnails[0],
        subscribers: (_h = (_g = info.owner.videoOwnerRenderer.subscriberCountText) == null ? void 0 : _g.simpleText) == null ? void 0 : _h.replace(" subscribers", "")
      },
      description: info.info.videoDetails.shortDescription,
      thumbnail: __spreadProps(__spreadValues({}, info.info.videoDetails.thumbnail.thumbnails[info.info.videoDetails.thumbnail.thumbnails.length - 1]), {
        id: info.info.videoDetails.videoId
      }),
      uploadedAt: info.dateText.simpleText,
      ratings: {
        likes: this.getInfoLikesCount(info) || 0,
        dislikes: 0
      },
      videos: _Util.getNext(nextData != null ? nextData : {}) || [],
      streamingData: info.info.streamingData || null,
      music: musicInfo
    });
    return payload;
  }
  static getInfoLikesCount(info) {
    var _a;
    const buttons = info.videoActions.menuRenderer.topLevelButtons;
    const button = buttons.find((button2) => {
      var _a2;
      return ((_a2 = button2.toggleButtonRenderer) == null ? void 0 : _a2.defaultIcon.iconType) === "LIKE";
    });
    if (!button)
      return 0;
    return parseInt((_a = button.toggleButtonRenderer.defaultText.accessibility) == null ? void 0 : _a.accessibilityData.label.split(" ")[0].replace(/,/g, ""));
  }
  static getNext(body, home = false) {
    var _a, _b, _c, _d, _e;
    const results = [];
    if (typeof body[Symbol.iterator] !== "function")
      return results;
    for (const result of body) {
      const details = home ? result : result.compactVideoRenderer;
      if (details) {
        try {
          let viewCount = details.viewCountText.simpleText;
          viewCount = (/^\d/.test(viewCount) ? viewCount : "0").split(" ")[0];
          results.push(
            new Video({
              id: details.videoId,
              title: (_b = details.title.simpleText) != null ? _b : (_a = details.title.runs[0]) == null ? void 0 : _a.text,
              views: parseInt(viewCount.replace(/,/g, "")) || 0,
              duration_raw: (_c = details.lengthText.simpleText) != null ? _c : details.lengthText.accessibility.accessibilityData.label,
              duration: _Util.parseDuration(details.lengthText.simpleText) / 1e3,
              channel: {
                name: details.shortBylineText.runs[0].text,
                id: details.shortBylineText.runs[0].navigationEndpoint.browseEndpoint.browseId,
                url: `https://www.youtube.com${details.shortBylineText.runs[0].navigationEndpoint.browseEndpoint.canonicalBaseUrl}`,
                icon: home ? details.channelThumbnailSupportedRenderers.channelThumbnailWithLinkRenderer.thumbnail.thumbnails[0] : details.channelThumbnail.thumbnails[0],
                subscribers: "0",
                verified: Boolean(details.ownerBadges[0].metadataBadgeRenderer.tooltip === "Verified")
              },
              thumbnail: __spreadProps(__spreadValues({}, details.thumbnail.thumbnails[details.thumbnail.thumbnails.length - 1]), {
                id: details.videoId
              }),
              uploadedAt: details.publishedTimeText.simpleText,
              ratings: {
                likes: 0,
                dislikes: 0
              },
              description: (_e = (_d = details.descriptionSnippet) == null ? void 0 : _d.runs[0]) == null ? void 0 : _e.text
            })
          );
        } catch (e) {
          continue;
        }
      }
    }
    return results;
  }
  static getMix(html) {
    var _a, _b;
    let data = null;
    try {
      const parsed = JSON.parse(html.split("var ytInitialData = ")[1].split(";</script>")[0]);
      data = parsed.contents.twoColumnWatchNextResults.playlist.playlist;
    } catch (e) {
    }
    if (!data)
      return null;
    const videos = data.contents.map((m) => {
      const t = m.playlistPanelVideoRenderer;
      return new Video({
        id: t.videoId,
        title: t.title.simpleText,
        thumbnail: {
          id: t.videoId,
          url: t.thumbnail.thumbnails[t.thumbnail.thumbnails.length - 1].url,
          height: t.thumbnail.thumbnails[t.thumbnail.thumbnails.length - 1].height,
          width: t.thumbnail.thumbnails[t.thumbnail.thumbnails.length - 1].width
        },
        duration: _Util.parseDuration(t.lengthText.simpleText),
        duration_raw: t.lengthText.simpleText,
        channel: {
          name: t.shortBylineText.runs[0].text,
          id: t.shortBylineText.runs[0].navigationEndpoint.browseEndpoint.browseId,
          url: `https://www.youtube.com${t.shortBylineText.runs[0].navigationEndpoint.browseEndpoint.canonicalBaseUrl}`,
          icon: null
        }
      });
    });
    const list = new Playlist(
      {
        id: data.playlistId,
        title: data.title,
        videoCount: data.contents.length,
        videos,
        link: data.playlistShareUrl,
        url: data.playlistShareUrl,
        thumbnail: ((_b = (_a = videos[0]) == null ? void 0 : _a.thumbnail) == null ? void 0 : _b.toJSON()) || null,
        channel: {
          name: data.ownerName.simpleText
        },
        mix: true
      },
      true
    );
    return list;
  }
  static parseHomepage(html) {
    let contents;
    try {
      contents = html.split("var ytInitialData = ")[1].split(";</script>")[0];
      contents = JSON.parse(contents).contents.twoColumnBrowseResultsRenderer.tabs[0].tabRenderer.content.richGridRenderer.contents;
    } catch (e) {
      return [];
    }
    if (!contents || !contents.length || !contents.find((x) => Object.keys(x)[0] === "richItemRenderer"))
      return [];
    contents = contents.filter((a) => Object.keys(a)[0] === "richItemRenderer").map((m) => m.richItemRenderer.content.videoRenderer);
    return _Util.getNext(contents, true);
  }
  static getPlaylistURL(url) {
    if (typeof url !== "string")
      return null;
    const group = PLAYLIST_ID.exec(url) || ALBUM_REGEX.exec(url);
    if (!group)
      return null;
    if (group[0].startsWith("RD") && !ALBUM_REGEX.exec(group[0]))
      return { url, mix: true };
    const finalURL = `https://www.youtube.com/playlist?list=${group[0]}`;
    return { url: finalURL, mix: false };
  }
  static validatePlaylist(url) {
    if (typeof url === "string" && (url.match(PLAYLIST_ID) !== null || url.match(ALBUM_REGEX) !== null))
      return;
    throw new Error("Invalid playlist url");
  }
  static filter(ftype) {
    switch (ftype) {
      case "playlist":
        return "EgIQAw%253D%253D";
      case "video":
        return "EgIQAQ%253D%253D";
      case "channel":
        return "EgIQAg%253D%253D";
      case "film":
        return "EgIQBA%253D%253D";
      default:
        throw new TypeError(`Invalid filter type "${ftype}"!`);
    }
  }
  static parseMS(milliseconds) {
    return {
      days: Math.trunc(milliseconds / 864e5),
      hours: Math.trunc(milliseconds / 36e5) % 24,
      minutes: Math.trunc(milliseconds / 6e4) % 60,
      seconds: Math.trunc(milliseconds / 1e3) % 60
    };
  }
  static durationString(data) {
    const items = Object.keys(data);
    const required = ["days", "hours", "minutes", "seconds"];
    const parsed = items.filter((x) => required.includes(x)).map((m) => data[m] > 0 ? data[m] : "");
    const final = parsed.slice(parsed.findIndex((x) => !!x)).map((x, i) => i == 0 ? x.toString() : x.toString().padStart(2, "0")).join(":");
    return final.length <= 3 ? `0:${final.padStart(2, "0") || 0}` : final;
  }
  static json(data) {
    try {
      return JSON.parse(data);
    } catch (e) {
      return null;
    }
  }
  static makeRequest() {
    return __async(this, arguments, function* (url = "", data = { data: {}, requestOptions: {} }) {
      const key = yield _Util.innertubeKey();
      const res = yield _Util.getHTML(`https://youtube.com/youtubei/v1${url}?key=${key}`, __spreadValues({
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Host: "www.youtube.com",
          Referer: "https://www.youtube.com"
        },
        body: JSON.stringify(__spreadValues({
          context: __spreadValues({
            client: __spreadValues({
              utcOffsetMinutes: 0,
              gl: "US",
              hl: "en",
              clientName: "WEB",
              clientVersion: "1.20220406.00.00",
              originalUrl: "https://www.youtube.com/"
            }, data.clientCtx || {})
          }, data.ctx || {})
        }, data.data || {}))
      }, data.requestOptions || {}));
      return _Util.json(res);
    });
  }
};
__name(_Util, "Util");
var Util = _Util;
var Util_default = Util;

// src/mod.ts
var SAFE_SEARCH_COOKIE = "PREF=f2=8000000";
var TrendingFilter = {
  MUSIC: "4gINGgt5dG1hX2NoYXJ0cw%3D%3D",
  GAMING: "4gIcGhpnYW1pbmdfY29ycHVzX21vc3RfcG9wdWxhcg%3D%3D",
  MOVIES: "4gIKGgh0cmFpbGVycw%3D%3D"
};
var _YouTube = class _YouTube {
  constructor() {
    return _YouTube;
  }
  static search(query, options) {
    return __async(this, null, function* () {
      if (!options)
        options = { limit: 100, type: "video", requestOptions: {} };
      if (!query || typeof query !== "string")
        throw new Error(`Invalid search query "${query}"!`);
      options.type = options.type || "video";
      const requestOptions = options.safeSearch ? __spreadProps(__spreadValues({}, options.requestOptions), { headers: { cookie: SAFE_SEARCH_COOKIE } }) : {};
      try {
        const filter = options.type === "all" ? null : Util_default.filter(options.type);
        const res = yield Util_default.makeRequest("/search", {
          data: {
            params: filter,
            query
          },
          clientCtx: {
            originalUrl: `https://youtube.com/results?search_query=${encodeURIComponent(query.trim()).replace(/%20/g, "+")}${filter}`
          },
          requestOptions
        });
        return Formatter.formatSearchResult(res.contents.twoColumnSearchResultsRenderer.primaryContents.sectionListRenderer.contents[0].itemSectionRenderer.contents, options);
      } catch (e) {
        const filter = options.type === "all" ? "" : `&sp=${Util_default.filter(options.type)}`;
        const url = `https://youtube.com/results?search_query=${encodeURIComponent(query.trim()).replace(/%20/g, "+")}&hl=en${filter}`;
        const html = yield Util_default.getHTML(url, requestOptions);
        return Util_default.parseSearchResult(html, options);
      }
    });
  }
  static searchOne(query, type, safeSearch, requestOptions) {
    if (!type)
      type = "video";
    return new Promise((resolve) => {
      _YouTube.search(query, { limit: 1, type, requestOptions, safeSearch: Boolean(safeSearch) }).then((res) => {
        if (!res || !res.length)
          return resolve(null);
        resolve(res[0]);
      }).catch(() => {
        resolve(null);
      });
    });
  }
  /**
   * Returns playlist details
   * @param {string} url Playlist URL
   * @param {object} [options] Options
   * @param {number} [options.limit=100] Playlist video limit
   * @param {RequestInit} [options.requestOptions] Request Options
   */
  static getPlaylist(url, options) {
    return __async(this, null, function* () {
      var _a;
      if (!options)
        options = { limit: 100, requestOptions: {}, fetchAll: false };
      if (!url || typeof url !== "string")
        throw new Error(`Expected playlist url, received ${typeof url}!`);
      Util_default.validatePlaylist(url);
      const resolved = Util_default.getPlaylistURL(url);
      if (!resolved)
        return null;
      url = resolved.url;
      const html = yield Util_default.getHTML(`${url}&hl=en`, options && options.requestOptions);
      const res = resolved.mix ? Util_default.getMix(html) : Util_default.getPlaylist(html, options && options.limit);
      try {
        if (!res && resolved.mix) {
          const videoId = new URL(url).searchParams.get("v");
          if (videoId) {
            const vid = yield _YouTube.getVideo(`https://www.youtube.com/watch?v=${videoId}`).catch(() => null);
            if (vid) {
              return new Playlist(
                {
                  id: vid.id,
                  title: `Mix - ${vid.title}`,
                  videoCount: 1,
                  lastUpdate: null,
                  views: vid.views,
                  url: `https://www.youtube.com/watch?v=${vid.id}`,
                  link: `https://www.youtube.com/watch?v=${vid.id}`,
                  channel: {
                    name: "youtube-sr"
                  },
                  thumbnail: ((_a = vid.thumbnail) == null ? void 0 : _a.toJSON()) || null,
                  videos: [vid],
                  mix: true,
                  fake: true
                },
                true
              );
            }
          }
        }
      } catch (e) {
      }
      if (res && res instanceof Playlist && options.fetchAll) {
        return yield res.fetch(options && options.limit).catch(() => res);
      }
      return res;
    });
  }
  /**
   * Returns basic video info
   * @param url Video url to parse
   * @param requestOptions Request options
   */
  static getVideo(url, requestOptions) {
    return __async(this, null, function* () {
      if (!url)
        throw new Error("Missing video url");
      if (url instanceof Video)
        url = url.url;
      const isValid = _YouTube.validate(url, "VIDEO");
      if (!isValid)
        throw new Error("Invalid video url");
      const html = yield Util_default.getHTML(`${url}&hl=en`, requestOptions);
      return Util_default.getVideo(html);
    });
  }
  /**
   * Fetches homepage videos
   */
  static homepage() {
    return __async(this, null, function* () {
      const html = yield Util_default.getHTML("https://www.youtube.com?hl=en");
      return Util_default.parseHomepage(html);
    });
  }
  /**
   * Attempts to parse `INNERTUBE_API_KEY`
   */
  static fetchInnerTubeKey() {
    return __async(this, null, function* () {
      return Util_default.fetchInnerTubeKey();
    });
  }
  static trending(options) {
    return __async(this, null, function* () {
      var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
      const type = TrendingFilter[options == null ? void 0 : options.type];
      const html = yield Util_default.getHTML(`https://www.youtube.com/feed/trending?${type ? "bp=" + type + "&hl=en" : "hl=en"}`);
      let json;
      try {
        json = JSON.parse(html.split("var ytInitialData =")[1].split(";</script>")[0]);
      } catch (e) {
        return [];
      }
      const content = (_k = (_j = (_i = (_h = (_g = (_f = (_e = (_d = (_c = (_b = (_a = json.contents) == null ? void 0 : _a.twoColumnBrowseResultsRenderer) == null ? void 0 : _b.tabs[0].tabRenderer) == null ? void 0 : _c.content) == null ? void 0 : _d.sectionListRenderer) == null ? void 0 : _e.contents[1]) == null ? void 0 : _f.itemSectionRenderer) == null ? void 0 : _g.contents[0]) == null ? void 0 : _h.shelfRenderer) == null ? void 0 : _i.content) == null ? void 0 : _j.expandedShelfContentsRenderer) == null ? void 0 : _k.items;
      if (!content || !Array.isArray(content))
        return [];
      const res = [];
      for (const item of content.map((m) => m.videoRenderer)) {
        res.push(
          new Video({
            title: item.title.runs[0].text,
            id: item.videoId,
            url: `https://www.youtube.com/watch?v=${item.videoId}`,
            description: (_m = (_l = item.descriptionSnippet) == null ? void 0 : _l.runs[0]) == null ? void 0 : _m.text,
            duration: Util_default.parseDuration(item.lengthText.simpleText) / 1e3 || 0,
            duration_raw: item.lengthText.simpleText,
            shorts: (_n = item.thumbnailOverlays) == null ? void 0 : _n.some((res2) => {
              var _a2;
              return ((_a2 = res2.thumbnailOverlayTimeStatusRenderer) == null ? void 0 : _a2.style) === "SHORTS";
            }),
            thumbnail: {
              id: item.videoId,
              url: item.thumbnail.thumbnails[item.thumbnail.thumbnails.length - 1].url,
              height: item.thumbnail.thumbnails[item.thumbnail.thumbnails.length - 1].height,
              width: item.thumbnail.thumbnails[item.thumbnail.thumbnails.length - 1].width
            },
            channel: {
              id: item.ownerText.runs[0].navigationEndpoint.browseEndpoint.browseId,
              name: item.ownerText.runs[0].text,
              url: `https://www.youtube.com${item.ownerText.runs[0].navigationEndpoint.browseEndpoint.canonicalBaseUrl}`,
              icon: {
                url: null,
                width: 0,
                height: 0
              },
              verified: item.ownerBadges ? item.ownerBadges[0].metadataBadgeRenderer.tooltip === "Verified" : false
            },
            uploadedAt: item.publishedTimeText.simpleText,
            views: item.viewCountText.simpleText.replace(/[^0-9]/g, "") || 0
          })
        );
      }
      return res;
    });
  }
  static getSuggestions(query) {
    return __async(this, null, function* () {
      if (!query)
        throw new Error("Search query was not provided!");
      try {
        const res = yield Util_default.getHTML(`https://suggestqueries-clients6.youtube.com/complete/search?client=youtube&gs_ri=youtube&ds=yt&q=${encodeURIComponent(query)}`);
        const partition = res.split("window.google.ac.h(")[1];
        const data = Util_default.json(partition.slice(0, partition.length - 1));
        return data[1].map((m) => m[0]);
      } catch (e) {
        const res = yield Util_default.getHTML(`https://clients1.google.com/complete/search?client=youtube&gs_ri=youtube&ds=yt&q=${encodeURIComponent(query)}`);
        const searchSuggestions = [];
        res.split("[").forEach((ele, index) => {
          if (!ele.split('"')[1] || index === 1)
            return;
          return searchSuggestions.push(ele.split('"')[1]);
        });
        searchSuggestions.pop();
        return searchSuggestions;
      }
    });
  }
  /**
   * Validates playlist
   * @param {string} url Playlist id or url/video id or url to validate
   * @param {"VIDEO"|"VIDEO_ID"|"PLAYLIST"|"PLAYLIST_ID"} type URL validation type
   * @returns {boolean}
   */
  static validate(url, type) {
    if (typeof url !== "string")
      return false;
    if (!type)
      type = "PLAYLIST";
    switch (type) {
      case "PLAYLIST":
        return _YouTube.Regex.PLAYLIST_URL.test(url);
      case "PLAYLIST_ID":
        return _YouTube.Regex.PLAYLIST_ID.test(url) || _YouTube.Regex.ALBUM.test(url);
      case "VIDEO":
        return _YouTube.Regex.VIDEO_URL.test(url);
      case "VIDEO_ID":
        return _YouTube.Regex.VIDEO_ID.test(url);
      default:
        return false;
    }
  }
  static isPlaylist(src) {
    try {
      Util_default.validatePlaylist(src);
      return true;
    } catch (e) {
      return false;
    }
  }
  static get Regex() {
    return {
      PLAYLIST_URL: Util_default.PlaylistURLRegex,
      PLAYLIST_ID: Util_default.PlaylistIDRegex,
      ALBUM: Util_default.AlbumRegex,
      VIDEO_ID: Util_default.VideoIDRegex,
      VIDEO_URL: Util_default.VideoRegex
    };
  }
};
__name(_YouTube, "YouTube");
var YouTube = _YouTube;
var mod_default = YouTube;
export {
  Channel,
  Formatter,
  Playlist,
  SAFE_SEARCH_COOKIE,
  Thumbnail,
  TrendingFilter,
  Util_default as Util,
  Video,
  YouTube,
  mod_default as default
};
//# sourceMappingURL=mod.mjs.map