Spaces:
Running
Running
Download bot/telegraph.py from Mega-Evolutions/Auto-Rename: direct link, hf CLI and curl.
- Browser
- Download file 5.33 kB
-
https://huggingface.co/spaces/Mega-Evolutions/Auto-Rename/resolve/main/bot/telegraph.py
- Command line
-
hf download hf://spaces/Mega-Evolutions/Auto-Rename/bot/telegraph.py
-
curl -L -o telegraph.py https://huggingface.co/spaces/Mega-Evolutions/Auto-Rename/resolve/main/bot/telegraph.py
5.33 kB
| """A minimal Telegraph (telegra.ph) client: one account for the bot, pages created from node lists.""" | |
| from __future__ import annotations | |
| import asyncio | |
| import json | |
| import logging | |
| from typing import Any, Awaitable, Callable, Dict, List, Optional | |
| import aiohttp | |
| log = logging.getLogger(__name__) | |
| API = "https://api.telegra.ph" | |
| CONTENT_LIMIT = 60_000 # Telegraph refuses a page whose content is over 64 KB; stay clear of it | |
| TITLE_LIMIT = 256 | |
| Node = Dict[str, Any] | |
| class TelegraphError(RuntimeError): | |
| """Telegraph refused or could not be reached; the message is safe to show to the user.""" | |
| def __init__(self, message: str, code: str = ""): | |
| super().__init__(message) | |
| self.code = code | |
| def content_size(nodes: List[Node]) -> int: | |
| """Bytes the content takes as it is sent.""" | |
| return len(dump(nodes).encode("utf-8")) | |
| def dump(nodes: List[Node]) -> str: | |
| return json.dumps(nodes, ensure_ascii=False, separators=(",", ":")) | |
| class Telegraph: | |
| """Creates pages under one account. The access token comes from ``load_token`` and is saved with ``save_token``.""" | |
| def __init__( | |
| self, | |
| load_token: Callable[[], Awaitable[Optional[str]]], | |
| save_token: Callable[[str], Awaitable[None]], | |
| *, | |
| api: str = API, | |
| short_name: str = "AutoRename", | |
| author: str = "Auto Rename Bot", | |
| timeout: float = 30, | |
| ): | |
| self._load = load_token | |
| self._save = save_token | |
| self.api = api.rstrip("/") | |
| self.short_name = short_name | |
| self.author = author | |
| self.author_url = "" | |
| self.timeout = timeout | |
| self._token: Optional[str] = None | |
| self._lock = asyncio.Lock() | |
| def set_author(self, name: str, url: str = "") -> None: | |
| """The name (and link) shown under the title of the pages; the bot's own, once it is known.""" | |
| if name.strip(): | |
| self.author = name.strip()[:128] | |
| self.author_url = url.strip()[:512] | |
| async def _call(self, method: str, **params: str) -> Dict[str, Any]: | |
| try: | |
| async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=self.timeout)) as session: | |
| async with session.post(f"{self.api}/{method}", data=params) as resp: | |
| data = await resp.json(content_type=None) | |
| except asyncio.TimeoutError: | |
| raise TelegraphError("Telegraph took too long to answer") from None | |
| except (aiohttp.ClientError, ValueError) as exc: | |
| raise TelegraphError(f"I couldn't reach Telegraph ({type(exc).__name__})") from exc | |
| if not isinstance(data, dict) or not data.get("ok"): | |
| code = str(data.get("error") if isinstance(data, dict) else "") or "UNKNOWN" | |
| if code.startswith("FLOOD_WAIT_"): | |
| raise TelegraphError(f"Telegraph asks to wait {code.rsplit('_', 1)[-1]} seconds", code) | |
| raise TelegraphError(f"Telegraph said {code}", code) | |
| result = data.get("result") | |
| if not isinstance(result, dict): | |
| raise TelegraphError("Telegraph sent an answer I don't understand") | |
| return result | |
| async def token(self) -> str: | |
| """The account's access token: remembered, else loaded, else a new account is made.""" | |
| async with self._lock: | |
| if self._token: | |
| return self._token | |
| saved = await self._load() | |
| if saved: | |
| self._token = saved | |
| return saved | |
| result = await self._call("createAccount", short_name=self.short_name, author_name=self.author) | |
| token = str(result.get("access_token") or "") | |
| if not token: | |
| raise TelegraphError("Telegraph did not give an access token") | |
| self._token = token | |
| await self._save(token) | |
| return token | |
| async def _forget_token(self) -> None: | |
| async with self._lock: | |
| self._token = None | |
| await self._save("") | |
| async def create_page(self, title: str, nodes: List[Node]) -> str: | |
| """Create a page and return its URL.""" | |
| content = dump(nodes) | |
| if len(content.encode("utf-8")) > 64 * 1024: | |
| raise TelegraphError("The page is too big for Telegraph", "CONTENT_TOO_BIG") | |
| for attempt in range(2): | |
| token = await self.token() | |
| params = {"access_token": token, "title": (title.strip() or "MediaInfo")[:TITLE_LIMIT], | |
| "author_name": self.author, "content": content, "return_content": "false"} | |
| if self.author_url: | |
| params["author_url"] = self.author_url | |
| try: | |
| result = await self._call("createPage", **params) | |
| except TelegraphError as exc: | |
| if exc.code == "ACCESS_TOKEN_INVALID" and attempt == 0: | |
| log.warning("the saved Telegraph token was rejected; making a new account") | |
| await self._forget_token() | |
| continue | |
| raise | |
| url = str(result.get("url") or "") | |
| if not url: | |
| raise TelegraphError("Telegraph did not return the page address") | |
| return url | |
| raise TelegraphError("Telegraph rejected the account twice") # pragma: no cover - the loop returns or raises | |