Skip to content
This repository was archived by the owner on May 9, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
9f5c895
chore: temporarily relocate initial bash preview scripts to old folder
Benexl Oct 31, 2025
515660b
feat: implement the main preview text logic in python
Benexl Oct 31, 2025
1d129a5
fix: remove extra bracket
Benexl Oct 31, 2025
9a0bb65
feat: implement image preview
Benexl Oct 31, 2025
7401a1a
feat: prefer to use direct implementation of graphics protocol over e…
Benexl Oct 31, 2025
925c30c
fix: typo should be text not info
Benexl Oct 31, 2025
44b3663
feat: grp studio, synonymns and tags separately for better ui / ux
Benexl Oct 31, 2025
106278e
feat: improve synopsis separator styling
Benexl Oct 31, 2025
097db71
feat: refactor ruling logic to function
Benexl Oct 31, 2025
e37f921
feat: include romaji title in synonymns if not already there
Benexl Oct 31, 2025
2d8c1d3
feat: remove colon for better ui
Benexl Oct 31, 2025
1928183
feat: next episode should come last in its grp for better ui ux
Benexl Oct 31, 2025
0c3a963
feat: use ?? where episodes are unknown
Benexl Oct 31, 2025
9a619b4
feat: use prefix in preview-script.py filename
Benexl Oct 31, 2025
1519c8b
feat: create the preview script in the cache/preview dir
Benexl Oct 31, 2025
29ce664
Merge remote-tracking branch 'origin/master' into feature/preview-scr…
Benexl Nov 3, 2025
a7b0f21
feat: rename info.py to media_info.py
Benexl Nov 18, 2025
6e287d3
feat: rewrite episode info script in python
Benexl Nov 18, 2025
8440ffb
feat: add a key for extra uniqueness
Benexl Nov 18, 2025
6409320
feat: create temp episode preview script
Benexl Nov 18, 2025
08ae878
feat: sanitize " in key
Benexl Nov 18, 2025
23ebff3
fix: add .py extension to final path
Benexl Nov 30, 2025
e8387f3
feat: character previews in python
Benexl Nov 30, 2025
6ccd96d
feat: review previews in python
Benexl Nov 30, 2025
5193df2
feat: airing schedule previews in python
Benexl Nov 30, 2025
393b9e6
feat: use actual file for preview script
Benexl Dec 1, 2025
9050dd7
feat: disable image for character, review, airing-schedule
Benexl Dec 1, 2025
091edb3
fix: remove extra bracket
Benexl Dec 1, 2025
a70db61
style: remove unnecessary comment
Benexl Dec 1, 2025
25a46bd
feat: disable airing schedule preview
Benexl Dec 1, 2025
76c1dcd
fix: specifying extension when saving file
Benexl Dec 1, 2025
f27c0b8
fix: order of operations
Benexl Dec 1, 2025
bd9bf24
feat: add more image render options
Benexl Dec 1, 2025
5237668
feat: implement other image renders
Benexl Dec 1, 2025
901d1e8
feat: rewrite FZF preview scripts to use ANSI utilities for improved …
Benexl Dec 1, 2025
26bc84e
fix: clean up whitespace in ANSI utilities and preview script
Benexl Dec 1, 2025
803c831
fix: improve value alignment in print_table_row for better formatting
Benexl Dec 2, 2025
1f72e0a
feat: enhance display width calculation for better text alignment in …
Benexl Dec 2, 2025
f4958cc
fix: clean up whitespace in display_width and print_table_row functions
Benexl Dec 2, 2025
c8c4e1b
feat: refactor terminal width handling in FZF scripts for improved co…
Benexl Dec 2, 2025
80771f6
feat: dynamic search rewrite in python
Benexl Dec 2, 2025
725754e
feat: improve text display for dynamic search
Benexl Dec 2, 2025
7b9de86
chore: cleanup old preview scripts
Benexl Dec 2, 2025
ece1f77
Merge branch 'master' into feature/preview-scripts-rewrite-to-python
Benexl Dec 2, 2025
3b00869
style: remove unused imports
Benexl Dec 2, 2025
6b8dfba
fix: remove double quotes
Benexl Dec 2, 2025
54233ac
feat: remove redundancy and stick to ansi_utils
Benexl Dec 2, 2025
d38dc31
feat: export ansi utils to preview root dir when doing dynamic previews
Benexl Dec 2, 2025
41aaf92
style: remove unused import
Benexl Dec 2, 2025
bf06d7e
Update viu_media/assets/scripts/fzf/media_info.py
Benexl Dec 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 202 additions & 0 deletions viu_media/assets/scripts/fzf/_ansi_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
"""
ANSI utilities for FZF preview scripts.

Lightweight stdlib-only utilities to replace Rich dependency in preview scripts.
Provides RGB color formatting, table rendering, and markdown stripping.
"""

