fix(api,frontend): render files by name without fetching, previewable share links

This commit is contained in:
hh committed 2026-08-13 03:49:29 +02:00
1 parent ef739838a5
commit e833de245a
13 files changed
+348 -45

No files matched your search

+97
View File
@@ -29,6 +29,42 @@ _KIND_EXTENSIONS = {
"voice": ".ogg",
}
_EXTENSION_MIMES = {
".flac": "audio/flac",
".gif": "image/gif",
".heic": "image/heic",
".jpeg": "image/jpeg",
".jpg": "image/jpeg",
".m4a": "audio/mp4",
".mov": "video/quicktime",
".mp3": "audio/mpeg",
".mp4": "video/mp4",
".ogg": "audio/ogg",
".pdf": "application/pdf",
".png": "image/png",
".svg": "image/svg+xml",
".txt": "text/plain",
".wav": "audio/wav",
".webm": "video/webm",
".webp": "image/webp",
}
_KIND_MIMES = {
"animation": "video/mp4",
"gif": "video/mp4",
"photo": "image/jpeg",
"video": "video/mp4",
"video_note": "video/mp4",
"voice": "audio/ogg",
}
_GENERIC_MIMES = {
"application/octet-stream",
"application/binary",
"binary/octet-stream",
"",
}
_INLINE_MIME_PREFIXES = ("image/", "video/", "audio/", "text/")
_INLINE_MIMES = {"application/pdf", "application/json"}
@@ -57,6 +93,45 @@ _PREVIEW_AGENTS = (
"python-requests",
)
_TRANSLIT = {
"а": "a",
"б": "b",
"в": "v",
"г": "g",
"д": "d",
"е": "e",
"ё": "e",
"ж": "zh",
"з": "z",
"и": "i",
"й": "y",
"к": "k",
"л": "l",
"м": "m",
"н": "n",
"о": "o",
"п": "p",
"р": "r",
"с": "s",
"т": "t",
"у": "u",
"ф": "f",
"х": "h",
"ц": "c",
"ч": "ch",
"ш": "sh",
"щ": "sch",
"ъ": "",
"ы": "y",
"ь": "",
"э": "e",
"ю": "yu",
"я": "ya",
}
_URL_UNSAFE = re.compile(r"[^A-Za-z0-9._-]+")
_URL_REPEATS = re.compile(r"_{2,}")
_UNSAFE_CHARS = re.compile(r'[\\/:*?"<>|\x00-\x1f]+')
_SPACES = re.compile(r"\s+")
_NAME_LIMIT = 120
@@ -86,6 +161,16 @@ def sanitize_name(name: str) -> str:
return cleaned or "file"
def url_slug(file_name: str) -> str:
lowered = "".join(
_TRANSLIT.get(ch, _TRANSLIT.get(ch.lower(), ch)) for ch in file_name
)
slug = _URL_REPEATS.sub("_", _URL_UNSAFE.sub("_", lowered)).strip("_.")
if not slug:
return "file"
return slug[:_NAME_LIMIT]
def media_file_name(
kind: str | None, mime: str | None, message_id: int, original: str | None = None
) -> str:
@@ -99,6 +184,18 @@ def story_file_name(peer_id: int, story_id: int, media_kind: str | None) -> str:
return f"story_{peer_id}_{story_id}{extension_for(media_kind or 'photo', None)}"
def resolve_mime(
kind: str | None, mime: str | None, file_name: str | None = None
) -> str:
if mime and mime.lower() not in _GENERIC_MIMES:
return mime
if file_name and "." in file_name:
by_extension = _EXTENSION_MIMES.get(f".{file_name.rsplit('.', 1)[1].lower()}")
if by_extension:
return by_extension
return _KIND_MIMES.get(kind or "", mime or "application/octet-stream")
def is_inline_mime(mime: str | None) -> bool:
if not mime:
return False