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 DB, PROXY, TZ
 14from database.database import get_db
 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 kwargs.get("show_progress") and "progress" not in kwargs:
 34        res = await send2tg(client, message, texts=f"🔗正在解析Reddit链接\n{url}", **kwargs)
 35        kwargs["progress"] = res[0]
 36    if kv := await get_db(db_key):
 37        logger.debug(f"Reddit preview {DB.ENGINE} cache hit for key={db_key}")
 38        if await copy_messages_from_db(client, message, key=db_key, kv=kv, **kwargs):
 39            return
 40        await modify_progress(text=f"❌从{DB.ENGINE}缓存中转发失败, 尝试重新解析...", **kwargs)
 41    logger.info(f"Reddit link preview for {url}")
 42
 43    post_info = await get_reddit_info(url)
 44    if error := post_info.get("error"):
 45        await modify_progress(text=f"❌Reddit链接解析失败{url}\n{error}", force_update=True, **kwargs)
 46        return
 47    sent_messages = await send2tg(client, message, **post_info, **kwargs)
 48    await modify_progress(del_status=True, **kwargs)
 49    await save_messages(messages=sent_messages, key=db_key)
 50
 51
 52async def get_reddit_info(url: str, **kwargs) -> dict:
 53    """Get Reddit post info."""
 54    api_url = url + ".json"
 55    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)
 56    if isinstance(resp, dict) and resp.get("hx_error"):
 57        return {"error": resp["hx_error"]}
 58    try:
 59        data = glom(resp, "0.data.children.0.data")
 60        title = data.get("title", "Title")
 61        author = data.get("author", "author")
 62        author_url = f"https://www.reddit.com/user/{author}"
 63        dt = nowstr()
 64        with contextlib.suppress(Exception):
 65            dt = datetime.fromtimestamp(data["created_utc"], tz=UTC).astimezone(ZoneInfo(TZ))
 66            dt = dt.strftime("%Y-%m-%d %H:%M:%S")
 67        desc = remove_preview_links(data.get("selftext", "")).strip()
 68        texts = f"🎈[{author}]({author_url})\n🕒{dt}\n**📝[{title}]({url})**\n{desc}"
 69        media = []
 70        if gallery := glom(data, "media_metadata.*", default=[]):  # multiple images
 71            for img in gallery:
 72                ext = img.get("m", "").split("/")[-1]  # image/png -> ping
 73                img_url = f"https://i.redd.it/{img['id']}.{ext}"
 74                media.append({"photo": download_file(img_url, proxy=PROXY.REDDIT, **kwargs)})
 75        elif data.get("url", "").startswith("https://i.redd.it/"):  # single image
 76            media.append({"photo": download_file(data["url"], proxy=PROXY.REDDIT, **kwargs)})
 77        if video_url := glom(data, "secure_media.reddit_video.fallback_url", default=""):
 78            media.append({"video": download_file(video_url, proxy=PROXY.REDDIT, **kwargs)})
 79        comments = ""
 80        for reply in glom(resp, "1.data.children.*.data"):
 81            author = reply.get("author", "author")
 82            author_url = f"https://www.reddit.com/user/{author}"
 83            comment = reply.get("body", "")
 84            if author == "[deleted]":
 85                continue
 86            if comment == "[removed]" or has_markdown_img(comment):
 87                continue
 88            cmt = f"💬**[{author}]({author_url})**: {comment}"
 89            comments += f"\n{blockquote(cmt)}"
 90        if comments:
 91            comments = f"\n{blockquote('💬**点此展开评论区**:')}{comments}"
 92        await modify_progress(text=f"⏬正在下载:\n{summay_media(media)}", force_update=True, **kwargs)
 93        media = await download_media(media, **kwargs)
 94    except Exception as e:
 95        logger.error(e)
 96        return {"error": str(e)}
 97    return {"texts": texts + comments, "media": media}
 98
 99
100def remove_preview_links(text: str) -> str:
101    """Remove the preview.redd.it links in the post contents."""
102    pattern = r"https?://preview\.redd\.it/\S+\s"
103    return re.sub(pattern, "", text)