import os
import re
import shutil
import textwrap
import unicodedata


def get_terminal_width() -> int:
"""
Get terminal width, prioritizing FZF preview environment variables.

Returns:
Terminal width in columns
"""
fzf_cols = os.environ.get("FZF_PREVIEW_COLUMNS")
if fzf_cols:
return int(fzf_cols)
return shutil.get_terminal_size((80, 24)).columns


def display_width(text: str) -> int:
"""
Calculate the actual display width of text, accounting for wide characters.

Args:
text: Text to measure

Returns:
Display width in terminal columns
"""
width = 0
for char in text:
# East Asian Width property: 'F' (Fullwidth) and 'W' (Wide) take 2 columns
if unicodedata.east_asian_width(char) in ("F", "W"):
width += 2
else:
width += 1
return width


def rgb_color(r: int, g: int, b: int, text: str, bold: bool = False) -> str:
"""
Format text with RGB color using ANSI escape codes.

Args:
r: Red component (0-255)
g: Green component (0-255)
b: Blue component (0-255)
text: Text to colorize
bold: Whether to make text bold

Returns:
ANSI-escaped colored text
"""
color_code = f"\x1b[38;2;{r};{g};{b}m"
bold_code = "\x1b[1m" if bold else ""
reset = "\x1b[0m"
return f"{color_code}{bold_code}{text}{reset}"


def parse_color(color_csv: str) -> tuple[int, int, int]:

Copilot AI Dec 2, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type hint tuple[int, int, int] uses Python 3.9+ syntax for generic types. For compatibility with Python 3.8 and earlier, this should be Tuple[int, int, int] from the typing module.

Similarly, line 188 uses int | None (Python 3.10+ syntax) instead of Optional[int].

Since these are standalone scripts that may run in various environments, consider using the more compatible typing module syntax or document the minimum Python version requirement (3.10+) for these scripts.

Copilot uses AI. Check for mistakes.
"""
Parse RGB color from comma-separated string.

Args:
color_csv: Color as 'R,G,B' string

Returns:
Tuple of (r, g, b) integers
"""
parts = color_csv.split(",")
return int(parts[0]), int(parts[1]), int(parts[2])


def print_rule(sep_color: str) -> None:
"""
Print a horizontal rule line.

Args:
sep_color: Color as 'R,G,B' string
"""
width = get_terminal_width()
r, g, b = parse_color(sep_color)
print(rgb_color(r, g, b, "─" * width))


def print_table_row(
key: str, value: str, header_color: str, key_width: int, value_width: int
) -> None:
"""
Print a two-column table row with left-aligned key and right-aligned value.

Args:
key: Left column text (header/key)
value: Right column text (value)
header_color: Color for key as 'R,G,B' string
key_width: Width for key column
value_width: Width for value column
"""
r, g, b = parse_color(header_color)
key_styled = rgb_color(r, g, b, key, bold=True)

# Get actual terminal width
term_width = get_terminal_width()

# Calculate display widths accounting for wide characters
key_display_width = display_width(key)

# Calculate actual value width based on terminal and key display width
actual_value_width = max(20, term_width - key_display_width - 2)

# Wrap value if it's too long (use character count, not display width for wrapping)
value_lines = textwrap.wrap(str(value), width=actual_value_width) if value else [""]

