2021-01-07 08:34:14 +00:00
|
|
|
import re
|
2022-02-25 18:10:48 +00:00
|
|
|
import sys
|
2021-01-07 08:34:14 +00:00
|
|
|
|
2024-03-23 09:50:42 +00:00
|
|
|
from typing import Literal
|
2022-02-25 18:10:48 +00:00
|
|
|
from itertools import islice
|
2021-01-07 08:34:14 +00:00
|
|
|
from os import path
|
|
|
|
|
2024-03-31 19:39:54 +00:00
|
|
|
import click
|
|
|
|
|
2021-01-07 08:34:14 +00:00
|
|
|
from twitchdl import twitch, utils
|
2021-06-09 13:07:07 +00:00
|
|
|
from twitchdl.commands.download import get_clip_authenticated_url
|
2021-01-07 08:34:14 +00:00
|
|
|
from twitchdl.download import download_file
|
2024-03-31 19:39:54 +00:00
|
|
|
from twitchdl.output import green, print_clip, print_json, yellow
|
2021-01-07 08:34:14 +00:00
|
|
|
|
2024-03-23 09:50:42 +00:00
|
|
|
ClipsPeriod = Literal["last_day", "last_week", "last_month", "all_time"]
|
2021-01-07 08:34:14 +00:00
|
|
|
|
2024-03-23 09:50:42 +00:00
|
|
|
|
|
|
|
def clips(
|
|
|
|
channel_name: str,
|
|
|
|
*,
|
|
|
|
all: bool = False,
|
|
|
|
download: bool = False,
|
|
|
|
json: bool = False,
|
|
|
|
limit: int = 10,
|
|
|
|
pager: int | None = None,
|
|
|
|
period: ClipsPeriod = "all_time",
|
|
|
|
):
|
2022-02-25 18:10:48 +00:00
|
|
|
# Ignore --limit if --pager or --all are given
|
2024-03-23 09:50:42 +00:00
|
|
|
limit = sys.maxsize if all or pager else limit
|
2022-02-25 18:10:48 +00:00
|
|
|
|
2024-03-23 09:50:42 +00:00
|
|
|
generator = twitch.channel_clips_generator(channel_name, period, limit)
|
2022-02-25 18:10:48 +00:00
|
|
|
|
2024-03-23 09:50:42 +00:00
|
|
|
if json:
|
2022-02-25 18:10:48 +00:00
|
|
|
return print_json(list(generator))
|
2021-05-18 12:25:49 +00:00
|
|
|
|
2024-03-23 09:50:42 +00:00
|
|
|
if download:
|
2022-02-25 18:10:48 +00:00
|
|
|
return _download_clips(generator)
|
|
|
|
|
2024-03-23 09:50:42 +00:00
|
|
|
if pager:
|
|
|
|
return _print_paged(generator, pager)
|
2021-05-18 12:25:49 +00:00
|
|
|
|
2024-03-23 09:50:42 +00:00
|
|
|
return _print_all(generator, all)
|
2021-05-18 12:25:49 +00:00
|
|
|
|
|
|
|
|
2021-01-07 08:34:14 +00:00
|
|
|
def _continue():
|
2024-03-31 19:39:54 +00:00
|
|
|
enter = click.style("Enter", bold=True, fg="green")
|
|
|
|
ctrl_c = click.style("Ctrl+C", bold=True, fg="yellow")
|
|
|
|
click.echo(f"Press {enter} to continue, {ctrl_c} to break.")
|
2021-01-07 08:34:14 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
input()
|
|
|
|
except KeyboardInterrupt:
|
|
|
|
return False
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
2022-02-25 18:10:48 +00:00
|
|
|
def _target_filename(clip):
|
2021-01-07 08:34:14 +00:00
|
|
|
url = clip["videoQualities"][0]["sourceURL"]
|
|
|
|
_, ext = path.splitext(url)
|
|
|
|
ext = ext.lstrip(".")
|
|
|
|
|
|
|
|
match = re.search(r"^(\d{4})-(\d{2})-(\d{2})T", clip["createdAt"])
|
2024-03-23 09:50:42 +00:00
|
|
|
if not match:
|
|
|
|
raise ValueError(f"Failed parsing date from: {clip['createdAt']}")
|
2021-01-07 08:34:14 +00:00
|
|
|
date = "".join(match.groups())
|
|
|
|
|
|
|
|
name = "_".join([
|
|
|
|
date,
|
|
|
|
clip["id"],
|
2021-01-14 20:38:56 +00:00
|
|
|
clip["broadcaster"]["login"],
|
2021-01-07 08:34:14 +00:00
|
|
|
utils.slugify(clip["title"]),
|
|
|
|
])
|
|
|
|
|
2024-03-28 11:06:50 +00:00
|
|
|
return f"{name}.{ext}"
|
2021-01-07 08:34:14 +00:00
|
|
|
|
|
|
|
|
2022-02-25 18:10:48 +00:00
|
|
|
def _download_clips(generator):
|
|
|
|
for clip in generator:
|
|
|
|
target = _target_filename(clip)
|
2021-05-18 12:23:56 +00:00
|
|
|
|
2022-02-25 18:10:48 +00:00
|
|
|
if path.exists(target):
|
2024-03-31 19:39:54 +00:00
|
|
|
click.echo(f"Already downloaded: {green(target)}")
|
2022-02-25 18:10:48 +00:00
|
|
|
else:
|
2021-06-09 13:07:07 +00:00
|
|
|
url = get_clip_authenticated_url(clip["slug"], "source")
|
2024-03-31 19:39:54 +00:00
|
|
|
click.echo(f"Downloading: {yellow(target)}")
|
2022-02-25 18:10:48 +00:00
|
|
|
download_file(url, target)
|
2021-05-18 12:23:56 +00:00
|
|
|
|
2021-01-07 08:34:14 +00:00
|
|
|
|
2024-03-23 09:50:42 +00:00
|
|
|
def _print_all(generator, all: bool):
|
2022-02-25 18:10:48 +00:00
|
|
|
for clip in generator:
|
2024-03-31 19:39:54 +00:00
|
|
|
click.echo()
|
2022-02-25 18:10:48 +00:00
|
|
|
print_clip(clip)
|
2021-05-18 12:23:56 +00:00
|
|
|
|
2024-03-23 09:50:42 +00:00
|
|
|
if not all:
|
2024-03-31 19:39:54 +00:00
|
|
|
click.secho(
|
|
|
|
"\nThere may be more clips. " +
|
|
|
|
"Increase the --limit, use --all or --pager to see the rest.",
|
|
|
|
dim=True
|
2022-02-25 18:10:48 +00:00
|
|
|
)
|
2021-01-07 08:34:14 +00:00
|
|
|
|
|
|
|
|
2022-02-25 18:10:48 +00:00
|
|
|
def _print_paged(generator, page_size):
|
|
|
|
iterator = iter(generator)
|
|
|
|
page = list(islice(iterator, page_size))
|
|
|
|
|
|
|
|
first = 1
|
|
|
|
last = first + len(page) - 1
|
2021-01-07 08:34:14 +00:00
|
|
|
|
2022-02-25 18:10:48 +00:00
|
|
|
while True:
|
2024-03-31 19:39:54 +00:00
|
|
|
click.echo("-" * 80)
|
2021-01-07 08:34:14 +00:00
|
|
|
|
2024-03-31 19:39:54 +00:00
|
|
|
click.echo()
|
2022-02-25 18:10:48 +00:00
|
|
|
for clip in page:
|
|
|
|
print_clip(clip)
|
2024-03-31 19:39:54 +00:00
|
|
|
click.echo()
|
2021-01-07 08:34:14 +00:00
|
|
|
|
2022-02-25 18:10:48 +00:00
|
|
|
last = first + len(page) - 1
|
2021-01-07 08:34:14 +00:00
|
|
|
|
2024-03-31 19:39:54 +00:00
|
|
|
click.echo("-" * 80)
|
|
|
|
click.echo(f"Clips {first}-{last} of ???")
|
2021-01-07 08:34:14 +00:00
|
|
|
|
2022-02-25 18:10:48 +00:00
|
|
|
first = first + len(page)
|
|
|
|
last = first + 1
|
|
|
|
|
|
|
|
page = list(islice(iterator, page_size))
|
|
|
|
if not page or not _continue():
|
|
|
|
break
|