declare module "tough-cookie" {
  export const version: string;

  export const PrefixSecurityEnum: Readonly<{
    DISABLED: string;
    SILENT: string;
    STRICT: string;
  }>;

  /**
   * Parse a cookie date string into a Date.
   * Parses according to RFC6265 Section 5.1.1, not Date.parse().
   */
  export function parseDate(string: string): Date;

  /**
   * Format a Date into a RFC1123 string (the RFC6265-recommended format).
   */
  export function formatDate(date: Date): string;

  /**
   * Transforms a domain-name into a canonical domain-name.
   * The canonical domain-name is a trimmed, lowercased, stripped-of-leading-dot
   * and optionally punycode-encoded domain-name (Section 5.1.2 of RFC6265).
   * For the most part, this function is idempotent (can be run again on its output without ill effects).
   */
  export function canonicalDomain(str: string): string;

  /**
   * Answers "does this real domain match the domain in a cookie?".
   * The str is the "current" domain-name and the domStr is the "cookie" domain-name.
   * Matches according to RFC6265 Section 5.1.3, but it helps to think of it as a "suffix match".
   *
   * The canonicalize parameter will run the other two parameters through canonicalDomain or not.
   */
  export function domainMatch(str: string, domStr: string, canonicalize?: boolean): boolean;

  /**
   * Given a current request/response path, gives the Path apropriate for storing in a cookie.
   * This is basically the "directory" of a "file" in the path, but is specified by Section 5.1.4 of the RFC.
   *
   * The path parameter MUST be only the pathname part of a URI (i.e. excludes the hostname, query, fragment, etc.).
   * This is the .pathname property of node's uri.parse() output.
   */
  export function defaultPath(path: string): string;

  /**
   * Answers "does the request-path path-match a given cookie-path?" as per RFC6265 Section 5.1.4.
   * Returns a boolean.
   *
   * This is essentially a prefix-match where cookiePath is a prefix of reqPath.
   */
  export function pathMatch(reqPath: string, cookiePath: string): boolean;

  /**
   * alias for Cookie.parse(cookieString[, options])
   */
  export function parse(cookieString: string, options?: Cookie.ParseOptions): Cookie | undefined;

  /**
   * alias for Cookie.fromJSON(string)
   */
  export function fromJSON(string: string): Cookie;

  export function getPublicSuffix(hostname: string): string | null;

  export function cookieCompare(a: Cookie, b: Cookie): number;

  export function permuteDomain(domain: string, allowSpecialUseDomain?: boolean): string[];

  export function permutePath(path: string): string[];

  export class Cookie {
    static parse(cookieString: string, options?: Cookie.ParseOptions): Cookie | undefined;

    static fromJSON(strOrObj: string | object): Cookie | null;

    constructor(properties?: Cookie.Properties);

    key: string;
    value: string;
    expires: Date | "Infinity";
    maxAge: number | "Infinity" | "-Infinity";
    domain: string | null;
    path: string | null;
    secure: boolean;
    httpOnly: boolean;
    extensions: string[] | null;
    creation: Date | null;
    creationIndex: number;

    hostOnly: boolean | null;
    pathIsDefault: boolean | null;
    lastAccessed: Date | null;
    sameSite: string;

    toString(): string;

    cookieString(): string;

    setExpires(exp: Date | string): void;

    setMaxAge(number: number): void;

    expiryTime(now?: number): number;

    expiryDate(now?: number): Date;

    TTL(now?: Date): number | typeof Infinity;

    isPersistent(): boolean;

    canonicalizedDomain(): string | null;

    cdomain(): string | null;

    inspect(): string;

    toJSON(): { [key: string]: any };

    clone(): Cookie;

    validate(): boolean | string;
  }

  export namespace Cookie {
    interface ParseOptions {
      loose?: boolean | undefined;
    }

    interface Properties {
      key?: string | undefined;
      value?: string | undefined;
      expires?: Date | "Infinity" | undefined;
      maxAge?: number | "Infinity" | "-Infinity" | undefined;
      domain?: string | undefined;
      path?: string | undefined;
      secure?: boolean | undefined;
      httpOnly?: boolean | undefined;
      extensions?: string[] | undefined;
      creation?: Date | undefined;
      creationIndex?: number | undefined;

      hostOnly?: boolean | undefined;
      pathIsDefault?: boolean | undefined;
      lastAccessed?: Date | undefined;
      sameSite?: string | undefined;
    }

    interface Serialized {
      [key: string]: any;
    }
  }

  export class CookieJar {
    static deserialize(serialized: CookieJar.Serialized | string, store?: Store): Promise<CookieJar>;
    static deserialize(
      serialized: CookieJar.Serialized | string,
      store: Store,
      cb: (err: Error | null, object: CookieJar) => void,
    ): void;
    static deserialize(
      serialized: CookieJar.Serialized | string,
      cb: (err: Error | null, object: CookieJar) => void,
    ): void;

    static deserializeSync(serialized: CookieJar.Serialized | string, store?: Store): CookieJar;

    static fromJSON(string: string): CookieJar;

    constructor(store?: Store, options?: CookieJar.Options);

    setCookie(
      cookieOrString: Cookie | string,
      currentUrl: string,
      options?: CookieJar.SetCookieOptions,
    ): Promise<Cookie>;
    setCookie(
      cookieOrString: Cookie | string,
      currentUrl: string,
      options: CookieJar.SetCookieOptions,
      cb: (err: Error | null, cookie: Cookie) => void,
    ): void;
    setCookie(
      cookieOrString: Cookie | string,
      currentUrl: string,
      cb: (err: Error | null, cookie: Cookie) => void,
    ): void;

    setCookieSync(cookieOrString: Cookie | string, currentUrl: string, options?: CookieJar.SetCookieOptions): Cookie;

    getCookies(currentUrl: string, options?: CookieJar.GetCookiesOptions): Promise<Cookie[]>;
    getCookies(
      currentUrl: string,
      options: CookieJar.GetCookiesOptions,
      cb: (err: Error | null, cookies: Cookie[]) => void,
    ): void;
    getCookies(currentUrl: string, cb: (err: Error | null, cookies: Cookie[]) => void): void;

    getCookiesSync(currentUrl: string, options?: CookieJar.GetCookiesOptions): Cookie[];

    getCookieString(currentUrl: string, options?: CookieJar.GetCookiesOptions): Promise<string>;
    getCookieString(
      currentUrl: string,
      options: CookieJar.GetCookiesOptions,
      cb: (err: Error | null, cookies: string) => void,
    ): void;
    getCookieString(currentUrl: string, cb: (err: Error | null, cookies: string) => void): void;

    getCookieStringSync(currentUrl: string, options?: CookieJar.GetCookiesOptions): string;

    getSetCookieStrings(currentUrl: string, options?: CookieJar.GetCookiesOptions): Promise<string[]>;
    getSetCookieStrings(
      currentUrl: string,
      options: CookieJar.GetCookiesOptions,
      cb: (err: Error | null, cookies: string[]) => void,
    ): void;
    getSetCookieStrings(currentUrl: string, cb: (err: Error | null, cookies: string[]) => void): void;

    getSetCookieStringsSync(currentUrl: string, options?: CookieJar.GetCookiesOptions): string[];

    serialize(): Promise<CookieJar.Serialized>;
    serialize(cb: (err: Error | null, serializedObject: CookieJar.Serialized) => void): void;

    serializeSync(): CookieJar.Serialized;

    toJSON(): CookieJar.Serialized;

    clone(store?: Store): Promise<CookieJar>;
    clone(store: Store, cb: (err: Error | null, newJar: CookieJar) => void): void;
    clone(cb: (err: Error | null, newJar: CookieJar) => void): void;

    cloneSync(store?: Store): CookieJar;

    removeAllCookies(): Promise<void>;
    removeAllCookies(cb: (err: Error | null) => void): void;

    removeAllCookiesSync(): void;
  }

  export namespace CookieJar {
    interface Options {
      allowSpecialUseDomain?: boolean | undefined;
      looseMode?: boolean | undefined;
      rejectPublicSuffixes?: boolean | undefined;
      prefixSecurity?: string | undefined;
    }

    interface SetCookieOptions {
      http?: boolean | undefined;
      secure?: boolean | undefined;
      now?: Date | undefined;
      ignoreError?: boolean | undefined;
    }

    interface GetCookiesOptions {
      http?: boolean | undefined;
      secure?: boolean | undefined;
      now?: Date | undefined;
      expire?: boolean | undefined;
      allPaths?: boolean | undefined;
    }

    interface Serialized {
      version: string;
      storeType: string;
      rejectPublicSuffixes: boolean;
      cookies: Cookie.Serialized[];
    }
  }

  export abstract class Store {
    synchronous: boolean;

    findCookie(domain: string, path: string, key: string, cb: (err: Error | null, cookie: Cookie | null) => void): void;

    findCookies(
      domain: string,
      path: string,
      allowSpecialUseDomain: boolean,
      cb: (err: Error | null, cookie: Cookie[]) => void,
    ): void;

    putCookie(cookie: Cookie, cb: (err: Error | null) => void): void;

    updateCookie(oldCookie: Cookie, newCookie: Cookie, cb: (err: Error | null) => void): void;

    removeCookie(domain: string, path: string, key: string, cb: (err: Error | null) => void): void;

    removeCookies(domain: string, path: string, cb: (err: Error | null) => void): void;

    getAllCookies(cb: (err: Error | null, cookie: Cookie[]) => void): void;
  }

  export class MemoryCookieStore extends Store {
    findCookie(domain: string, path: string, key: string, cb: (err: Error | null, cookie: Cookie | null) => void): void;
    findCookie(domain: string, path: string, key: string): Promise<Cookie | null>;

    findCookies(
      domain: string,
      path: string,
      allowSpecialUseDomain: boolean,
      cb: (err: Error | null, cookie: Cookie[]) => void,
    ): void;
    findCookies(domain: string, path: string, cb: (err: Error | null, cookie: Cookie[]) => void): void;
    findCookies(domain: string, path: string, allowSpecialUseDomain?: boolean): Promise<Cookie[]>;

    putCookie(cookie: Cookie, cb: (err: Error | null) => void): void;
    putCookie(cookie: Cookie): Promise<void>;

    updateCookie(oldCookie: Cookie, newCookie: Cookie, cb: (err: Error | null) => void): void;
    updateCookie(oldCookie: Cookie, newCookie: Cookie): Promise<void>;

    removeCookie(domain: string, path: string, key: string, cb: (err: Error | null) => void): void;
    removeCookie(domain: string, path: string, key: string): Promise<void>;

    removeCookies(domain: string, path: string, cb: (err: Error | null) => void): void;
    removeCookies(domain: string, path: string): Promise<void>;

    getAllCookies(cb: (err: Error | null, cookie: Cookie[]) => void): void;
    getAllCookies(): Promise<Cookie[]>;
  }
}

declare module "@distube/ytdl-core" {
  import { Dispatcher, ProxyAgent, request } from "undici";
  import { Cookie as CK, CookieJar } from "tough-cookie";
  import { CookieAgent } from "http-cookie-agent/undici";
  import { Readable } from "stream";

  namespace ytdl {
    type Filter =
      | "audioandvideo"
      | "videoandaudio"
      | "video"
      | "videoonly"
      | "audio"
      | "audioonly"
      | ((format: videoFormat) => boolean);

    interface Agent {
      dispatcher: Dispatcher;
      jar: CookieJar;
      localAddress?: string;
    }

    interface getInfoOptions {
      lang?: string;
      requestCallback?: () => {};
      rewriteRequest?: (
        url: string,
        requestOptions: Parameters<typeof request>[1],
      ) => { url: string; requestOptions: Parameters<typeof request>[1] };
      fetch?: (url: string, requestOptions: Parameters<typeof request>[1]) => Promise<Response>;
      requestOptions?: Parameters<typeof request>[1];
      agent?: Agent;
      playerClients?: Array<"WEB_EMBEDDED" | "TV" | "IOS" | "ANDROID" | "WEB">;
    }

    interface chooseFormatOptions {
      quality?:
        | "lowest"
        | "highest"
        | "highestaudio"
        | "lowestaudio"
        | "highestvideo"
        | "lowestvideo"
        | (string & {})
        | number
        | string[]
        | number[];
      filter?: Filter;
      format?: videoFormat;
    }

    interface downloadOptions extends getInfoOptions, chooseFormatOptions {
      range?: {
        start?: number;
        end?: number;
      };
      begin?: string | number | Date;
      liveBuffer?: number;
      highWaterMark?: number;
      IPv6Block?: string;
      dlChunkSize?: number;
    }

    interface videoFormat {
      itag: number;
      url: string;
      mimeType?: string;
      bitrate?: number;
      audioBitrate?: number;
      width?: number;
      height?: number;
      initRange?: { start: string; end: string };
      indexRange?: { start: string; end: string };
      lastModified: string;
      contentLength: string;
      quality: "tiny" | "small" | "medium" | "large" | "hd720" | "hd1080" | "hd1440" | "hd2160" | "highres" | string;
      qualityLabel:
        | "144p"
        | "144p 15fps"
        | "144p60 HDR"
        | "240p"
        | "240p60 HDR"
        | "270p"
        | "360p"
        | "360p60 HDR"
        | "480p"
        | "480p60 HDR"
        | "720p"
        | "720p60"
        | "720p60 HDR"
        | "1080p"
        | "1080p60"
        | "1080p60 HDR"
        | "1440p"
        | "1440p60"
        | "1440p60 HDR"
        | "2160p"
        | "2160p60"
        | "2160p60 HDR"
        | "4320p"
        | "4320p60";
      projectionType?: "RECTANGULAR";
      fps?: number;
      averageBitrate?: number;
      audioQuality?: "AUDIO_QUALITY_LOW" | "AUDIO_QUALITY_MEDIUM";
      colorInfo?: {
        primaries: string;
        transferCharacteristics: string;
        matrixCoefficients: string;
      };
      highReplication?: boolean;
      approxDurationMs?: string;
      targetDurationSec?: number;
      maxDvrDurationSec?: number;
      audioSampleRate?: string;
      audioChannels?: number;

      // Added by ytdl-core
      container: "flv" | "3gp" | "mp4" | "webm" | "ts";
      hasVideo: boolean;
      hasAudio: boolean;
      codecs: string;
      videoCodec?: string;
      audioCodec?: string;

      isLive: boolean;
      isHLS: boolean;
      isDashMPD: boolean;
    }

    interface thumbnail {
      url: string;
      width: number;
      height: number;
    }

