#!/usr/bin/python

import os
import functools
import sys

from contextlib import contextmanager

from yt_dlp import YoutubeDL, parse_options
from yt_dlp.utils import match_filter_func, DateRange
from yt_dlp.postprocessor import FFmpegExtractAudioPP


site = "yt"

category = ""

filter = ""

not_live = "!is_live & live_status != ?'is_upcoming'"

out_tmpl = "/mnt/hdd1/ASMR archive/{}/{}-%(id)s.%(ext)s"

ydl = YoutubeDL(parse_options([
  "--compat-options", "youtube-dl",
  "--convert-thumbnails", "jpg",
  "-cw",
  "-f", "ba",
  "-N", "8",
  "-R", "100",
  "--live-from-start",
  "--downloader", "aria2c",
# "--downloader-args", "aria2c:-j 8 -x 16 -k 1M -s 8 --file-allocation=falloc --show-console-readout false --summary-interval 0",
  "--downloader-args", "aria2c:--file-allocation=falloc --show-console-readout false --summary-interval 0",
  "--write-description",
  "--write-info-json",
  "--write-annotations",
  "--write-thumbnail",
  "--all-subs",
  "--prefer-ffmpeg",
  "--download-archive", "finished_videos",
  "--cookies", "cookies.txt",
  "-o", out_tmpl.format("dummy", "dummy"),
  "--ignore-no-formats-error",
  "--extractor-args", "youtube:player_client=default,-ios",
]).ydl_opts)

failed = []


@contextmanager
def with_opts(opts):
  saved = {key: ydl.params[key] for key in opts.keys()}
  for key, value in opts.items():
    ydl.params[key] = value
  try:
    yield
  finally:
    for key, value in saved.items():
      ydl.params[key] = value


def make_with_video_opts():
  format = "bestaudio/best"
  video_opts = {"format": format}
  video_format_selector = ydl.build_format_selector(format)
  video_pp = FFmpegExtractAudioPP(ydl, "best", "5", False)

  @contextmanager
  def with_video_opts(opts):
    with with_opts(opts):
      with with_opts(video_opts):
        saved = ydl.format_selector
        ydl.format_selector = video_format_selector
        ydl._pps["post_process"].append(video_pp)
        try:
          yield
        finally:
          ydl.format_selector = saved
          ydl._pps["post_process"].pop()

  return with_video_opts


with_video_opts = make_with_video_opts()

rplay_opts = {
  "username": os.environ["RPLAY_USER"],
  "password": os.environ["RPLAY_PASS"],
}


@contextmanager
def with_twitch_opts(opts):
  with with_opts(opts):
    with with_opts({"allsubtitles": False, "writesubtitles": False, "writeautomaticsub": False}):
      yield


@functools.lru_cache
def make_filter_func(filter):
  if filter == "":
    return None
  return match_filter_func(filter)


def make_filter(filter, ids):
  _filter = [f"{not_live}{{}}{filter}".format("" if filter == "" else " & ")]
  for id in ids:
    _filter.append(f"id = '{id}'")
  return tuple(_filter)


def category_filter(fn):
  if not category:
    return fn

  def f(info, incomplete):
    if fn:
      result = fn(info, incomplete)
      if result is not None:
        return result
    if incomplete:
      return None
    chapters = info.get("chapters", None)
    if chapters is not None and len(chapters) == 1 and \
        chapters[0]["title"] == category:
      return None
    return "does not pass filter"

  return f


def yt_dl(id, name, ids=[], **kw):
  if not id.startswith("PL"):
    id = "UU" + id[2:]
  if not isinstance(ids, list):
    ids = [ids]
  if id.startswith("UU") and len(ids) == 0 and filter == "":
    raise Exception("Nothing to download")
  print(">>>", name, flush=True)
  ydl.params["match_filter"] = make_filter_func(make_filter(filter, ids))
  ydl.params["outtmpl"]["default"] = out_tmpl.format(name, "yt")
  with with_opts(kw):
    try:
      return ydl.download([f"https://www.youtube.com/playlist?list={id}"])
    except Exception as e:
      return 1 if "YouTube said: The playlist does not exist" in str(e) else 0


def uise_dl(*_):
  print(">>> uise", flush=True)
  ydl.params["match_filter"] = make_filter_func(make_filter(filter, []))
  ydl.params["outtmpl"]["default"] = out_tmpl.format("uise", "nc")
  with with_video_opts({}):
    return ydl.download(["https://uise-official.com/videos"])


def kemomimi_dl(*_):
  print(">>> kemomimi", flush=True)
  ydl.params["match_filter"] = make_filter_func(make_filter(filter, []))
  ydl.params["outtmpl"]["default"] = out_tmpl.format("kemomimi", "nc")
  with with_video_opts({}):
    return ydl.download(["https://kemomimirefle.net/videos"])


def macoto_dl(*_):
  print(">>> macoto", flush=True)
  ydl.params["match_filter"] = make_filter_func(make_filter(filter, []))
  ydl.params["outtmpl"]["default"] = out_tmpl.format("macoto", "nc")
  with with_video_opts({}):
    return ydl.download(["https://rnqq.jp/videos"])


def nico_dl(id, name, ids=[], **kw):
  print(">>>", name, flush=True)
  ydl.params["match_filter"] = make_filter_func(make_filter(filter, ids))
  ydl.params["outtmpl"]["default"] = out_tmpl.format(name, "nc")
  with with_video_opts(kw):
    return ydl.download([f"https://nicochannel.jp/{id}/videos"])


def twitch_dl(id, name, ids=[], **kw):
  print(">>>", name, flush=True)
  ydl.params["match_filter"] = \
    category_filter(make_filter_func(make_filter(filter, ids)))
  ydl.params["outtmpl"]["default"] = out_tmpl.format(name, "ttv")
  with with_twitch_opts(kw):
    return ydl.download([f"https://www.twitch.tv/{id}/videos"])


def twc_dl(id, name, ids=[], **kw):
  print(">>>", name, flush=True)
  ydl.params["match_filter"] = make_filter_func(make_filter(filter, []))
  ydl.params["outtmpl"]["default"] = out_tmpl.format(name, "twc")
  with with_video_opts(kw):
    with with_opts({
      "external_downloader": {"default": "ffmpeg"},
      "external_downloader_args": {},
    }):
      return ydl.download([f"https://twitcasting.tv/{id}/archive/"])


def rplay_dl(id, name, ids=[], **kw):
  print(">>>", name, flush=True)
  ydl.params["match_filter"] = make_filter_func(make_filter(filter, []))
  ydl.params["outtmpl"]["default"] = out_tmpl.format(name, "rplay")
  with with_opts(kw):
    with with_video_opts(rplay_opts):
      return ydl.download([f"https://rplay.live/{id}"])


def get_dl():
  match site:
    case "nico": return nico_dl
    case "twitch": return twitch_dl
    case "uise": return uise_dl
    case "kemomimi": return kemomimi_dl
    case "macoto": return macoto_dl
    case "twitcasting": return twc_dl
    case "yt": return yt_dl
    case "rplay": return rplay_dl
    case _: raise ValueError(f"Unknown downloader '{site}'")


debug_name = sys.argv[1] if len(sys.argv) >= 2 else None


def dl(id, name, *args, **kw):
  if debug_name is not None and name != debug_name:
    return
  try:
    code = get_dl()(id, name, *args, **kw)
  except Exception as e:
    if debug_name is not None:
      raise e
    print(e, file=sys.stderr)
    code = 1
  if code != 0:
    failed.append(f"{id} - {name} - {code}")


ydl.params["no_warnings"] = True

with ydl:
# dl("PLjbMjMw6sj-cJU9oRtNIrB75FDiz9zii3", "remilia")
  dl("PLUEoTqBkugGOrDoN-70gZubhKYCQOGa1A", "annytf")
# dl("PLnFlg248hrLjtOy4TSYSILZdNN-YK8fEe", "uno")
  dl("PLzr1j1JTrDJ8Bblz20BvkkoOZYjdYe2sx", "halo")

  filter = "title *= 'HalO ASMR'"
  dl("UC-8ztH6Fer47pgGBHvbHddQ", "halo")

  filter = "title != ''"
  dl("UCtghgNWV1KGU0lt-vxWCKqA", "annytf")
  dl("UCJo3ai--w3Epj8qfiQmxe6Q", "jooin")
  dl("UCYNi4N5LWGzu5vOCBYIE_Ew", "luburi")
  dl("UCCCuLW_4FVQC9e7VQ9tAx-A", "tav")
# dl("UCUc1BJgiUT6G7gA-FL5Qclg", "miamumu") # dead
  dl("UCJkWVMvaDwgkZl8GByMNjIA", "suzu")
  dl("UCPs2O3sO6s_RnPSwgKd_U8g", "limseol")
  dl("UCxiUwyYxn6gco3ZBXX7qijA", "nanu")
  dl("UCDpBZxaMAmeaRL7RwNEzfEg", "eunppo")

  filter = "title ~= '(?i)kiss|lick|nom|eat'"
  dl("UCP8LJ-QZkctlGwOKwG7wegw", "cowi", ["GTYY-SWpSF8"])

  filter = "title *= '-red-'"
  dl("PLwRxuK_ONUYXMkqgT16v1AFu_XXOcWJEy", "ubye")

  filter = "title ~= '(?ui)ASMR|ASMR|耳舐め|耳はむ|ear\\s?(lick|eat)'"

  dl("UClTpLK8b6FISvdwEEEIMjug", "tuna")
  dl("UCzqQYhCoGsQhzUjtFjppW1Q", "naco")
  dl("UC-HM1zRR5d5nVK2rurtld5A", "naco")
  dl("UCLPCeXN2YoLSN8IrELMregQ", "miko")
  dl("UCCbWSmnC9UMza60JjuJJ2lQ", "ramune")
