2017-03-23 19:23:31 +00:00
import ast , dbtools , html , io , logging , moviepy . editor , os , PIL . Image , random , re , setuptools , string , bottools . strings , sys , telegram . ext , telegram , time , twitools , twitools . streaming , urllib . request , tweepy
2017-03-22 00:53:51 +00:00
def getTwo ( message ) :
try :
return twitools . twoBotHelper ( message . chat_id )
except ValueError :
message . reply_text ( bottools . strings . noauth )
except tweepy . error . TweepError as e :
raise
def twoExceptions ( e , message ) :
text = {
32 : bottools . strings . badToken ,
36 : bottools . strings . selfSpam ,
64 : bottools . strings . accountSuspended ,
88 : bottools . strings . rateLimit ,
89 : bottools . strings . badToken ,
99 : bottools . strings . badToken ,
130 : bottools . strings . overload ,
131 : bottools . strings . twitterError ,
161 : bottools . strings . followLimit ,
185 : bottools . strings . tweetLimit ,
186 : bottools . strings . longTweet ,
187 : bottools . strings . dupTweet ,
205 : bottools . strings . rateLimit ,
226 : bottools . strings . automatedTweet ,
271 : bottools . strings . selfMute ,
272 : bottools . strings . notMuted ,
323 : bottools . strings . multipleGIFs ,
326 : bottools . strings . accountLocked ,
354 : bottools . strings . longTweet
} . get ( e . api_code )
message . reply_text ( text or bottools . strings . twoFail )
2017-03-24 00:48:40 +00:00
def callback ( bot , update ) :
args = update . callback_query . data . split ( )
2017-03-24 12:08:47 +00:00
try :
feature = commands [ args [ 0 ] [ 1 : ] ]
try :
feature ( bot , update , args [ 1 : ] )
except :
feature ( bot , update )
except :
update . callback_query . reply_text ( bottools . strings . unknownCommand )
2017-03-24 00:48:40 +00:00
def mentionHelper ( bot , update ) :
args = update . message . text . split ( )
try :
feature = commands [ args [ 1 ] [ 1 : ] ]
try :
feature ( bot , update , args [ 2 : ] )
except :
2017-03-24 12:08:47 +00:00
print ( e )
2017-03-24 00:48:40 +00:00
feature ( bot , update )
2017-03-24 12:08:47 +00:00
except Exception as e :
logging . exception ( e )
update . message . reply_text ( bottools . strings . unknownCommand )
2017-03-24 00:48:40 +00:00
2017-03-22 00:53:51 +00:00
# Actual methods:
# ---------------
def start ( bot , update ) :
2017-03-22 11:18:07 +00:00
update . message . reply_text ( bottools . strings . start % { " name " : setuptools . botname ( ) } )
2017-03-22 00:53:51 +00:00
def fish ( bot , update ) :
dbtools . dbHelper ( ) . addFish ( update . message . chat_id )
update . message . reply_text ( bottools . strings . fishThanks )
def getTweetID ( tlid , cid ) :
try :
db = dbtools . dbHelper ( )
db . executeQuery ( " SELECT tid FROM timelines WHERE nr = %i AND cid = %i ; " % ( int ( tlid ) , int ( cid ) ) )
return db . getNext ( ) [ 0 ]
except Exception :
raise ValueError ( " No such tweet in timeline " )
def toggleTweet ( bot , update ) :
try :
update . message . reply_text ( bottools . strings . toggleTweet % ( bottools . strings . toggleTweetOn if dbtools . dbHelper ( ) . toggleTweet ( update . message . chat_id ) else bottools . strings . toggleTweetOff ) )
except tweepy . error . TweepError as e :
bottools . methods . twoExceptions ( e , update . message )
2017-03-24 21:24:55 +00:00
def toggleConfirmations ( bot , update ) :
try :
update . message . reply_text ( bottools . strings . toggleConfirmations % ( bottools . strings . toggleTweetOn if dbtools . dbHelper ( ) . toggleConfirmations ( update . message . chat_id ) else bottools . strings . toggleTweetOff ) )
except tweepy . error . TweepError as e :
bottools . methods . twoExceptions ( e , update . message )
2017-03-22 00:53:51 +00:00
def unknown ( bot , update ) :
update . message . reply_text ( bottools . strings . unknownCommand )
2017-03-24 00:48:40 +00:00
def makeMenu ( buttons , columns = 2 ) :
2017-03-23 21:39:54 +00:00
return [ buttons [ i : i + columns ] for i in range ( 0 , len ( buttons ) , columns ) ]
2017-03-22 00:53:51 +00:00
# Authentication process
def auth ( bot , update ) :
db = dbtools . dbHelper ( )
cid = update . message . chat_id
if not ( db . ato ( cid ) or db . ase ( cid ) ) :
auth = tweepy . OAuthHandler ( setuptools . cke ( ) , setuptools . cse ( ) )
update . message . reply_text ( bottools . strings . auth % auth . get_authorization_url ( ) )
dbtools . dbHelper ( ) . storeToken ( cid , auth . request_token )
else :
update . message . reply_text ( bottools . strings . authimp )
def verify ( bot , update , args ) :
db = dbtools . dbHelper ( )
cid = update . message . chat_id
if db . ato ( cid ) and not db . ase ( cid ) :
auth = tweepy . OAuthHandler ( setuptools . cke ( ) , setuptools . cse ( ) )
auth . request_token = ast . literal_eval ( db . ato ( cid ) )
try :
auth . get_access_token ( args [ 0 ] )
dbtools . dbHelper ( ) . storeUser ( cid , auth . access_token , auth . access_token_secret )
update . message . reply_text ( bottools . strings . verify )
except Exception as e :
dbtools . dbHelper ( ) . deleteUser ( update . message . chat_id )
update . message . reply_text ( bottools . strings . verifyfail )
else :
update . message . reply_text ( bottools . strings . verifyimp )
def unauth ( bot , update ) :
dbtools . dbHelper ( ) . deleteUser ( update . message . chat_id )
update . message . reply_text ( bottools . strings . unauth % setuptools . url ( ) )
# User methods
def follow ( bot , update , args ) :
try :
two = bottools . methods . getTwo ( update . message )
for user in args :
two . api . create_friendship ( screen_name = user )
except tweepy . error . TweepError as e :
bottools . methods . twoExceptions ( e , update . message )
def unfollow ( bot , update , args ) :
try :
two = bottools . methods . getTwo ( update . message )
for user in args :
two . api . destroy_friendship ( screen_name = user )
except tweepy . error . TweepError as e :
bottools . methods . twoExceptions ( e , update . message )
# Tweet methods
def explicitTweet ( bot , update , args , reply = None ) :
try :
two = bottools . methods . getTwo ( update . message )
if update . message . photo or update . message . document or update . message . video or update . message . sticker :
fid = update . message . document . file_id if update . message . document else update . message . sticker . file_id if update . message . sticker else update . message . video . file_id if update . message . video else update . message . photo [ - 1 ] . file_id
path = bot . getFile ( fid ) . file_path
media = urllib . request . urlopen ( path )
mobj = io . BytesIO ( media . read ( ) )
filename = path . split ( " / " ) [ - 1 ]
if filename . split ( " . " ) [ - 1 ] . lower ( ) == " webp " :
out = io . BytesIO ( )
PIL . Image . open ( mobj ) . convert ( ' RGB ' ) . save ( out , format = " JPEG " )
filename = " %s .jpg " % filename . split ( " . " ) [ 0 ]
if update . message . document and filename . split ( " . " ) [ - 1 ] . lower ( ) == " mp4 " :
temp = ' ' . join ( random . choice ( string . ascii_letters + string . digits ) for i in range ( 32 ) )
with open ( " tmp/ %s . %s " % ( temp , filename . split ( " . " ) [ - 1 ] ) , " wb " ) as f :
f . write ( mobj . getvalue ( ) )
moviepy . editor . VideoFileClip ( " tmp/ %s . %s " % ( temp , filename . split ( " . " ) [ - 1 ] ) ) . resize ( 0.3 ) . write_gif ( " tmp/ %s .gif " % temp )
filename = " %s .gif " % temp
out = open ( " tmp/ %s .gif " % temp , " rb " )
else :
out = mobj
2017-03-24 15:25:24 +00:00
status = two . api . update_with_media ( filename , update . message . caption , reply , file = out )
2017-03-22 00:53:51 +00:00
out . close ( )
else :
2017-03-24 15:25:24 +00:00
status = two . tweet ( ' ' . join ( args ) , reply )
2017-03-24 21:24:55 +00:00
if dbtools . dbHelper ( ) . getCStatus ( update . message . chat_id ) :
bottools . methods . tweetMessage ( status , update . message . chat_id , bot )
2017-03-22 00:53:51 +00:00
except tweepy . error . TweepError as e :
bottools . methods . twoExceptions ( e , update . message )
def reply ( bot , update , args ) :
try :
reply = bottools . methods . getTweetID ( args [ 0 ] , update . message . chat_id )
2017-03-23 19:23:31 +00:00
two = bottools . methods . getTwo ( update . message )
otweet = twitools . getTweet ( reply )
sender = otweet . user . screen_name
if not ( " @ %s " % sender . strip ( " @ " ) ) in [ ( " @ %s " % a . strip ( " @ " ) ) for a in args ] :
mentions = [ ]
for m in re . split ( ' [^ \ w@]+ ' , otweet . text ) :
try :
if m [ 0 ] == " @ " :
mentions + = [ m ]
except :
pass
for m in mentions :
2017-03-23 21:39:54 +00:00
if m in args or m == " @ %s " % two . whoami ( ) . strip ( " @ " ) or m == " @ %s " % sender . strip ( " @ " ) :
2017-03-23 19:23:31 +00:00
mentions . remove ( m )
else :
mentions = [ ]
if " @ %s " % sender . strip ( " @ " ) != " @ %s " % two . whoami ( ) . strip ( " @ " ) :
first = [ " @ %s " % sender . strip ( " @ " ) ]
else :
2017-03-23 21:39:54 +00:00
try :
first = [ mentions [ 0 ] ]
mentions . remove ( mentions [ 0 ] )
except :
first = [ " " ]
2017-03-23 19:23:31 +00:00
pargs = first + args [ 1 : ] + mentions
2017-03-22 00:53:51 +00:00
except :
update . message . reply_text ( bottools . strings . cantfind % args [ 0 ] )
2017-03-23 19:23:31 +00:00
raise
2017-03-22 00:53:51 +00:00
2017-03-23 19:23:31 +00:00
bottools . methods . explicitTweet ( bot , update , pargs , reply )
2017-03-22 00:53:51 +00:00
2017-03-24 12:08:47 +00:00
def quote ( bot , update , args ) :
try :
reply = bottools . methods . getTweetID ( args [ 0 ] , update . message . chat_id )
two = bottools . methods . getTwo ( update . message )
otweet = twitools . getTweet ( reply )
sender = otweet . user . screen_name
args + = [ " https://twitter.com/ %s /status/ %i " % ( sender , int ( reply ) ) ]
except :
update . message . reply_text ( bottools . strings . cantfind % args [ 0 ] )
raise
2017-03-25 12:06:01 +00:00
bottools . methods . explicitTweet ( bot , update , args [ 1 : ] )
2017-03-24 12:08:47 +00:00
2017-03-22 00:53:51 +00:00
def retweet ( bot , update , args ) :
2017-03-24 00:48:40 +00:00
message = update . message or update . callback_query . message
2017-03-22 00:53:51 +00:00
for tweet in args :
try :
2017-03-24 00:48:40 +00:00
tid = bottools . methods . getTweetID ( tweet , message . chat_id )
bottools . methods . getTwo ( message ) . api . retweet ( tid )
2017-03-22 00:53:51 +00:00
except ValueError :
2017-03-24 00:48:40 +00:00
message . reply_text ( bottools . strings . cantfind % tweet )
2017-03-22 00:53:51 +00:00
except tweepy . error . TweepError as e :
2017-03-24 00:48:40 +00:00
bottools . methods . twoExceptions ( e , message )
2017-03-22 00:53:51 +00:00
2017-03-24 14:34:53 +00:00
def thread ( bot , update , args ) :
message = update . message or update . callback_query . message
tid = bottools . methods . getTweetID ( args [ 0 ] , message . chat_id )
i = 0
try :
count = int ( args [ 1 ] )
except :
count = 5
tweets = [ twitools . getTweet ( tid ) ]
if tweets [ - 1 ] . in_reply_to_status_id :
nexttid = tweets [ - 1 ] . in_reply_to_status_id
while i < count :
tweets + = [ twitools . getTweet ( nexttid ) ]
if not tweets [ - 1 ] . in_reply_to_status_id :
break
nexttid = tweets [ - 1 ] . in_reply_to_status_id
i + = 1
for tweet in tweets :
2017-03-24 16:02:21 +00:00
tweetMessage ( tweet , message . chat_id , bot )
2017-03-24 14:34:53 +00:00
2017-03-22 00:53:51 +00:00
def like ( bot , update , args ) :
2017-03-24 00:48:40 +00:00
message = update . message or update . callback_query . message
2017-03-22 00:53:51 +00:00
for tweet in args :
try :
2017-03-24 00:48:40 +00:00
tid = bottools . methods . getTweetID ( tweet , message . chat_id )
bottools . methods . getTwo ( message ) . api . create_favorite ( tid )
2017-03-22 00:53:51 +00:00
except ValueError :
2017-03-24 00:48:40 +00:00
message . reply_text ( bottools . strings . cantfind % tweet )
2017-03-22 00:53:51 +00:00
except tweepy . error . TweepError as e :
2017-03-24 00:48:40 +00:00
bottools . methods . twoExceptions ( e , message )
2017-03-22 00:53:51 +00:00
def tweet ( bot , update ) :
try :
if dbtools . dbHelper ( ) . getTStatus ( update . message . chat_id ) :
bottools . methods . explicitTweet ( bot , update , [ update . message . text ] )
except twepy . error . TweepError as e :
bottools . methods . twoExceptions ( e , update . message )
# Timelines
2017-03-24 12:08:47 +00:00
def tweetMessage ( status , cid , bot ) :
2017-03-24 00:48:40 +00:00
db = dbtools . dbHelper ( )
try :
2017-03-24 12:08:47 +00:00
db . executeQuery ( " SELECT MAX(nr) FROM timelines WHERE cid = %i ; " % int ( cid ) )
2017-03-24 00:48:40 +00:00
i = int ( db . getNext ( ) [ 0 ] ) + 1
except :
i = 1
2017-03-24 12:08:47 +00:00
db . executeQuery ( " INSERT INTO timelines VALUES( %i , %i , %i ); " % ( cid , i , status . id ) )
2017-03-24 00:48:40 +00:00
db . commit ( )
buttons = [
telegram . InlineKeyboardButton ( " Like " , callback_data = " /like %i " % i ) ,
telegram . InlineKeyboardButton ( " Retweet " , callback_data = " /retweet %i " % i ) ,
2017-03-24 12:08:47 +00:00
telegram . InlineKeyboardButton ( " Reply " , switch_inline_query_current_chat = " /reply %i " % i ) ,
telegram . InlineKeyboardButton ( " Quote " , switch_inline_query_current_chat = " /quote %i " % i )
2017-03-24 00:48:40 +00:00
]
2017-03-24 14:34:53 +00:00
if status . in_reply_to_status_id :
buttons + = [ telegram . InlineKeyboardButton ( " View Thread " , callback_data = " /thread %i " % i ) ]
2017-03-24 00:48:40 +00:00
rmu = telegram . InlineKeyboardMarkup ( makeMenu ( buttons ) )
2017-03-24 12:08:47 +00:00
bot . sendMessage ( chat_id = cid , text = " Tweet %i : \n %s (@ %s ) at %s : \n %s " % ( i , status . author . name , status . author . screen_name , status . created_at , html . unescape ( status . text ) ) , reply_markup = rmu )
2017-03-24 00:48:40 +00:00
2017-03-24 16:02:21 +00:00
def search ( bot , update , args ) :
try :
count = int ( args [ 0 ] )
query = ' ' . join ( args [ 1 : ] )
except :
count = 5
query = ' ' . join ( args )
try :
two = bottools . methods . getTwo ( update . message )
2017-03-25 15:21:55 +00:00
lt = [ ]
2017-03-24 16:02:21 +00:00
for tweet in two . api . search ( q = query , rpp = count , result_type = " recent " ) [ : count ] :
2017-03-25 15:21:55 +00:00
lt + = [ tweet ]
lt . reverse ( )
for tweet in lt :
2017-03-24 16:02:21 +00:00
tweetMessage ( tweet , update . message . chat_id , bot )
except tweepy . error . TweepError as e :
bottools . methods . twoExceptions ( e , update . message )
2017-03-24 15:25:24 +00:00
def user ( bot , update , args ) :
try :
count = int ( args [ 1 ] )
except :
count = 5
try :
two = bottools . methods . getTwo ( update . message )
2017-03-25 15:21:55 +00:00
lt = [ ]
2017-03-24 21:46:43 +00:00
for status in two . api . user_timeline ( args [ 0 ] , count = count ) :
2017-03-25 15:21:55 +00:00
lt + = [ status ]
lt . reverse ( )
for status in lt :
2017-03-24 15:25:24 +00:00
tweetMessage ( status , update . message . chat_id , bot )
except tweepy . error . TweepError as e :
bottools . methods . twoExceptions ( e , update . message )
def selfTweets ( bot , update , args ) :
try :
count = int ( args [ 0 ] )
except :
count = 5
bottools . methods . user ( bot , update , [ bottools . methods . getTwo ( update . message ) . whoami ( ) , count ] )
2017-03-24 00:48:40 +00:00
2017-03-22 00:53:51 +00:00
def timeline ( bot , update , args = [ 10 ] ) :
try :
count = int ( args [ 0 ] )
except :
count = 10
db = dbtools . dbHelper ( )
db . executeQuery ( " DELETE FROM timelines WHERE cid = %i ; " % int ( update . message . chat_id ) )
2017-03-24 00:48:40 +00:00
db . commit ( )
2017-03-22 00:53:51 +00:00
try :
two = bottools . methods . getTwo ( update . message )
2017-03-25 15:21:55 +00:00
lt = [ ]
2017-03-22 00:53:51 +00:00
for status in two . api . home_timeline ( count = count ) :
2017-03-25 15:21:55 +00:00
lt + = [ status ]
lt . reverse ( )
for status in lt :
2017-03-24 12:08:47 +00:00
tweetMessage ( status , update . message . chat_id , bot )
2017-03-22 00:53:51 +00:00
except tweepy . error . TweepError as e :
bottools . methods . twoExceptions ( e , update . message )
2017-03-23 13:18:52 +00:00
# Streaming
2017-03-23 16:32:06 +00:00
2017-03-23 13:18:52 +00:00
mentionstreams = { }
2017-03-23 16:01:05 +00:00
def makeStream ( bot , cid ) :
two = twitools . twoBotHelper ( cid )
stream = tweepy . Stream ( auth = two . auth , listener = twitools . streaming . BotStreamListener ( bot , cid ) )
2017-03-25 15:21:55 +00:00
stream . filter ( track = [ " @ %s " % two . whoami ( ) . strip ( " @ " ) ] , async = True )
2017-03-23 16:01:05 +00:00
return stream
try :
for u in dbtools . dbHelper ( ) . mentionsOn ( ) :
mentionstreams [ u ] = makeStream ( telegram . Bot ( token = setuptools . token ( ) ) , u )
except Exception as e :
print ( e )
2017-03-23 13:18:52 +00:00
def mentionstream ( bot , update ) :
global mentionstreams
2017-03-23 16:01:05 +00:00
try :
dbtools . dbHelper ( ) . toggleMentions ( update . message . chat_id )
if update . message . chat_id in mentionstreams :
mentionstreams . pop ( update . message . chat_id ) . disconnect ( )
update . message . reply_text ( bottools . strings . toggleMentions % bottools . strings . toggleTweetOff )
else :
mentionstreams [ update . message . chat_id ] = makeStream ( bot , update . message . chat_id )
update . message . reply_text ( bottools . strings . toggleMentions % bottools . strings . toggleTweetOn )
except tweepy . error . TweepError as e :
bottools . methods . twoExceptions ( e , update . message )
2017-03-23 13:18:52 +00:00
2017-03-23 17:14:22 +00:00
# Admin interaction
def togglebroadcasts ( bot , update ) :
try :
update . message . reply_text ( bottools . strings . toggleBroadcasts % ( bottools . strings . toggleTweetOn if dbtools . dbHelper ( ) . toggleBroadcasts ( update . message . chat_id ) else bottools . strings . toggleTweetOff ) )
except tweepy . error . TweepError as e :
bottools . methods . twoExceptions ( e , update . message )
2017-03-23 12:05:48 +00:00
# Administrator
def isadmin ( message ) :
two = bottools . methods . getTwo ( message )
if two . whoami ( ) . strip ( " @ " ) == setuptools . admin ( ) . strip ( " @ " ) :
return True
return False
def restart ( bot , update ) :
if bottools . methods . isadmin ( update . message ) :
update . message . reply_text ( bottools . strings . restart )
time . sleep ( 0.5 )
os . execl ( sys . executable , sys . executable , * sys . argv )
2017-03-23 12:06:58 +00:00
else :
bottools . methods . unknown ( bot , update )
2017-03-23 16:01:05 +00:00
2017-03-23 16:32:06 +00:00
def broadcast ( bot , update , args ) :
2017-03-23 17:14:22 +00:00
if bottools . methods . isadmin ( update . message ) :
for u in dbtools . dbHelper ( ) . broadcastUsers ( ) :
2017-03-23 19:23:31 +00:00
try :
bot . sendMessage ( chat_id = u , text = ' ' . join ( args ) )
except :
logging . exception ( " Could not send broadcast. " )
2017-03-23 17:14:22 +00:00
else :
bottools . methods . unknown ( bot , update )
def emergency ( bot , update , args ) :
2017-03-23 16:32:06 +00:00
if bottools . methods . isadmin ( update . message ) :
for u in dbtools . dbHelper ( ) . allUsers ( ) :
2017-03-23 19:23:31 +00:00
try :
bot . sendMessage ( chat_id = u , text = ' ' . join ( args ) )
except :
logging . exception ( " Could not send emergency broadcast. " )
2017-03-23 16:32:06 +00:00
else :
bottools . methods . unknown ( bot , update )
2017-03-24 00:48:40 +00:00
# Variables
commands = {
" auth " : auth ,
" broadcast " : broadcast ,
" emergency " : emergency ,
" fish " : fish ,
" follow " : follow ,
" help " : start ,
" like " : like ,
" login " : auth ,
" logout " : unauth ,
" mentionstream " : mentionstream ,
2017-03-24 12:08:47 +00:00
" quote " : quote ,
2017-03-24 00:48:40 +00:00
" reply " : reply ,
" restart " : restart ,
" retweet " : retweet ,
2017-03-24 16:02:21 +00:00
" search " : search ,
2017-03-24 15:25:24 +00:00
" self " : selfTweets ,
2017-03-24 00:48:40 +00:00
" start " : start ,
2017-03-24 14:34:53 +00:00
" thread " : thread ,
2017-03-24 00:48:40 +00:00
" timeline " : timeline ,
" togglebroadcasts " : togglebroadcasts ,
2017-03-24 21:24:55 +00:00
" toggleconfirmations " : toggleConfirmations ,
2017-03-24 00:48:40 +00:00
" togglementions " : mentionstream ,
2017-03-24 21:24:55 +00:00
" toggletweet " : toggleTweet ,
2017-03-24 00:48:40 +00:00
" tweet " : explicitTweet ,
" unauth " : unauth ,
" unfollow " : unfollow ,
2017-03-24 15:25:24 +00:00
" user " : user ,
2017-03-24 00:48:40 +00:00
" verify " : verify
}
pargs = [
broadcast ,
emergency ,
follow ,
like ,
2017-03-24 12:08:47 +00:00
quote ,
2017-03-24 00:48:40 +00:00
reply ,
retweet ,
2017-03-24 16:02:21 +00:00
search ,
2017-03-24 15:25:24 +00:00
selfTweets ,
2017-03-24 14:34:53 +00:00
thread ,
2017-03-24 00:48:40 +00:00
timeline ,
toggleTweet ,
2017-03-24 15:25:24 +00:00
user ,
2017-03-24 00:48:40 +00:00
explicitTweet ,
unfollow ,
verify
]