if not value_lines:
value_lines = [""]

# Print first line with properly aligned value
first_line = value_lines[0]
first_line_display_width = display_width(first_line)

# Use manual spacing to right-align based on display width
spacing = term_width - key_display_width - first_line_display_width - 2
if spacing > 0:
print(f"{key_styled} {' ' * spacing}{first_line}")
else:
print(f"{key_styled} {first_line}")

# Print remaining wrapped lines (left-aligned, indented)
for line in value_lines[1:]:
print(f"{' ' * (key_display_width + 2)}{line}")


def strip_markdown(text: str) -> str:
"""
Strip markdown formatting from text.

Removes:
- Headers (# ## ###)
- Bold (**text** or __text__)
- Italic (*text* or _text_)
- Links ([text](url))
- Code blocks (```code```)
- Inline code (`code`)

Args:
text: Markdown-formatted text

Returns:
Plain text with markdown removed
"""
if not text:
return ""

# Remove code blocks first
text = re.sub(r"```[\s\S]*?```", "", text)

# Remove inline code
text = re.sub(r"`([^`]+)`", r"\1", text)

# Remove headers
text = re.sub(r"^#{1,6}\s+", "", text, flags=re.MULTILINE)

# Remove bold (** or __)
text = re.sub(r"\*\*(.+?)\*\*", r"\1", text)
text = re.sub(r"__(.+?)__", r"\1", text)

# Remove italic (* or _)
text = re.sub(r"\*(.+?)\*", r"\1", text)
text = re.sub(r"_(.+?)_", r"\1", text)

# Remove links, keep text
text = re.sub(r"\[(.+?)\]\(.+?\)", r"\1", text)

# Remove images
text = re.sub(r"!\[.*?\]\(.+?\)", "", text)

return text.strip()


def wrap_text(text: str, width: int | None = None) -> str:

Copilot AI Dec 2, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type hint int | None uses Python 3.10+ union syntax. For compatibility with earlier Python versions (3.8-3.9), this should be Optional[int] from the typing module.

Line 68 also has a similar issue with tuple[int, int, int] instead of Tuple[int, int, int].

Since these are standalone scripts, ensure they're compatible with the project's minimum Python version or document the requirement for Python 3.10+.

Copilot uses AI. Check for mistakes.
"""
Wrap text to terminal width.

Args:
text: Text to wrap
width: Width to wrap to (defaults to terminal width)

Returns:
Wrapped text
"""
if width is None:
width = get_terminal_width()

return textwrap.fill(text, width=width)
22 changes: 0 additions & 22 deletions viu_media/assets/scripts/fzf/airing-schedule-info.template.sh

This file was deleted.

75 changes: 0 additions & 75 deletions viu_media/assets/scripts/fzf/airing-schedule-preview.template.sh

This file was deleted.

36 changes: 36 additions & 0 deletions viu_media/assets/scripts/fzf/airing_schedule_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import sys
from _ansi_utils import (
print_rule,
print_table_row,
strip_markdown,
wrap_text,
get_terminal_width,
)

HEADER_COLOR = sys.argv[1]
SEPARATOR_COLOR = sys.argv[2]

# Get terminal dimensions
term_width = get_terminal_width()

# Print title centered
print("{ANIME_TITLE}".center(term_width))

rows = [
("Total Episodes", "{TOTAL_EPISODES}"),
]

print_rule(SEPARATOR_COLOR)
for key, value in rows:
print_table_row(key, value, HEADER_COLOR, 15, term_width - 20)

rows = [
("Upcoming Episodes", "{UPCOMING_EPISODES}"),
]

print_rule(SEPARATOR_COLOR)
for key, value in rows:
print_table_row(key, value, HEADER_COLOR, 15, term_width - 20)

print_rule(SEPARATOR_COLOR)
print(wrap_text(strip_markdown("""{SCHEDULE_TABLE}"""), term_width))
41 changes: 0 additions & 41 deletions viu_media/assets/scripts/fzf/character-info.template.sh

This file was deleted.

Loading
Loading