# dl("UCzkIhb88NMB68HJdZROcItA", "homari") # dead
# dl("UCDXGC_JfSl9Yo-S0pnvZpqQ", "lune")
# dl("UCgIGoHQm984AprANXHCb4jg", "lune")
# dl("UCZVXiQEMDNSxBKpxSCxWK5w", "lune")
  dl("UClxHGWFGOA-Mt0It-kQZAdQ", "ruru")
# dl("UCczXor4HpvWvET6CZiBlLBg", "dokuro") # dead
  dl("UCsJGYHpzh4zGFApEPG4gGpQ", "amakawa")
# dl("UCYfnSR25I87OKz8cpbJQwFA", "nako") # dead
  dl("UCVTXFAdxNbDMFfB67Ffl8jw", "shinguuin")
# dl("UCwvycbDmTqmtVTkl9eUp0cA", "ito")
  dl("UCHE25f3cfppcibo7JNIMZYQ", "ito")
# dl("UCH23b7S9nGz85-Rz5aypqDw", "dokuro") # dead
# dl("UCFLramz6JF8VVJ3zmXRo0IQ", "maimai")
# dl("UCxL1rd_BdRw4v6KYTPUKtHg", "maimai")
# dl("UCYGUA7rUV4IXYodoBPgrb0Q", "maimai")
  dl("UC4Ik3TGMI_ABtMK6IgdxjaQ", "maimai")
# dl("UCBZ9AMgYu0ZentozPB6CCqg", "racal")
# dl("UC0N7LwN7p6DT4sQoK18fANw", "racal")

  filter = "title *= '耳舐め'"

  dl("UCmVomBV_EV5WpXhlyqBXUww", "komae")
  dl("UCBJFtEEDnCpz8koPH-nLWUA", "kurumi", ["laIHW_8MUTQ"])
  dl("UCfWbowAT-RwfHNZnE_yuZSQ", "futatama")
# dl("UCogosC4m9ecyGXb73IJYrRQ", "kurono") # dead
# dl("UCRN2oPzTdAEtooR2F2Uh5OQ", "kurono") # dead
# dl("UCh676lvHWdqAxReGnz4dEiQ", "kurono") # dead
# dl("UC-L2RmFB6t2swKLSk9hlUkA", "kurono") # dead
# dl("UCIPYGWF2KwSDyl5_KWVDmKw", "kurono") # dead
  dl("UCqqt5VBaU7lKa3cPpv9b0jg", "usamiya")
  dl("UChBWfU4fuT2gkJWPjf4_llA", "chloe")
  dl("UCrKBVdbexrxZNJO5n4GSb3g", "yura")
# dl("UCbr8HF9BU6_KhP3PTk8CIaQ", "eve", ["xEWHvwGS9v8"])
  dl("UCkAcXtlbt8Nvt8HyAeDeDYQ", "yueko")
  dl("UCnsPXprq_TkW2czHotZd3FA", "harugumo")
  dl("UC9PGxFdFkAge6TK8oPJJmQQ", "piyoko")

  filter = "title ~= '(?ui)耳(はむ|ハム)|はむはむ|耳[舐な]め|ear\\s?(lick|eat)'"

  dl("UCiZyc9uhPft4ax1CTTMM2Bg", "yuara")
# dl("UCT8T1_V8OAAJec_4Kp3OE2g", "luna")
# dl("UCMEBqPuazNaTGVk-orUTDsw", "luna")
# dl("UCQxbT0xl92A4nS2ME3FozWg", "luna")
  dl("UCduzt7zB-dzwx0ANLbejDbg", "haru")
  dl("UCILHoVh5mT1Q7y4ZHpD3HfQ", "shirone")
# dl("UC2WDkMb6EP9lIogbgAsjs6w", "mikami") # dead
# dl("UCNomdKfjGPeJCo3bXaHHPGw", "hasuki")
# dl("UCy22UyEJlNfj3A0fMEvUcuw", "tumugi") # dead
# dl("UClIL4oekLdVqLqYS3xEv6EA", "tumugi") # dead
  dl("UCJDsCcYUxXqV16Qv-qeoPlQ", "inari")
  dl("UCTRSxJecJ7igpBKutPRBD-Q", "ranran")
# dl("UChwKF5tJjv7Mx4RufeqmViQ", "inuku") # dead
# dl("UCJCHA7JkpKwbpS_DAF4AHpQ", "hayuri") # dead-ish
# dl("UCxXMl42RVs7E44G5-SAywLA", "owred")
  dl("UCt2iHBH-wEwGMpCd-e1GaUA", "owred")
  dl("UC3n-A4K3F_4tY_0EmpsDfkA", "suzutuki")
