mirror of
https://github.com/ihabunek/twitch-dl
synced 2024-08-30 18:32:25 +00:00
Replace custom coloring fns with click.echo and style
This commit is contained in:
parent
9cf3ec2f07
commit
3ae99fe159
@ -5,10 +5,12 @@ from typing import Literal
|
||||
from itertools import islice
|
||||
from os import path
|
||||
|
||||
import click
|
||||
|
||||
from twitchdl import twitch, utils
|
||||
from twitchdl.commands.download import get_clip_authenticated_url
|
||||
from twitchdl.download import download_file
|
||||
from twitchdl.output import print_out, print_clip, print_json
|
||||
from twitchdl.output import green, print_clip, print_json, yellow
|
||||
|
||||
ClipsPeriod = Literal["last_day", "last_week", "last_month", "all_time"]
|
||||
|
||||
@ -41,7 +43,9 @@ def clips(
|
||||
|
||||
|
||||
def _continue():
|
||||
print_out("Press <green><b>Enter</green> to continue, <yellow><b>Ctrl+C</yellow> to break.")
|
||||
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.")
|
||||
|
||||
try:
|
||||
input()
|
||||
@ -76,22 +80,23 @@ def _download_clips(generator):
|
||||
target = _target_filename(clip)
|
||||
|
||||
if path.exists(target):
|
||||
print_out(f"Already downloaded: <green>{target}</green>")
|
||||
click.echo(f"Already downloaded: {green(target)}")
|
||||
else:
|
||||
url = get_clip_authenticated_url(clip["slug"], "source")
|
||||
print_out(f"Downloading: <yellow>{target}</yellow>")
|
||||
click.echo(f"Downloading: {yellow(target)}")
|
||||
download_file(url, target)
|
||||
|
||||
|
||||
def _print_all(generator, all: bool):
|
||||
for clip in generator:
|
||||
print_out()
|
||||
click.echo()
|
||||
print_clip(clip)
|
||||
|
||||
if not all:
|
||||
print_out(
|
||||
"\n<dim>There may be more clips. " +
|
||||
"Increase the --limit, use --all or --pager to see the rest.</dim>"
|
||||
click.secho(
|
||||
"\nThere may be more clips. " +
|
||||
"Increase the --limit, use --all or --pager to see the rest.",
|
||||
dim=True
|
||||
)
|
||||
|
||||
|
||||
@ -103,17 +108,17 @@ def _print_paged(generator, page_size):
|
||||
last = first + len(page) - 1
|
||||
|
||||
while True:
|
||||
print_out("-" * 80)
|
||||
click.echo("-" * 80)
|
||||
|
||||
print_out()
|
||||
click.echo()
|
||||
for clip in page:
|
||||
print_clip(clip)
|
||||
print_out()
|
||||
click.echo()
|
||||
|
||||
last = first + len(page) - 1
|
||||
|
||||
print_out("-" * 80)
|
||||
print_out(f"<yellow>Clips {first}-{last}</yellow>")
|
||||
click.echo("-" * 80)
|
||||
click.echo(f"Clips {first}-{last} of ???")
|
||||
|
||||
first = first + len(page)
|
||||
last = first + 1
|
||||
|
@ -19,7 +19,7 @@ from twitchdl.download import download_file
|
||||
from twitchdl.entities import Data, DownloadOptions
|
||||
from twitchdl.exceptions import ConsoleError
|
||||
from twitchdl.http import download_all
|
||||
from twitchdl.output import blue, bold, dim, green, print_log, print_out, yellow
|
||||
from twitchdl.output import blue, bold, dim, green, print_log, yellow
|
||||
|
||||
|
||||
def download(ids: list[str], args: DownloadOptions):
|
||||
|
@ -1,9 +1,11 @@
|
||||
import click
|
||||
import m3u8
|
||||
|
||||
from twitchdl import utils, twitch
|
||||
from twitchdl.commands.download import get_video_placeholders
|
||||
from twitchdl.entities import Data
|
||||
from twitchdl.exceptions import ConsoleError
|
||||
from twitchdl.output import print_table, print_video, print_clip, print_json, print_out, print_log
|
||||
from twitchdl.output import bold, print_table, print_video, print_clip, print_json, print_log
|
||||
|
||||
def info(id: str, *, json: bool = False):
|
||||
video_id = utils.parse_video_identifier(id)
|
||||
@ -46,25 +48,25 @@ def info(id: str, *, json: bool = False):
|
||||
|
||||
|
||||
def video_info(video, playlists, chapters):
|
||||
print_out()
|
||||
click.echo()
|
||||
print_video(video)
|
||||
|
||||
print_out()
|
||||
print_out("Playlists:")
|
||||
click.echo()
|
||||
click.echo("Playlists:")
|
||||
for p in m3u8.loads(playlists).playlists:
|
||||
print_out(f"<b>{p.stream_info.video}</b> {p.uri}")
|
||||
click.echo(f"{bold(p.stream_info.video)} {p.uri}")
|
||||
|
||||
if chapters:
|
||||
print_out()
|
||||
print_out("Chapters:")
|
||||
click.echo()
|
||||
click.echo("Chapters:")
|
||||
for chapter in chapters:
|
||||
start = utils.format_time(chapter["positionMilliseconds"] // 1000, force_hours=True)
|
||||
duration = utils.format_time(chapter["durationMilliseconds"] // 1000)
|
||||
print_out(f'{start} <b>{chapter["description"]}</b> ({duration})')
|
||||
click.echo(f'{start} {bold(chapter["description"])} ({duration})')
|
||||
|
||||
placeholders = get_video_placeholders(video, format = "mkv")
|
||||
placeholders = [[f"{{{k}}}", v] for k, v in placeholders.items()]
|
||||
print_out("")
|
||||
click.echo("")
|
||||
print_table(["Placeholder", "Value"], placeholders)
|
||||
|
||||
|
||||
@ -86,11 +88,11 @@ def video_json(video, playlists, chapters):
|
||||
print_json(video)
|
||||
|
||||
|
||||
def clip_info(clip):
|
||||
print_out()
|
||||
def clip_info(clip: Data):
|
||||
click.echo()
|
||||
print_clip(clip)
|
||||
print_out()
|
||||
print_out("Download links:")
|
||||
click.echo()
|
||||
click.echo("Download links:")
|
||||
|
||||
for q in clip["videoQualities"]:
|
||||
print_out("<b>{quality}p{frameRate}</b> {sourceURL}".format(**q))
|
||||
click.echo(f"{bold(q['quality'])} [{q['frameRate']} fps] {q['sourceURL']}")
|
||||
|
@ -1,8 +1,10 @@
|
||||
import sys
|
||||
|
||||
import click
|
||||
|
||||
from twitchdl import twitch
|
||||
from twitchdl.exceptions import ConsoleError
|
||||
from twitchdl.output import print_log, print_out, print_paged_videos, print_video, print_json, print_video_compact
|
||||
from twitchdl.output import print_log, print_paged_videos, print_video, print_json, print_video_compact
|
||||
|
||||
|
||||
def videos(
|
||||
@ -38,7 +40,7 @@ def videos(
|
||||
return
|
||||
|
||||
if total_count == 0:
|
||||
print_out("<yellow>No videos found</yellow>")
|
||||
click.echo("No videos found")
|
||||
return
|
||||
|
||||
if pager:
|
||||
@ -50,18 +52,18 @@ def videos(
|
||||
if compact:
|
||||
print_video_compact(video)
|
||||
else:
|
||||
print_out()
|
||||
click.echo()
|
||||
print_video(video)
|
||||
count += 1
|
||||
|
||||
print_out()
|
||||
print_out("-" * 80)
|
||||
print_out(f"<yellow>Videos 1-{count} of {total_count}</yellow>")
|
||||
click.echo()
|
||||
click.echo("-" * 80)
|
||||
click.echo(f"Videos 1-{count} of {total_count}")
|
||||
|
||||
if total_count > count:
|
||||
print_out()
|
||||
print_out(
|
||||
"<dim>There are more videos. Increase the --limit, use --all or --pager to see the rest.</dim>"
|
||||
click.secho(
|
||||
"\nThere are more videos. Increase the --limit, use --all or --pager to see the rest.",
|
||||
dim=True
|
||||
)
|
||||
|
||||
|
||||
|
@ -1,51 +1,11 @@
|
||||
import click
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
|
||||
from itertools import islice
|
||||
from twitchdl import utils
|
||||
from typing import Any, Match
|
||||
from typing import Any, Generator
|
||||
|
||||
|
||||
START_CODES = {
|
||||
'b': '\033[1m',
|
||||
'dim': '\033[2m',
|
||||
'i': '\033[3m',
|
||||
'u': '\033[4m',
|
||||
'red': '\033[91m',
|
||||
'green': '\033[92m',
|
||||
'yellow': '\033[93m',
|
||||
'blue': '\033[94m',
|
||||
'magenta': '\033[95m',
|
||||
'cyan': '\033[96m',
|
||||
}
|
||||
|
||||
END_CODE = '\033[0m'
|
||||
|
||||
START_PATTERN = "<(" + "|".join(START_CODES.keys()) + ")>"
|
||||
END_PATTERN = "</(" + "|".join(START_CODES.keys()) + ")>"
|
||||
|
||||
USE_ANSI_COLOR = "--no-color" not in sys.argv
|
||||
|
||||
|
||||
def start_code(match: Match[str]) -> str:
|
||||
name = match.group(1)
|
||||
return START_CODES[name]
|
||||
|
||||
|
||||
def colorize(text: str) -> str:
|
||||
text = re.sub(START_PATTERN, start_code, text)
|
||||
text = re.sub(END_PATTERN, END_CODE, text)
|
||||
|
||||
return text
|
||||
|
||||
|
||||
def strip_tags(text: str) -> str:
|
||||
text = re.sub(START_PATTERN, '', text)
|
||||
text = re.sub(END_PATTERN, '', text)
|
||||
|
||||
return text
|
||||
from twitchdl.entities import Data
|
||||
|
||||
|
||||
def truncate(string: str, length: int) -> str:
|
||||
@ -55,11 +15,6 @@ def truncate(string: str, length: int) -> str:
|
||||
return string
|
||||
|
||||
|
||||
def print_out(*args, **kwargs):
|
||||
args = [colorize(a) if USE_ANSI_COLOR else strip_tags(a) for a in args]
|
||||
print(*args, **kwargs)
|
||||
|
||||
|
||||
def print_json(data: Any):
|
||||
click.echo(json.dumps(data))
|
||||
|
||||
@ -87,38 +42,38 @@ def print_table(headers: list[str], data: list[list[str]]):
|
||||
print_row(row)
|
||||
|
||||
|
||||
def print_video(video):
|
||||
def print_video(video: Data):
|
||||
published_at = video["publishedAt"].replace("T", " @ ").replace("Z", "")
|
||||
length = utils.format_duration(video["lengthSeconds"])
|
||||
|
||||
channel = f"<blue>{video['creator']['displayName']}</blue>" if video["creator"] else ""
|
||||
playing = f"playing <blue>{video['game']['name']}</blue>" if video["game"] else ""
|
||||
channel = blue(video['creator']['displayName']) if video["creator"] else ""
|
||||
playing = f"playing {blue(video['game']['name'])}" if video["game"] else ""
|
||||
|
||||
# Can't find URL in video object, strange
|
||||
url = f"https://www.twitch.tv/videos/{video['id']}"
|
||||
|
||||
print_out(f"<b>Video {video['id']}</b>")
|
||||
print_out(f"<green>{video['title']}</green>")
|
||||
click.secho(f"Video {video['id']}", bold=True)
|
||||
click.secho(f"{video['title']}", fg="green")
|
||||
|
||||
if channel or playing:
|
||||
print_out(" ".join([channel, playing]))
|
||||
click.echo(" ".join([channel, playing]))
|
||||
|
||||
if video["description"]:
|
||||
print_out(f"Description: {video['description']}")
|
||||
click.echo(f"Description: {video['description']}")
|
||||
|
||||
print_out(f"Published <blue>{published_at}</blue> Length: <blue>{length}</blue> ")
|
||||
print_out(f"<i>{url}</i>")
|
||||
click.echo(f"Published {blue(published_at)} Length: {blue(length)} ")
|
||||
click.secho(url, italic=True)
|
||||
|
||||
|
||||
def print_video_compact(video):
|
||||
def print_video_compact(video: Data):
|
||||
id = video["id"]
|
||||
date = video["publishedAt"][:10]
|
||||
game = video["game"]["name"] if video["game"] else ""
|
||||
title = truncate(video["title"], 80).ljust(80)
|
||||
print_out(f'<b>{id}</b> {date} <green>{title}</green> <blue>{game}</blue>')
|
||||
click.echo(f"{bold(id)} {date} {green(title)} {blue(game)}")
|
||||
|
||||
|
||||
def print_paged_videos(generator, page_size: int, total_count: int):
|
||||
def print_paged_videos(generator: Generator[Data, None, None], page_size: int, total_count: int):
|
||||
iterator = iter(generator)
|
||||
page = list(islice(iterator, page_size))
|
||||
|
||||
@ -126,17 +81,17 @@ def print_paged_videos(generator, page_size: int, total_count: int):
|
||||
last = first + len(page) - 1
|
||||
|
||||
while True:
|
||||
print_out("-" * 80)
|
||||
click.echo("-" * 80)
|
||||
|
||||
print_out()
|
||||
click.echo()
|
||||
for video in page:
|
||||
print_video(video)
|
||||
print_out()
|
||||
click.echo()
|
||||
|
||||
last = first + len(page) - 1
|
||||
|
||||
print_out("-" * 80)
|
||||
print_out(f"<yellow>Videos {first}-{last} of {total_count}</yellow>")
|
||||
click.echo("-" * 80)
|
||||
click.echo(f"Videos {first}-{last} of {total_count}")
|
||||
|
||||
first = first + len(page)
|
||||
last = first + 1
|
||||
@ -146,28 +101,27 @@ def print_paged_videos(generator, page_size: int, total_count: int):
|
||||
break
|
||||
|
||||
|
||||
def print_clip(clip):
|
||||
def print_clip(clip: Data):
|
||||
published_at = clip["createdAt"].replace("T", " @ ").replace("Z", "")
|
||||
length = utils.format_duration(clip["durationSeconds"])
|
||||
channel = clip["broadcaster"]["displayName"]
|
||||
playing = (
|
||||
f"playing <blue>{clip['game']['name']}</blue>"
|
||||
if clip["game"] else ""
|
||||
)
|
||||
playing = f"playing {blue(clip['game']['name'])}" if clip["game"] else ""
|
||||
|
||||
print_out(f"Clip <b>{clip['slug']}</b>")
|
||||
print_out(f"<green>{clip['title']}</green>")
|
||||
print_out(f"<blue>{channel}</blue> {playing}")
|
||||
print_out(
|
||||
f"Published <blue>{published_at}</blue>" +
|
||||
f" Length: <blue>{length}</blue>" +
|
||||
f" Views: <blue>{clip["viewCount"]}</blue>"
|
||||
click.echo(f"Clip {bold(clip['slug'])}")
|
||||
click.secho(clip["title"], fg="green")
|
||||
click.echo(f"{blue(channel)} {playing}")
|
||||
click.echo(
|
||||
f"Published {blue(published_at)}" +
|
||||
f" Length: {blue(length)}" +
|
||||
f" Views: {blue(clip['viewCount'])}"
|
||||
)
|
||||
print_out(f"<i>{clip['url']}</i>")
|
||||
click.secho(clip["url"], italic=True)
|
||||
|
||||
|
||||
def _continue():
|
||||
print_out("Press <green><b>Enter</green> to continue, <yellow><b>Ctrl+C</yellow> to break.")
|
||||
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.")
|
||||
|
||||
try:
|
||||
input()
|
||||
|
@ -1,3 +1,4 @@
|
||||
import click
|
||||
import logging
|
||||
import time
|
||||
|
||||
@ -6,7 +7,7 @@ from dataclasses import dataclass, field
|
||||
from statistics import mean
|
||||
from typing import Dict, NamedTuple, Optional, Deque
|
||||
|
||||
from twitchdl.output import print_out
|
||||
from twitchdl.output import blue
|
||||
from twitchdl.utils import format_size, format_time
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -127,11 +128,11 @@ class Progress:
|
||||
|
||||
progress = " ".join([
|
||||
f"Downloaded {self.vod_downloaded_count}/{self.vod_count} VODs",
|
||||
f"<blue>{self.progress_perc}%</blue>",
|
||||
f"of <blue>~{format_size(self.estimated_total)}</blue>" if self.estimated_total else "",
|
||||
f"at <blue>{format_size(self.speed)}/s</blue>" if self.speed else "",
|
||||
f"ETA <blue>{format_time(self.remaining_time)}</blue>" if self.remaining_time is not None else "",
|
||||
blue(self.progress_perc),
|
||||
f"of ~{blue(format_size(self.estimated_total))}" if self.estimated_total else "",
|
||||
f"at {blue(format_size(self.speed))}/s" if self.speed else "",
|
||||
f"ETA {blue(format_time(self.remaining_time))}" if self.remaining_time is not None else "",
|
||||
])
|
||||
|
||||
print_out(f"\r{progress} ", end="")
|
||||
click.echo(f"\r{progress} ", nl=False)
|
||||
self.last_printed = now
|
||||
|
@ -11,7 +11,7 @@ def _format_size(value: float, digits: int, unit: str):
|
||||
return f"{int(value)}{unit}"
|
||||
|
||||
|
||||
def format_size(bytes_: int, digits: int = 1):
|
||||
def format_size(bytes_: int | float, digits: int = 1):
|
||||
if bytes_ < 1024:
|
||||
return _format_size(bytes_, digits, "B")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user