Spaces:
Paused
Paused
File size: 5,409 Bytes
e99a4e1 bdab4b9 e99a4e1 29b26c5 1f1751e e99a4e1 a5577b3 e99a4e1 1f1751e ac529dc bcba4b2 e99a4e1 3f38962 e99a4e1 3d5772b e99a4e1 3f38962 e99a4e1 3f38962 e99a4e1 a5577b3 e99a4e1 1f1751e 5177c84 9de8641 e99a4e1 faf516b 3f38962 e99a4e1 bdab4b9 e99a4e1 b576cce e99a4e1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | #!/usr/bin/env python3
# coding: utf-8
# ytdlbot - generic.py
import logging
import os
from pathlib import Path
import yt_dlp
from config import AUDIO_FORMAT
from utils import is_youtube
from database.model import get_format_settings, get_quality_settings
from engine.base import BaseDownloader
def match_filter(info_dict):
if info_dict.get("is_live"):
raise NotImplementedError("Skipping live video")
return None # Allow download for non-live videos
class YoutubeDownload(BaseDownloader):
@staticmethod
def get_format(m):
return [
f"bestvideo[ext=mp4][height={m}]+bestaudio[ext=m4a]",
f"bestvideo[vcodec^=avc][height={m}]+bestaudio[acodec^=mp4a]/best[vcodec^=avc]/best",
]
def _setup_formats(self) -> list | None:
if not is_youtube(self._url):
return [None]
quality, format_ = get_quality_settings(self._chat_id), get_format_settings(self._chat_id)
# quality: high, medium, low, custom
# format: audio, video, document
formats = []
defaults = [
# webm , vp9 and av01 are not streamable on telegram, so we'll extract only mp4
"bestvideo[ext=mp4][vcodec!*=av01][vcodec!*=vp09]+bestaudio[ext=m4a]/bestvideo+bestaudio",
"bestvideo[vcodec^=avc]+bestaudio[acodec^=mp4a]/best[vcodec^=avc]/best",
None,
]
audio = AUDIO_FORMAT or "m4a"
maps = {
"high-audio": [f"bestaudio[ext={audio}]"],
"high-video": defaults,
"high-document": defaults,
"medium-audio": [f"bestaudio[ext={audio}]"], # no mediumaudio :-(
"medium-video": self.get_format(720),
"medium-document": self.get_format(720),
"low-audio": [f"bestaudio[ext={audio}]"],
"low-video": self.get_format(480),
"low-document": self.get_format(480),
"custom-audio": "",
"custom-video": "",
"custom-document": "",
}
if quality == "custom":
pass
# TODO not supported yet
# get format from ytdlp, send inlinekeyboard button to user so they can choose
# another callback will be triggered to download the video
# available_options = {
# "480P": "best[height<=480]",
# "720P": "best[height<=720]",
# "1080P": "best[height<=1080]",
# }
# markup, temp_row = [], []
# for quality, data in available_options.items():
# temp_row.append(types.InlineKeyboardButton(quality, callback_data=data))
# if len(temp_row) == 3: # Add a row every 3 buttons
# markup.append(temp_row)
# temp_row = []
# # Add any remaining buttons as the last row
# if temp_row:
# markup.append(temp_row)
# self._bot_msg.edit_text("Choose the format", reply_markup=types.InlineKeyboardMarkup(markup))
# return None
formats.extend(maps[f"{quality}-{format_}"])
# extend default formats if not high*
if quality != "high":
formats.extend(defaults)
return formats
def _download(self, formats) -> list:
output = Path(self._tempdir.name, "%(title).70s.%(ext)s").as_posix()
ydl_opts = {
"progress_hooks": [lambda d: self.download_hook(d)],
"outtmpl": output,
"restrictfilenames": False,
"quiet": True,
"match_filter": match_filter,
}
# setup cookies for youtube only
if is_youtube(self._url):
# use cookies from browser firstly
if browsers := os.getenv("BROWSERS"):
ydl_opts["cookiesfrombrowser"] = browsers.split(",")
if os.path.isfile("youtube-cookies.txt") and os.path.getsize("youtube-cookies.txt") > 100:
ydl_opts["cookiefile"] = "youtube-cookies.txt"
# try add extract_args if present
if potoken := os.getenv("POTOKEN"):
ydl_opts["extractor_args"] = {"youtube": ["player-client=web,default", f"po_token=web+{potoken}"]}
# for new version? https://github.com/yt-dlp/yt-dlp/wiki/PO-Token-Guide
# ydl_opts["extractor_args"] = {
# "youtube": [f"po_token=web.player+{potoken}", f"po_token=web.gvs+{potoken}"]
# }
if self._url.startswith("https://drive.google.com"):
# Always use the `source` format for Google Drive URLs.
formats = ["source"] + formats
files = None
for f in formats:
ydl_opts["format"] = f
logging.info("yt-dlp options: %s", ydl_opts)
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
ydl.download([self._url])
files = list(Path(self._tempdir.name).glob("*"))
break
return files
def _start(self, formats=None):
# start download and upload, no cache hit
# user can choose format by clicking on the button(custom config)
default_formats = self._setup_formats()
if formats is not None:
# formats according to user choice
default_formats = formats + self._setup_formats()
self._download(default_formats)
self._upload()
|