text: import os
  import random
  import time
  from typing import Dict, List, Optional, Union
  
  from gppt import LoginInfo
  from pixivpy3 import AppPixivAPI
  from pixivpy3.utils import JsonDict
  
  from .pixiv_types import IllustInfo
  
  
  class PixivBaseDownloader:
      def __init__(self, aapi: AppPixivAPI, login_info: LoginInfo, save_dir: str):
          self.aapi = aapi
          self.login_info = login_info
          self.save_dir = save_dir
  
      @staticmethod
      def rand_sleep(base: float = 0.1, rand: float = 2.5) -> None:
          time.sleep(base + rand * random.random())
  
      @staticmethod
      def ext_links(illust: JsonDict) -> Union[List[str], str]:
          links: List[str] = [page.image_urls.original for page in illust.meta_pages]
          link: str = illust.meta_single_page.get(
              "original_image_url", illust.image_urls.large
          )
  
          return links if links != [] else link
  
      def retrieve_works(self, target_id: int) -> List[IllustInfo]:
          urls: List[IllustInfo] = []
          next: Optional[Dict[str, str]] = {}
          while next is not None:
              if next == {}:
                  res_json = self.aapi.user_illusts(target_id, type="illust")
              else:
                  res_json = self.aapi.user_illusts(**next)  # type: ignore
              if "error" in res_json and "invalid_grant" in res_json["error"]["message"]:
                  self.aapi.auth()
                  continue
              for illust in res_json["illusts"]:
                  urls.append(
                      {
                          "id": illust.id,
                          "title": illust.title,
                          "link": self.ext_links(illust),
                      }
                  )
              next = self.aapi.parse_qs(res_json["next_url"])
              self.rand_sleep(1.5)
          else:
              return urls
  
      def download(self, data: List[IllustInfo], save_path: str) -> None:
          os.makedirs(save_path, exist_ok=True)
          data_len = len(data)
          d_width = len(str(data_len))
          for idx, image_data in enumerate(data):
              title, id_ = image_data["title"].replace("/", "／"), image_data["id"]
              links = image_data["link"]
              print(
                  f"\033[K[%0{d_width}d/%0{d_width}d]: %s (id: %d)"
                  % (idx + 1, data_len, title, id_)
              )
              self.__download(links, title, id_, save_path)
  
              print("\033[K\033[A\033[K", end="", flush=True)
  
      def __download(
          self, links: Union[str, List[str]], title: str, id_: int, save_path: str
      ) -> None:
          if type(links) is list:
              for link in links:
                  basename_: str = link.split("/")[-1]
                  fname = "{}_{}_{}".format(id_, title, basename_.split("_")[-1])
                  print("\033[K" + fname, end="\r")
                  self.aapi.download(link, path=save_path, fname=fname)
          elif type(links) is str:
              link = links
              basename_ = link.split("/")[-1]
              fname = "{}_{}_{}".format(id_, title, basename_.split("_")[-1])
              print("\033[K" + fname, end="\r")
              self.aapi.download(link, path=save_path, fname=fname)
  