Title
Telegram storage sends images as Documents without captions — should use send_illust() for Photo + metadata
Body
Describe the bug
When using STORAGE = Telegram with ALBUM_ID, images are sent to the channel as Documents (files) without any caption. The author name, tweet text, and original link are all missing.
In contrast, when GALLERY_ID is configured, images are sent as Photos in a media group with proper captions containing metadata. This is the expected behavior for ALBUM_ID as well.
To Reproduce
- Configure
.env:
STORAGE = Local,Telegram
ALBUM_ID = -100xxxxxxxx
# GALLERY_ID not set
-
Send a Twitter/X link to the bot.
-
Observe the channel: images appear as file attachments with no text.
Expected behavior
Images should be posted as Photos (via send_media_group) with the same caption format used by send_to_gallery(): author, tweet text, and original URL.
Root Cause
In storage/__init__.py, Storage.store() passes illust.all_files (a list[File]) to each storage driver, stripping the Illust object that contains the caption:
# storage/__init__.py — current
async def store(self, illust: Illust):
tasks = [disk.store(illust.all_files) for disk in self.disks]
The Telegram.store() method only receives list[File] and calls bot.send_doc() which sends raw files:
# storage/telegram.py — current
async def store(self, files: list[File]):
for file in files:
tasks.append(bot.send_doc(file, chat_id=ALBUM_ID))
Proposed Solution
Pass the full Illust object through the storage interface so drivers can access both files and metadata.
1. storage/__init__.py — pass illust instead of illust.all_files:
async def store(self, illust: Illust):
- tasks = [disk.store(illust.all_files) for disk in self.disks]
+ tasks = [disk.store(illust) for disk in self.disks]
2. storage/local.py — adapt to new signature:
-async def store(self, files: list[File]):
+async def store(self, illust: Illust):
+ files = illust.all_files
destinations = {file.destination for file in files}
3. storage/telegram.py — use send_illust() with fallback:
-async def store(self, files: list[File]):
- tasks = []
- for file in files:
- size = await file.size()
- if size > 50 * 1024 * 1024:
- logger.warning(...)
- continue
- tasks.append(bot.send_doc(file, chat_id=ALBUM_ID))
- await run_in_pool(tasks, MAX_PARALLEL_UPLOAD)
+async def store(self, illust: Illust):
+ try:
+ await bot.send_illust(illust, chat_id=ALBUM_ID)
+ except Exception as e:
+ logger.error("Failed to send photos, falling back to docs: {}", e)
+ tasks = []
+ for file in illust.all_files:
+ size = await file.size()
+ if size > 50 * 1024 * 1024:
+ logger.warning(...)
+ continue
+ tasks.append(bot.send_doc(file, chat_id=ALBUM_ID))
+ await run_in_pool(tasks, MAX_PARALLEL_UPLOAD)
The fallback to send_doc() preserves backward compatibility for edge cases where Photo upload fails.
Impact on other storage drivers
The other drivers (s3.py, googledrive.py, mega.py, onedrive.py) also need the signature updated from store(self, files: list[File]) to store(self, illust: Illust), extracting illust.all_files internally. The change is mechanical.
Additional context
This was tested on nazurin v2.9.6 with TWITTER_API = syndication. The send_illust() path works reliably — it's already used by send_to_gallery() for the GALLERY_ID channel and produces the expected Photo + Caption output.
A workaround without code changes is to set GALLERY_ID to the same channel as ALBUM_ID, but this results in duplicate posts (one from gallery, one from storage).
中文
问题描述
DOCS.md
使用 STORAGE = Telegram + ALBUM_ID 时,图片以 Document(文件)形式发送到频道,没有标题、作者、原文链接。
根因
Storage.store() 传 illust.all_files 给存储驱动,丢失了 Illust 对象中的 caption 信息。Telegram 驱动调用 send_doc() 发送裸文件。
修改建议
三处改动:storage/__init__.py 传完整 illust,local.py 适配新签名,telegram.py 改用 send_illust() 发 Photo + Caption(带降级 fallback)。
Title
Telegram storage sends images as Documents without captions — should use send_illust() for Photo + metadataBody
Describe the bug
When using
STORAGE = TelegramwithALBUM_ID, images are sent to the channel as Documents (files) without any caption. The author name, tweet text, and original link are all missing.In contrast, when
GALLERY_IDis configured, images are sent as Photos in a media group with proper captions containing metadata. This is the expected behavior forALBUM_IDas well.To Reproduce
.env:Send a Twitter/X link to the bot.
Observe the channel: images appear as file attachments with no text.
Expected behavior
Images should be posted as Photos (via
send_media_group) with the same caption format used bysend_to_gallery(): author, tweet text, and original URL.Root Cause
In
storage/__init__.py,Storage.store()passesillust.all_files(alist[File]) to each storage driver, stripping theIllustobject that contains the caption:The
Telegram.store()method only receiveslist[File]and callsbot.send_doc()which sends raw files:Proposed Solution
Pass the full
Illustobject through the storage interface so drivers can access both files and metadata.1.
storage/__init__.py— passillustinstead ofillust.all_files:2.
storage/local.py— adapt to new signature:3.
storage/telegram.py— usesend_illust()with fallback:The fallback to
send_doc()preserves backward compatibility for edge cases where Photo upload fails.Impact on other storage drivers
The other drivers (
s3.py,googledrive.py,mega.py,onedrive.py) also need the signature updated fromstore(self, files: list[File])tostore(self, illust: Illust), extractingillust.all_filesinternally. The change is mechanical.Additional context
This was tested on nazurin v2.9.6 with
TWITTER_API = syndication. Thesend_illust()path works reliably — it's already used bysend_to_gallery()for theGALLERY_IDchannel and produces the expected Photo + Caption output.A workaround without code changes is to set
GALLERY_IDto the same channel asALBUM_ID, but this results in duplicate posts (one from gallery, one from storage).中文
问题描述
DOCS.md
使用
STORAGE = Telegram+ALBUM_ID时,图片以 Document(文件)形式发送到频道,没有标题、作者、原文链接。根因
Storage.store()传illust.all_files给存储驱动,丢失了Illust对象中的 caption 信息。Telegram 驱动调用send_doc()发送裸文件。修改建议
三处改动:
storage/__init__.py传完整illust,local.py适配新签名,telegram.py改用send_illust()发 Photo + Caption(带降级 fallback)。