    interface captionTrack {
      baseUrl: string;
      name: {
        simpleText:
          | "Afrikaans"
          | "Albanian"
          | "Amharic"
          | "Arabic"
          | "Armenian"
          | "Azerbaijani"
          | "Bangla"
          | "Basque"
          | "Belarusian"
          | "Bosnian"
          | "Bulgarian"
          | "Burmese"
          | "Catalan"
          | "Cebuano"
          | "Chinese (Simplified)"
          | "Chinese (Traditional)"
          | "Corsican"
          | "Croatian"
          | "Czech"
          | "Danish"
          | "Dutch"
          | "English"
          | "English (auto-generated)"
          | "Esperanto"
          | "Estonian"
          | "Filipino"
          | "Finnish"
          | "French"
          | "Galician"
          | "Georgian"
          | "German"
          | "Greek"
          | "Gujarati"
          | "Haitian Creole"
          | "Hausa"
          | "Hawaiian"
          | "Hebrew"
          | "Hindi"
          | "Hmong"
          | "Hungarian"
          | "Icelandic"
          | "Igbo"
          | "Indonesian"
          | "Irish"
          | "Italian"
          | "Japanese"
          | "Javanese"
          | "Kannada"
          | "Kazakh"
          | "Khmer"
          | "Korean"
          | "Kurdish"
          | "Kyrgyz"
          | "Lao"
          | "Latin"
          | "Latvian"
          | "Lithuanian"
          | "Luxembourgish"
          | "Macedonian"
          | "Malagasy"
          | "Malay"
          | "Malayalam"
          | "Maltese"
          | "Maori"
          | "Marathi"
          | "Mongolian"
          | "Nepali"
          | "Norwegian"
          | "Nyanja"
          | "Pashto"
          | "Persian"
          | "Polish"
          | "Portuguese"
          | "Punjabi"
          | "Romanian"
          | "Russian"
          | "Samoan"
          | "Scottish Gaelic"
          | "Serbian"
          | "Shona"
          | "Sindhi"
          | "Sinhala"
          | "Slovak"
          | "Slovenian"
          | "Somali"
          | "Southern Sotho"
          | "Spanish"
          | "Spanish (Spain)"
          | "Sundanese"
          | "Swahili"
          | "Swedish"
          | "Tajik"
          | "Tamil"
          | "Telugu"
          | "Thai"
          | "Turkish"
          | "Ukrainian"
          | "Urdu"
          | "Uzbek"
          | "Vietnamese"
          | "Welsh"
          | "Western Frisian"
          | "Xhosa"
          | "Yiddish"
          | "Yoruba"
          | "Zulu"
          | string;
      };
      vssId: string;
      languageCode:
        | "af"
        | "sq"
        | "am"
        | "ar"
        | "hy"
        | "az"
        | "bn"
        | "eu"
        | "be"
        | "bs"
        | "bg"
        | "my"
        | "ca"
        | "ceb"
        | "zh-Hans"
        | "zh-Hant"
        | "co"
        | "hr"
        | "cs"
        | "da"
        | "nl"
        | "en"
        | "eo"
        | "et"
        | "fil"
        | "fi"
        | "fr"
        | "gl"
        | "ka"
        | "de"
        | "el"
        | "gu"
        | "ht"
        | "ha"
        | "haw"
        | "iw"
        | "hi"
        | "hmn"
        | "hu"
        | "is"
        | "ig"
        | "id"
        | "ga"
        | "it"
        | "ja"
        | "jv"
        | "kn"
        | "kk"
        | "km"
        | "ko"
        | "ku"
        | "ky"
        | "lo"
        | "la"
        | "lv"
        | "lt"
        | "lb"
        | "mk"
        | "mg"
        | "ms"
        | "ml"
        | "mt"
        | "mi"
        | "mr"
        | "mn"
        | "ne"
        | "no"
        | "ny"
        | "ps"
        | "fa"
        | "pl"
        | "pt"
        | "pa"
        | "ro"
        | "ru"
        | "sm"
        | "gd"
        | "sr"
        | "sn"
        | "sd"
        | "si"
        | "sk"
        | "sl"
        | "so"
        | "st"
        | "es"
        | "su"
        | "sw"
        | "sv"
        | "tg"
        | "ta"
        | "te"
        | "th"
        | "tr"
        | "uk"
        | "ur"
        | "uz"
        | "vi"
        | "cy"
        | "fy"
        | "xh"
        | "yi"
        | "yo"
        | "zu"
        | string;
      kind: string;
      rtl?: boolean;
      isTranslatable: boolean;
    }

    interface audioTrack {
      captionTrackIndices: number[];
    }

    interface translationLanguage {
      languageCode: captionTrack["languageCode"];
      languageName: captionTrack["name"];
    }

    interface VideoDetails {
      videoId: string;
      title: string;
      shortDescription: string;
      lengthSeconds: string;
      keywords?: string[];
      channelId: string;
      isOwnerViewing: boolean;
      isCrawlable: boolean;
      thumbnails: thumbnail[];
      averageRating: number;
      allowRatings: boolean;
      viewCount: string;
      author: string;
      isPrivate: boolean;
      isUnpluggedCorpus: boolean;
      isLiveContent: boolean;
      isLive: boolean;
    }

    interface Media {
      category: string;
      category_url: string;
      game?: string;
      game_url?: string;
      year?: number;
      song?: string;
      artist?: string;
      artist_url?: string;
      writers?: string;
      licensed_by?: string;
      thumbnails: thumbnail[];
    }