# dl("UCtkBvPW0fkgmE-lj9RlJyQA", "aoi") # dead
# dl("UCl7pnzKUArh-lmMyGKpKjBQ", "shirotora") # dead
# dl("UCt_bvJGK87JMKOfJAQoLpmw", "jaana") # dead
  dl("UCMUUne96oLHAimhloegnkvQ", "yuduru")
  dl("UC-GIPz2K7lJDSOnnnj9cBgw", "ayaka")
  dl("UCSH4t_nhsNIoxPza4ooYqaA", "healthy")
# dl("UCTQ-icCxW8F0VhtqLfnZTLg", "meteo")
  dl("UCxsiLbj55-onJKm1vgTjbVA", "meteo")
# dl("UCE6WJGTZFE3guWBkR3IqBZw", "mitsuha") # dead
# dl("UCBR4HsvBp5jYRzNdSDlW0Bw", "sharo") # dead-ish
  dl("UCDhFPOhFxEdegzifhkPrACg", "ena")
  dl("UCS-xRujIU-uqF7B5t-Adc2A", "temako")
# dl("UCP8TJll-FkcJ0CtvWHN7xVw", "ayase")
  dl("UCeZ-VL2_-AU79tTAxZTWOZQ", "ayase")
# dl("UCXqClceek-h7kFDZ9vIxsoA", "aloa")
  dl("UCFjwOnhLjpigSowSeynOT_w", "aloa")
  dl("UCoSNgJh6phOkwzJu_0-KdrA", "sherley")
  dl("UCjq8Shumwsy5wLO9Ztr-T3w", "suzune")
  dl("UCjD4AeekxxUrutvAKXOMBGw", "fuuko")
# dl("UCA3P4185gyjFjXJdi0s5bsA", "shio") # dead
# dl("UCirnH4WpQIIbTvWtpAL3Q7w", "hiyona")
# dl("UCve2CPQeU0VEwWoCiks2BUA", "hiyona")
# dl("UC4pEHXxZYVwpC0tpvdtrK_g", "asase") # dead
# dl("UCNCmqP7ZDj-QRPE03D3JmXw", "koyoi")
  dl("UC7Ulb58uVOW3E3S5Jxj8yQQ", "aone")
  dl("UCDbUooahbXHudJMGVoIVzoQ", "yuma")
# dl("UCJvlpuVIAyx34oYXi-uciNQ", "supika") # dead
  dl("UC9zG-G5mJRn8JkM2deTcE3w", "purple")
# dl("UCVeahxbvGsbiYmeSfBaM88Q", "seya") # dead-ish
# dl("UC1WBwX78MCwrb8lM34sTz_w", "riruru")
  dl("UCPm_q_f69fdS7G1bqxZ595A", "riruru")
  dl("UCKeb6z5wj8kBLIygfVKAZZg", "momino") # dead
# dl("UCxhyT_JuX9c2yV_X7pZx2qw", "feit")
  dl("UCHp3W3FXdfGowMCVbg8N6vQ", "feit")
  dl("UCBDqrp-jFIyp84FZv2SI3hA", "shirakawa")
  dl("UCJbXqv2GVcaZNvqfuAfi7yg", "yorumiya")
  dl("UC_xpCnfLvFtbKIVSm-cJX0w", "cocoa")
  dl("UC0RSwNM5hbZ17nr8HoR6pqw", "namu")
  dl("UC3SHm5_q1kxrdJA7poe_kmA", "yukine")
  dl("UCToWxWu-3-DBf9uml1qJJDQ", "varny")
  dl("UCCAqJSuxj9X42VEnOdmSIcA", "erina")
# dl("UChBuLRzY1hCTOy_6sp3SaGQ", "tsumu") # dead
# dl("UChCUm0eQshlCZ8PgUowbTcQ", "aisu")
  dl("UCbFcyBfP54pLO9ta4N-QBFQ", "aisu")
# dl("UC2YhOXYOfkWBczWCYOaYLrg", "komomo") # dead
# dl("UCUeGClnHNPZsr1wUsjj7-JQ", "kefilia")
  dl("UCIk4fDXXNOoyjuKsajVFA8w", "kefilia")
# dl("UCYxFrLurusR4Au0PgER5QMg", "mugi") # dead
# dl("UCWx3ITpX86qDaWMWhDCys0A", "mugi") # dead
  dl("UCQ1OcBFSr7GM9o60ZWIo6Eg", "oyu")
# dl("UC8wF-h8ewn77jUJQqWJcnww", "sumire") # dead
# dl("UCg8xjMj7TZbc8iGic_KKUKw", "sumire") # dead
# dl("UCb7gzM9W7YUxD4Cfd-88w7w", "dia") # dead
# dl("UCCWbAiWoJYGucf-AYR4_Bow", "milky")
# dl("UC1LWFiW6Eu5XY_fYUsSxgbA", "milky")
# dl("UCw9sECNli7eY75pYS-lBiHw", "milky")
  dl("UC5V6douQYQUMWQxqxwfpZUw", "momo")
  dl("UCCerPBczdUtl1S-qqdoB1ug", "asahi")
