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

@ -2,5 +2,4 @@ requests==2.27.1
beautifulsoup4==4.11.1
urllib3==1.26.9
sqlalchemy==1.4.36
sqlalchemy_utils==0.38.2
pytz==2022.1
sqlalchemy_utils==0.38.2

View file

@ -1,17 +1,15 @@
import json
from datetime import datetime
from random import randint
from time import sleep
import requests
from bs4 import BeautifulSoup
from requests.adapters import HTTPAdapter
from sqlalchemy.orm import Session
from urllib3.util import Retry
import log
from giveaway import Giveaway
from tables import engine, TableGiveaway
from tables import TableNotification, TableGiveaway
logger = log.get_logger(__name__)
@ -69,7 +67,7 @@ class SteamGifts:
return session
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)
soup = BeautifulSoup(r.text, 'html.parser')
return soup
@ -85,6 +83,20 @@ class SteamGifts:
logger.error("⛔ 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):
if giveaway.time_remaining_in_minutes is None:
return False
@ -139,25 +151,6 @@ class SteamGifts:
logger.error(f"Failed entering giveaway {giveaway.giveaway_game_id}")
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):
n = page
run = True
@ -180,7 +173,6 @@ class SteamGifts:
if not len(unentered_game_list) or (all_games_list_count == pinned_giveaway_count):
txt = f"We have run out of gifts to consider."
logger.info(txt)
run = False
break
for item in unentered_game_list:
@ -200,15 +192,15 @@ class SteamGifts:
if if_enter_giveaway:
res = self.enter_giveaway(giveaway)
if res:
self.create_or_update_giveaway(giveaway, True)
TableGiveaway.upsert_giveaway(giveaway, True)
self.points -= int(giveaway.cost)
txt = f"🎉 One more game! Has just entered {giveaway.game_name}"
logger.info(txt)
sleep(randint(4, 15))
else:
self.create_or_update_giveaway(giveaway, False)
TableGiveaway.upsert_giveaway(giveaway, False)
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
# 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

View file

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

View file

@ -17,11 +17,11 @@ class Notification:
self.pushover_user_key = None
self.message_prefix = "SG-bot: "
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 send_won(self, message):
self.__send('won', message)
def send_error(self, message):
self.__send('error', message)
def enable_pushover(self, token, user_key):
logger.debug("Enabling pushover notifications.")
@ -29,6 +29,12 @@ class Notification:
self.pushover_token = token
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):
conn = http.client.HTTPSConnection("api.pushover.net:443")
conn.request("POST", "/1/messages.json",
@ -47,5 +53,3 @@ class Notification:
with Session(engine) as session:
session.add(n)
session.commit()

View file

@ -68,15 +68,15 @@ def run():
logger.info(f"Going to sleep for {random_seconds / 60} minutes.")
sleep(random_seconds)
except SteamGiftsException as e:
notification.send('error', e)
notification.send_error(e)
sleep(5)
exit(-1)
except Exception as 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)
exit(-1)
if __name__ == '__main__':
run()
run()

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
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.metadata
@ -19,16 +18,34 @@ class TableNotification(Base):
medium = Column(String(50), nullable=False)
success = Column(Boolean, 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())
__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):
__tablename__ = 'giveaway'
steam_app_id = Column(String(15), primary_key=True, nullable=False)
giveaway_game_id = Column(String(10), primary_key=True, nullable=False)
steam_url = Column(String(100), nullable=False)
game_name = Column(String(200), nullable=False)
giveaway_id = Column(String(10), primary_key=True, nullable=False)
steam_id = Column(Integer, ForeignKey('steam_item.steam_id'), primary_key=True)
giveaway_uri = Column(String(200), nullable=False)
user = Column(String(40), nullable=False)
giveaway_created_at = Column(DateTime(timezone=True), nullable=False)
@ -37,16 +54,52 @@ class TableGiveaway(Base):
copies = Column(Integer(), nullable=False)
contributor_level = Column(Integer(), nullable=False)
entered = Column(Boolean(), nullable=False)
won = Column(Boolean(), nullable=False)
game_entries = Column(Integer(), 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())
steam_item = relationship("TableSteamItem", back_populates="giveaways")
__mapper_args__ = {"eager_defaults": True}
@classmethod
def unix_timestamp_to_utc_datetime(cls, 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):
create_database(engine.url)
@ -55,4 +108,4 @@ if not database_exists(engine.url):
Base.metadata.create_all(engine)
else:
# Connect the database if exists.
engine.connect()
engine.connect()