forked from emptyteeth/ytdl-tg-bot
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbot.py
176 lines (140 loc) · 5.79 KB
/
bot.py
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#!/usr/bin/env python
from __future__ import unicode_literals
import pprint
import yt_dlp
import re
import time
from os import environ, getenv
from telegram import Update, Bot, Message
from telegram.ext import Updater, MessageHandler, Filters, CallbackContext
class Telegram:
def __init__(self, token: str, chatid: int):
self.token = token
self.chatid = chatid
self.bot = Bot(self.token)
self.updater = Updater(getenv('tgtoken'))
idflt = Filters.chat(int(getenv('tgchatid')))
dispatcher = self.updater.dispatcher
dispatcher.add_handler(MessageHandler(idflt, self.message_handler))
def start_polling(self):
self.updater.start_polling()
self.updater.idle()
def send_message(self, text: str) -> Message:
print("send_message: " + text, flush=True)
return self.bot.send_message(chat_id=self.chatid, text=text)
def edit_message(self, message: Message, text: str) -> Message:
self.bot.edit_message_text(text=text, chat_id=message.chat_id, message_id=message.message_id)
return message
def message_handler(self, update: Update, context: CallbackContext):
if not update.message:
return
print(f"Received: {update.message.text}", flush=True)
urlmatch = re.match('^.*(https?://[\S]+).*$', update.message.text, re.I)
if not urlmatch:
update.message.reply_text("Show me the URL")
return
url = urlmatch.group(1)
MyDownloader(update, self).download(url)
class MyDownloader:
def __init__(self, update: Update, telegram_bot: Telegram):
self.update = update
self.telegram_bot = telegram_bot
self.status_msg = None
self.last_msg_time = time.time()
self.yt_info = None
def my_hook(self, d):
if d['status'] == 'finished':
# self.telegram_bot.send_message(f"finished downloading, starting convert:\n{d['filename']}\nsize: {str(round(d['total_bytes'] / 1024 / 1024, 1))}MB")
# self.update.message.reply_text(f"finished downloading, starting convert:\n{d['filename']}\nsize: {str(round(d['total_bytes'] / 1024 / 1024, 1))}MB")
# pprint.pprint(d)
self.yt_info = d["info_dict"]
if d['status'] == 'downloading':
print(d['filename'], d['_percent_str'], d['_eta_str'])
filetype = "unknown"
if d['info_dict']['acodec'] != 'none':
filetype = "audio"
if d['info_dict']['vcodec'] != 'none':
filetype = "audio+video"
elif d['info_dict']['vcodec'] != 'none':
filetype = "video"
if (self.status_msg and time.time() - self.last_msg_time) > 5:
self.telegram_bot.edit_message(self.status_msg, f'Downloading {filetype}... {d["_percent_str"]}')
self.last_msg_time = time.time()
if d['status'] == 'error':
# self.telegram_bot.send_message(f"error:\n{d['filename']}")
self.update.message.reply_text(f"error:\n{d['filename']}")
def download(self, url):
self.last_msg_time = time.time()
ytdldir = getenv('ytdldir')
opts = {
'format': getenv('format'),
'logger': MyLogger(self.telegram_bot),
'progress_hooks': [self.my_hook],
'ignoreerrors': True,
'overwrites': True,
'nopostoverwrites': True,
'continuedl': True,
'writeinfojson': True,
'writethumbnail': True,
'check_formats': 'selected',
'merge_output_format': 'mp4',
'subtitleslangs': 'en.*,nl.*,du.*,-live_chat',
'sleep_interval': 2,
'socket_timeout': 8,
'retries': 3,
'noplaylist': True,
'paths': {"temp": "/tmp", "home": ytdldir},
'postprocessors': [{
# Embed metadata in video using ffmpeg.
'key': 'FFmpegMetadata',
'add_chapters': True,
'add_metadata': True,
}, {
'key': 'FFmpegSubtitlesConvertor',
'format': 'srt'
}, {
'key': 'FFmpegThumbnailsConvertor',
'format': 'jpg',
# Run this before the actual video download
'when': 'before_dl'
}, {
'key': 'EmbedThumbnail',
'already_have_thumbnail': True
}, {
'key': 'FFmpegEmbedSubtitle'
}
],
'outtmpl': '.' + getenv('ouputformat'),
}
with yt_dlp.YoutubeDL(opts) as ydl:
self.status_msg = self.update.message.reply_text('Downloading...', quote=True)
pprint.pprint(opts)
try:
ydl.download([url])
self.telegram_bot.edit_message(self.status_msg, f"Download Completed")
except Exception as ex:
self.telegram_bot.edit_message(self.status_msg, f'Unexpected error occurred: {ex=}')
print(f"Unexpected error occurred: {ex=}", flush=True)
class MyLogger(object):
def __init__(self, telegram_bot: Telegram):
self.telegram_bot = telegram_bot
def debug(self, msg):
print("debug: " + msg)
pass
def warning(self, msg):
print("warning: " + msg)
pass
def error(self, msg):
self.telegram_bot.send_message(msg)
def main():
print("App started v0.01", flush=True)
for env in ["tgtoken", "tgchatid", "ytdldir"]:
if env not in environ:
print(env + ' not found', flush=True)
exit(1)
del env
telegram_bot = Telegram(getenv('tgtoken'), int(getenv('tgchatid')))
telegram_bot.send_message("Ready")
telegram_bot.start_polling()
if __name__ == '__main__':
main()