32 خطوط
1.6 KiB
Python
32 خطوط
1.6 KiB
Python
"""Opt-in, administrator-provided licensed webfonts. Never load paths from SchDoc."""
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
|
|
def fonts():
|
|
directory=os.getenv('FONT_DIR')
|
|
if not directory: return {}
|
|
root=Path(directory).resolve()
|
|
manifest=root/'fonts.json'
|
|
values=json.loads(manifest.read_text())
|
|
result={}
|
|
for family,variants in values.items():
|
|
if isinstance(variants,str): variants=[{'file':variants}]
|
|
for index,variant in enumerate(variants):
|
|
file=(root/variant['file']).resolve()
|
|
if not file.is_relative_to(root) or not file.is_file() or file.suffix.lower() not in ('.ttf','.otf','.woff','.woff2'):
|
|
raise ValueError('Invalid configured font path')
|
|
weight=str(variant.get('weight','normal')); style=variant.get('style','normal')
|
|
if weight not in {'normal','bold','100','200','300','400','500','600','700','800','900'} or style not in {'normal','italic','oblique'}:
|
|
raise ValueError('Invalid configured font variant')
|
|
result[f'{len(result)}{file.suffix.lower()}']={'family':family,'file':file,'weight':weight,'style':style}
|
|
return result
|
|
|
|
def stylesheet():
|
|
rules=[]
|
|
for name,font in fonts().items():
|
|
# JSON strings safely quote arbitrary family names inside CSS strings.
|
|
family=json.dumps(font['family'],ensure_ascii=True).replace('<','\\3c ')
|
|
rules.append(f"@font-face{{font-family:{family};src:url('/fonts/{name}');font-weight:{font['weight']};font-style:{font['style']};font-display:block}}")
|
|
return '\n'.join(rules)
|