    interface Author {
      id: string;
      name: string;
      avatar: string; // to remove later
      thumbnails?: thumbnail[];
      verified: boolean;
      user?: string;
      channel_url: string;
      external_channel_url?: string;
      user_url?: string;
      subscriber_count?: number;
    }

    interface MicroformatRenderer {
      thumbnail: {
        thumbnails: thumbnail[];
      };
      embed: {
        iframeUrl: string;
        flashUrl: string;
        width: number;
        height: number;
        flashSecureUrl: string;
      };
      title: {
        simpleText: string;
      };
      description: {
        simpleText: string;
      };
      lengthSeconds: string;
      ownerProfileUrl: string;
      ownerGplusProfileUrl?: string;
      externalChannelId: string;
      isFamilySafe: boolean;
      availableCountries: string[];
      isUnlisted: boolean;
      hasYpcMetadata: boolean;
      viewCount: string;
      category: string;
      publishDate: string;
      ownerChannelName: string;
      liveBroadcastDetails?: {
        isLiveNow: boolean;
        startTimestamp: string;
        endTimestamp?: string;
      };
      uploadDate: string;
    }

    interface storyboard {
      templateUrl: string;
      thumbnailWidth: number;
      thumbnailHeight: number;
      thumbnailCount: number;
      interval: number;
      columns: number;
      rows: number;
      storyboardCount: number;
    }

    interface Chapter {
      title: string;
      start_time: number;
    }

    interface MoreVideoDetails
      extends Omit<VideoDetails, "author" | "thumbnail" | "shortDescription">,
        Omit<MicroformatRenderer, "title" | "description"> {
      published: number;
      video_url: string;
      age_restricted: boolean;
      likes: number | null;
      media: Media;
      author: Author;
      thumbnails: thumbnail[];
      storyboards: storyboard[];
      chapters: Chapter[];
      description: string | null;
    }

