Skip to content

Commit ac45381

Browse files
committed
Added basic interactivity/UI.
1 parent dafc124 commit ac45381

9 files changed

+213
-41
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
TwiiterAPI.txt
22
__pycache__
33
testAuth.py
4+
venv
5+
my_keys.json
6+

bots/autoreply.py

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
import tweepy
55
import logging
6-
from config import create_api
76
import time
87

98
logging.basicConfig(level=logging.INFO)

bots/config.py

-24
This file was deleted.

bots/favRetweet.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33

44
import tweepy
55
import logging
6-
from config import create_api
76
import json
87

8+
from styles import in_color, styled_input
9+
910
logging.basicConfig(level=logging.INFO)
1011
logger = logging.getLogger()
1112

@@ -36,11 +37,12 @@ def on_status(self, tweet):
3637
def on_error(self, status):
3738
logger.error(status)
3839

39-
def main(keywords):
40-
api = create_api()
40+
def retweet(api):
41+
keyword = styled_input("Enter keyword(s) to search seperated by space ─ ")
42+
keyword = keyword.split(' ')
4143
tweets_listener = FavRetweetListener(api)
4244
stream = tweepy.Stream(api.auth, tweets_listener)
4345
stream.filter(track=keywords, languages=["en"])
4446

4547
if __name__ == "__main__":
46-
main(["Python", "Tweepy"])
48+
retweet(api)

bots/followfollowers.py

+5-12
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,18 @@
33

44
import tweepy
55
import logging
6-
from config import create_api
76
import time
87

98
logging.basicConfig(level=logging.INFO)
109
logger = logging.getLogger()
1110

1211
def follow_followers(api):
13-
logger.info("Retrieving and following followers")
14-
for follower in tweepy.Cursor(api.followers).items():
15-
if not follower.following:
16-
logger.info(f"Following {follower.name}")
17-
follower.follow()
18-
19-
def main():
20-
api = create_api()
2112
while True:
22-
follow_followers(api)
13+
logger.info("Retrieving and following followers")
14+
for follower in tweepy.Cursor(api.followers).items():
15+
if not follower.following:
16+
logger.info(f"Following {follower.name}")
17+
follower.follow()
2318
logger.info("Waiting...")
2419
time.sleep(60)
2520

26-
if __name__ == "__main__":
27-
main()

bots/getUser.py

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import tweepy
2+
import sys
3+
sys.path.append('..')
4+
5+
from styles import in_color, styled_input
6+
7+
8+
def getUser(api) -> None:
9+
user_name = styled_input('Enter a username ─ ')
10+
11+
user = api.get_user(user_name)
12+
13+
# FIXME: Extract details from response and display beautifully.
14+
print(user)
15+

requirements.txt

+2
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ requests-oauthlib==1.3.0
88
six==1.15.0
99
tweepy==3.9.0
1010
urllib3==1.25.9
11+
stdiomask-0.0.6
12+

styles.py

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
def in_color(color: str, text: str) -> str:
2+
color_for_str = {
3+
'red': '1',
4+
'green': '2',
5+
'yellow': '3',
6+
'blue': '4',
7+
'purple': '5',
8+
'cyan': '6',
9+
}
10+
# We can use 3 instead of 9 if high-contrast is eg. less compatible?
11+
return f"\033[9{color_for_str[color]}m{text}\033[0m"
12+
13+
14+
def styled_input(label: str) -> str:
15+
return input(in_color('blue', label))

twibot.py