# dl("UCeYQXRzXGSUKx-wEU0KQfJA", "panda")
  dl("UCO2BY1T4BsJyjzv84OtyNQw", "nemuko")
# dl("UC-tOh87D217FKuLjnaf8_OA", "ria") # dead
# dl("UCuaFSHfJJHw2i5Y6SOdPWNA", "doraku")
# dl("UC_ssu7UNKFG8Knwllm1mxZQ", "mion")
  dl("UC2RbhqU7qvLFUTVYOwMABbQ", "mion")
# dl("UC9I-8CYeBNFk5B89FQYyEgQ", "ooya") # dead-ish
# dl("UCYIOb9XgJOJunfH-yzVN7aQ", "kagami")
# dl("UCXQ7CBCTyElq7myYawEVyWg", "kagami")
# dl("UC8s36w6hhVhBzvZX0jxRGNw", "momoka") # dead
  dl("UCi5klq2zW-tLaLs9uzZUVRw", "yaemurasaki")
# dl("UCMXkJBy_bglr-RrlXsf60-w", "amano")
# dl("UC1suAx8sVb52vZJFwFF_SDg", "amano") # dead
# dl("UCjbV-hgiVzSYSihh18x25hw", "sena")
# dl("UCZtp25WVIHt28j6V9DjKIig", "sena") # dead
  dl("UCh9LsHsWcjQblQoXijy0ikA", "onemuri")
  dl("UCISQ9DgJdyTUCMtBNC-dl4A", "u-lili")
# dl("UCL_JDSf10F9R33iuPyM3QQA", "beako") # dead
  dl("UCE0YGnb-V10QZs7fv59E2Tw", "iroha")
  dl("UCCEejtWAO80M7eFYZtdfJeA", "kyandie")
# dl("UCJqkQ9QiC2wGwk1MdDJsROw", "shiroai", ["DiTzdNBJ0YE", "1KpFbzBv-L4", "cTvERNcRiII", "eObaP7BaAg0", "16ZN6atVlAA", "mV8f-B_Ll7w", "m038WOqYMRM", "RdnXHZxmu_w", "WMCSWirwVOA", "do8AFwBKrEY", "JlofiLhhweU", "jpsMeXf47d8", "xfqw8uDWfpc", "pBRXyMiNwKQ", "MoPR2TRPTSY"]) # dead
# dl("UCgFPoDei_iNbdRze0nUxKIw", "uise")
  dl("UCM4it9UUl53plaOjnfXasMQ", "uise")
# dl("UCqrZB8N7c7GDMS4xFeTgW4A", "riri")
  dl("UC1pQJGjg-QYu7cYCYw-a2CA", "riri")
# dl("UCMoXjlb90Isq9Jpb9iDZznQ", "umeru")
# dl("UCGRYiM3Em0zL2J0IzSMMyyA", "umeru")
  dl("UCsbsxLjdyUE06WICVyPPPVA", "umeru")
  dl("UCH0ObmokE-zUOeihkKwWySA", "yumenoshiori")
  dl("UCbqj2TLEZVwurXqyN0wuPHA", "miwu")
  dl("UCzeKqHQqEtsNfxO4JT9cA0w", "yuko")
# dl("UCHCbTXJHv9bk-kngMQq205Q", "konami") # dead-ish
# dl("UCzSbQMjTExShTgZ-sXHlSSQ", "momonoi") # dead-ish
  dl("UCBWWA6gRiTDT9EVsf5gmMKg", "miwa")
  dl("UCWNV-ixuEAxaso9rLk5PRFQ", "sizuku")
  dl("UCb1WRIxK9AJua80LfWB1MNA", "kake")
  dl("UCLzqq27175MKIFfiOHVX56g", "larry")
  dl("UCM1nL55m_QImE0ZRqvGmWWQ", "luka")
  dl("UC1NnllmOZWFHcStCQr-WicQ", "hayu")
# dl("UC0h9jHsCBG1k0ywLRpdkOng", "hoshina")
  dl("UCTp5NHgkwroqGzoQlQSyJAQ", "mel")
# dl("UC-kG7cGA_6wqhVssiurNKyQ", "chiery", ["oztbMR87u7Q"]) # dead-ish
# dl("UC__uh_NUfPNFBvWVmzpIa1A", "renge")
  dl("UCXKkQe2rYRI-hGmCtpCk-FA", "nekoyuu")
# dl("UCRxkVxAPMyboVc7jdhlz-7w", "hina") # dead
  dl("UCV8M0aUrbszv2DLcd_PaqWw", "asagiri")
# dl("UCPvUwa9OtwFa-0JqUPQyM_Q", "shiruko") # dead
# dl("UCoqcxR_jTVaVmfqt9V2m5FQ", "uruga")
  dl("UCa2HuzAYLZXOW6_0QJRY-Pg", "uruga")
