update v0.1.1
This commit is contained in:
178
bot/handlers.py
178
bot/handlers.py
@@ -1,9 +1,8 @@
|
||||
from typing import Optional
|
||||
from pathlib import Path
|
||||
import httpx
|
||||
from typing import Optional
|
||||
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from telegram.ext import ContextTypes
|
||||
|
||||
from .config import DOWNLOAD_DIR, COOKIES_FILE, BROWSER, CONNECT_TIMEOUT, READ_TIMEOUT
|
||||
from .utils import is_instagram_story_url, VIDEO_SUFFIXES, IMAGE_SUFFIXES, extract_instagram_username
|
||||
from .ytdlp_client import build_opts, run
|
||||
@@ -276,33 +275,33 @@ class Handlers:
|
||||
self.sending_active[chat_id] = False
|
||||
|
||||
async def _download_file(self, url: str, into: Path) -> Path:
|
||||
print(f"[DBG] _download_file: url={url}, into={into}") # DBG
|
||||
into.parent.mkdir(parents=True, exist_ok=True)
|
||||
timeout = httpx.Timeout(30.0)
|
||||
async with httpx.AsyncClient(timeout=timeout, follow_redirects=True) as client:
|
||||
r = await client.get(url)
|
||||
r.raise_for_status()
|
||||
ctype = r.headers.get('content-type', '')
|
||||
print(f"[DBG] _download_file: content-type={ctype}") # DBG
|
||||
print(f"[DBG] _download_file: url={url}, into={into}") # DBG
|
||||
into.parent.mkdir(parents=True, exist_ok=True)
|
||||
timeout = httpx.Timeout(30.0)
|
||||
async with httpx.AsyncClient(timeout=timeout, follow_redirects=True) as client:
|
||||
r = await client.get(url)
|
||||
r.raise_for_status()
|
||||
ctype = r.headers.get('content-type', '')
|
||||
print(f"[DBG] _download_file: content-type={ctype}") # DBG
|
||||
|
||||
ext = ''
|
||||
if 'image/jpeg' in ctype:
|
||||
ext = '.jpg'
|
||||
elif 'image/png' in ctype:
|
||||
ext = '.png'
|
||||
elif 'image/webp' in ctype:
|
||||
ext = '.webp'
|
||||
elif 'image/avif' in ctype:
|
||||
ext = '.avif'
|
||||
elif 'image/heic' in ctype or 'image/heif' in ctype:
|
||||
ext = '.heic'
|
||||
ext = ''
|
||||
if 'image/jpeg' in ctype:
|
||||
ext = '.jpg'
|
||||
elif 'image/png' in ctype:
|
||||
ext = '.png'
|
||||
elif 'image/webp' in ctype:
|
||||
ext = '.webp'
|
||||
elif 'image/avif' in ctype:
|
||||
ext = '.avif'
|
||||
elif 'image/heic' in ctype or 'image/heif' in ctype:
|
||||
ext = '.heic'
|
||||
|
||||
if not into.suffix:
|
||||
into = into.with_suffix(ext or '.jpg')
|
||||
if not into.suffix:
|
||||
into = into.with_suffix(ext or '.jpg')
|
||||
|
||||
into.write_bytes(r.content)
|
||||
print(f"[DBG] _download_file: saved {into}") # DBG
|
||||
return into
|
||||
into.write_bytes(r.content)
|
||||
print(f"[DBG] _download_file: saved {into}") # DBG
|
||||
return into
|
||||
|
||||
def _pick_path(self, entry) -> Optional[Path]:
|
||||
if isinstance(entry, dict):
|
||||
@@ -313,6 +312,7 @@ class Handlers:
|
||||
p = Path(fp)
|
||||
if p.exists():
|
||||
return p
|
||||
|
||||
fn = entry.get('_filename')
|
||||
if fn:
|
||||
p = Path(fn)
|
||||
@@ -320,14 +320,19 @@ class Handlers:
|
||||
return p
|
||||
return None
|
||||
|
||||
async def _send_images_from_playlist_with_fallback(self, info: dict | None, message, chat_id: int) -> int:
|
||||
async def _send_images_from_playlist_with_fallback(
|
||||
self, info: Optional[dict], message, chat_id: int
|
||||
) -> int:
|
||||
if not isinstance(info, dict):
|
||||
return 0
|
||||
|
||||
entries = info.get('entries') or []
|
||||
sent = 0
|
||||
|
||||
for idx, entry in enumerate(entries):
|
||||
fp = self._pick_path(entry)
|
||||
temp_file: Optional[Path] = None
|
||||
|
||||
try:
|
||||
if fp and fp.exists():
|
||||
suffix = (fp.suffix or '').lower()
|
||||
@@ -343,10 +348,12 @@ class Handlers:
|
||||
urls = [t.get('url') for t in thumbs if isinstance(t, dict) and t.get('url')]
|
||||
if urls:
|
||||
image_url = max(urls, key=len)
|
||||
|
||||
if not image_url and isinstance(entry, dict):
|
||||
cand = entry.get('url') or entry.get('thumbnail')
|
||||
if isinstance(cand, str) and cand.startswith(('http://', 'https://')):
|
||||
image_url = cand
|
||||
|
||||
if image_url:
|
||||
temp_file = await self._download_file(image_url, DOWNLOAD_DIR / f"img_{idx}")
|
||||
await self._send_photo_safe(message, temp_file, chat_id)
|
||||
@@ -356,72 +363,73 @@ class Handlers:
|
||||
temp_file.unlink(missing_ok=True)
|
||||
if fp:
|
||||
fp.unlink(missing_ok=True)
|
||||
|
||||
return sent
|
||||
|
||||
async def _send_playlist_mixed_with_images(self, info: dict | None, message, chat_id: int) -> int:
|
||||
if not isinstance(info, dict):
|
||||
print("[DBG] _send_playlist_mixed_with_images: info is not dict") # DBG
|
||||
return 0
|
||||
async def _send_playlist_mixed_with_images(
|
||||
self, info: Optional[dict], message, chat_id: int
|
||||
) -> int:
|
||||
if not isinstance(info, dict):
|
||||
print("[DBG] _send_playlist_mixed_with_images: info is not dict")
|
||||
return 0
|
||||
|
||||
entries = info.get('entries') or []
|
||||
print(f"[DBG] playlist entries={len(entries)}") # DBG
|
||||
entries = info.get('entries') or []
|
||||
print(f"[DBG] playlist entries={len(entries)}")
|
||||
|
||||
sent = 0
|
||||
for idx, entry in enumerate(entries):
|
||||
print(f"[DBG] entry[{idx}] keys={list(entry.keys()) if isinstance(entry, dict) else type(entry)}") # DBG
|
||||
fp = self._pick_path(entry)
|
||||
temp_file: Path | None = None
|
||||
sent = 0
|
||||
for idx, entry in enumerate(entries):
|
||||
print(f"[DBG] entry[{idx}] keys={list(entry.keys()) if isinstance(entry, dict) else type(entry)}")
|
||||
fp = self._pick_path(entry)
|
||||
temp_file: Optional[Path] = None
|
||||
|
||||
try:
|
||||
if fp and fp.exists():
|
||||
suffix = (fp.suffix or '').lower()
|
||||
print(f"[DBG] entry[{idx}] local file={fp}, suffix={suffix}") # DBG
|
||||
|
||||
if suffix in IMAGE_SUFFIXES:
|
||||
print(f"[DBG] entry[{idx}] send as photo") # DBG
|
||||
await self._send_photo_safe(message, fp, chat_id)
|
||||
sent += 1
|
||||
elif suffix in VIDEO_SUFFIXES:
|
||||
print(f"[DBG] entry[{idx}] transcode/send video") # DBG
|
||||
out_mp4 = await transcode_to_mobile_mp4(fp)
|
||||
try:
|
||||
await self._send_video_safe(message, out_mp4, chat_id)
|
||||
try:
|
||||
if fp and fp.exists():
|
||||
suffix = (fp.suffix or '').lower()
|
||||
print(f"[DBG] entry[{idx}] local file={fp}, suffix={suffix}")
|
||||
if suffix in IMAGE_SUFFIXES:
|
||||
print(f"[DBG] entry[{idx}] send as photo")
|
||||
await self._send_photo_safe(message, fp, chat_id)
|
||||
sent += 1
|
||||
elif suffix in VIDEO_SUFFIXES:
|
||||
print(f"[DBG] entry[{idx}] transcode/send video")
|
||||
out_mp4 = await transcode_to_mobile_mp4(fp)
|
||||
try:
|
||||
await self._send_video_safe(message, out_mp4, chat_id)
|
||||
sent += 1
|
||||
finally:
|
||||
out_mp4.unlink(missing_ok=True)
|
||||
else:
|
||||
print(f"[DBG] entry[{idx}] send as document")
|
||||
await self._send_document_safe(message, fp, chat_id)
|
||||
sent += 1
|
||||
finally:
|
||||
out_mp4.unlink(missing_ok=True)
|
||||
else:
|
||||
print(f"[DBG] entry[{idx}] send as document") # DBG
|
||||
await self._send_document_safe(message, fp, chat_id)
|
||||
sent += 1
|
||||
else:
|
||||
print(f"[DBG] entry[{idx}] no local file, try thumbnails/url") # DBG
|
||||
image_url = None
|
||||
thumbs = entry.get('thumbnails') if isinstance(entry, dict) else None
|
||||
print(f"[DBG] entry[{idx}] no local file, try thumbnails/url")
|
||||
image_url = None
|
||||
thumbs = entry.get('thumbnails') if isinstance(entry, dict) else None
|
||||
|
||||
if isinstance(thumbs, list) and thumbs:
|
||||
urls = [t.get('url') for t in thumbs if isinstance(t, dict) and t.get('url')]
|
||||
if urls:
|
||||
image_url = max(urls, key=len)
|
||||
print(f"[DBG] entry[{idx}] thumbnail url={image_url}") # DBG
|
||||
if isinstance(thumbs, list) and thumbs:
|
||||
urls = [t.get('url') for t in thumbs if isinstance(t, dict) and t.get('url')]
|
||||
if urls:
|
||||
image_url = max(urls, key=len)
|
||||
print(f"[DBG] entry[{idx}] thumbnail url={image_url}")
|
||||
|
||||
if not image_url and isinstance(entry, dict):
|
||||
cand = entry.get('url') or entry.get('thumbnail')
|
||||
if isinstance(cand, str) and cand.startswith(('http://', 'https://')):
|
||||
image_url = cand
|
||||
print(f"[DBG] entry[{idx}] direct url={image_url}") # DBG
|
||||
if not image_url and isinstance(entry, dict):
|
||||
cand = entry.get('url') or entry.get('thumbnail')
|
||||
if isinstance(cand, str) and cand.startswith(('http://', 'https://')):
|
||||
image_url = cand
|
||||
print(f"[DBG] entry[{idx}] direct url={image_url}")
|
||||
|
||||
if image_url:
|
||||
temp_file = await self._download_file(image_url, DOWNLOAD_DIR / f"story_img_{idx}")
|
||||
await self._send_photo_safe(message, temp_file, chat_id)
|
||||
sent += 1
|
||||
else:
|
||||
print(f"[DBG] entry[{idx}] no image url found") # DBG
|
||||
if image_url:
|
||||
temp_file = await self._download_file(image_url, DOWNLOAD_DIR / f"story_img_{idx}")
|
||||
await self._send_photo_safe(message, temp_file, chat_id)
|
||||
sent += 1
|
||||
else:
|
||||
print(f"[DBG] entry[{idx}] no image url found")
|
||||
finally:
|
||||
if temp_file:
|
||||
temp_file.unlink(missing_ok=True)
|
||||
if fp:
|
||||
fp.unlink(missing_ok=True)
|
||||
|
||||
finally:
|
||||
if temp_file:
|
||||
temp_file.unlink(missing_ok=True)
|
||||
if fp:
|
||||
fp.unlink(missing_ok=True)
|
||||
|
||||
print(f"[DBG] _send_playlist_mixed_with_images: sent={sent}") # DBG
|
||||
return sent
|
||||
print(f"[DBG] _send_playlist_mixed_with_images: sent={sent}")
|
||||
return sent
|
||||
|
||||
Reference in New Issue
Block a user