Replace custom coloring fns with click.echo and style

This commit is contained in:
Ivan Habunek 2024-03-31 21:39:54 +02:00
parent 9cf3ec2f07
commit 3ae99fe159
No known key found for this signature in database
GPG Key ID: F5F0623FF5EBCB3D
7 changed files with 86 additions and 122 deletions

View File

@ -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

View File

@ -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):

View File

@ -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']}")

View File

@ -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
)

View File

@ -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()

View File

@ -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

View File

@ -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")