main
  1#!/usr/bin/env python
  2# -*- coding: utf-8 -*-
  3import contextlib
  4import re
  5from datetime import UTC, datetime
  6from zoneinfo import ZoneInfo
  7
  8from glom import glom
  9from loguru import logger
 10from pyrogram.client import Client
 11from pyrogram.types import Message
 12
 13from config import PROXY, TZ
 14from database.r2 import get_cf_r2
 15from messages.database import copy_messages_from_db, save_messages
 16from messages.progress import modify_progress
 17from messages.sender import send2tg
 18from messages.utils import blockquote, summay_media
 19from networking import download_file, download_media, hx_req
 20from preview.utils import has_markdown_img
 21from utils import nowstr
 22
 23
 24async def preview_reddit(client: Client, message: Message, url: str = "", db_key: str = "", **kwargs):
 25    """Preview reddit link in the message.
 26
 27    Args:
 28        client (Client): The Pyrogram client.
 29        message (Message): The trigger message object.
 30        url (str, optional): Reddit link
 31        db_key (str, optional): The cache key.
 32    """
 33    if kv := await get_cf_r2(db_key):
 34        logger.debug(f"Reddit preview cache hit for key={db_key}")
 35        if await copy_messages_from_db(client, message, key=db_key, kv=kv, **kwargs):
 36            return
 37        logger.warning("❌从缓存中转发失败, 尝试重新解析...")
 38    if kwargs.get("show_progress") and "progress" not in kwargs:
 39        res = await send2tg(client, message, texts=f"🔗正在解析Reddit链接\n{url}", **kwargs)
 40        kwargs["progress"] = res[0]
 41
 42    post_info = await get_reddit_info(url)
 43    if error := post_info.get("error"):
 44        await modify_progress(text=f"❌Reddit链接解析失败{url}\n{error}", force_update=True, **kwargs)
 45        return
 46    sent_messages = await send2tg(client, message, **post_info, **kwargs)
 47    await modify_progress(del_status=True, **kwargs)
 48    await save_messages(messages=sent_messages, key=db_key)
 49
 50
 51async def get_reddit_info(url: str, **kwargs) -> dict:
 52    """Get Reddit post info."""
 53    api_url = url + ".json"
 54    resp = await hx_req(api_url, proxy=PROXY.REDDIT, check_kv={"0.data.dist": 1, "1.data.children.0.kind": "t1"}, check_keys=["0.data.children.0.data.selftext"], **kwargs)
 55    if isinstance(resp, dict) and resp.get("hx_error"):
 56        return {"error": resp["hx_error"]}
 57    try:
 58        data = glom(resp, "0.data.children.0.data")
 59        title = data.get("title", "Title")
 60        author = data.get("author", "author")
 61        author_url = f"https://www.reddit.com/user/{author}"
 62        dt = nowstr()
 63        with contextlib.suppress(Exception):
 64            dt = datetime.fromtimestamp(data["created_utc"], tz=UTC).astimezone(ZoneInfo(TZ))
 65            dt = dt.strftime("%Y-%m-%d %H:%M:%S")
 66        desc = remove_preview_links(data.get("selftext", "")).strip()
 67        texts = f"🎈[{author}]({author_url})\n🕒{dt}\n**📝[{title}]({url})**\n{desc}"
 68        media = []
 69        if gallery := glom(data, "media_metadata.*", default=[]):  # multiple images
 70            for img in gallery:
 71                ext = img.get("m", "").split("/")[-1]  # image/png -> ping
 72                img_url = f"https://i.redd.it/{img['id']}.{ext}"
 73                media.append({"photo": download_file(img_url, proxy=PROXY.REDDIT, **kwargs)})
 74        elif data.get("url", "").startswith("https://i.redd.it/"):  # single image
 75            media.append({"photo": download_file(data["url"], proxy=PROXY.REDDIT, **kwargs)})
 76        if video_url := glom(data, "secure_media.reddit_video.fallback_url", default=""):
 77            media.append({"video": download_file(video_url, proxy=PROXY.REDDIT, **kwargs)})
 78        comments = ""
 79        for reply in glom(resp, "1.data.children.*.data"):
 80            author = reply.get("author", "author")
 81            author_url = f"https://www.reddit.com/user/{author}"
 82            comment = reply.get("body", "")
 83            if author == "[deleted]":
 84                continue
 85            if comment == "[removed]" or has_markdown_img(comment):
 86                continue
 87            comments += f"\n💬**[{author}]({author_url})**: {comment}"
 88        if comments:
 89            comments = blockquote(f"💬**点击展开评论**:{comments}")
 90        await modify_progress(text=f"⏬正在下载:\n{summay_media(media)}", force_update=True, **kwargs)
 91        media = await download_media(media, **kwargs)
 92    except Exception as e:
 93        logger.error(e)
 94        return {"error": str(e)}
 95    return {"texts": texts + comments, "media": media}
 96
 97
 98def remove_preview_links(text: str) -> str:
 99    """Remove the preview.redd.it links in the post contents."""
100    pattern = r"https?://preview\.redd\.it/\S+\s"
101    return re.sub(pattern, "", text)