From f03a58a802261c82d40475d62c021601c3d31344 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Fri, 1 May 2026 22:46:10 -0500 Subject: [PATCH] Improve background URL generation --- src/copyvios/background.py | 96 ++++++++++++++++++++++------------------------ 1 file changed, 45 insertions(+), 51 deletions(-) diff --git a/src/copyvios/background.py b/src/copyvios/background.py index dffac8c..ead211d 100644 --- a/src/copyvios/background.py +++ b/src/copyvios/background.py @@ -1,11 +1,10 @@ __all__ = ["get_background"] -import bisect +import functools import json import logging import random import re -import urllib.parse from dataclasses import dataclass from datetime import UTC, date, datetime, timedelta from typing import Self @@ -18,16 +17,16 @@ from .cookies import get_cookies logger = logging.getLogger(__name__) -THUMB_SIZES = [20, 40, 60, 120, 250, 330, 500, 960, 1280, 1920, 3840] - @dataclass(frozen=True) class BackgroundInfo: filename: str + + +@dataclass(frozen=True) +class BackgroundURLs: url: str descurl: str - width: int - height: int @dataclass(frozen=True) @@ -54,27 +53,6 @@ def _get_commons_site() -> Site: return cache.bot.wiki.add_site(project="wikimedia", lang="commons") -def _load_file(site: Site, filename: str) -> BackgroundInfo | None: - prefix = "File:" - try: - data = site.api_query( - action="query", - prop="imageinfo", - iiprop="url|size|canonicaltitle", - titles=prefix + filename, - ) - res = list(data["query"]["pages"].values())[0]["imageinfo"][0] - name = res["canonicaltitle"] - assert isinstance(name, str), name - except Exception: - logger.exception(f"Failed to get info for file {prefix + filename!r}") - return None - name = name.removeprefix(prefix).replace(" ", "_") - return BackgroundInfo( - name, res["url"], res["descriptionurl"], res["width"], res["height"] - ) - - def _get_fresh_from_potd() -> BackgroundInfo | None: site = _get_commons_site() date = datetime.now(UTC).strftime("%Y-%m-%d") @@ -93,7 +71,7 @@ def _get_fresh_from_potd() -> BackgroundInfo | None: if not filename: logger.exception(f"Failed to extract POTD from {page.title!r}") return None - return _load_file(site, filename) + return BackgroundInfo(filename) def _get_fresh_from_list() -> BackgroundInfo | None: @@ -114,19 +92,7 @@ def _get_fresh_from_list() -> BackgroundInfo | None: except IndexError: logger.exception(f"Failed to find any images on {page.title!r}") return None - return _load_file(site, filename) - - -def _build_url(screen: ScreenInfo, background: BackgroundInfo) -> str: - width = screen.width - if background.width / background.height > screen.width / screen.height: - width = int(background.width / background.height * screen.height) - i = bisect.bisect_right(THUMB_SIZES, width) - width = THUMB_SIZES[i] if i < len(THUMB_SIZES) else background.width - if width >= background.width: - return background.url - url = background.url.replace("/commons/", "/commons/thumb/") - return f"{url}/{width}px-{urllib.parse.quote(background.filename)}" + return BackgroundInfo(filename) _BACKGROUNDS = { @@ -134,20 +100,48 @@ _BACKGROUNDS = { "list": _get_fresh_from_list, } -_BACKGROUND_CACHE: dict[str, BackgroundInfo | None] = {} +_BACKGROUND_INFO_CACHE: dict[str, BackgroundInfo | None] = {} _LAST_BACKGROUND_UPDATES: dict[str, date] = { key: datetime.min.date() for key in _BACKGROUNDS } -def _get_background(selected: str) -> BackgroundInfo | None: +def _get_background_info(selected: str) -> BackgroundInfo | None: next_day = _LAST_BACKGROUND_UPDATES[selected] + timedelta(days=1) max_age = datetime(next_day.year, next_day.month, next_day.day, tzinfo=UTC) if datetime.now(UTC) > max_age: update_func = _BACKGROUNDS.get(selected, _get_fresh_from_list) - _BACKGROUND_CACHE[selected] = update_func() + _BACKGROUND_INFO_CACHE[selected] = update_func() _LAST_BACKGROUND_UPDATES[selected] = datetime.now(UTC).date() - return _BACKGROUND_CACHE[selected] + return _BACKGROUND_INFO_CACHE[selected] + + +@functools.lru_cache(maxsize=256) +def _get_background_urls( + background: BackgroundInfo, screen_width: int +) -> BackgroundURLs | None: + site = _get_commons_site() + prefix = "File:" + try: + data = site.api_query( + action="query", + prop="imageinfo", + iiprop="url|canonicaltitle", + iiurlwidth=screen_width, + titles=prefix + background.filename, + ) + res = list(data["query"]["pages"].values())[0]["imageinfo"][0] + name = res["canonicaltitle"] + assert isinstance(name, str), name + url = res["thumburl"] + descurl = res["descriptionurl"] + except Exception: + logger.exception( + f"Failed to get info for file {prefix + background.filename!r}" + ) + return None + name = name.removeprefix(prefix).replace(" ", "_") + return BackgroundURLs(url=url, descurl=descurl) def get_background(selected: str) -> tuple[str | None, str | None]: @@ -161,9 +155,9 @@ def get_background(selected: str) -> tuple[str | None, str | None]: else: screen = ScreenInfo() - background = _get_background(selected) - if background: - bg_url = _build_url(screen, background) - return bg_url, background.descurl - else: - return None, None + bg_info = _get_background_info(selected) + if bg_info is not None: + bg_urls = _get_background_urls(bg_info, screen.width) + if bg_urls is not None: + return bg_urls.url, bg_urls.descurl + return None, None