This repository has been archived by the owner on Mar 27, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
run.rb
executable file
·236 lines (206 loc) · 8.56 KB
/
run.rb
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
235
236
#!/usr/bin/env ruby
require 'telegram/bot'
require 'net/http'
require 'pp'
#sanity check before starting
fail_msg = String.new
fail_msg << "settings.rb is missing\n" if File.exist?('./settings.rb') == false
fail_msg << "scripts directory is missing\n" if File.exist?('./scripts') == false
fail_msg << "static_messages directory is missing\n" if File.exist?('./static_messages') == false
abort("#{fail_msg}Aborting...") if ! fail_msg.empty?
require_relative 'settings.rb' #Settings
require_relative 'api_movie.rb' #CouchPotato API
require_relative 'api_show.rb' #Sonarr API
require_relative 'commands.rb' #/X Telegram command methods
require_relative 'callbacks.rb' #Telegram callback methods
def ack_callback(message, display_message = true)
#Delete message and notify user that we got the request
begin
Telegram::Bot::Client.run(@token) do |bot|
if display_message == true
bot.api.editMessageText(chat_id: message.message.chat.id, message_id: message.message.message_id, text: "#{message.from.username}Request received. Please wait...", reply_markup: "") #Removes buttons. Changes text
bot.api.answerCallbackQuery(callback_query_id: message.id, show_alert: false, text: "Request received. Please wait...") #Sends a pop-up notification
else
bot.api.deleteMessage(chat_id: message.message.chat.id, message_id: message.message.message_id) #Deletes message and buttons
end
end
rescue
puts "Error handling callback query. Error: " + $!.message
end
end
def delete_message(message)
#Deletes a message referred to by message_id
begin
Telegram::Bot::Client.run(@token) do |bot|
bot.api.deleteMessage(chat_id: message.message.chat.id, message_id: message.message.message_id) #Deletes message and buttons
end
rescue
puts "Error deleting message. Error: " + $!.message
end
end
def message_from_admin?(message)
return @admin_userids.include? message.from.id.to_s
end
def handle_callback_query(message)
#callbacks that start with a "!" ("!DMS|tt123456") can ONLY be submitted
#by an admin. Ignore if normal user presses
#Get "DLM" from "DLM|abc123"
command = message.data.split("|")[0].upcase
if command.start_with?('!') then
#verify an admin pressed this button
if ! message_from_admin?(message)
Telegram::Bot::Client.run(@token) {|bot| bot.api.answerCallbackQuery(callback_query_id: message.id, show_alert: false, text: "Requires admin approval")}
return
end
command = command.split("!")[1]
elsif command.start_with?('#') then
#is this an ignored command
return
end
ack_callback(message) #Change the movie/show selection message to "Request received..."
case command
when "DLM" #download movie
process_callback_dlm(message)
when "DLS" #download show
process_callback_dls(message)
when "RDLM" #force re-download movie
process_callback_rdlm(message)
when "NRDLM" #don't re-download movie
process_callback_nrdlm(message)
end
delete_message(message) #Delete the "Request received..." message
rescue => e
handle_exception(e, message, true)
end
def handle_user_join(message)
message.new_chat_members.each do |i|
if ! i.username.nil?
#Greet by username
send_message(message.chat.id, "@#{i.username} Welcome to the group!\n\n#{File.read('static_messages/welcome-message.txt')}")
elsif ! i.first_name.nil?
#Greet by first name
send_message(message.chat.id, "Welcome to the group, #{i.first_name}!\n\n#{File.read('static_messages/welcome-message.txt')}")
else
#They have no username or first name. Generic greeting
send_message(message.chat.id, "Welcome to the group!\n\n#{File.read('static_messages/welcome-message.txt')}")
end
end
end
def handle_message(message)
#message#text will be nil if there was no message sent, but something still happened in the group
#For example: A user left/joined the group, the group name changed, etc
if ! message.reply_to_message.nil? then
#drop message. Someone's replying to a message
#send by our bot
return
end
if message.text.nil?
# Find out if user(s) joined the group. If so, welcome them
if ! message.new_chat_members.nil?
handle_user_join(message)
else
#Handle non-messages and non-joins here
end
return #so that we don't try to process this as a command (below)
end
case message.text.split(" ")[0].split("@")[0].downcase #Get "/m" from "/m movie name" or "/m@botname movie name"
when "/m", "/movie" #Movie download request - "/m Movie Name"
process_command_m(message)
when "/s", "/show" #Show download request - "/s Show Name"
process_command_s(message)
when "/a", "/admin" #User is sending an admin-only command
process_command_a(message)
when "/help" #Show command syntax
send_message(message.chat.id, File.read('static_messages/help.txt'))
when "/welcome" #show welcome instructions
send_message(message.chat.id, File.read('static_messages/welcome-message.txt'))
else #Response not a command
send_message(message.chat.id, "'#{message.text}' is not a valid command.\nSend '/help' for instructions")
end
rescue => e
handle_exception(e, message, true)
end
def handle_exception(e, message, notify_users)
puts "=" * 60
puts "EXCEPTION HIT!"
puts "=" * 60
puts "PRINTING INSPECT..."
puts e.inspect
puts "=" * 30
puts "PRINTING BACKTRACE..."
puts e.backtrace
puts "=" * 60
if notify_users == true then
#is this a callback query or a message
case message
when Telegram::Bot::Types::Message
send_message(message.chat.id, "The bot has run into an issue while processing a request.\n\nAsk #{@admin_name} (@#{@admin_username}) for assistance.")
when Telegram::Bot::Types::CallbackQuery
send_message(message.message.chat.id, "The bot has run into an issue while processing a request.\n\nAsk #{@admin_name} (@#{@admin_username}) for assistance.")
end
end
end
def send_message(chatid, message_text, imageurl = nil)
if imageurl != nil
#Send message with text as html link to image
Telegram::Bot::Client.run(@token) {|bot| bot.api.send_message(chat_id: chatid, text: "#{message_text}<a href=\"#{imageurl}\">.</a>", parse_mode: "HTML") }
else
#Send a plain-text message
Telegram::Bot::Client.run(@token) {|bot| bot.api.send_message(chat_id: chatid, text: message_text) }
end
end
def send_message_markdown(chatid, message_text)
#Send a plain-text message
Telegram::Bot::Client.run(@token) {|bot| bot.api.send_message(chat_id: chatid, text: "```#{message_text}```", parse_mode: 'Markdown') }
end
def send_question(chatid, question_text, answers = [ ])
if ! answers.empty? then
begin
keyboard = Telegram::Bot::Types::InlineKeyboardMarkup.new(inline_keyboard: answers)
Telegram::Bot::Client.run(@token) {|bot| bot.api.send_message(chat_id: chatid, text: question_text, reply_markup: keyboard) }
rescue
puts "ERROR: " + $!.message
end
else
puts "send_question called without any possible answers provided"
end
end
def validate_incoming_data(message)
message = message.message if message.is_a? Telegram::Bot::Types::CallbackQuery
return "Received message is not from a valid source! Type: \"#{message.chat.type}\". Ignoring." if ! @allowed_sources.include?(message.chat.type)
return "Unauthorized user sent message. User ID: #{message.from.id} Source ID: #{message.chat.id}." if ! @authorized_chatids.include?(message.chat.id.to_s)
return true
end
#DEBUG
#puts get_show_profile_list
#puts get_movie_profile_list
#puts get_rootfolderpath
#puts movie_imdbid_to_title("tt0499549")
#abort
#Disabled output buffering so that
#systemd can see our stdout messages in realtime
STDOUT.sync = true
#Main loop - listen for new messages
Telegram::Bot::Client.run(@token) do |bot|
bot.listen do |message|
validation = validate_incoming_data(message)
if validation == true then
#Change message.from.username to something we can call the user
#This makes referring to the user in replies much easier
#@Username or their first name
if ! message.from.username.nil? #Username -> @Username
message.from.username = "@" + message.from.username + " "
elsif ! message.from.first_name.nil? #Username -> John
message.from.username = message.from.first_name + ", "
end
case message
when Telegram::Bot::Types::Message
handle_message(message) #entrypoint for all messages
when Telegram::Bot::Types::CallbackQuery
handle_callback_query(message) #entrypoint for all callback queries
end
else
puts validation
end
end
end