diff --git a/.drone.yml b/.drone.yml index 86f8ea6..55189de 100644 --- a/.drone.yml +++ b/.drone.yml @@ -15,5 +15,10 @@ steps: from_secret: slack_token SLACK_CHANNEL: from_secret: slack_channel + B2_KEY_ID: + from_secret: b2_key_id + B2_APP_KEY: + from_secret: b2_app_key + B2_BUCKET_ID: a4cd3ebe8b7f0f246c6d0913 commands: - bash run.sh diff --git a/b2.py b/b2.py new file mode 100644 index 0000000..dad0a36 --- /dev/null +++ b/b2.py @@ -0,0 +1,56 @@ +import hashlib +import requests +from urllib.parse import quote as urlquote + + +class Client: + def __init__(self, key_id, app_key): + self.key_id = key_id + self.app_key = app_key + self.auth() + + def auth(self): + r = requests.get('https://api.backblazeb2.com/b2api/v2/b2_authorize_account', auth=(self.key_id, self.app_key)) + r.raise_for_status() + data = r.json() + self.auth_token = data['authorizationToken'] + self.download_url = data['downloadUrl'] + self.api_url = data['apiUrl'] + + def request(self, method, *args, **kwargs): + if not self.auth_token: + self.auth() + + if 'Authorization' not in kwargs.get('headers', {}): + kwargs.setdefault('headers', {})['Authorization'] = self.auth_token + r = requests.request(method, *args, **kwargs) + r.raise_for_status() + return r + + def get(self, *args, **kwargs): + return self.request('get', *args, **kwargs) + + def post(self, *args, **kwargs): + return self.request('post', *args, **kwargs) + + def get_object(self, bucket, path): + try: + r = self.get(f'{self.download_url}/file/{bucket}/{path}') + except requests.HTTPError as e: + if e.response.status_code == 404: + return None + raise e + + return r.content + + def put_object(self, bucket_id, path, data): + upload = self.post(f'{self.api_url}/b2api/v2/b2_get_upload_url', json={'bucketId': bucket_id}).json() + filename = path.split('/')[-1] + headers = { + 'Authorization': upload['authorizationToken'], + 'X-Bz-File-Name': urlquote(filename), + 'Content-Type': 'b2/x-auto', + 'Content-Length': str(len(data)), + 'X-Bz-Content-Sha1': hashlib.sha1(data).hexdigest() + } + self.post(upload['uploadUrl'], headers=headers, data=data) diff --git a/bot.py b/bot.py index ad0994d..ee04839 100644 --- a/bot.py +++ b/bot.py @@ -11,6 +11,8 @@ from selenium.webdriver.chrome.options import Options as ChromeOptions from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys +import b2 + EMOJI = { 'absent': ':black_large_square:', @@ -87,6 +89,7 @@ class Solver: self.body = self.driver.find_element(By.TAG_NAME, 'body') self.body.click() self.words = pathlib.Path('dictionary.txt').read_text().splitlines() + self.b2_client = b2.Client(os.environ['B2_KEY_ID'], os.environ['B2_APP_KEY']) def setup_driver(self): options = ChromeOptions() @@ -95,6 +98,22 @@ class Solver: options.add_argument('--remote-debugging-port=9222') return webdriver.Chrome(options=options) + def restore_state(self): + data = self.b2_client.get_object('cupboard', 'wordle_state.json') + if data: + self.driver.execute_script( + "window.localStorage.setItem('statistics', arguments[1]);", + data.decode('utf-8') + ) + + def save_state(self): + state = driver.execute_script("return window.localStorage.getItem('statistics')") + self.b2_client.put_object( + os.environ['B2_BUCKET_ID'], + 'wordle_state.json', + state.encode('utf-8') + ) + def input_word(self, word): for char in word: self.body.send_keys(char)