# dl("UCj3TTwtlWEQZvpScHw2hhIQ", "enaseimu") # dead
  dl("UCZI_JKy0TGluCdB76G-GISQ", "mochimomo")
  dl("UCumU69kwL8a0uWmNEZqLI7A", "ako")
  dl("UCZ3pa-Ps7K_sh1ejEFxTzHg", "elika", ["D-xPmD0laW4"])
  dl("UCAGYRcBLIqZTs-kr3IMikWg", "ozi")
  dl("UCQYy35PowPpc6ImRH1TQgcw", "nora")
  dl("UCgcaQD1O1IWKtOSW9XGk6vg", "shion")
  dl("UCwFBKqPIXtloEldc4G-P_uQ", "rosetta")
# dl("UCfT8ofFtwZsztHvIM5olE1A", "roiro") # dead
# dl("UCHDgKsDB6ipVqWAFWEybR0Q", "roiro") # dead
  dl("UCvVrRUZrEVmt8TgOVeb9r1A", "haruno")
  dl("UCplom1ixJt3dt2JHpI5kCTg", "makura")
# dl("UCE9t22kLamDFUV1Nb2EA8xw", "neonch")
  dl("UCHC5t0p9rDyDjhvMlVKuihA", "neonch")
  dl("UCa8LEwtYMIqB_FFZq75ST4Q", "lunatear")
  dl("UCjjIr39JMBz7RpgAa0XhqwA", "hinata")
# dl("UCl2se3m54i1H_6WGoH81F9g", "lilisu") # dead
  dl("UCy0mupR-8VcgnCsPP7tIOZA", "naka")
# dl("UCXdI2anIT0P_-_2vviBFkyw", "fuwari") # dead
  dl("UCVcs89x6NHP-dvmjoiYhe1A", "nymphelia")
  dl("UCYMkR_QkkirwZ4L4piQgOLw", "kogoe")
  dl("UCj3YhVeKkYqy8x-UKn_luLw", "nikomi")
  dl("UCJfPi7abBn7nKXq0q-QGdmg", "kuo")
  dl("UC9lOyzDOb8y0hoHf9x_3aiw", "amae")
  dl("UCNM_m69g5_WDIBvukcDIvsA", "lilian")
  dl("UCVinH3_I8ZdbR0bPq1nxTSA", "tsun")
# dl("UCldW6LX2_ILUs6tUAS3s4JQ", "rinne") # dead
  dl("UCOOHwfIJaEOLs_9x2bjBprg", "yume")
# dl("UCixCDwbH3Xu3R4fK7vcbjTw", "himeka")
  dl("UCM7k98nZxbrL0diaeN79q9g", "timaki")
  dl("UC4m3QmmV7i3v_0zupv-Ec4A", "ludan")
  dl("UCctWtO1TTuxawRF7ngqv9Ww", "oto")
# dl("UCN_LPqJDj8XIqawWPX7k8NA", "bestia")
  dl("UC5FRTHV4mq4VoQ89Rrymbwg", "kigetsu")
  dl("UCP3pDau1JBOukp4AjyFCgHQ", "elle")
  dl("UCTW5lSI0XPGdRDuTn-XeLVQ", "more")
  dl("UC6kI9UelZ7W8kOOkv6gLXUA", "enmo")
  dl("UCP6oR1jM5dvNA1vWuh0bcCA", "fuyui")
  dl("UC8Drt-KLzN6BFYepyefEvZA", "chii")
  dl("UC6nHJCkHrkaMV4sBcUqpOvA", "neko")
  dl("UCuEvgULDVKQu6zErurOyJUg", "capu")
# dl("UCuUcMALAWv7N_VASpgJkh3Q", "mahina") # dead
  dl("UCRyDw23J-s5_SjKW0lsViLg", "chiyuri")
  dl("UCDnVSaFDYJskTrpqKvgTTqw", "maron")
  dl("UC_vlhwQ5RG8PZOt3qZiSqsQ", "maron")
  dl("UCo54dcvExskwhUZQ8KbidhQ", "chio")
  dl("UC5rGahXwE0UrGtHjwmJ7CiQ", "nemu")
  dl("UCgN9ZWEEr9YFj8Ztppi-uPw", "reya")
# dl("UC16pE1GHRfFI0QKFfkvgvBg", "yamino") # dead
  dl("UCx7tK20sT7nF83pO_KdPYbg", "setsune")

  dl("UCNj88lUpk9fyzQydjbsuzRw", "toiki", daterange=DateRange("20220617"))

  filter = filter[:-1] + "|舔耳'"
