fix: audio-only format, m4a/mp3 support, source URL in caption
This commit is contained in:
parent
053f6c8afc
commit
839cd57f6f
3 changed files with 50 additions and 38 deletions
8
bot.py
8
bot.py
|
|
@ -562,18 +562,18 @@ async def process_queue_item(item: QueueItem):
|
||||||
|
|
||||||
video_file = open(video_path, 'rb')
|
video_file = open(video_path, 'rb')
|
||||||
caption = get_text(item.locale, 'caption', bot_username=TELEGRAM_BOT_USERNAME)
|
caption = get_text(item.locale, 'caption', bot_username=TELEGRAM_BOT_USERNAME)
|
||||||
|
caption += f"\n\n{item.url}"
|
||||||
|
|
||||||
# Определяем имя файла для отправки
|
# Определяем имя файла для отправки
|
||||||
video_filename = Path(video_path).name
|
video_filename = Path(video_path).name
|
||||||
|
|
||||||
# Отправляем как документ, чтобы Telegram НЕ сжимал видео
|
# Отправляем как документ — Telegram сам определит тип по расширению
|
||||||
# (reply_video сжимает, что приводит к потере качества и одинаковому размеру)
|
|
||||||
await item.original_message.reply_document(
|
await item.original_message.reply_document(
|
||||||
document=video_file,
|
document=video_file,
|
||||||
filename=video_filename,
|
filename=video_filename,
|
||||||
caption=caption,
|
caption=caption,
|
||||||
read_timeout=600, # 10 минут на ответ от Telegram
|
read_timeout=600,
|
||||||
write_timeout=600, # 10 минут на отправку файла
|
write_timeout=600,
|
||||||
connect_timeout=60,
|
connect_timeout=60,
|
||||||
pool_timeout=60
|
pool_timeout=60
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -295,12 +295,20 @@ def download_youtube_video(url: str, max_retries: int = 3, format_id: str | None
|
||||||
combined_fallback = ['best[ext=mp4]/best', 'best']
|
combined_fallback = ['best[ext=mp4]/best', 'best']
|
||||||
|
|
||||||
requested_height = None # высота, запрошенная пользователем
|
requested_height = None # высота, запрошенная пользователем
|
||||||
|
is_audio_only = False
|
||||||
|
|
||||||
if format_id:
|
if format_id:
|
||||||
is_specific_code = not ('[' in format_id or ']' in format_id)
|
is_specific_code = not ('[' in format_id or ']' in format_id)
|
||||||
|
# Если format_id запрашивает только аудио, не подмешиваем видео-форматы
|
||||||
|
# и не валидируем наличие видео-потока
|
||||||
|
first_selector = format_id.split('/')[0]
|
||||||
|
is_audio_only = 'bestaudio' in first_selector
|
||||||
requested_height = _extract_height_from_format_id(format_id)
|
requested_height = _extract_height_from_format_id(format_id)
|
||||||
|
|
||||||
if requested_height is not None:
|
if is_audio_only:
|
||||||
|
format_options = [format_id]
|
||||||
|
logger.info(f"[DOWNLOAD] Аудио-only режим, format_id: {format_id}")
|
||||||
|
elif requested_height is not None:
|
||||||
# Конкретный format_id (из /formats) ставим ПЕРВЫМ —
|
# Конкретный format_id (из /formats) ставим ПЕРВЫМ —
|
||||||
# он точно указывает выбранные пользователем format codes.
|
# он точно указывает выбранные пользователем format codes.
|
||||||
# Height-ограниченный селектор идёт как fallback
|
# Height-ограниченный селектор идёт как fallback
|
||||||
|
|
@ -354,17 +362,16 @@ def download_youtube_video(url: str, max_retries: int = 3, format_id: str | None
|
||||||
|
|
||||||
logger.info(f"[DOWNLOAD] Попытка {attempt + 1}: успешно скачано с форматом {format_option}")
|
logger.info(f"[DOWNLOAD] Попытка {attempt + 1}: успешно скачано с форматом {format_option}")
|
||||||
|
|
||||||
# Проверяем, что файл содержит видео-поток, а не только аудио
|
# Проверяем, что файл содержит видео-поток (только для видео-форматов)
|
||||||
# (yt-dlp c allow_unplayable_formats может скачать av01 формат
|
if not is_audio_only:
|
||||||
# и отказаться от мержа, вернув только аудио)
|
downloaded = _find_latest_downloaded()
|
||||||
downloaded = _find_latest_downloaded()
|
if downloaded and not _file_has_video_stream(downloaded):
|
||||||
if downloaded and not _file_has_video_stream(downloaded):
|
logger.warning(f"[DOWNLOAD] Файл {downloaded.name} не содержит видео-потока (только аудио). Удаляем и пробуем следующий формат...")
|
||||||
logger.warning(f"[DOWNLOAD] Файл {downloaded.name} не содержит видео-потока (только аудио). Удаляем и пробуем следующий формат...")
|
try:
|
||||||
try:
|
downloaded.unlink()
|
||||||
downloaded.unlink()
|
except Exception:
|
||||||
except Exception:
|
pass
|
||||||
pass
|
continue
|
||||||
continue
|
|
||||||
|
|
||||||
download_success = True
|
download_success = True
|
||||||
break
|
break
|
||||||
|
|
@ -392,14 +399,15 @@ def download_youtube_video(url: str, max_retries: int = 3, format_id: str | None
|
||||||
ydl.download([url])
|
ydl.download([url])
|
||||||
logger.info(f"[DOWNLOAD] Попытка {attempt + 1}: успешно скачано без cookies")
|
logger.info(f"[DOWNLOAD] Попытка {attempt + 1}: успешно скачано без cookies")
|
||||||
|
|
||||||
downloaded = _find_latest_downloaded()
|
if not is_audio_only:
|
||||||
if downloaded and not _file_has_video_stream(downloaded):
|
downloaded = _find_latest_downloaded()
|
||||||
logger.warning(f"[DOWNLOAD] Файл {downloaded.name} без видео-потока. Удаляем и пробуем следующий формат...")
|
if downloaded and not _file_has_video_stream(downloaded):
|
||||||
try:
|
logger.warning(f"[DOWNLOAD] Файл {downloaded.name} без видео-потока. Удаляем и пробуем следующий формат...")
|
||||||
downloaded.unlink()
|
try:
|
||||||
except Exception:
|
downloaded.unlink()
|
||||||
pass
|
except Exception:
|
||||||
continue
|
pass
|
||||||
|
continue
|
||||||
|
|
||||||
download_success = True
|
download_success = True
|
||||||
cookies_valid = False # Отключаем cookies для следующих попыток
|
cookies_valid = False # Отключаем cookies для следующих попыток
|
||||||
|
|
@ -668,10 +676,10 @@ def get_youtube_formats(url: str) -> list[dict]:
|
||||||
'filesize_mb': round(total_size / 1024 / 1024, 1) if total_size else None,
|
'filesize_mb': round(total_size / 1024 / 1024, 1) if total_size else None,
|
||||||
})
|
})
|
||||||
|
|
||||||
# Добавляем аудиодорожку
|
# Добавляем аудиодорожку (M4A в приоритете — Telegram поддерживает только MP3/M4A для reply_audio)
|
||||||
if best_audio_info['size']:
|
if best_audio_info['size']:
|
||||||
result.append({
|
result.append({
|
||||||
'format_id': 'bestaudio/best',
|
'format_id': 'bestaudio[ext=m4a]/bestaudio[ext=mp3]/bestaudio/best',
|
||||||
'label': f"Audio only ({best_audio_info['ext']})",
|
'label': f"Audio only ({best_audio_info['ext']})",
|
||||||
'quality': 'audio',
|
'quality': 'audio',
|
||||||
'ext': best_audio_info['ext'],
|
'ext': best_audio_info['ext'],
|
||||||
|
|
@ -871,15 +879,19 @@ def download_stream():
|
||||||
|
|
||||||
# Безопасное имя файла без кириллицы для заголовка
|
# Безопасное имя файла без кириллицы для заголовка
|
||||||
safe_filename = video_path.name.encode('ascii', 'ignore').decode('ascii') or 'youtube_video.mp4'
|
safe_filename = video_path.name.encode('ascii', 'ignore').decode('ascii') or 'youtube_video.mp4'
|
||||||
if not safe_filename.endswith(('.mp4', '.webm', '.mkv')):
|
if not safe_filename.endswith(('.mp4', '.webm', '.mkv', '.m4a', '.mp3')):
|
||||||
safe_filename = 'youtube_video.mp4'
|
safe_filename = 'youtube_video.mp4'
|
||||||
|
|
||||||
# Определяем content-type
|
# Определяем content-type по реальному расширению файла
|
||||||
content_type = 'video/mp4'
|
ext = video_path.suffix.lower()
|
||||||
if video_path.suffix == '.webm':
|
content_type_map = {
|
||||||
content_type = 'video/webm'
|
'.webm': 'video/webm',
|
||||||
elif video_path.suffix == '.mkv':
|
'.mkv': 'video/x-matroska',
|
||||||
content_type = 'video/x-matroska'
|
'.mp4': 'video/mp4',
|
||||||
|
'.m4a': 'audio/mp4',
|
||||||
|
'.mp3': 'audio/mpeg',
|
||||||
|
}
|
||||||
|
content_type = content_type_map.get(ext, 'video/mp4')
|
||||||
|
|
||||||
logger.info(f"[REQUEST {request_id}] Отправляем файл: {safe_filename}, Content-Type: {content_type}, размер: {len(video_data)} байт")
|
logger.info(f"[REQUEST {request_id}] Отправляем файл: {safe_filename}, Content-Type: {content_type}, размер: {len(video_data)} байт")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,14 +27,14 @@
|
||||||
.youtube.com TRUE / FALSE 1776287761000 ST-yve142 session_logininfo=AFmmF2swRQIgZPfEOdmfC8u5sHvE1aOagKEvp5rRUe5hRUeLiYmxLDwCIQDqFIR59yZ_aBb5BLYSpK7LGdJ6YZqnh32USuOyMZTC5g%3AQUQ3MjNmd0ZzX01fTjViQ2kzMDJEWG5Ed09zMGF1TlhJcm81YWt3WWdKS2RCZkY3Z2NmMVhudUF4MFVZdFlHd0YtaEU0R3VHNHQ3VmFSZHdfR1RIcnBJNUtXeWhKWVVScE1ZcXNJdzRfdkFGVi1lZzY2dWxCcVVGZ0FPSjNzVmFjTVg1YTBYS0xBajEzU1REM3dnbUc5U3E3NHVtLVRLLXRn
|
.youtube.com TRUE / FALSE 1776287761000 ST-yve142 session_logininfo=AFmmF2swRQIgZPfEOdmfC8u5sHvE1aOagKEvp5rRUe5hRUeLiYmxLDwCIQDqFIR59yZ_aBb5BLYSpK7LGdJ6YZqnh32USuOyMZTC5g%3AQUQ3MjNmd0ZzX01fTjViQ2kzMDJEWG5Ed09zMGF1TlhJcm81YWt3WWdKS2RCZkY3Z2NmMVhudUF4MFVZdFlHd0YtaEU0R3VHNHQ3VmFSZHdfR1RIcnBJNUtXeWhKWVVScE1ZcXNJdzRfdkFGVi1lZzY2dWxCcVVGZ0FPSjNzVmFjTVg1YTBYS0xBajEzU1REM3dnbUc5U3E3NHVtLVRLLXRn
|
||||||
.youtube.com TRUE / TRUE 1807824503515 __Secure-1PSIDTS sidts-CjUBWhotCSAL5EMsgNfc0JD8UVvU5vyCYbx9ZFc0Nnry9Qc7YHRzl6a7o8Zm6bPYHoFyKALKlBAA
|
.youtube.com TRUE / TRUE 1807824503515 __Secure-1PSIDTS sidts-CjUBWhotCSAL5EMsgNfc0JD8UVvU5vyCYbx9ZFc0Nnry9Qc7YHRzl6a7o8Zm6bPYHoFyKALKlBAA
|
||||||
.youtube.com TRUE / TRUE 1807824503517 __Secure-3PSIDTS sidts-CjUBWhotCSAL5EMsgNfc0JD8UVvU5vyCYbx9ZFc0Nnry9Qc7YHRzl6a7o8Zm6bPYHoFyKALKlBAA
|
.youtube.com TRUE / TRUE 1807824503517 __Secure-3PSIDTS sidts-CjUBWhotCSAL5EMsgNfc0JD8UVvU5vyCYbx9ZFc0Nnry9Qc7YHRzl6a7o8Zm6bPYHoFyKALKlBAA
|
||||||
.youtube.com TRUE / TRUE 1793313256 VISITOR_INFO1_LIVE vFr43YvHJaE
|
.youtube.com TRUE / TRUE 1793314544 VISITOR_INFO1_LIVE vFr43YvHJaE
|
||||||
.youtube.com TRUE / TRUE 1793313256 VISITOR_PRIVACY_METADATA CgJSVRIEGgAgMg%3D%3D
|
.youtube.com TRUE / TRUE 1793314544 VISITOR_PRIVACY_METADATA CgJSVRIEGgAgMg%3D%3D
|
||||||
.youtube.com TRUE / FALSE 1776288519000 ST-tladcw session_logininfo=AFmmF2swRQIgZPfEOdmfC8u5sHvE1aOagKEvp5rRUe5hRUeLiYmxLDwCIQDqFIR59yZ_aBb5BLYSpK7LGdJ6YZqnh32USuOyMZTC5g%3AQUQ3MjNmd0ZzX01fTjViQ2kzMDJEWG5Ed09zMGF1TlhJcm81YWt3WWdKS2RCZkY3Z2NmMVhudUF4MFVZdFlHd0YtaEU0R3VHNHQ3VmFSZHdfR1RIcnBJNUtXeWhKWVVScE1ZcXNJdzRfdkFGVi1lZzY2dWxCcVVGZ0FPSjNzVmFjTVg1YTBYS0xBajEzU1REM3dnbUc5U3E3NHVtLVRLLXRn
|
.youtube.com TRUE / FALSE 1776288519000 ST-tladcw session_logininfo=AFmmF2swRQIgZPfEOdmfC8u5sHvE1aOagKEvp5rRUe5hRUeLiYmxLDwCIQDqFIR59yZ_aBb5BLYSpK7LGdJ6YZqnh32USuOyMZTC5g%3AQUQ3MjNmd0ZzX01fTjViQ2kzMDJEWG5Ed09zMGF1TlhJcm81YWt3WWdKS2RCZkY3Z2NmMVhudUF4MFVZdFlHd0YtaEU0R3VHNHQ3VmFSZHdfR1RIcnBJNUtXeWhKWVVScE1ZcXNJdzRfdkFGVi1lZzY2dWxCcVVGZ0FPSjNzVmFjTVg1YTBYS0xBajEzU1REM3dnbUc5U3E3NHVtLVRLLXRn
|
||||||
.youtube.com TRUE / FALSE 0 PREF tz=UTC&f7=100&f6=40000000&hl=en
|
.youtube.com TRUE / FALSE 0 PREF tz=UTC&f7=100&f6=40000000&hl=en
|
||||||
.youtube.com TRUE / FALSE 1776288527000 ST-xuwub9 session_logininfo=AFmmF2swRQIgZPfEOdmfC8u5sHvE1aOagKEvp5rRUe5hRUeLiYmxLDwCIQDqFIR59yZ_aBb5BLYSpK7LGdJ6YZqnh32USuOyMZTC5g%3AQUQ3MjNmd0ZzX01fTjViQ2kzMDJEWG5Ed09zMGF1TlhJcm81YWt3WWdKS2RCZkY3Z2NmMVhudUF4MFVZdFlHd0YtaEU0R3VHNHQ3VmFSZHdfR1RIcnBJNUtXeWhKWVVScE1ZcXNJdzRfdkFGVi1lZzY2dWxCcVVGZ0FPSjNzVmFjTVg1YTBYS0xBajEzU1REM3dnbUc5U3E3NHVtLVRLLXRn
|
.youtube.com TRUE / FALSE 1776288527000 ST-xuwub9 session_logininfo=AFmmF2swRQIgZPfEOdmfC8u5sHvE1aOagKEvp5rRUe5hRUeLiYmxLDwCIQDqFIR59yZ_aBb5BLYSpK7LGdJ6YZqnh32USuOyMZTC5g%3AQUQ3MjNmd0ZzX01fTjViQ2kzMDJEWG5Ed09zMGF1TlhJcm81YWt3WWdKS2RCZkY3Z2NmMVhudUF4MFVZdFlHd0YtaEU0R3VHNHQ3VmFSZHdfR1RIcnBJNUtXeWhKWVVScE1ZcXNJdzRfdkFGVi1lZzY2dWxCcVVGZ0FPSjNzVmFjTVg1YTBYS0xBajEzU1REM3dnbUc5U3E3NHVtLVRLLXRn
|
||||||
.youtube.com TRUE / FALSE 1809297256 SIDCC AKEyXzVsS5YLUQD8z9C1v-mL2JIyS_lqX6qpnZKQ_AFrB5WfKI8t61IDvWwihKLswvR3ya_Y2JOP
|
.youtube.com TRUE / FALSE 1809298544 SIDCC AKEyXzVa7lSTdOSv8wBZg33qEiiwbNCETtCNC9xssuu_BPPxNep2Lc2negI0NHWARFHb_MwD8V_c
|
||||||
.youtube.com TRUE / TRUE 1809297256 __Secure-1PSIDCC AKEyXzXDaKBNexbPjEPwCB8IDGZRrPTCTOVNDWgBRtsKv5XcaCCg5JxpeRXlk2gX4lidlrONyC52
|
.youtube.com TRUE / TRUE 1809298544 __Secure-1PSIDCC AKEyXzX8DfBF1L6BIhnm19j-ZBSyE16TpQVvn6vIBB_zA5dma1mjRuTuWTlS3ut3feYm1YMhme8q
|
||||||
.youtube.com TRUE / TRUE 1809297256 __Secure-3PSIDCC AKEyXzUF0D1vjEN7XqU2ReXIRFuti0YZjmliSwyRcCUSq5rUlGmYoYmzjSngu8HtDmEiioigkUI9
|
.youtube.com TRUE / TRUE 1809298544 __Secure-3PSIDCC AKEyXzUfC0IlqutC5s9_cf3HrI_S4F8ui7NJPayGnr2TMOS5u0EuoUVZaKgJm6vklINRtl0oO9hR
|
||||||
.youtube.com TRUE / FALSE 1776288585000 ST-3opvp5 session_logininfo=AFmmF2swRQIgZPfEOdmfC8u5sHvE1aOagKEvp5rRUe5hRUeLiYmxLDwCIQDqFIR59yZ_aBb5BLYSpK7LGdJ6YZqnh32USuOyMZTC5g%3AQUQ3MjNmd0ZzX01fTjViQ2kzMDJEWG5Ed09zMGF1TlhJcm81YWt3WWdKS2RCZkY3Z2NmMVhudUF4MFVZdFlHd0YtaEU0R3VHNHQ3VmFSZHdfR1RIcnBJNUtXeWhKWVVScE1ZcXNJdzRfdkFGVi1lZzY2dWxCcVVGZ0FPSjNzVmFjTVg1YTBYS0xBajEzU1REM3dnbUc5U3E3NHVtLVRLLXRn
|
.youtube.com TRUE / FALSE 1776288585000 ST-3opvp5 session_logininfo=AFmmF2swRQIgZPfEOdmfC8u5sHvE1aOagKEvp5rRUe5hRUeLiYmxLDwCIQDqFIR59yZ_aBb5BLYSpK7LGdJ6YZqnh32USuOyMZTC5g%3AQUQ3MjNmd0ZzX01fTjViQ2kzMDJEWG5Ed09zMGF1TlhJcm81YWt3WWdKS2RCZkY3Z2NmMVhudUF4MFVZdFlHd0YtaEU0R3VHNHQ3VmFSZHdfR1RIcnBJNUtXeWhKWVVScE1ZcXNJdzRfdkFGVi1lZzY2dWxCcVVGZ0FPSjNzVmFjTVg1YTBYS0xBajEzU1REM3dnbUc5U3E3NHVtLVRLLXRn
|
||||||
.youtube.com TRUE / TRUE 0 YSC KTvrS45hA30
|
.youtube.com TRUE / TRUE 0 YSC KTvrS45hA30
|
||||||
.instagram.com TRUE / TRUE 1801240452128 datr hGdNaS-QqakSYV8X2eqVTIyA
|
.instagram.com TRUE / TRUE 1801240452128 datr hGdNaS-QqakSYV8X2eqVTIyA
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue