on-win notification

- added notifications when a won giveaway is detected
 - a notification will only be sent once a day
This commit is contained in:
mcinj 2022-05-08 21:55:09 -04:00
parent 405dd11a9b
commit 3d3752de22
6 changed files with 99 additions and 50 deletions

View file

@ -3,4 +3,3 @@ beautifulsoup4==4.11.1
urllib3==1.26.9 urllib3==1.26.9
sqlalchemy==1.4.36 sqlalchemy==1.4.36
sqlalchemy_utils==0.38.2 sqlalchemy_utils==0.38.2
pytz==2022.1

View file

@ -1,17 +1,15 @@
import json import json
from datetime import datetime
from random import randint from random import randint
from time import sleep from time import sleep
import requests import requests
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from requests.adapters import HTTPAdapter from requests.adapters import HTTPAdapter
from sqlalchemy.orm import Session
from urllib3.util import Retry from urllib3.util import Retry
import log import log
from giveaway import Giveaway from giveaway import Giveaway
from tables import engine, TableGiveaway from tables import TableNotification, TableGiveaway
logger = log.get_logger(__name__) logger = log.get_logger(__name__)
@ -69,7 +67,7 @@ class SteamGifts:
return session return session
def get_soup_from_page(self, url): def get_soup_from_page(self, url):
r = self.requests_retry_session().get(url) self.requests_retry_session().get(url)
r = requests.get(url, cookies=self.cookie) r = requests.get(url, cookies=self.cookie)
soup = BeautifulSoup(r.text, 'html.parser') soup = BeautifulSoup(r.text, 'html.parser')
return soup return soup
@ -85,6 +83,20 @@ class SteamGifts:
logger.error("⛔ Cookie is not valid.") logger.error("⛔ Cookie is not valid.")
raise SteamGiftsException("Cookie is not valid.") raise SteamGiftsException("Cookie is not valid.")
won = soup.select("a[title='Giveaways Won'] div.fade_infinite")
if won:
number_won = soup.select_one("a[title='Giveaways Won'] div.fade_infinite").text
won_notifications = TableNotification.get_won_notifications_today()
if won_notifications and len(won_notifications) >= 1:
logger.debug("Win(s) detected, but we have already notified that there are won games waiting "
"to be received. Doing nothing.")
else:
logger.debug("Win(s) detected. Going to send a notification.")
logger.info(f"WINNER! You have {number_won} game(s) waiting to be claimed.")
self.notification.send_won(f"WINNER! You have {number_won} game(s) waiting to be claimed.")
else:
logger.debug('No wins detected. Doing nothing.')
def should_we_enter_giveaway(self, giveaway): def should_we_enter_giveaway(self, giveaway):
if giveaway.time_remaining_in_minutes is None: if giveaway.time_remaining_in_minutes is None:
return False return False
@ -139,25 +151,6 @@ class SteamGifts:
logger.error(f"Failed entering giveaway {giveaway.giveaway_game_id}") logger.error(f"Failed entering giveaway {giveaway.giveaway_game_id}")
return False return False
def create_or_update_giveaway(self, giveaway, entered):
g = TableGiveaway(
steam_app_id=giveaway.steam_app_id,
steam_url=giveaway.steam_url,
game_name=giveaway.game_name,
giveaway_game_id=giveaway.giveaway_game_id,
giveaway_uri=giveaway.giveaway_uri,
user=giveaway.user,
giveaway_created_at=TableGiveaway.unix_timestamp_to_utc_datetime(giveaway.time_created_timestamp),
giveaway_ended_at=TableGiveaway.unix_timestamp_to_utc_datetime(giveaway.time_remaining_timestamp),
cost=giveaway.cost,
copies=giveaway.copies,
contributor_level=giveaway.contributor_level,
entered=entered,
game_entries=giveaway.game_entries)
with Session(engine) as session:
session.merge(g)
session.commit()
def evaluate_giveaways(self, page=1): def evaluate_giveaways(self, page=1):
n = page n = page
run = True run = True
@ -180,7 +173,6 @@ class SteamGifts:
if not len(unentered_game_list) or (all_games_list_count == pinned_giveaway_count): if not len(unentered_game_list) or (all_games_list_count == pinned_giveaway_count):
txt = f"We have run out of gifts to consider." txt = f"We have run out of gifts to consider."
logger.info(txt) logger.info(txt)
run = False
break break
for item in unentered_game_list: for item in unentered_game_list:
@ -200,15 +192,15 @@ class SteamGifts:
if if_enter_giveaway: if if_enter_giveaway:
res = self.enter_giveaway(giveaway) res = self.enter_giveaway(giveaway)
if res: if res:
self.create_or_update_giveaway(giveaway, True) TableGiveaway.upsert_giveaway(giveaway, True)
self.points -= int(giveaway.cost) self.points -= int(giveaway.cost)
txt = f"🎉 One more game! Has just entered {giveaway.game_name}" txt = f"🎉 One more game! Has just entered {giveaway.game_name}"
logger.info(txt) logger.info(txt)
sleep(randint(4, 15)) sleep(randint(4, 15))
else: else:
self.create_or_update_giveaway(giveaway, False) TableGiveaway.upsert_giveaway(giveaway, False)
else: else:
self.create_or_update_giveaway(giveaway, False) TableGiveaway.upsert_giveaway(giveaway, False)
# if we are on any filter type except New and we get to a giveaway that exceeds our # if we are on any filter type except New and we get to a giveaway that exceeds our
# max time left amount, then we don't need to continue to look at giveaways as any # max time left amount, then we don't need to continue to look at giveaways as any
# after this point will also exceed the max time left # after this point will also exceed the max time left

