Created
December 1, 2020 02:10
-
-
Save NivenT/e56c6301350e7eac3646d084fbfa16df to your computer and use it in GitHub Desktop.
Don't you hate not owning a ps5? This might help (but probably won't). Periodically checks for in-stock ps5s and then launches firefox when one is found. If you want, you can make a free trial [Twilio account](www.twilio.com/referral/DNJ8MN) and then provide a file containing your account sid, account auth token, account phone number, and person…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
import requests | |
import sys | |
from html.parser import HTMLParser | |
from validators import url as is_url | |
from os import system as cmdline | |
from time import sleep | |
from twilio.rest import Client | |
def print_usage(prog_name): | |
print('Usage:') | |
print(f' {prog_name} (-h | --help)') | |
print(f' {prog_name} TWILIO_INFO_FILE') | |
print(f' {prog_name}') | |
def format_alert(stock): | |
return f'PS5s are \'{stock.status}\' ({stock.name}) at \n{stock.url}' | |
class Twilio: | |
def __init__(self, path): | |
self.sid = '' | |
self.auth = '' | |
self.from_num = '' | |
self.to_num = '' | |
try: | |
with open(path, 'r') as info: | |
lines = info.readlines() | |
self.sid = lines[0] | |
self.auth = lines[1] | |
self.from_num = lines[2] | |
self.to_num = lines[3] | |
except: | |
pass | |
def send_sms(self, stock): | |
if '' in [self.sid, self.auth, self.from_num, self.to_num]: return | |
client = Client(self.sid, self.auth) | |
msg = format_alert(stock) | |
client.api.account.messages.create(to=self.to_num, from_=self.from_num, body=msg) | |
class Stock: | |
def __init__(self): | |
self.count = 0 | |
self.name = 'N/A' | |
self.status = 'N/A' | |
self.url = 'N/A' | |
def __repr__(self): | |
return f'{{\n name: {self.name}\n status: {self.status}\n url: {self.url}\n}}' | |
def update(self, data): | |
if self.count == 0: self.url = data | |
elif self.count == 1: self.name = data | |
elif self.count == 2: self.status = data | |
self.count += 1 | |
class StockParser(HTMLParser): | |
def __init__(self): | |
super().__init__() | |
self.stocks = [] | |
self.curr = Stock() | |
self.in_tr = False | |
self.in_td = False | |
def handle_starttag(self, tag, attr): | |
if tag == 'tr': | |
self.in_tr = True | |
elif self.in_tr: | |
if tag == 'a': | |
#print(f'{tag}: {attr}') | |
self.curr.update(attr[0][1]) | |
elif tag == 'td': | |
self.in_td = True | |
def handle_endtag(self, tag): | |
if tag == 'tr': | |
self.in_tr = False | |
self.stocks += [self.curr] | |
self.curr = Stock() | |
elif tag == 'td': | |
self.in_td = False | |
def handle_data(self, data): | |
if self.in_tr and self.in_td: | |
self.curr.update(data) | |
self.in_td = False | |
def is_well_formed(stock): | |
if 'N/A' in [stock.name, stock.status, stock.url]: | |
return False | |
if 'Ebay' in stock.name: | |
return False | |
magic_number = len('Out of Stock') + len('Stock Available') | |
if len(stock.status) > magic_number: | |
return False | |
if not is_url(stock.url): | |
return False | |
return True | |
def extract_table(resp): | |
if resp.status_code/100 != 2: | |
print(f'response ({r.status_code}) error message:\n{r.text}') | |
return '' | |
table_start = resp.text.find('<table') | |
if table_start == -1: | |
print('Could not find table') | |
return '' | |
table_end = resp.text.find('</table', table_start) | |
if table_end == -1: | |
print('Could not find end of table') | |
return '' | |
table_str = resp.text[table_start:table_end+len('</table>')] | |
return table_str | |
def open_url(url): | |
cmdline(f'firefox {url}') | |
def alert(twil, stock): | |
print(f'\a{format_alert(stock)}\a') | |
twil.send_sms(stock) | |
open_url(stock.url) | |
def check_stock(twil): | |
r = requests.get('https://www.nowinstock.net/videogaming/consoles/sonyps5/') | |
table_str = extract_table(r) | |
if table_str == '': return | |
parser = StockParser() | |
parser.feed(table_str) | |
stocks = filter(is_well_formed, parser.stocks) | |
#stocks = list(stocks) | |
for s in stocks: | |
#print(s) | |
if 'Out' not in s.status and 'out' not in s.status: | |
alert(twil, s) | |
#alert(twil, stocks[8]) | |
def main(): | |
if len(sys.argv) > 2 or len([x for x in ['-h', '--help'] if x in sys.argv]) > 0: | |
print_usage(sys.argv[0]) | |
else: | |
CHECKS_PER_PRINT = 20 | |
SECS_PER_CHECK = 30 | |
twil = Twilio(sys.argv[1] if len(sys.argv) > 1 else '') | |
counter = 0 | |
while True: | |
if counter%CHECKS_PER_PRINT == 0: print(f'Check number {counter}...') | |
check_stock(twil) | |
sleep(SECS_PER_CHECK) | |
counter += 1 | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment