2023-08-14 22:39:47 -07:00
from datetime import datetime
2022-09-24 17:56:58 -07:00
import platform
2022-09-25 03:39:15 -07:00
import pytz
2023-08-15 17:33:29 -07:00
from tweety . types import *
2022-09-24 17:56:58 -07:00
2023-08-18 01:34:25 -07:00
# from talent_lists import is_cross_company, talents
import talent_lists as tl
2022-09-27 15:09:09 -07:00
import util
2022-09-24 17:56:58 -07:00
class TalentTweet :
2023-08-14 22:39:47 -07:00
# Serialized one-liner format:
2023-08-16 18:48:13 -07:00
# {tweet} {author} {time in seconds since epoch UTC} m {mention set} r {reply to author} q {quote tweet author} rt {retweeted user's id} rtm {mentions in retweet}
2023-08-14 22:39:47 -07:00
def serialize ( self ) :
2023-08-16 18:48:13 -07:00
s = f ' { self . tweet_id } { self . author_id } { int ( self . date_time . timestamp ( ) ) } '
if self . date_time . tzinfo is None :
print ( f ' warning: serialized tweet { self . tweet_id } has a NAIVE timestamp! ' )
if len ( self . rt_mentions ) > 0 :
s + = ' rtm '
for n in self . rt_mentions :
s + = f ' { n } '
2023-08-14 22:39:47 -07:00
2023-08-15 17:33:29 -07:00
if self . rt_author_id != None :
2023-08-16 18:48:13 -07:00
s + = f ' rt { self . rt_author_id } '
2023-08-14 22:39:47 -07:00
return s [ : - 1 ] # stop here since retweets can't have other info
if len ( self . mentions ) > 0 :
s + = ' m '
for id in self . mentions :
s + = f ' { id } '
if self . reply_to :
s + = f ' r { self . reply_to } '
2023-08-16 18:48:13 -07:00
if self . quote_tweeted :
s + = f ' q { self . quote_tweeted } '
2023-08-14 22:39:47 -07:00
return s [ : - 1 ]
2022-09-25 03:39:15 -07:00
@staticmethod
def deserialize ( serialized_str : str ) :
2023-08-17 02:28:29 -07:00
token_check = serialized_str . split ( ' # ' ) [ 0 ]
if len ( token_check ) < 3 :
2022-09-25 03:39:15 -07:00
raise ValueError ( ' not enough tokens to reconstruct a TalentTweet ' )
2023-08-17 02:28:29 -07:00
tokens = serialized_str . split ( )
2022-09-25 03:39:15 -07:00
tweet_id , author_id = int ( tokens [ 0 ] ) , int ( tokens [ 1 ] )
2023-08-14 22:39:47 -07:00
date_time = datetime . fromtimestamp ( float ( tokens [ 2 ] ) , tz = pytz . utc )
2022-09-25 03:39:15 -07:00
2023-08-16 18:48:13 -07:00
mentions = list ( )
2022-09-25 03:39:15 -07:00
reply_to = None
quote_retweeted = None
2023-08-16 18:48:13 -07:00
rt = None
rtm = list ( )
2022-09-25 03:39:15 -07:00
mode = ' '
for i in range ( 3 , len ( tokens ) ) :
2023-08-20 16:05:32 -07:00
if not tokens [ i ] . isnumeric ( ) : # mode switch
2022-09-25 03:39:15 -07:00
mode = tokens [ i ]
continue
if tokens [ i ] . isnumeric ( ) :
if mode == ' m ' : # mentions
2023-08-17 02:28:29 -07:00
mentions . append ( int ( tokens [ i ] ) )
2022-09-25 03:39:15 -07:00
continue
2023-08-20 23:26:53 -07:00
elif mode == ' r ' : # reply_to
2022-09-25 03:39:15 -07:00
reply_to = int ( tokens [ i ] )
continue
2023-08-20 23:26:53 -07:00
elif mode == ' q ' : # quote_retweeted
2022-09-25 03:39:15 -07:00
quote_retweeted = int ( tokens [ i ] )
2023-08-20 23:26:53 -07:00
elif mode == ' rt ' : # retweeted user
2023-08-16 18:48:13 -07:00
rt = int ( tokens [ i ] )
2023-08-20 23:26:53 -07:00
elif mode == ' rtm ' : # retweet/qrt mentions
2023-08-17 02:28:29 -07:00
rtm . append ( int ( tokens [ i ] ) )
2023-08-20 16:05:32 -07:00
else :
raise ValueError ( f ' encountered invalid mode token { mode } ' )
2022-09-25 03:39:15 -07:00
return TalentTweet (
tweet_id = tweet_id , author_id = author_id ,
2023-08-16 18:48:13 -07:00
date_time = date_time , mrq = ( mentions , reply_to , quote_retweeted ) ,
rt_author_id = rt , rt_mentions = rtm
2022-09-25 03:39:15 -07:00
)
2023-08-15 17:33:29 -07:00
## Creates a TalentTweet from a Tweety-library Tweet.
@staticmethod
def create_from_tweety ( tweety : Tweet ) :
2023-08-16 18:48:13 -07:00
if tweety . is_retweet :
2023-08-19 03:19:08 -07:00
rtm = { int ( x . id ) for x in tweety . retweeted_tweet . user_mentions }
2023-08-18 18:20:53 -07:00
elif tweety . quoted_tweet :
2023-08-19 03:19:08 -07:00
rtm = { int ( x . id ) for x in tweety . quoted_tweet . user_mentions }
elif tweety . replied_to :
rtm = { int ( x . id ) for x in tweety . replied_to . user_mentions }
2023-08-16 18:48:13 -07:00
else :
2023-08-19 03:19:08 -07:00
rtm = set ( )
2023-08-16 18:48:13 -07:00
2023-08-15 17:33:29 -07:00
return TalentTweet (
tweet_id = int ( tweety . id ) , author_id = int ( tweety . author . id ) ,
date_time = tweety . date , text = tweety . text ,
mrq = (
2023-08-19 03:19:08 -07:00
{ int ( x . id ) for x in tweety . user_mentions } ,
2023-08-18 01:34:25 -07:00
int ( tweety . original_tweet [ ' in_reply_to_user_id_str ' ] ) if tweety . is_reply else None ,
2023-08-15 17:33:29 -07:00
int ( tweety . quoted_tweet . author . id ) if tweety . quoted_tweet is not None else None
) ,
rt_author_id = tweety . retweeted_tweet . author . id if tweety . is_retweet else None ,
2023-08-16 18:48:13 -07:00
rt_mentions = rtm
2023-08-15 17:33:29 -07:00
)
2022-09-27 02:49:03 -07:00
2023-08-15 17:33:29 -07:00
def __init__ ( self , tweet_id : int , author_id : int , date_time : datetime , text : str = None , mrq : tuple [ list [ int ] , int | None , int | None ] = None , rt_author_id : int = None , rt_mentions : list [ int ] = None ) :
# basic information
2022-09-25 03:39:15 -07:00
self . tweet_id , self . author_id = tweet_id , author_id
2023-08-15 17:33:29 -07:00
self . username = util . get_username_local ( self . author_id )
2022-09-25 03:39:15 -07:00
self . date_time = date_time
2023-08-15 17:33:29 -07:00
self . text = text
2023-08-18 01:34:25 -07:00
# filter users to only be talents
self . mentions = { x for x in mrq [ 0 ] if x in tl . talents }
self . rt_mentions = { x for x in rt_mentions if x in tl . talents }
2023-08-18 21:44:30 -07:00
self . mentions . difference_update ( self . rt_mentions )
2023-08-20 02:33:16 -07:00
try : self . rt_mentions . remove ( self . author_id )
except : pass
2023-08-16 18:48:13 -07:00
2023-08-18 01:34:25 -07:00
self . reply_to = mrq [ 1 ]
self . quote_tweeted = mrq [ 2 ]
2023-08-16 18:48:13 -07:00
self . rt_author_id = rt_author_id
2023-08-18 01:34:25 -07:00
try : self . mentions . remove ( self . reply_to )
except : pass
# -1 if user is not in company
self . reply_to = self . reply_to if self . reply_to is None or self . reply_to in tl . talents else - 1
self . quote_tweeted = self . quote_tweeted if self . quote_tweeted is None or self . quote_tweeted in tl . talents else - 1
self . rt_author_id = self . rt_author_id if self . rt_author_id is None or self . rt_author_id in tl . talents else - 1
2023-08-16 18:48:13 -07:00
# all users involved except for the author
self . all_parties = { self . reply_to , self . quote_tweeted , rt_author_id }
self . all_parties . update ( self . mentions , self . rt_mentions )
try : self . all_parties . remove ( None )
2022-10-01 13:33:20 -07:00
except : pass
2023-08-16 18:48:13 -07:00
try : self . all_parties . remove ( self . author_id )
except : pass
2023-08-18 18:20:53 -07:00
if not self . is_cross_company ( ) :
print ( f ' WARNING: { self . tweet_id } is not cross-company! ' )
2022-09-25 03:39:15 -07:00
2022-09-24 17:56:58 -07:00
def __repr__ ( self ) - > str :
return (
2023-08-16 18:48:13 -07:00
f ' ====================================================== \n '
2023-08-15 17:33:29 -07:00
f ' { self . tweet_id } from { self . username } : \n '
2022-09-24 17:56:58 -07:00
f ' { self . get_datetime_str ( ) } \n '
2023-08-15 17:33:29 -07:00
f ' parties: { self . get_all_parties_usernames ( ) } \n '
2022-09-25 03:39:15 -07:00
f ' mentions: { self . mentions } \n '
f ' reply_to: { self . reply_to } \n '
2023-08-19 03:19:08 -07:00
f ' rtm: { self . rt_mentions } \n '
2023-08-16 18:48:13 -07:00
f ' quote_retweeted: { self . quote_tweeted } \n '
2023-08-15 17:33:29 -07:00
f ' cross-company? { self . is_cross_company ( ) } \n '
2022-09-25 03:39:15 -07:00
f ' { self . serialize ( ) } \n '
2023-08-16 18:48:13 -07:00
f ' ---- \n { self . announce_text ( ) } \n ---- \n '
2023-08-15 17:33:29 -07:00
f ' { self . url ( ) } '
2022-09-24 17:56:58 -07:00
)
2023-08-15 17:33:29 -07:00
def url ( self ) :
2023-08-18 01:34:25 -07:00
return util . get_tweet_url ( self . tweet_id , self . username )
2023-08-15 17:33:29 -07:00
2022-09-25 03:39:15 -07:00
def is_cross_company ( self ) :
2023-08-20 16:05:32 -07:00
if self . author_id == self . rt_author_id :
return False
2022-09-25 03:39:15 -07:00
for other_id in self . all_parties :
2023-08-18 01:34:25 -07:00
if tl . is_cross_company ( self . author_id , other_id ) :
2023-08-14 22:39:47 -07:00
return True
2023-08-20 16:05:32 -07:00
2022-09-24 17:56:58 -07:00
return False
2022-09-25 03:39:15 -07:00
def get_all_parties_usernames ( self ) :
if len ( self . all_parties ) > 0 :
2022-09-24 17:56:58 -07:00
s = str ( )
2022-09-25 03:39:15 -07:00
for id in self . all_parties :
2022-09-27 02:49:03 -07:00
s + = f ' { util . get_username_local ( id ) } , '
2022-09-24 17:56:58 -07:00
return s [ 0 : - 2 ]
return ' none '
def get_datetime_str ( self ) :
unpad = ' # ' if platform . system ( ) == ' Windows ' else ' - '
2023-08-18 21:44:30 -07:00
return self . date_time . strftime ( f ' %b % { unpad } d, %Y · % { unpad } I:%M%p (%Z) ' )
2023-08-16 18:48:13 -07:00
2023-08-18 01:34:25 -07:00
def announce_text ( self ) :
2023-08-16 18:48:13 -07:00
# templates
2023-08-17 02:28:29 -07:00
TWEET = ' {0} tweeted mentioning {1} ! '
2023-08-18 01:34:25 -07:00
REPLY = ' {0} replied to {1} ! '
2023-08-20 02:33:16 -07:00
REPLY_TO_MENTION_B = ' {0} replied to a tweet {1} mentioning {2} ! ' #########################
2023-08-16 18:48:13 -07:00
RETWEET = ' {0} retweeted {1} ! '
2023-08-18 01:34:25 -07:00
RETWEET_MENTIONS_B = ' {0} shared a tweet {1} mentioning {2} ! ' #########################
2023-08-16 18:48:13 -07:00
QUOTE_TWEET = ' {0} quote tweeted {1} ! '
2023-08-18 01:34:25 -07:00
QUOTED_TWEET_MENTIONS_B = ' {0} quoted a tweet {1} mentioning {2} ! ' #########################
2023-08-16 18:48:13 -07:00
author_username = f ' @/ { util . get_username_with_company ( self . author_id ) } '
ret = str ( )
2023-08-17 02:28:29 -07:00
2023-08-16 18:48:13 -07:00
print_mention_ids = set ( self . mentions )
2023-08-17 02:28:29 -07:00
try : print_mention_ids . remove ( None )
except : pass
mention_usernames = [ f ' @/ { util . get_username_with_company ( x ) } ' for x in print_mention_ids ]
2023-08-18 01:34:25 -07:00
def rtm_msg ( TEMPLATE : str , rtm_author_username : str ) :
2023-08-18 22:34:46 -07:00
nonlocal ret
if ( self . rt_author_id is not None and self . rt_author_id != - 1 ) \
or ( self . quote_tweeted is not None and self . quote_tweeted != - 1 ) : # rtm tweet is from talent; rtm should be everyone
2023-08-18 01:34:25 -07:00
rtm_names = [ f ' @/ { util . get_username_with_company ( x ) } ' for x in self . rt_mentions ]
between = f ' from { rtm_author_username } '
ret + = TEMPLATE . format ( author_username , between , " , " . join ( rtm_names ) )
2023-08-18 01:36:38 -07:00
else : # rtm tweet is not from a talent; rtm should just be cross company
2023-08-18 01:34:25 -07:00
rtm_names = [ f ' @/ { util . get_username_with_company ( x ) } ' for x in self . rt_mentions if tl . is_cross_company ( self . author_id , x ) ]
ret + = TEMPLATE . format ( author_username , ' ' , " , " . join ( rtm_names ) )
2023-08-16 18:48:13 -07:00
# Tweet types
if self . rt_author_id is not None : # retweet
2023-08-18 01:34:25 -07:00
rt_username = f ' @/ { util . get_username_with_company ( self . rt_author_id ) } ' if self . rt_author_id != - 1 else None
2023-08-16 18:48:13 -07:00
if len ( self . rt_mentions ) > 0 :
2023-08-18 01:34:25 -07:00
rtm_msg ( RETWEET_MENTIONS_B , rt_username )
2023-08-16 18:48:13 -07:00
else :
2023-08-18 01:34:25 -07:00
ret + = RETWEET . format ( author_username , rt_username )
2023-08-19 02:32:28 -07:00
mention_usernames . clear ( )
2023-08-16 18:48:13 -07:00
elif self . reply_to is not None : # reply
2023-08-18 01:34:25 -07:00
reply_username = f ' @/ { util . get_username_with_company ( self . reply_to ) } ' if self . reply_to != - 1 else None
if len ( self . rt_mentions ) > 0 :
rtm_msg ( REPLY_TO_MENTION_B , reply_username )
else :
ret + = REPLY . format ( author_username , reply_username )
2023-08-16 18:48:13 -07:00
elif self . quote_tweeted is not None : # qrt
2023-08-18 01:34:25 -07:00
quoted_username = f ' @/ { util . get_username_with_company ( self . quote_tweeted ) } ' if self . quote_tweeted != - 1 else None
2023-08-16 18:48:13 -07:00
if len ( self . rt_mentions ) > 0 :
2023-08-18 01:34:25 -07:00
rtm_msg ( QUOTED_TWEET_MENTIONS_B , quoted_username )
2023-08-16 18:48:13 -07:00
else :
ret + = QUOTE_TWEET . format ( author_username , quoted_username )
elif len ( self . mentions ) > 0 : # standalone tweet
2023-08-17 02:28:29 -07:00
ret + = TWEET . format ( author_username , " , " . join ( mention_usernames ) )
2023-08-19 02:32:28 -07:00
mention_usernames . clear ( )
2023-08-16 18:48:13 -07:00
else :
raise ValueError ( f ' TalentTweet { self . tweet_id } has insufficient other parties ' )
# mention line
2023-08-19 02:32:28 -07:00
if len ( mention_usernames ) > 0 :
2023-08-16 18:48:13 -07:00
ret + = (
2023-08-19 03:19:08 -07:00
' \n Mentions: '
2023-08-16 18:48:13 -07:00
f ' { " , " . join ( mention_usernames ) } '
)
2023-08-18 21:44:30 -07:00
# date
2023-08-18 01:34:25 -07:00
ret + = f ' \n \n { self . get_datetime_str ( ) } '
2023-08-16 18:48:13 -07:00
return ret