View file

@ -5,7 +5,7 @@ from logging.handlers import RotatingFileHandler
log_format = "%(levelname)s %(asctime)s - %(message)s" log_format = "%(levelname)s %(asctime)s - %(message)s"
logging.basicConfig( logging.basicConfig(
handlers=[RotatingFileHandler('../config/debug.log', maxBytes=100000, backupCount=10)], handlers=[RotatingFileHandler('../config/debug.log', maxBytes=500000, backupCount=10)],
level=logging.DEBUG, level=logging.DEBUG,
format=log_format) format=log_format)
@ -14,6 +14,7 @@ stream.setLevel(logging.INFO)
stream_format = logging.Formatter(log_format) stream_format = logging.Formatter(log_format)
stream.setFormatter(stream_format) stream.setFormatter(stream_format)
def get_logger(name): def get_logger(name):
l = logging.getLogger(name) l = logging.getLogger(name)
l.addHandler(stream) l.addHandler(stream)

View file

@ -17,11 +17,11 @@ class Notification:
self.pushover_user_key = None self.pushover_user_key = None
self.message_prefix = "SG-bot: " self.message_prefix = "SG-bot: "
def send(self, type_of_error, message): def send_won(self, message):
logger.debug(f"Attempting to notify: {message}") self.__send('won', message)
if self.pushover:
logger.debug("Pushover enabled. Sending message.") def send_error(self, message):
self.__pushover(type_of_error, message) self.__send('error', message)
def enable_pushover(self, token, user_key): def enable_pushover(self, token, user_key):
logger.debug("Enabling pushover notifications.") logger.debug("Enabling pushover notifications.")
@ -29,6 +29,12 @@ class Notification:
self.pushover_token = token self.pushover_token = token
self.pushover_user_key = user_key self.pushover_user_key = user_key
def __send(self, type_of_error, message):
logger.debug(f"Attempting to notify: {message}")
if self.pushover:
logger.debug("Pushover enabled. Sending message.")
self.__pushover(type_of_error, message)
def __pushover(self, type_of_error, message): def __pushover(self, type_of_error, message):
conn = http.client.HTTPSConnection("api.pushover.net:443") conn = http.client.HTTPSConnection("api.pushover.net:443")
conn.request("POST", "/1/messages.json", conn.request("POST", "/1/messages.json",
@ -47,5 +53,3 @@ class Notification:
with Session(engine) as session: with Session(engine) as session:
session.add(n) session.add(n)
session.commit() session.commit()

View file

@ -68,12 +68,12 @@ def run():
logger.info(f"Going to sleep for {random_seconds / 60} minutes.") logger.info(f"Going to sleep for {random_seconds / 60} minutes.")
sleep(random_seconds) sleep(random_seconds)
except SteamGiftsException as e: except SteamGiftsException as e:
notification.send('error', e) notification.send_error(e)
sleep(5) sleep(5)
exit(-1) exit(-1)
except Exception as e: except Exception as e:
logger.error(e) logger.error(e)
notification.send('error', "Something happened and the bot had to quit!") notification.send_error("Something happened and the bot had to quit!")
sleep(5) sleep(5)
exit(-1) exit(-1)

View file

@ -1,9 +1,8 @@
from sqlalchemy import create_engine, Integer, String, Column, Table, \
MetaData, DateTime, Numeric, Enum, Boolean, TIMESTAMP, func
from sqlalchemy_utils import database_exists, create_database
from sqlalchemy.orm import registry
from datetime import datetime from datetime import datetime
import pytz
from sqlalchemy import create_engine, Integer, String, Column, DateTime, Boolean, func, ForeignKey
from sqlalchemy.orm import registry, relationship, Session
from sqlalchemy_utils import database_exists, create_database
mapper_registry = registry() mapper_registry = registry()
mapper_registry.metadata mapper_registry.metadata
@ -19,16 +18,34 @@ class TableNotification(Base):
medium = Column(String(50), nullable=False) medium = Column(String(50), nullable=False)
success = Column(Boolean, nullable=False) success = Column(Boolean, nullable=False)
created_at = Column(DateTime(timezone=True), server_default=func.now()) created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
__mapper_args__ = {"eager_defaults": True} __mapper_args__ = {"eager_defaults": True}
@classmethod
def get_won_notifications_today(cls):
with Session(engine) as session:
return session.query(TableNotification)\
.filter(func.DATE(TableNotification.created_at) == datetime.utcnow().date())\
.filter_by(type='won')\
.all()
class TableSteamItem(Base):
__tablename__ = 'steam_item'
steam_id = Column(String(15), primary_key=True, nullable=False)
game_name = Column(String(200), nullable=False)
steam_url = Column(String(100), nullable=False)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
giveaways = relationship("TableGiveaway", back_populates="steam_item")
class TableGiveaway(Base): class TableGiveaway(Base):
__tablename__ = 'giveaway' __tablename__ = 'giveaway'
steam_app_id = Column(String(15), primary_key=True, nullable=False) giveaway_id = Column(String(10), primary_key=True, nullable=False)
giveaway_game_id = Column(String(10), primary_key=True, nullable=False) steam_id = Column(Integer, ForeignKey('steam_item.steam_id'), primary_key=True)
steam_url = Column(String(100), nullable=False)
game_name = Column(String(200), nullable=False)
giveaway_uri = Column(String(200), nullable=False) giveaway_uri = Column(String(200), nullable=False)
user = Column(String(40), nullable=False) user = Column(String(40), nullable=False)
giveaway_created_at = Column(DateTime(timezone=True), nullable=False) giveaway_created_at = Column(DateTime(timezone=True), nullable=False)
@ -37,16 +54,52 @@ class TableGiveaway(Base):
copies = Column(Integer(), nullable=False) copies = Column(Integer(), nullable=False)
contributor_level = Column(Integer(), nullable=False) contributor_level = Column(Integer(), nullable=False)
entered = Column(Boolean(), nullable=False) entered = Column(Boolean(), nullable=False)
won = Column(Boolean(), nullable=False)
game_entries = Column(Integer(), nullable=False) game_entries = Column(Integer(), nullable=False)
created_at = Column(DateTime(timezone=True), server_default=func.now()) created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now()) updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
steam_item = relationship("TableSteamItem", back_populates="giveaways")
__mapper_args__ = {"eager_defaults": True} __mapper_args__ = {"eager_defaults": True}
@classmethod @classmethod
def unix_timestamp_to_utc_datetime(cls, timestamp): def unix_timestamp_to_utc_datetime(cls, timestamp):
return datetime.utcfromtimestamp(timestamp) return datetime.utcfromtimestamp(timestamp)
@classmethod
def upsert_giveaway(cls, giveaway, entered):
with Session(engine) as session:
result = session.query(TableGiveaway).filter_by(giveaway_id=giveaway.giveaway_game_id,
steam_id=giveaway.steam_app_id).all()
if result:
steam_id = result[0].steam_id
else:
item = TableSteamItem(
steam_id=giveaway.steam_app_id,
steam_url=giveaway.steam_url,
game_name=giveaway.game_name)
session.merge(item)
session.flush()
steam_id = item.steam_id
g = TableGiveaway(
giveaway_id=giveaway.giveaway_game_id,
steam_id=steam_id,
giveaway_uri=giveaway.giveaway_uri,
user=giveaway.user,
giveaway_created_at=TableGiveaway.unix_timestamp_to_utc_datetime(giveaway.time_created_timestamp),
giveaway_ended_at=TableGiveaway.unix_timestamp_to_utc_datetime(giveaway.time_remaining_timestamp),
cost=giveaway.cost,
copies=giveaway.copies,
contributor_level=giveaway.contributor_level,
entered=entered,
won=False,
game_entries=giveaway.game_entries)
session.merge(g)
session.commit()
if not database_exists(engine.url): if not database_exists(engine.url):
create_database(engine.url) create_database(engine.url)