# dl("UCWSQEKOm92zSuehOjO5V7YA", "rie")
  dl("UCA-fOslAD1Q0BG1TtwPWYiQ", "nobara")
  dl("UCctSISJhirVG9vx6MSFn9ng", "yumebi")
  dl("UCOHK3Ro-EOc8075CdmOKLmQ", "babu")
  dl("UCXe8hqIk_Yap31y7EOCMdzg", "tabasuko")
  dl("UC84NqpdQcM4hwqJnAomGVoQ", "akahime")
  dl("UCjv4bfP_67WLuPheS-Z8Ekg", "mizuki")

  filter = filter[:-1] + "|귀\\s*핥기'"

  dl("UCz_mKIftqZEofRnagfM5RaA", "zephyr", [
    "o3cXX6MWKfw",
    "zgbOUzwIGdY",
    "kFWqaZrIhrA",
  ])
  dl("UCUKwI4euFtcQMhTJMIxWdvg", "hesy")
# dl("UCByoa5Md3ErDN-54DircWoQ", "yousu")
  dl("UCwAHlrMU83unv0rxM6nuCJw", "nein")
  dl("UCey1FitZjMj2Qc7xm-MpTlQ", "liyu")
  dl("UC2QCfVihICfB5B4puTjs0rA", "taeri")

  filter = filter[:-1] + "|licking|eating'"
  dl("UCutTrr9QN9qDjxPrtZvPlog", "minne")

  filter = "title ~= '(?ui)耳(はむ|ハム)|はむはむ|耳[舐な]め|ear\\s?(lick|eat)|asmr'"
  dl("UCuf5zqlYUzB1T7Za2OlNfKA", "parkdona")
  dl("UC52nnTXLGl1ZZVQc-YXAKLQ", "parkdona")

  filter = "title *= 'ASMR'"
  dl("UC9GBmdwFYuiirNGrPn5Wb0Q", "hayuvod")
  dl("UCCLDgC261pujpqlr8_mzK_g", "momiji")
  dl("UChEejxuuRu15AaVBV5kkM0g", "sohee")
  dl("UCGIDvgCG2v47r33D14QlasA", "jusia")
  dl("UCv1QC0A6RUWRqmg7Q-jsmLg", "hapu")
  dl("UCr-8mZlAFkrOQqxdzs7BrGw", "miamumu")
  dl("UCRcFS2Jvl0oJ-jhsY7vFIVQ", "suzune_j")
  dl("UCs6wZSCR74SCM72TLhcUnuA", "merico")
# dl("UCZdSEVJWnMk2j5Gmwtk7dnQ", "vlamy")
  dl("UCz8dUmP07FybEIiSzMu6fAA", "vlamy")
  dl("UCvgbuonmEURc7sGXLWPUYDQ", "cygnus")
  dl("UCerrcJ-mzPCmcs6bzsFnR1w", "deepblueok")
  dl("UCL08OrEF4ILXShxe5GBbKjw", "deepblueok")
  dl("UCq8DOsnZC6CV0GhalVUsRNQ", "shuya")
  dl("UCSi3eBG6jQfAqOHbfYAhroA", "zunbird")
  dl("UCbL9Lh7LiDwdOgJxuFDInEg", "nyabi")
  dl("UC9vLE2xn-bkwfDZvgygg4Dg", "prunella")

  dl("UCXWVCYpZVxKmWwVXCAdkU-A", "bada", [
    "FPpGkUUEa9Q",
  ], daterange=DateRange("20240701"))

  filter = "title ~= '(?ui)耳(はむ|ハム)|耳?舐め|ear\\s?(lick|eat)'"
  dl("UCagSiljXqKFmDiNQGhzauGw", "ribon")

# filter = "title ~= '耳を?(はむ|舐め)'"
# dl("UCWC0nFi6fg8ewN58XFrEnVg", "konomin")
# dl("UCPnj9r2r4n3dA4kVx2kjARg", "konomin")

  filter = "title ~= '耳?([舐な]め|はむ)'"
  dl("UCjMiUOZ3mTbu-VL2KXt4C4A", "airi")

# filter = "title ~= '(?ui)耳([舐〇◯]め|はむ)|ear\\s?(eat|lick)'"
# dl("UCql1K6rzLqUv1-ZpWG9EADg", "ono") # dead

# filter = "title *= '耳はむ'"
# dl("UCegFXbQB_RGe_Vk57j8Rk5w", "aikawa") # dead

  filter = "title ~= '(?ui)耳はむ|耳?[舐〇○◯な]め|ear\\s?(lick|eat)'"
  dl("UC8pyfuVBgK1TtBeXJZusITQ", "gangimari", [
    "9gVznu9z9Tg",
    "03nmjvFAGbA",
    "UuleGVVsg5g",
  ])
  dl("UCZkZnbVO2bECxwcGlE9YOGg", "tenka")

# filter = "title ~= '耳はむ|耳.め'"
# dl("UCDpajB_XSyvpBmAJqkwTMzQ", "pikon")
# dl("UCaHOwP5OBwQ1KmpV6u6vWjQ", "pikon")
# dl("UClCcU5C361YkLIOZZ_4dxAQ", "medjed")