+167
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
import argparse
2+
import logging
3+
import tweepy
4+
import time
5+
import os
6+
import sys
7+
import json
8+
import stdiomask
9+
10+
from typing import Any, Dict, List, Optional, Tuple
11+
from styles import in_color, styled_input
12+
from bots.getUser import getUser
13+
from bots.followfollowers import follow_followers
14+
from bots.favRetweet import retweet
15+
from bots.autoreply import check_mentions
16+
17+
auth_keys = {
18+
'TWITTER_CONSUMER_KEY': '',
19+
'TWITTER_CONSUMER_SECRET': '',
20+
'TWITTER_ACCESS_TOKEN': '',
21+
'TWITTER_ACCESS_TOKEN_SECRET': '',
22+
}
23+
24+
# Basic config needs to be called atleast once, to set the level properly.
25+
logging.basicConfig()
26+
# Set the level to INFO to write all logs with level >= info to stdout.
27+
logging.root.setLevel(logging.INFO)
28+
# Get the logger object
29+
logger = logging.getLogger()
30+
31+
32+
def read_keys_from_env_vars() -> bool:
33+
global auth_keys
34+
logger.info(' Searching for Authentication keys in Environment varibales...')
35+
time.sleep(1)
36+
for key in auth_keys:
37+
auth_keys[key] = os.getenv(auth_keys[key])
38+
if auth_keys[key] is None:
39+
logger.error(f' Key─ {key} not found in environment variables. Select other method for authentication.\n')
40+
time.sleep(1)
41+
return False
42+
logger.info(' All Authentication keys found.')
43+
return True
44+
45+
def read_keys_from_user() -> None:
46+
global auth_keys
47+
logger.info(' Please Enter the following authentication keys to login...')
48+
time.sleep(0.5)
49+
for key in auth_keys:
50+
if key.endswith('_SECRET'):
51+
auth_keys[key] = stdiomask.getpass(in_color('blue', f"{key} -> "), mask="*")
52+
else:
53+
auth_keys[key] = styled_input(f"{key} -> ")
54+
55+
def read_keys_from_file() -> None:
56+
global auth_keys
57+
print('Please ensure that your JSON file is in curent working directory.')
58+
filename = styled_input('Enter the filename ─ ')
59+
filename = filename + '.json'
60+
if os.path.exists(f"./{filename}"):
61+
file = open(filename)
62+
db = json.load(file)
63+
if db.keys() == auth_keys.keys():
64+
auth_keys = db
65+
logger.info(' All Authentication keys found.\n')
66+
return None
67+
else:
68+
logger.error(' File missing some keys. Please re-check the file.\n')
69+
read_keys_from_file()
70+
return None
71+
else:
72+
logger.error('Incorrect path. Please try again.\n')
73+
read_keys_from_file()
74+
return None
75+
76+
def get_authentication_method_and_verify() -> Any:
77+
global auth_keys
78+
print('Please select an authentication method:')
79+
print('\t[1] Get authentication keys from my Environment variables.')
80+
print('\t[2] Get authentication keys from an input file.')
81+
print('\t[3] Let me input the authentication keys myself.\n')
82+
auth_method = input('Enter your choice ─ ')
83+
while auth_method not in ['1', '2', '3']:
84+
print('You have entered an incorrect input. Please enter a valid choice.')
85+
auth_method = input('Enter your choice ─ ')
86+
87+
if auth_method == '1':
88+
keys = read_keys_from_env_vars()
89+
if not keys:
90+
return False
91+
elif auth_method == '2':
92+
read_keys_from_file()
93+
elif auth_method == '3':
94+
read_keys_from_user()
95+
else:
96+
logger.error(' An error occured. Please restart TwiBot.')
97+
sys.exit(0)
98+
99+
logger.info(' Authenticating...')
100+
101+
auth = tweepy.OAuthHandler(auth_keys['TWITTER_CONSUMER_KEY'],
102+
auth_keys['TWITTER_CONSUMER_SECRET'])
103+
auth.set_access_token(auth_keys['TWITTER_ACCESS_TOKEN'],
104+
auth_keys['TWITTER_ACCESS_TOKEN_SECRET'])
105+
106+
api = tweepy.API(auth, wait_on_rate_limit=True,
107+
wait_on_rate_limit_notify=True)
108+
109+
return api
110+
111+
112+
def print_welcome_header(slow: bool=True) -> None:
113+
os.system('cls' if os.name == 'nt' else 'clear')
114+
print(in_color('purple', '────────────────────────────────────────────────────────────'))
115+
print(in_color('purple', ' Welcome to TwiBot'))
116+
print(in_color('purple', '────────────────────────────────────────────────────────────\n'))
117+
if slow:
118+
time.sleep(1)
119+
120+
def get_feature_choice() -> str:
121+
print('Twibot can do the following for you. Please select an option:')
122+
print('\t[1] Search twitter for a user.')
123+
print('\t[2] Follow-back all your followers.')
124+
print('\t[3] Search and re-tweet a tweet.')
125+
print('\t[4] Autoreply to tweets mentioning you, or some keyword.\n')
126+
127+
choice = input('Enter your choice ─ ')
128+
while choice not in ['1', '2', '3', '4']:
129+
print('You have entered an incorrect input. Please enter a valid choice.')
130+
choice = input('Enter your choice ─ ')
131+
132+
return choice
133+
134+
def main():
135+
"""
136+
Launch TwiBot.
137+
"""
138+
print_welcome_header(slow=True)
139+
140+
api = get_authentication_method_and_verify()
141+
while not api:
142+
api = get_authentication_method_and_verify()
143+
144+
try:
145+
response = api.verify_credentials()
146+
except Exception as e:
147+
logger.error("Error creating API. Bad Authentication data", exc_info=True)
148+
sys.exit(0)
149+
150+
print(in_color('green', "Authentication OK ─ API created...\n"))
151+
time.sleep(1.5)
152+
153+
print_welcome_header(slow=False)
154+
choice = get_feature_choice()
155+
156+
if choice == '1':
157+
getUser(api)
158+
elif choice == '2':
159+
follow_followers(api)
160+
elif choice == '3':
161+
retweet(api)
162+
elif choice == '4':
163+
check_mentions(api)
164+
165+
166+
if __name__ == '__main__':
167+
main()

0 commit comments

Comments
 (0)