Compare commits

...

7 Commits

Author SHA1 Message Date
Mike Lang a2403b56cd schedulebot: fix time zones 2 months ago
Mike Lang c53c5a98d5 pubbot: work in years besides 2024 2 months ago
Mike Lang 2c423f65fb prizebot: Fix year regex 2 months ago
Mike Lang 6b7ae95c1f prizebot: make it work for years besides 2024 2 months ago
Mike Lang 15f4767f32 fix another issue with the thing i yolo'd into prod 2 months ago
Mike Lang b24612d271 fix typo in prev commit 2 months ago
Mike Lang 67d351e549 cutter: Add mode where it only uploads rows with uploader_whitelist set
So you can have a "special" cutter that doesn't upload most videos
2 months ago

@ -123,7 +123,7 @@ class Cutter(object):
ERROR_RETRY_INTERVAL = 5
RETRYABLE_UPLOAD_ERROR_WAIT_INTERVAL = 5
def __init__(self, upload_locations, dbmanager, stop, name, segments_path, tags):
def __init__(self, upload_locations, dbmanager, stop, name, segments_path, tags, uploader_explicit_only=False):
"""upload_locations is a map {location name: upload location backend}
Conn is a database connection.
Stop is an Event triggering graceful shutdown when set.
@ -136,6 +136,7 @@ class Cutter(object):
self.stop = stop
self.segments_path = segments_path
self.tags = tags
self.uploader_explicit_only = uploader_explicit_only
self.logger = logging.getLogger(type(self).__name__)
self.refresh_conn()
@ -241,14 +242,18 @@ class Cutter(object):
"""Return a list of all available candidates that we might be able to cut."""
# We only accept candidates if they haven't excluded us by whitelist,
# and we are capable of uploading to their desired upload location.
uploader_condition = "(uploader_whitelist IS NULL OR %(name)s = ANY (uploader_whitelist))"
if self.uploader_explicit_only:
uploader_condition = "%(name)s = ANY (uploader_whitelist)"
built_query = sql.SQL("""
SELECT id, {}
FROM events
WHERE state = 'EDITED'
AND (uploader_whitelist IS NULL OR %(name)s = ANY (uploader_whitelist))
AND {}
AND upload_location = ANY (%(upload_locations)s)
""").format(
sql.SQL(", ").join(sql.Identifier(key) for key in CUT_JOB_PARAMS)
sql.SQL(", ").join(sql.Identifier(key) for key in CUT_JOB_PARAMS),
sql.SQL(uploader_condition),
)
result = query(self.conn, built_query, name=self.name, upload_locations=list(self.upload_locations.keys()))
return result.fetchall()
@ -870,6 +875,7 @@ def main(
tags='',
metrics_port=8003,
backdoor_port=0,
uploader_explicit_only=False,
):
"""dbconnect should be a postgres connection string, which is either a space-separated
list of key=value pairs, or a URI like:
@ -960,7 +966,7 @@ def main(
if not no_updater:
needs_updater[location] = backend
cutter = Cutter(upload_locations, dbmanager, stop, name, base_dir, tags)
cutter = Cutter(upload_locations, dbmanager, stop, name, base_dir, tags, uploader_explicit_only)
transcode_checkers = [
TranscodeChecker(location, backend, dbmanager, stop)
for location, backend in needs_transcode_check.items()

@ -344,6 +344,7 @@
pubbot:: {
zulip_email: "blog-bot@chat.videostrike.team",
zulip_api_key: "",
year: "2024",
# The id for this year's total
total_id: "RZZQRDQNLNLW",
# The ids of any prizes to watch
@ -353,6 +354,7 @@
prizebot:: {
email: "blog-bot@chat.videostrike.team",
api_key: "",
year: $.pubbot.year,
state: "/prizebot_state.json",
// Path in host fs for the state file.
// Must exist and be initialized to "{}"

@ -15,8 +15,8 @@ from .zulip import Client
Prize = namedtuple("Prize", ["id", "link", "type", "title", "state", "result"])
def get_prizes(type):
resp = requests.get(f"https://desertbus.org/2024/prizes/{type}", {"User-Agent": ""})
def get_prizes(year, type):
resp = requests.get(f"https://desertbus.org/{year}/prizes/{type}", {"User-Agent": ""})
resp.raise_for_status()
html = BeautifulSoup(resp.content.decode(), "html.parser")
@ -24,7 +24,7 @@ def get_prizes(type):
prizes = []
for a in main.find_all("a"):
# look for prize links
match = re.match("^/\d+/prize/([A-Z]+)$", a["href"])
match = re.match("^/[^/]+/prize/([A-Z]+)$", a["href"])
if not match:
continue
# skip image links
@ -73,8 +73,10 @@ def main(config_file, test=False, all=False, once=False, interval=60):
"""
Config:
url, email, api_key: zulip creds
year: the correct URL part for the prizes page: https://desertbus.org/YEAR/prizes/giveaway
state: path to state file
"""
logging.basicConfig(level="INFO")
config = get_config(config_file)
with open(config['state']) as f:
# state is {id: last seen state}
@ -83,7 +85,7 @@ def main(config_file, test=False, all=False, once=False, interval=60):
while True:
start = time.time()
for type in ('live', 'silent', 'giveaway'):
prizes = get_prizes(type)
prizes = get_prizes(config['year'], type)
for prize in prizes:
logging.info(f"Got prize: {prize}")
if prize.state == "sold" and (all or state.get(prize.id, "sold") != "sold"):

@ -40,7 +40,7 @@ def get_current(channel):
giveaway_cache = [None, None]
def get_giveaway():
def get_giveaway(year):
REFRESH_RISING = 30
REFRESH_FALLING = 300
t, g = giveaway_cache
@ -48,7 +48,7 @@ def get_giveaway():
timeout = REFRESH_RISING if g is None else REFRESH_FALLING
if t is None or now - t > timeout:
try:
g = _get_giveaway()
g = _get_giveaway(year)
except Exception:
logging.warning("Failed to fetch giveaway", exc_info=True)
else:
@ -57,8 +57,8 @@ def get_giveaway():
return giveaway_cache[1]
def _get_giveaway():
resp = session.get("https://desertbus.org/2024/donate", headers={"User-Agent": ""})
def _get_giveaway(year):
resp = session.get(f"https://desertbus.org/{year}/donate", headers={"User-Agent": ""})
resp.raise_for_status()
html = BeautifulSoup(resp.content.decode(), "html.parser")
island = html.find("astro-island", **{"component-export": "DonateForm"})
@ -73,18 +73,18 @@ def _get_giveaway():
prize_cache = {}
def get_prize_name(id):
def get_prize_name(year, id):
if id not in prize_cache:
try:
prize_cache[id] = _get_prize_name(id)
prize_cache[id] = _get_prize_name(year, id)
except Exception:
logging.warning(f"Failed to get prize title for {id}", exc_info=True)
return "Unknown prize"
return prize_cache[id]
def _get_prize_name(id):
resp = requests.get(f"https://desertbus.org/2024/prize/{id}", {"User-Agent": ""})
def _get_prize_name(year, id):
resp = requests.get(f"https://desertbus.org/{year}/prize/{id}", {"User-Agent": ""})
resp.raise_for_status()
html = BeautifulSoup(resp.content.decode(), "html.parser")
div = html.body.main.find("div", **{"class": lambda cl: "text-brand-gold" in cl})
@ -97,6 +97,7 @@ def main(conf_file, message_log_file, name=socket.gethostname()):
zulip_url
zulip_email
zulip_api_key
year
total_id: id for donation total channel
prize_ids: list of ids for prizes to watch bids for
"""
@ -104,6 +105,7 @@ def main(conf_file, message_log_file, name=socket.gethostname()):
config = get_config(conf_file)
client = Client(config["zulip_url"], config["zulip_email"], config["zulip_api_key"])
year = config["year"]
message_log = open(message_log_file, "a")
def write_log(log):
@ -144,7 +146,7 @@ def main(conf_file, message_log_file, name=socket.gethostname()):
increase = None if total is None else msg["d"] - total
log["increase"] = increase
increase_str = "" if increase is None else " (+${:.2f})".format(msg["d"] - total)
giveaway_amount = get_giveaway()
giveaway_amount = get_giveaway(year)
entries_str = ""
if increase is not None and giveaway_amount is not None:
if (increase + 0.005) % giveaway_amount < 0.01:
@ -163,7 +165,7 @@ def main(conf_file, message_log_file, name=socket.gethostname()):
log["type"] = "prize"
prize_id = msg["c"].removeprefix("bid:")
log["prize_id"] = prize_id
prize_name = get_prize_name(prize_id)
prize_name = get_prize_name(year, prize_id)
log["prize_name"] = prize_name
data = msg["d"]
logging.info(f"Prize update for {prize_id}: {data}")

@ -7,6 +7,7 @@ import logging
import time
from calendar import timegm
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
import gevent.pool
import argh
@ -75,7 +76,9 @@ def hour_to_shift(hour, start_time):
"""Converts an hour number into a datetime, shift number (0-3), shift name, and hour-of-shift (1-6)"""
start_time = datetime.utcfromtimestamp(start_time)
current_time = (start_time + timedelta(hours=hour)).replace(minute=0, second=0, microsecond=0)
current_time_pst = current_time - timedelta(hours=8)
utc = ZoneInfo("utc")
pst = ZoneInfo("America/Vancouver")
current_time_pst = current_time.replace(tzinfo=utc).astimezone(pst)
hour_pst = current_time_pst.hour
shift = hour_pst // 6
shift_name = ["zeta", "dawn-guard", "alpha-flight", "night-watch"][shift]
@ -217,7 +220,7 @@ def parse_schedule(sheets_client, user_ids, schedule_sheet_id, schedule_sheet_na
for row in raw_schedule:
name = row[0].lower()
if name in ["", "Chat Member", "Hour of the Run"] or name.startswith("-") or name.startswith("["):
if name in ["", "chat member", "hour of the run"] or name.startswith("-") or name.startswith("["):
continue
if name not in user_ids:
logging.warning(f"No user id known for user {name}")

Loading…
Cancel
Save