# filter = "title ~= '耳はむ|耳舐め|はむはむ'"
# dl("UCqKU1Z7X6xqdkO3-aaVf6Aw", "naka", [
#   "uOmc0aw2f4M",
#   "ZJqBWNo9YIA",
#   "uqMueJXfqKo",
# ])

# filter = "title ~= '(?ui)耳はむ|耳?[舐〇◯な]め|ear.*(lick|eat)'"
# dl("UC4UG8DZVDlA0RoH6FodhcFA", "babu")

  filter = "title ~= '(?ui)ear\\s?(eat|lick)'"
  dl("UCc01DNoHeMy2kK9gNIhl4fw", "emma")

  filter = "title *= 'ASMR'"
  dl("UCvoQO7lOcmlD5WVuOLmCgmQ", "zenya")

  filter = "title ~= '(?i)lick|kiss'"
  dl("UCWzqNRcPaC45O2ScRnF2vGA", "zenya")

# filter = "description ~= '(?i)ear\\s*(lick|eat)'"
# dl("UCUr8O6Z8JyAg83KJbc_u_bQ", "miyu")

  site = "nico"

  filter = ""

  dl("kanase.ito", "ito")
  dl("luneasmr", "lune")
  dl("amino_pikon", "pikon")
  dl("piyopiyohiyona", "hiyona")
  dl("komaru-asmr", "komaru")
  dl("renge", "renge")
  dl("hasukirui", "hasuki")

  filter = "title *= '耳舐め'"
  dl("toikiasmr", "toiki")

  site = "twitch"

  filter = ""
  category = "ASMR"
  dl("nymphelia", "nymphelia")
  dl("jakotimaki", "timaki")
  dl("harukazekagami", "kagami")
  dl("rie_miyasaka", "rie")
  category = ""

  filter = "title ~= '(?ui)耳(はむ|ハム)|はむはむ|耳[舐な]め|ear\\s?(lick|eat)'"

  dl("riricoayase", "ayase")
  dl("xxx_evech_xxx", "eve")
  dl("momogakoyoi", "koyoi")
  dl("datenshi_lune", "lune")
  dl("tsuki_0915", "tsuki")
  dl("racalsan", "racal")
  dl("mayoiludan", "ludan")

  filter = "title *= 'ASMR'"
  dl("zenyahima", "zenya")

  site = "uise"
  filter = "title *= '耳舐め'"
  dl("uise-official", "uise")

  site = "kemomimi"
  filter = "title *= '耳舐め'"
  dl("kemomimirefle", "kemomimi")

  site = "macoto"
  filter = "title *= '耳舐め'"
  dl("macoto", "macoto")

  site = "twitcasting"

  filter = ""
  dl("harukazekagami", "kagami")

  filter = "title *= 'ASMR'"
  dl("medikaraed", "medjed")

  site = "rplay"
  filter = "title ~= '耳舐め|귀\\s*핥기|ASMR'"
  dl("creatorhome/65eeb4b237043dc0b5654f86", "renge")
  dl("creatorhome/667adc9e9aa7f739a2158ff3", "mel")
  dl("c/tenka_dolce", "tenka")
  dl("c/ohkaxx", "hinami")
  dl("creatorhome/66222d8e29e6ac9b2314be2c", "meruku")
  dl("c/furachi", "furachi")
  dl("creatorhome/669fe6a8e35d6393c11137fc", "umeru")
  dl("c/chachamaru", "chachamaru")
  dl("creatorhome/66213fd14eb65b8366a63916", "zephyr")
  dl("creatorhome/66758fec9aa7f739a22e76dc", "nikomi")
  dl("creatorhome/6696a5810ea7eacfd5b7302c", "kana")
  dl("creatorhome/65c26a6f134118411762043d", "healthy")
  dl("creatorhome/66d81abf542a038b4090a59a", "licorice")
  dl("c/cheermomoch", "cheermomo")
  dl("creatorhome/66a09bbce35d6393c199bb0c", "koyoi")
  dl("creatorhome/669a42e73d5473edbb2868dd", "tsuki")
  dl("creatorhome/6687dd0b0ea7eacfd52fcccc", "norarimiya")
  dl("c/jakotimaki", "timaki")
  dl("creatorhome/666cf3c8b98ff0a59ed31eee", "uruga")
  dl("c/racal_ra", "racal")
  dl("c/hatsukoi_himeka", "himeka")
  dl("c/irokoimakura", "makura")
  dl("creatorhome/67b28067b18e62e14188a385", "cowi")
  dl("creatorhome/6733a233392784fa9c91f240", "koneru")
  dl("creatorhome/67a0859115f8d9969cc7c28b", "robin")

with open("warning.txt", "w") as f:
  if len(failed) != 0:
    print("Failed to fetch these creators:", file=sys.stderr)
    for line in failed:
      print(" ", line, file=sys.stderr)
      f.write(f"{line}\n")