auto-sync: 2026-04-30 02:10:01

This commit is contained in:
Stream
2026-04-30 02:10:01 +03:00
parent 91b2502ee1
commit 4cfd909cc5
3 changed files with 194 additions and 14 deletions

View File

@@ -82,6 +82,69 @@ def _draw_text_centered(image: Image.Image, text: str,
image.paste(overlay.convert("RGB"), (0, 0), overlay)
def draw_karaoke_line(frame: Image.Image, text: str, words: list,
t: float, font, y_ratio: float = 0.82):
"""Рисует karaoke-строку: каждое слово своим цветом по таймингам.
Слова до текущего момента → жёлтые (255, 220, 0)
Текущее слово → жёлтое + glow (чуть крупнее, ярче)
Слова после → белые (255, 255, 255)
"""
if not words:
# Fallback: нет word-timestamps — рисуем всю строку жёлтым
_draw_text_centered(frame, text, font, font, True, 255, y_ratio=y_ratio, alpha=255)
return
draw = ImageDraw.Draw(frame)
# Измеряем общую ширину
total_width = sum(draw.textlength(w["word"] + " ", font=font) for w in words)
x = (WIDTH - total_width) // 2
y = int(HEIGHT * y_ratio)
COLOR_DONE = (255, 220, 0, 255) # уже пропето — жёлтый
COLOR_WHITE = (255, 255, 255, 200) # ещё не пропето — белый
COLOR_SHADOW = (0, 0, 0, 180)
overlay = Image.new("RGBA", (WIDTH, HEIGHT), (0, 0, 0, 0))
od = ImageDraw.Draw(overlay)
# Глоу-шрифт (чуть крупнее для текущего слова)
try:
glow_font = ImageFont.truetype(FONT_ACTIVE, FONT_SIZE + 4)
except Exception:
glow_font = font
for w in words:
word_text = w["word"] + " "
ww = draw.textlength(word_text, font=font)
if t >= w["end"]:
color = COLOR_DONE
use_font = font
elif t >= w["start"]:
# Текущее слово — жёлтый + glow
color = (255, 235, 50, 255) # чуть ярче
use_font = glow_font
# Glow: рисуем ещё раз с небольшим сдвигом и полупрозрачностью
od.text((x - 1, y - 1), word_text, font=glow_font, fill=(255, 220, 0, 80))
od.text((x + 1, y + 1), word_text, font=glow_font, fill=(255, 220, 0, 80))
else:
color = COLOR_WHITE
use_font = font
# Тень
od.text((x + 2, y + 2), word_text, font=use_font, fill=COLOR_SHADOW)
# Основной текст
od.text((x, y), word_text, font=use_font, fill=color)
x = int(x + ww)
if frame.mode == "RGBA":
frame.alpha_composite(overlay)
else:
frame.paste(overlay.convert("RGB"), (0, 0), overlay)
def draw_text_with_alpha(image: Image.Image, text: str,
font_active, font_inactive,
alpha: int = 255, active: bool = True,
@@ -308,15 +371,20 @@ def render_with_bg(segments: list[dict], audio_path: str, bg_video: str,
gap = (next_seg["start"] - t) if next_seg else 999
if active_seg:
# Активный сегмент — рисуем с fade in/out
frames_from_start = int((t - active_seg["start"]) * fps)
fade_alpha = min(255, int(255 * frames_from_start / max(FADE_FRAMES, 1)))
frames_to_end = int((active_seg["end"] - t) * fps)
fade_alpha = min(fade_alpha, int(255 * frames_to_end / max(FADE_FRAMES, 1)))
# Активный сегмент — karaoke-эффект если есть word-timestamps
has_words = isinstance(active_seg.get("words"), list) and len(active_seg.get("words", [])) > 0
if has_words:
draw_karaoke_line(frame, active_seg["text"], active_seg["words"], t, font_active)
else:
# Fallback без word-timestamps — старый fade in/out
frames_from_start = int((t - active_seg["start"]) * fps)
fade_alpha = min(255, int(255 * frames_from_start / max(FADE_FRAMES, 1)))
frames_to_end = int((active_seg["end"] - t) * fps)
fade_alpha = min(fade_alpha, int(255 * frames_to_end / max(FADE_FRAMES, 1)))
_draw_text_centered(frame, active_seg["text"],
font_active, font_inactive,
True, max(fade_alpha, 128))
_draw_text_centered(frame, active_seg["text"],
font_active, font_inactive,
True, max(fade_alpha, 128))
elif gap > 20 and next_seg:
# Длинная пауза (>20s) — показываем прогресс-бар