2020-06-02 00:05:02 +12:00
|
|
|
import random
|
|
|
|
import socket
|
|
|
|
import webbrowser
|
2021-02-06 21:35:50 +13:00
|
|
|
|
|
|
|
import praw
|
2021-02-25 22:32:06 +13:00
|
|
|
from prawcore.exceptions import ResponseException
|
2020-06-02 00:05:02 +12:00
|
|
|
|
2021-02-07 14:05:18 +13:00
|
|
|
from bulkredditdownloader.errors import RedditLoginFailed
|
2021-02-07 14:09:31 +13:00
|
|
|
from bulkredditdownloader.json_helper import JsonFile
|
2021-02-07 14:05:18 +13:00
|
|
|
from bulkredditdownloader.utils import GLOBAL
|
2021-02-06 21:35:50 +13:00
|
|
|
|
2020-06-02 00:05:02 +12:00
|
|
|
|
2021-02-25 22:32:06 +13:00
|
|
|
|
2020-06-02 00:05:02 +12:00
|
|
|
class Reddit:
|
2021-02-25 22:32:06 +13:00
|
|
|
|
2021-02-07 01:29:13 +13:00
|
|
|
def __init__(self, refresh_token: str = None):
|
2021-02-25 22:32:06 +13:00
|
|
|
self.SCOPES = ['identity', 'history', 'read', 'save']
|
2020-06-02 00:05:02 +12:00
|
|
|
self.PORT = 7634
|
|
|
|
self.refresh_token = refresh_token
|
|
|
|
self.redditInstance = None
|
|
|
|
self.arguments = {
|
2021-02-25 22:32:06 +13:00
|
|
|
"client_id": GLOBAL.reddit_client_id,
|
|
|
|
"client_secret": GLOBAL.reddit_client_secret,
|
|
|
|
"user_agent": str(socket.gethostname())
|
2020-06-02 00:05:02 +12:00
|
|
|
}
|
|
|
|
|
2021-02-07 01:29:13 +13:00
|
|
|
def begin(self) -> praw.Reddit:
|
2020-06-02 00:05:02 +12:00
|
|
|
if self.refresh_token:
|
|
|
|
self.arguments["refresh_token"] = self.refresh_token
|
|
|
|
self.redditInstance = praw.Reddit(**self.arguments)
|
|
|
|
try:
|
|
|
|
self.redditInstance.auth.scopes()
|
|
|
|
return self.redditInstance
|
|
|
|
except ResponseException:
|
2021-02-25 22:32:06 +13:00
|
|
|
self.arguments["redirect_uri"] = "http://localhost:" + \
|
|
|
|
str(self.PORT)
|
2020-06-02 00:05:02 +12:00
|
|
|
self.redditInstance = praw.Reddit(**self.arguments)
|
|
|
|
reddit, refresh_token = self.getRefreshToken(*self.SCOPES)
|
|
|
|
else:
|
2021-02-25 22:32:06 +13:00
|
|
|
self.arguments["redirect_uri"] = "http://localhost:" + \
|
|
|
|
str(self.PORT)
|
2020-06-02 00:05:02 +12:00
|
|
|
self.redditInstance = praw.Reddit(**self.arguments)
|
|
|
|
reddit, refresh_token = self.getRefreshToken(*self.SCOPES)
|
|
|
|
|
2021-02-06 21:35:50 +13:00
|
|
|
JsonFile(GLOBAL.configDirectory).add({"reddit_username": str(
|
|
|
|
reddit.user.me()), "reddit": refresh_token}, "credentials")
|
2020-06-02 00:05:02 +12:00
|
|
|
return self.redditInstance
|
|
|
|
|
2021-02-07 01:29:13 +13:00
|
|
|
def recieve_connection(self) -> socket:
|
2020-06-02 00:05:02 +12:00
|
|
|
"""Wait for and then return a connected socket..
|
|
|
|
Opens a TCP connection on port 8080, and waits for a single client.
|
|
|
|
"""
|
|
|
|
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
|
|
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
2020-06-06 02:23:45 +12:00
|
|
|
server.bind(('0.0.0.0', self.PORT))
|
2020-06-02 00:05:02 +12:00
|
|
|
server.listen(1)
|
|
|
|
client = server.accept()[0]
|
|
|
|
server.close()
|
|
|
|
return client
|
|
|
|
|
2021-02-07 01:29:13 +13:00
|
|
|
def send_message(self, client: socket, message: str):
|
2020-06-02 00:05:02 +12:00
|
|
|
"""Send message to client and close the connection."""
|
2021-02-06 21:35:50 +13:00
|
|
|
client.send('HTTP/1.1 200 OK\r\n\r\n{}'.format(message).encode('utf-8'))
|
2020-06-02 00:05:02 +12:00
|
|
|
client.close()
|
|
|
|
|
2021-02-07 01:29:13 +13:00
|
|
|
def getRefreshToken(self, scopes: list[str]) -> tuple[praw.Reddit, str]:
|
2020-06-02 00:05:02 +12:00
|
|
|
state = str(random.randint(0, 65000))
|
|
|
|
url = self.redditInstance.auth.url(scopes, state, 'permanent')
|
|
|
|
print("---Setting up the Reddit API---\n")
|
2021-02-06 21:35:50 +13:00
|
|
|
print("Go to this URL and login to reddit:\n", url, sep="\n", end="\n\n")
|
2021-02-25 22:32:06 +13:00
|
|
|
webbrowser.open(url, new=2)
|
2020-06-02 00:05:02 +12:00
|
|
|
|
|
|
|
client = self.recieve_connection()
|
|
|
|
data = client.recv(1024).decode('utf-8')
|
|
|
|
str(data)
|
|
|
|
param_tokens = data.split(' ', 2)[1].split('?', 1)[1].split('&')
|
2021-02-06 21:35:50 +13:00
|
|
|
params = {key: value for (key, value) in [token.split('=') for token in param_tokens]}
|
2020-06-02 00:05:02 +12:00
|
|
|
if state != params['state']:
|
2021-02-06 21:35:50 +13:00
|
|
|
self.send_message(client, 'State mismatch. Expected: {} Received: {}'.format(state, params['state']))
|
2020-06-02 00:05:02 +12:00
|
|
|
raise RedditLoginFailed
|
2021-02-25 22:32:06 +13:00
|
|
|
if 'error' in params:
|
2020-06-02 00:05:02 +12:00
|
|
|
self.send_message(client, params['error'])
|
|
|
|
raise RedditLoginFailed
|
2021-02-25 22:32:06 +13:00
|
|
|
|
2020-06-02 00:05:02 +12:00
|
|
|
refresh_token = self.redditInstance.auth.authorize(params['code'])
|
|
|
|
self.send_message(client,
|
2021-02-25 22:32:06 +13:00
|
|
|
"<script>"
|
|
|
|
"alert(\"You can go back to terminal window now.\");"
|
|
|
|
"</script>"
|
|
|
|
)
|
2021-02-06 21:35:50 +13:00
|
|
|
return self.redditInstance, refresh_token
|