File size: 3,017 Bytes
44a3896
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import hashlib
import io
import random

import requests
from PIL import Image

OPENVERSE_URL = "https://api.openverse.engineering/v1/images/"

DEFAULT_QUERIES = (
    "nature landscape",
    "scenic outdoor",
    "abstract texture background",
    "colorful sky",
    "urban architecture",
    "peaceful garden",
    "ocean horizon",
    "mountain vista",
)

USER_AGENT = "cursor-pilot-background-fetch/1.0"


def _download_image(url: str, timeout: int = 25) -> Image.Image | None:
    try:
        resp = requests.get(
            url,
            timeout=timeout,
            headers={"User-Agent": USER_AGENT},
        )
        resp.raise_for_status()
        img = Image.open(io.BytesIO(resp.content))
        img.load()
        return img.convert("RGB")
    except (OSError, requests.RequestException):
        return None


def _search_openverse(query: str, page_size: int = 20) -> list[str]:
    page = random.randint(1, 5)
    try:
        resp = requests.get(
            OPENVERSE_URL,
            params={
                "q": query,
                "license": "cc0,by,by-sa",
                "page_size": page_size,
                "page": page,
                "mature": "false",
            },
            timeout=25,
            headers={"User-Agent": USER_AGENT},
        )
        resp.raise_for_status()
        data = resp.json()
    except (requests.RequestException, ValueError):
        return []

    urls = []
    for item in data.get("results", []):
        url = item.get("url") or item.get("thumbnail")
        if url and url.startswith("http"):
            urls.append(url)
    random.shuffle(urls)
    return urls


def _fit_background(image: Image.Image, size: tuple[int, int]) -> Image.Image:
    target_w, target_h = size
    src_w, src_h = image.size
    scale = max(target_w / src_w, target_h / src_h)
    new_w, new_h = int(src_w * scale), int(src_h * scale)
    resized = image.resize((new_w, new_h), Image.Resampling.LANCZOS)
    left = (new_w - target_w) // 2
    top = (new_h - target_h) // 2
    return resized.crop((left, top, left + target_w, top + target_h)).convert("RGB")


def fetch_public_background(
    query: str | None,
    size: tuple[int, int],
    max_attempts: int = 8,
) -> tuple[Image.Image, dict]:
    """Fetch a CC-licensed background from Openverse (always from the web, no local assets)."""
    search_query = query or random.choice(DEFAULT_QUERIES)
    urls = _search_openverse(search_query)

    for url in urls[:max_attempts]:
        img = _download_image(url)
        if img is None or min(img.size) < 240:
            continue
        fitted = _fit_background(img, size)
        digest = hashlib.sha1(url.encode()).hexdigest()[:10]
        return fitted, {
            "query": search_query,
            "source": "openverse",
            "image_id": digest,
        }

    fallback = Image.new("RGB", size, color=(100, 140, 180))
    return fallback, {
        "query": search_query,
        "source": "fallback",
        "image_id": "none",
    }