merge upstream: daily set hydration and the readme image name

This commit is contained in:
Ethan Stoner
2026-08-27 00:21:29 -07:00
4 changed files with 47 additions and 14 deletions
+1
View File
@@ -1,4 +1,5 @@
*.png
*.jpg
*.txt
*.log
!nouns.txt
+1 -1
View File
@@ -37,7 +37,7 @@ $env:QUERY_SOURCE="trends"; python src/main.py # PowerShell
You should also have an Ollama account created (for the LLM), the `ollama` tool installed, and you should have signed in to the Ollama CLI via the command line using `ollama signin`. This project will use a minimal amount of Ollama cloud usage using `gemma4:cloud`. If you wish to use a different model, please change the `model` parameter in the `get_ollama_response` function in `src/llm_utils.py`.
You must also provide an image for the script to upload to complete the visual search task. Currently, this image is named `keypress_times.png` and is located in the root directory of the project (yes, I used a random image from my keyboard analysis to do this). You may provide an image of your own, just ensure that the absolute path of the image is placed in the `VISUAL_SEARCH_IMAGE_PATH` constant at the top of `rewards_tasks.py`.
You must also provide an image for the script to upload to complete the visual search task. Currently, this image is named `visual_search.jpg` and is located in the root directory of the project. You may provide an image of your own, just ensure that the absolute path of the image is placed in the `VISUAL_SEARCH_IMAGE_PATH` constant at the top of `rewards_tasks.py`.
Activate the virtual environment & install dependencies (you may have to use `python -m poetry` instead of `poetry`).
You must have Python 3.12+ and Poetry installed.
+12
View File
@@ -184,6 +184,18 @@ def main():
driver.execute_script("arguments[0].click();", elements.get_points_breakdown_button())
wait_until(lambda: elements.get_sidebar_section() is not None, 30)
# The section exists before it has content: the panel renders a
# "Loading..." placeholder inside it first, and that satisfies the
# presence check above immediately. Waiting only for the section leaves
# the two selectors below reading an empty panel, so they report FAILED
# for markup that is fine, on a page that is merely slow. Wait for the
# content itself. A selector that really is broken still reports FAILED,
# it just costs the timeout first.
wait_until(
lambda: elements.get_points_earned_from_searches_on_points_breakdown() is not None,
30,
)
report.check("get_sidebar_section", elements.get_sidebar_section)
report.check(
"get_points_earned_from_searches_on_points_breakdown",
+33 -13
View File
@@ -61,24 +61,39 @@ class RewardsTaskUtils:
elem = self.wait_for_element(element_getter, timeout)
self.move_to_and_click(elem)
def complete_bing_daily_set(self):
def complete_bing_daily_set(self, expected_activities: int = 3):
self.switch_to_earn_page()
self.wait_for_then_click(self.elements.get_open_daily_set_button)
daily_set_links = self.wait_for_element(self.elements.get_daily_set_elements)
# The panel hydrates progressively, so the first non-empty snapshot can
# hold fewer than 3 activities. wait_for_element returns on the first
# truthy result, so a 1-element list satisfied it and indexing [1] and
# [2] then raised IndexError, taking the whole task down. Wait for the
# full set instead, and if it never fills, work with what is there.
def full_activity_list():
activities = self.elements.get_daily_set_elements()
self.move_to_and_click(daily_set_links[0])
time.sleep(random.uniform(2, 3))
self.driver.switch_to.window(self.driver.current_window_handle) # refocus on the main tab
return activities if len(activities) >= expected_activities else False
self.move_to_and_click(daily_set_links[1])
time.sleep(random.uniform(2, 3))
self.driver.switch_to.window(self.driver.current_window_handle)
try:
daily_set_links = self.wait_for_element(full_activity_list, timeout=30)
except TimeoutException:
daily_set_links = self.elements.get_daily_set_elements()
self.move_to_and_click(daily_set_links[2])
time.sleep(random.uniform(2, 3))
self.driver.switch_to.window(self.driver.current_window_handle)
print(f"[WARNING] Daily set panel only shows {len(daily_set_links)} of {expected_activities} activities")
# Re-read the panel per index: clicking an activity can re-render it and
# stale the captured references.
for index in range(len(daily_set_links)):
activities = self.elements.get_daily_set_elements()
if index >= len(activities):
break
self.move_to_and_click(activities[index])
time.sleep(random.uniform(2, 3))
self.driver.switch_to.window(self.driver.current_window_handle) # refocus on the main tab
self.tab_utils.close_all_other_tabs()
@@ -205,9 +220,14 @@ class RewardsTaskUtils:
def read_search_points(self):
"""Open the points breakdown, read the Bing search row, close it again."""
self.switch_to_earn_page()
self.wait_for_then_click(self.elements.get_points_breakdown_button)
close_btn = self.wait_for_element(self.elements.get_close_button_on_points_breakdown)
# 30s rather than the default 10s: this runs after the earlier tasks have
# navigated away, so the earn page re-renders from scratch first and the
# breakdown button regularly needs longer than 10s to appear. Timing out
# here skipped the entire search task while points were still available.
self.wait_for_then_click(self.elements.get_points_breakdown_button, timeout=30)
close_btn = self.wait_for_element(self.elements.get_close_button_on_points_breakdown, timeout=15)
points_earned, max_pts = self.elements.get_points_earned_from_searches_on_points_breakdown()