Support full 2GB/2h video downloads via Local Bot API, clean VK wiki links and remove fallback links

This commit is contained in:
2026-08-14 19:46:16 +05:00
parent 3ded8d3edd
commit 144dd3cb52
5 changed files with 47 additions and 33 deletions
+4 -4
View File
@@ -55,11 +55,11 @@ class Settings(BaseSettings):
# Media & Video Limits
video_max_size_mb_cloud: int = 49
video_max_size_mb_local: int = 500
video_max_duration_sec: int = 600
video_max_size_mb_local: int = 2000
video_max_duration_sec: int = 7200
video_max_height: int = 720
media_download_timeout_sec: int = 60
yt_dlp_timeout_sec: int = 300
media_download_timeout_sec: int = 120
yt_dlp_timeout_sec: int = 600
# Text Styling & Decoration
header_text: str = ""
+1 -8
View File
@@ -243,15 +243,8 @@ class MAXPoster:
logger.warning("MAX bot token or chat ID is not set; skipping MAX post.")
return [], None
link_only = [m for m in media_items if m.is_link_only]
link_text = ""
if link_only:
lines = [f"- {m.media_type}: {m.original_url}" for m in link_only]
link_text = "\n\nМедиа по ссылке:\n" + "\n".join(lines)
full_raw = (raw_text + link_text).strip()
formatted_text = format_post_text(
full_raw,
raw_text,
parse_mode="html",
bold_first_line=settings.format_first_line_bold,
vk_url=vk_url,
+1
View File
@@ -131,6 +131,7 @@ class MediaProcessor:
f"best[height<={settings.video_max_height}][filesize<{max_size}]"
f"/best[height<={settings.video_max_height}]"
f"/bestvideo[height<={settings.video_max_height}][filesize<{max_size}]+bestaudio/best"
f"/bestvideo[height<={settings.video_max_height}]+bestaudio/best"
f"/best[filesize<{max_size}]"
f"/best"
),
+40 -12
View File
@@ -43,6 +43,35 @@ def strip_trailing_hashtags(text: str) -> str:
return "\n".join(lines).rstrip()
def clean_vk_wiki_links(text: str, parse_mode: str = "html") -> str:
"""
Converts VK wiki links to clickable links:
- [club12345|Name] -> <a href="https://vk.com/club12345">Name</a>
- [id12345|Name] -> <a href="https://vk.com/id12345">Name</a>
- [public12345|Name] -> <a href="https://vk.com/public12345">Name</a>
- [event12345|Name] -> <a href="https://vk.com/event12345">Name</a>
- [https://example.com|Title] -> <a href="https://example.com">Title</a>
"""
def _replace_vk(match: re.Match) -> str:
prefix = match.group(1)
obj_id = match.group(2)
title = match.group(3)
if parse_mode == "html":
return f'<a href="https://vk.com/{prefix}{obj_id}">{html.escape(title)}</a>'
return f"[{title}](https://vk.com/{prefix}{obj_id})"
def _replace_url(match: re.Match) -> str:
url = match.group(1)
title = match.group(2)
if parse_mode == "html":
return f'<a href="{html.escape(url, quote=True)}">{html.escape(title)}</a>'
return f"[{title}]({url})"
text = re.sub(r"\[(club|id|public|event)(\d+)\|([^\]]+)\]", _replace_vk, text)
text = re.sub(r"\[(https?://[^\s\|]+)\|([^\]]+)\]", _replace_url, text)
return text
def format_post_text(
raw_text: str,
*,
@@ -68,31 +97,30 @@ def format_post_text(
formatted_lines: list[str] = []
for idx, line in enumerate(lines):
if idx == title_idx and bold_first_line and line.strip():
cleaned_line = clean_vk_wiki_links(line, parse_mode=parse_mode) if parse_mode == "html" else line
if idx == title_idx and bold_first_line and cleaned_line.strip():
if parse_mode == "html":
escaped = html.escape(line.strip())
formatted_lines.append(f"<b>{escaped}</b>")
# If clean_vk_wiki_links was run, keep existing <a> tags safe
formatted_lines.append(f"<b>{cleaned_line.strip()}</b>")
else:
formatted_lines.append(f"**{line.strip()}**")
formatted_lines.append(f"**{cleaned_line.strip()}**")
# Blank line after header if next line is not empty
if idx + 1 < len(lines) and lines[idx + 1].strip() != "":
formatted_lines.append("")
else:
if parse_mode == "html":
formatted_lines.append(html.escape(line))
else:
formatted_lines.append(line)
formatted_lines.append(cleaned_line)
normalized_body = re.sub(r"\n{3,}", "\n\n", "\n".join(formatted_lines)).strip()
raw_body = "\n".join(formatted_lines)
normalized_body = re.sub(r"\n{3,}", "\n\n", raw_body).strip()
parts: list[str] = []
if header:
parts.append(html.escape(header) if parse_mode == "html" else header)
parts.append(html.escape(header) if parse_mode == "html" and "<" not in header else header)
if normalized_body:
parts.append(normalized_body)
if footer:
parts.append(html.escape(footer) if parse_mode == "html" else footer)
parts.append(html.escape(footer) if parse_mode == "html" and "<" not in footer else footer)
if tags:
parts.append(html.escape(tags) if parse_mode == "html" else tags)
parts.append(html.escape(tags) if parse_mode == "html" and "<" not in tags else tags)
return "\n\n".join(part for part in parts if part).strip()
+1 -9
View File
@@ -371,16 +371,8 @@ class TelegramPoster:
3. Tries sendRichMessage first.
4. If unavailable, falls back to legacy media groups / single media / text.
"""
# Append link-only media notice if any videos/photos couldn't be downloaded
link_only = [m for m in media_items if m.is_link_only]
link_text = ""
if link_only:
lines = [f"- {m.media_type}: <a href=\"{m.original_url}\">ссылка</a>" for m in link_only]
link_text = "\n\n<i>Медиа по ссылке:</i>\n" + "\n".join(lines)
full_raw = (raw_text + link_text).strip()
formatted_text = format_post_text(
full_raw,
raw_text,
parse_mode="html",
bold_first_line=settings.format_first_line_bold,
vk_url=vk_url,