File size: 1,544 Bytes
152ccef
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
"""Optional archived Telegram counters from the official TGStat API."""
import os
import re

import requests


def archive_link(username, message_id):
    if not re.fullmatch(r"[A-Za-z][A-Za-z0-9_]{2,}", username) or not re.fullmatch(r"[1-9]\d*", str(message_id)):
        raise ValueError("Invalid public Telegram post")
    return f"https://tgstat.ru/channel/@{username}/{message_id}"


def archived_post(username, message_id, fallback_title, get=requests.get):
    link = archive_link(username, message_id)
    token = os.getenv("TGSTAT_API_TOKEN", "").strip()
    if not token:
        return None
    # Do not scrape challenge pages or guess a number from unrelated page content.
    response = get("https://api.tgstat.ru/posts/get", params={
        "token": token, "postId": f"https://t.me/{username}/{message_id}"},
        timeout=(4, 8), allow_redirects=False)
    response.raise_for_status()
    data = response.json()
    post = data.get("response")
    if data.get("status") != "ok" or not isinstance(post, dict):
        return None
    views = post.get("views")
    if type(views) is not int or views < 0:
        return None
    source = str(post.get("link", "")).removeprefix("https://").removeprefix("http://")
    match = re.fullmatch(r"(?:t.me|telegram.me)/([A-Za-z][A-Za-z0-9_]{2,})/([1-9]\d*)/?", source)
    if not match or match[1].lower() != username.lower() or match[2] != str(message_id):
        return None
    return {"views": views, "title": f"{fallback_title} (TGStat)", "display_url": link, "source": "tgstat"}