-
Notifications
You must be signed in to change notification settings - Fork 0
/
bot
executable file
·234 lines (219 loc) · 11.2 KB
/
bot
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
require 'telegram/bot'
require 'colorize'
require 'json'
require_relative 'convert.rb'
require_relative 'schedule.rb'
STDOUT.sync = true
START_TIME = Time.now # to ignore old messages
RETRY_DURATION = 5 # maybe the user accidentally blocked the bot
RETRY_ATTEMPTS = 5 # 403 happens when you just added it to group, but after a moment 403 disappears.
LOGO_OUTPUT = 0.05 # line output speed for logos
CONFIG = JSON.parse(IO.read('config.json'))
# 30 seconds was enough for 100 MB files.
STASH_DURATION = {
'15MB' => 8,
'30MB' => 13,
'50MB' => 21,
'100MB' => 34
}
MISC_BASE = 'videos'
Dir.mkdir(MISC_BASE) unless Dir.exist?(MISC_BASE)
if ARGV.any? { |arg| ['-h', '--help', '-help'].include?(arg) }
puts <<~HELP
Usage: ruby bot.rb [options]
Options:
--keep_files Keep files after processing.
--verbose Enable ffmpeg output.
--silent Suppress all output.
-h, --help Show this help message.
Example:
ruby bot.rb --verbose Specify parameters using spaces without commas.
HELP
exit
end
valid_args = {
keep: '--keep_files',
verbose: '--verbose',
silent: '--silent',
}
valid_args_keys = valid_args.values
invalid_args = ARGV.select { |arg| !valid_args_keys.include?(arg) && !arg.start_with?('--server=') }
if invalid_args.any?
invalid_args_string = invalid_args.map { |arg| "#{arg} (invalid)" }.join(', ')
abort "Invalid arguments: #{invalid_args_string}. See bor.rb -h for help.".red.bold
end
api_server = ARGV.find { |arg| arg.start_with?('--server=') }
api_server_url = api_server ? api_server.split('=')[1] : CONFIG['API_SERVER']
keep_files = ARGV.include?(valid_args[:keep])
verbose_mode = ARGV.include?(valid_args[:verbose])
silent_mode = ARGV.include?(valid_args[:silent])
if verbose_mode && silent_mode
abort 'impossible to use --verbose and --silent at the same time'.red.bold
end
if silent_mode
STDOUT.reopen(File.new('/dev/null', 'w'))
STDERR.reopen(File.new('/dev/null', 'w'))
else
system('clear')
end
logo = File.read('logo.txt') if File.exist?('logo.txt')
logo.each_line do |line|
print "#{line}".red.on_black
sleep(LOGO_OUTPUT)
end
def judge_cleaner(file_path, keep_files)
File.delete(file_path) if !keep_files && File.exist?(file_path)
end
media_threads = {}
group_files = {}
mutex = Mutex.new
Telegram::Bot::Client.run(CONFIG['TOKEN'], url: api_server_url) do |bot|
begin
bot.listen do |msg|
next if msg.date < START_TIME.to_i
Thread.new {
begin
caption = msg.caption
retries = 0
if msg.is_a?(Telegram::Bot::Types::ChatMemberUpdated)
puts "Chat member updated, skipping message processing.".yellow.italic
next
end
begin
puts sprintf(
"[ID: #{msg.chat.id}][%-10s%-20s: %-20s] [TIME: %-20s]\n",
"New message from ".green,
"#{msg.from.first_name}".green.bold,
"#{msg.text}".black.on_white.italic,
"#{Time.now}".cyan
) if msg.text
case msg.text
when '/start'
bot.api.send_message(
chat_id: msg.chat.id,
text: "Hello, *#{msg.from.first_name}*\ntelegram requirement:\n\\- The duration of circle video is limited to one minute",
parse_mode: 'MarkdownV2'
)
end
if msg.video
puts sprintf(
"[ID: #{msg.chat.id}][%-10s %-20s - %-20s] [TIME: %-20s]\n",
"#{msg.from.first_name}".green.bold,
"sent the video".green,
"#{msg.video.file_id}".black.on_white.italic,
"#{Time.now}".cyan
)
Thread.new do
video_file = bot.api.get_file(file_id: msg.video.file_id)
video_path = video_file.file_path
converted_video = "#{video_path}-CONVERTED.mp4"
processor = VideoProcessor.new
processor.input = video_path
processor.output = converted_video
processor.verbose = verbose_mode
processor.convert_to_note
if caption
begin
scheduler = CaptionSchedule.new
scheduler.schedule(caption) do
CONFIG['channels'].each { |channel_id|
bot.api.send_video_note(
chat_id: channel_id,
video_note: Faraday::UploadIO.new(converted_video, 'video/mp4'),
)
}
processor.remove_junk unless keep_files
end
rescue CaptionError
bot.api.send_message(
chat_id: msg.chat.id,
text: "Invalid time format, process will not be executed"
)
end
else
bot.api.send_video_note(chat_id: msg.chat.id, video_note: Faraday::UploadIO.new(converted_video, 'video/mp4'))
processor.remove_junk unless keep_files
end
puts sprintf("[TIME: %-20s] [%-10s]\n", "#{Time.new}".cyan.blink, "Completed successfully".green.bold)
end
elsif msg.document && msg.media_group_id
media_group_id = msg.media_group_id
mutex.synchronize {
puts sprintf(
"[ID: #{msg.chat.id}][%-10s %-20s - %-20s] [TIME: %-20s]\n",
"#{msg.from.first_name}".green.bold,
"sent document".green,
"#{msg.document.file_id}".black.on_white.italic,
"#{Time.now}".cyan
)
document_file = bot.api.get_file(file_id: msg.document.file_id)
document_path = document_file.file_path
group_files[media_group_id] ||= []
group_files[media_group_id] << "file '#{document_path.gsub(/['"]/, '')}'\n"
}
unless media_threads[media_group_id]
media_threads[media_group_id] = Thread.new do
sleep(STASH_DURATION['100MB']) # WORK ON IT!
stash_path = File.expand_path("./#{MISC_BASE}/#{media_group_id}.txt")
concated_video = "#{stash_path}.mp4"
File.open(stash_path, 'a+') { |f|
group_files[media_group_id].each { |rec| f.write(rec) }
}
group_files.delete(media_group_id)
processor = VideoProcessor.new
processor.input = stash_path
processor.output = concated_video
processor.verbose = verbose_mode
processor.concat_to_mpeg
movie = FFMPEG::Movie.new(concated_video)
bot.api.send_video(
chat_id: msg.chat.id,
video: Faraday::UploadIO.new(concated_video, 'video/mp4'),
caption: 'Send me that video if you want to get a circle message',
supports_streaming: true,
width: movie.width,
height: movie.height
)
File.foreach(stash_path) do |line|
if line =~ /file '(.*?)'/
file_path = Regexp.last_match(1)
judge_cleaner(file_path, keep_files)
end
end
processor.remove_junk unless keep_files
puts sprintf("[TIME: %-20s] [%-10s]\n", "#{Time.new}".cyan.blink, "Completed successfully".green.bold)
media_threads.delete(media_group_id)
end
end
media_threads[media_group_id].join if media_threads[media_group_id] && !media_threads[media_group_id].alive?
end
rescue Telegram::Bot::Exceptions::ResponseError => e
if e.error_code == 403
puts "Bot was blocked by the user.".red.bold
elsif e.error_code == 400
bot.api.send_message(chat_id: msg.chat.id, text: "```\n#{e}```", parse_mode: 'MarkdownV2')
puts "#{e}".red.blink + " - Telegram limitations".red
else
puts "#{e}".red.blink
end
rescue FFMPEG::Error => e
puts "#{e}".red
rescue Net::ReadTimeout => e
puts "[#{retries}/#{RETRY_ATTEMPTS}] Network timeout error: #{e.message}".red.bold
if retries < RETRY_ATTEMPTS
sleep(RETRY_DURATION)
retries += 1
retry
else
puts "Exceeded maximum retry attempts. Stopping retry.".red.bold
end
end
rescue NoMethodError => e
puts "NoMethodError: #{e.message} - Perhaps the message does not have right property.".red
end
} # Thread
end
rescue Interrupt
puts "\n[#{Time.now}] Bot has been stopped\n".green.underline.italic
end
end