11bfd2b3ee
Один канал жил под ключами Durov/durov/@name в трёх слоях (tgcache-файлы, data/cache/ каталоги, SQLite-строки) -> дубли кеша, двойные походы в Telegram, осиротевшие деревья. ID<->username НЕ унифицируем (сознательно). - channel_key.py: canonical_channel_key (strip @, -100... числовые verbatim, иначе lowercase; безопасно и для API-вызовов). - tg_cache._cache_file_path прогоняет ключ через canonical. - post_parser.get_channel_username -> lowercase (обе ветки; канонизирует SQLite/media-URL/t.me). Только эти 2 строки. - api_server.get_media: fs_channel = canonical_channel_key(channel) ПОСЛЕ проверки дайджеста (дайджест — по ИСХОДНОМУ url, иначе ломаются выданные ссылки); fs_channel во всех путях/ключах/download ниже. - migrate_channel_keys_sync в lifespan (после init_db_sync, до client.start, через asyncio.to_thread): канал целиком FS-потом-SQL. Обязательный os.path.samefile guard ДО merge/rmtree — на case-insensitive FS Durov/durov один inode, иначе снесли бы кеш. FS-сбой -> SQL пропуск (строки старорегистровые, дерево видно свиперу, нет вечных orphan). SQL-merge PK-safe (twin -> merge added=max/mime non-NULL + DELETE, иначе plain UPDATE). Идемпотентно. closes #24 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
30 lines
950 B
Python
30 lines
950 B
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# flake8: noqa
|
|
# pylint: disable=missing-function-docstring
|
|
|
|
"""Canonical channel key.
|
|
|
|
Dependency-free helper shared by tg_cache, post_parser and api_server. Kept free of
|
|
any project imports so it can be imported by all three layers without introducing a
|
|
circular import.
|
|
"""
|
|
|
|
from typing import Union
|
|
|
|
|
|
def canonical_channel_key(channel: Union[str, int]) -> str:
|
|
"""Canonical cache/DB key for a channel.
|
|
|
|
Telegram usernames are case-insensitive -> lowercase them.
|
|
Numeric '-100...' ids keep their exact string form. The '@' prefix is stripped.
|
|
The canonical form is also SAFE for Telegram API calls (usernames case-insensitive
|
|
on the API side; numeric unchanged) -- callers may thread one value through both
|
|
filesystem paths and API calls.
|
|
"""
|
|
s = str(channel).strip().lstrip('@')
|
|
if s.startswith('-100') and s[4:].isdigit():
|
|
return s
|
|
return s.lower()
|