114 lines
2.8 KiB
Python
114 lines
2.8 KiB
Python
import re
|
||
from dataclasses import dataclass
|
||
from functools import lru_cache
|
||
from time import time as now
|
||
from typing import *
|
||
|
||
import youtube_dl
|
||
|
||
from ..functions import escape_all, pretty_duration, reply
|
||
from ..models import Message
|
||
|
||
HELP = """Gibt Informationen zu Youtube-Videos aus.
|
||
Some text containing a <Youtube URL>.
|
||
"""
|
||
|
||
youtube_re = re.compile(
|
||
r"\byoutu(\.be/|be\.com/(embed/|v/|watch\?\w*v=))(?P<id>[0-9A-Za-z_-]{10,11})\b"
|
||
)
|
||
|
||
|
||
def init(bot):
|
||
bot.on_message(handle)
|
||
|
||
|
||
@lru_cache(maxsize=5)
|
||
def load_info(url, cachetoken):
|
||
"""The cachetoken is just there to bust the LRU cache after a while."""
|
||
return Info.from_url(url)
|
||
|
||
|
||
def cachetoken(quant_m=15):
|
||
"""Return a cache token with the given time frame"""
|
||
return int(now() / 60 / quant_m)
|
||
|
||
|
||
async def handle(message: Message):
|
||
if message.command in {"u", "url"}:
|
||
return
|
||
|
||
match = youtube_re.search(message.text)
|
||
if not match:
|
||
return
|
||
|
||
youtube_id = match["id"]
|
||
|
||
info = load_info(youtube_id, cachetoken())
|
||
escape_all(info)
|
||
details = [
|
||
f"🖋 {info.author}",
|
||
f"⏱ {pretty_duration(info.duration_seconds)}",
|
||
f"📺 {info.width}×{info.height}",
|
||
f"👀 {info.view_count:_}",
|
||
]
|
||
tag = (info.categories[:1] or info.tags[:1] or [""])[0]
|
||
if tag:
|
||
details.append(f"🏷 {tag}")
|
||
text = f"<b>{info.title}</b> — {', '.join(details)}"
|
||
await reply(message, html=text)
|
||
|
||
|
||
class Nolog:
|
||
def debug(self, msg):
|
||
pass
|
||
|
||
def warning(self, msg):
|
||
pass
|
||
|
||
def error(self, msg):
|
||
pass
|
||
|
||
|
||
ytdl = youtube_dl.YoutubeDL({"skip_download": True, "logger": Nolog()})
|
||
|
||
|
||
@dataclass
|
||
class Info:
|
||
author: str
|
||
title: str
|
||
description: str
|
||
duration_seconds: int
|
||
view_count: int
|
||
thumbnail: str
|
||
width: int
|
||
height: int
|
||
categories: List[str]
|
||
tags: List[str]
|
||
|
||
@classmethod
|
||
def from_url(cls, url):
|
||
info = ytdl.extract_info(url, download=False)
|
||
new = cls(
|
||
author=info["uploader"] or info["creator"] or info["uploader_id"] or "",
|
||
title=info["title"] or info["alt_title"] or "",
|
||
description=info["description"] or "",
|
||
duration_seconds=info["duration"] or 0,
|
||
view_count=info["view_count"] or 0,
|
||
thumbnail=(
|
||
info["thumbnail"]
|
||
or (info["thumbnails"][-1] if info["thumbnails"] else "")
|
||
),
|
||
categories=info["categories"] or [],
|
||
tags=info["tags"] or [],
|
||
width=info["width"] or 0,
|
||
height=info["height"] or 0,
|
||
)
|
||
if info["formats"]:
|
||
new.width, new.height = max(
|
||
(
|
||
(f["width"] or new.width),
|
||
(f["height"] or new.height),
|
||
)
|
||
for f in info["formats"]
|
||
)
|
||
return new
|