"""空き枠の取得元。 各 provider は fetch(studio, date) -> [{"name": 部屋名, "slots": [{"start": 分, "status"}]}] と booking_url(studio) を持つモジュール。status は "free" | "booked" | "closed"。 studios.json の "provider" で使う provider を選ぶ(null ならオンラインで見られないスタジオ)。 取得結果は CACHE_SECONDS の間メモリに置き、同じ日付を何度開いても相手サイトに負荷をかけない。 """ import threading import time from . import rinky PROVIDERS = { "rinky": rinky, } CACHE_SECONDS = 300 _cache = {} _cache_lock = threading.Lock() def booking_url(studio): provider = PROVIDERS.get(studio.get("provider")) return provider.booking_url(studio) if provider else None def fetch(studio_id, studio, day): """(rooms, fetched_at) を返す。provider が無ければ (None, None)。""" provider = PROVIDERS.get(studio.get("provider")) if not provider: return None, None key = (studio_id, day.isoformat()) with _cache_lock: hit = _cache.get(key) if hit and time.time() - hit[1] < CACHE_SECONDS: return hit rooms = provider.fetch(studio, day) entry = (rooms, time.time()) with _cache_lock: _cache[key] = entry return entry