    interface videoInfo {
      iv_load_policy?: string;
      iv_allow_in_place_switch?: string;
      iv_endscreen_url?: string;
      iv_invideo_url?: string;
      iv3_module?: string;
      rmktEnabled?: string;
      uid?: string;
      vid?: string;
      focEnabled?: string;
      baseUrl?: string;
      storyboard_spec?: string;
      serialized_ad_ux_config?: string;
      player_error_log_fraction?: string;
      sffb?: string;
      ldpj?: string;
      videostats_playback_base_url?: string;
      innertube_context_client_version?: string;
      t?: string;
      fade_in_start_milliseconds: string;
      timestamp: string;
      ad3_module: string;
      relative_loudness: string;
      allow_below_the_player_companion: string;
      eventid: string;
      token: string;
      atc: string;
      cr: string;
      apply_fade_on_midrolls: string;
      cl: string;
      fexp: string[];
      apiary_host: string;
      fade_in_duration_milliseconds: string;
      fflags: string;
      ssl: string;
      pltype: string;
      enabled_engage_types: string;
      hl: string;
      is_listed: string;
      gut_tag: string;
      apiary_host_firstparty: string;
      enablecsi: string;
      csn: string;
      status: string;
      afv_ad_tag: string;
      idpj: string;
      sfw_player_response: string;
      account_playback_token: string;
      encoded_ad_safety_reason: string;
      tag_for_children_directed: string;
      no_get_video_log: string;
      ppv_remarketing_url: string;
      fmt_list: string[][];
      ad_slots: string;
      fade_out_duration_milliseconds: string;
      instream_long: string;
      allow_html5_ads: string;
      core_dbp: string;
      ad_device: string;
      itct: string;
      root_ve_type: string;
      excluded_ads: string;
      aftv: string;
      loeid: string;
      cver: string;
      shortform: string;
      dclk: string;
      csi_page_type: string;
      ismb: string;
      gpt_migration: string;
      loudness: string;
      ad_tag: string;
      of: string;
      probe_url: string;
      vm: string;
      afv_ad_tag_restricted_to_instream: string;
      gapi_hint_params: string;
      cid: string;
      c: string;
      oid: string;
      ptchn: string;
      as_launched_in_country: string;
      avg_rating: string;
      fade_out_start_milliseconds: string;
      midroll_prefetch_size: string;
      allow_ratings: string;
      thumbnail_url: string;
      iurlsd: string;
      iurlmq: string;
      iurlhq: string;
      iurlmaxres: string;
      ad_preroll: string;
      tmi: string;
      trueview: string;
      host_language: string;
      innertube_api_key: string;
      show_content_thumbnail: string;
      afv_instream_max: string;
      innertube_api_version: string;
      mpvid: string;
      allow_embed: string;
      ucid: string;
      plid: string;
      midroll_freqcap: string;
      ad_logging_flag: string;
      ptk: string;
      vmap: string;
      watermark: string[];
      dbp: string;
      ad_flags: string;
      html5player: string;
      formats: videoFormat[];
      related_videos: relatedVideo[];
      no_embed_allowed?: boolean;
      player_response: {
        playabilityStatus: {
          status: string;
          playableInEmbed: boolean;
          miniplayer: {
            miniplayerRenderer: {
              playbackMode: string;
            };
          };
          contextParams: string;
        };
        streamingData: {
          expiresInSeconds: string;
          formats: {}[];
          adaptiveFormats: {}[];
        };
        captions?: {
          playerCaptionsRenderer: {
            baseUrl: string;
            visibility: string;
          };
          playerCaptionsTracklistRenderer: {
            captionTracks: captionTrack[];
            audioTracks: audioTrack[];
            translationLanguages: translationLanguage[];
            defaultAudioTrackIndex: number;
          };
        };
        microformat: {
          playerMicroformatRenderer: MicroformatRenderer;
        };
        videoDetails: VideoDetails;
        playerConfig: {
          audioConfig: {
            loudnessDb: number;
            perceptualLoudnessDb: number;
            enablePerFormatLoudness: boolean;
          };
          streamSelectionConfig: { maxBitrate: string };
          mediaCommonConfig: { dynamicReadaheadConfig: {}[] };
          webPlayerConfig: { webPlayerActionsPorting: {}[] };
        };
      };
      videoDetails: MoreVideoDetails;
    }

    interface relatedVideo {
      id?: string;
      title?: string;
      published?: string;
      author: Author | "string"; // to remove the `string` part later
      ucid?: string; // to remove later
      author_thumbnail?: string; // to remove later
      short_view_count_text?: string;
      view_count?: string;
      length_seconds?: number;
      video_thumbnail?: string; // to remove later
      thumbnails: thumbnail[];
      richThumbnails: thumbnail[];
      isLive: boolean;
    }

    interface Cookie {
      name: string;
      value: string;
      expirationDate?: number;
      domain?: string;
      path?: string;
      secure?: boolean;
      httpOnly?: boolean;
      hostOnly?: boolean;
      sameSite?: string;
    }

    function getBasicInfo(url: string, options?: getInfoOptions): Promise<videoInfo>;
    function getInfo(url: string, options?: getInfoOptions): Promise<videoInfo>;
    function downloadFromInfo(info: videoInfo, options?: downloadOptions): Readable;
    function chooseFormat(format: videoFormat | videoFormat[], options?: chooseFormatOptions): videoFormat | never;
    function filterFormats(formats: videoFormat | videoFormat[], filter?: Filter): videoFormat[];
    function validateID(string: string): boolean;
    function validateURL(string: string): boolean;
    function getURLVideoID(string: string): string | never;
    function getVideoID(string: string): string | never;
    function createProxyAgent(options: ProxyAgent.Options | string): Agent;
    function createProxyAgent(options: ProxyAgent.Options | string, cookies?: (Cookie | CK)[]): Agent;
    function createAgent(): Agent;
    function createAgent(cookies?: (Cookie | CK)[]): Agent;
    function createAgent(cookies?: (Cookie | CK)[], opts?: CookieAgent.Options): Agent;
    const version: number;
  }

  function ytdl(link: string, options?: ytdl.downloadOptions): Readable;

  export = ytdl;
}
