#!/usr/bin/env python3 from __future__ import annotations import html import re import discord def is_missing(value: str | None) -> bool: text = (value or "").strip().lower() return text in {"", "n/a", "none", "null"} def fit_embed_value(text: str, max_len: int = 1000) -> str: value = (text or "").strip() if is_missing(value): value = "Unbekannt" if len(value) <= max_len: return value return value[: max_len - 3] + "..." def fit_embed_description(text: str, max_len: int = 3800) -> str: value = (text or "").strip() if len(value) <= max_len: return value return value[: max_len - 3] + "..." def format_tag_badges(tags_text: str) -> str: if is_missing(tags_text): return "Unbekannt" parts = [part.strip() for part in tags_text.split(",") if part.strip()] if not parts: return "Unbekannt" return " ".join(f"`{part}`" for part in parts) def format_single_badge(text: str) -> str: if is_missing(text): return "Unbekannt" return f"`{fit_embed_value(text, max_len=200)}`" def compact_text(text: str) -> str: raw = text or "" raw = re.sub(r"<\s*br\s*/?\s*>", " ", raw, flags=re.IGNORECASE) raw = re.sub(r"", " ", raw, flags=re.IGNORECASE) raw = re.sub(r"<[^>]+>", "", raw) raw = html.unescape(raw) return " ".join(raw.replace("\n", " ").split()) def add_line(lines: list[str], label: str, value: str) -> None: if is_missing(value): return lines.append(f"**{label}:** {fit_embed_value(value)}") def make_links_view(anilist_url: str) -> discord.ui.View | None: if is_missing(anilist_url): return None view = discord.ui.View(timeout=None) view.add_item(discord.ui.Button(label="Zum Anime", style=discord.ButtonStyle.link, url=anilist_url)) return view def build_movie_embed(item: dict, index: int) -> discord.Embed: title = fit_embed_value( str(item.get("title_schedule_english") or item.get("title_english_anilist") or item.get("title", "")), max_len=200, ) anilist_url = str(item.get("anilist_url", "")).strip() embed = discord.Embed( title=title, url=anilist_url if not is_missing(anilist_url) else None, color=discord.Color.from_rgb(30, 144, 255), ) tags_badges = format_tag_badges(str(item.get("tags", ""))) genres_badges = format_tag_badges(str(item.get("genres", ""))) romaji_badge = format_single_badge(str(item.get("title_romaji", ""))) native_badge = format_single_badge(str(item.get("title_native", ""))) description_text = compact_text(str(item.get("description", ""))) lines: list[str] = [] add_line(lines, "Anime Typ", str(item.get("format", ""))) add_line(lines, "Genres", genres_badges) add_line(lines, "Tags", tags_badges) add_line(lines, "Release", str(item.get("release", ""))) add_line(lines, "Studios", str(item.get("studio", ""))) add_line(lines, "Romaji", romaji_badge) add_line(lines, "Nativ", native_badge) add_line(lines, "Beschreibung", description_text) embed.description = fit_embed_description("\n".join(lines) if lines else "Keine Details verfuegbar") cover = (item.get("cover_image") or "").strip() if cover: embed.set_image(url=cover) embed.set_footer( text=( "Daten: AniList, AnimeSchedule, TMDB | " "This product uses the TMDB API but is not endorsed or certified by TMDB. " f"| Eintrag #{index}" ) ) return embed