Skip to content
Merged
8 changes: 7 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ DATABASE_URL=sqlite:///helldivers2.db
LOG_LEVEL=INFO
SCRAPE_INTERVAL=300

# Hell Divers 2 API Configuration
# Hell Divers 2 API Configuration (Community API: https://api.helldivers2.dev)
# Base URL should point to the API endpoint
HELLDIVERS_API_BASE=NA

# Required headers for the Hell Divers 2 API
# X-Super-Client: Application name (identifies your app to the API)
# X-Super-Contact: Developer contact (email for API issues/abuse reports)
HELLDIVERS_API_CLIENT_NAME=NA
HELLDIVERS_API_CONTACT=NA
23 changes: 23 additions & 0 deletions .github/workflows/auto-assign.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Auto Assign PR

on:
pull_request:
types: [opened]

permissions:
pull-requests: write

jobs:
assign:
runs-on: ubuntu-latest
steps:
- name: Auto assign PR to author
uses: actions/github-script@v7
with:
script: |
github.rest.issues.addAssignees({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
assignees: [context.payload.pull_request.user.login]
})
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ dev = [
"black>=23.7.0",
"ruff>=0.0.280",
"mypy>=1.4.1",
"types-requests>=2.31.0",
]

[project.urls]
Expand Down
24 changes: 21 additions & 3 deletions src/collector.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def collect_all_data(self):
self.db.save_war_status(war_data)
logger.info("War status collected")

# Collect statistics
# Collect statistics (extracted from war status)
stats_data = self.scraper.get_statistics()
if stats_data:
self.db.save_statistics(stats_data)
Expand All @@ -69,11 +69,29 @@ def collect_all_data(self):
if campaigns:
for campaign in campaigns:
campaign_id = campaign.get("id")
planet_index = campaign.get("planet_index")
if campaign_id and planet_index:
if campaign_id and campaign.get("planet") and "index" in campaign["planet"]:
planet_index = campaign["planet"].get("index")
self.db.save_campaign(campaign_id, planet_index, campaign)
logger.info(f"Collected {len(campaigns)} campaigns")

# Collect assignments (Major Orders)
assignments = self.scraper.get_assignments()
if assignments:
self.db.save_assignments(assignments)
logger.info(f"Collected {len(assignments)} assignments")

# Collect dispatches (news)
dispatches = self.scraper.get_dispatches()
if dispatches:
self.db.save_dispatches(dispatches)
logger.info(f"Collected {len(dispatches)} dispatches")

# Collect planet events
events = self.scraper.get_planet_events()
if events is not None:
Comment thread
surrealwolf marked this conversation as resolved.
self.db.save_planet_events(events)
logger.info(f"Collected {len(events)} planet events")

logger.info("Data collection cycle completed successfully")

except Exception as e:
Expand Down
4 changes: 3 additions & 1 deletion src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ class Config:
API_TIMEOUT = 30
SCRAPE_INTERVAL = 300 # 5 minutes

# Hell Divers 2 API Endpoints
# Hell Divers 2 API Endpoints (Community-maintained at api.helldivers2.dev)
HELLDIVERS_API_BASE = os.getenv("HELLDIVERS_API_BASE", "NA")
HELLDIVERS_API_CLIENT_NAME = os.getenv("HELLDIVERS_API_CLIENT_NAME", "NA")
HELLDIVERS_API_CONTACT = os.getenv("HELLDIVERS_API_CONTACT", "NA")

# Logging
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO")
Expand Down
138 changes: 138 additions & 0 deletions src/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,42 @@ def init_db(self):
"""
)

# Assignments table (Major Orders)
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS assignments (
id INTEGER PRIMARY KEY AUTOINCREMENT,
assignment_id INTEGER UNIQUE,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
data TEXT NOT NULL
)
"""
)

# Dispatches table (News/Announcements)
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS dispatches (
id INTEGER PRIMARY KEY AUTOINCREMENT,
dispatch_id INTEGER UNIQUE,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
data TEXT NOT NULL
)
"""
)

# Planet events table
cursor.execute(
"""
CREATE TABLE IF NOT EXISTS planet_events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
event_id INTEGER UNIQUE,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
data TEXT NOT NULL
)
"""
)

# Index for faster queries
cursor.execute("CREATE INDEX IF NOT EXISTS idx_war_timestamp ON war_status(timestamp)")
cursor.execute(
Expand All @@ -80,6 +116,9 @@ def init_db(self):
cursor.execute(
"CREATE INDEX IF NOT EXISTS idx_planet_index ON planet_status(planet_index)"
)
cursor.execute("CREATE INDEX IF NOT EXISTS idx_assignment_timestamp ON assignments(timestamp)")
cursor.execute("CREATE INDEX IF NOT EXISTS idx_dispatch_timestamp ON dispatches(timestamp)")
cursor.execute("CREATE INDEX IF NOT EXISTS idx_event_timestamp ON planet_events(timestamp)")

conn.commit()

Expand Down Expand Up @@ -218,3 +257,102 @@ def get_active_campaigns(self) -> List[Dict]:
except Exception as e:
logger.error(f"Failed to get active campaigns: {e}")
return []

def save_assignments(self, data: List[Dict]) -> bool:
"""Save assignments (Major Orders) to database"""
try:
with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()
for assignment in data:
assignment_id = assignment.get("id")
if assignment_id:
cursor.execute(
"INSERT OR REPLACE INTO assignments (assignment_id, data) VALUES (?, ?)",
(assignment_id, json.dumps(assignment)),
)
conn.commit()
return True
except Exception as e:
logger.error(f"Failed to save assignments: {e}")
return False

def save_dispatches(self, data: List[Dict]) -> bool:
"""Save dispatches (news/announcements) to database"""
try:
with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()
for dispatch in data:
dispatch_id = dispatch.get("id")
if dispatch_id:
cursor.execute(
"INSERT OR REPLACE INTO dispatches (dispatch_id, data) VALUES (?, ?)",
(dispatch_id, json.dumps(dispatch)),
)
conn.commit()
return True
except Exception as e:
logger.error(f"Failed to save dispatches: {e}")
return False

def save_planet_events(self, data: List[Dict]) -> bool:
"""Save planet events to database"""
try:
with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()
for event in data:
event_id = event.get("id")
if event_id:
cursor.execute(
"INSERT OR REPLACE INTO planet_events (event_id, data) VALUES (?, ?)",
(event_id, json.dumps(event)),
)
conn.commit()
return True
except Exception as e:
logger.error(f"Failed to save planet events: {e}")
return False

def get_latest_assignments(self, limit: int = 10) -> List[Dict]:
"""Get latest assignments"""
try:
with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()
cursor.execute(
"SELECT data FROM assignments ORDER BY timestamp DESC LIMIT ?",
(limit,),
)
results = cursor.fetchall()
return [json.loads(row[0]) for row in results]
except Exception as e:
logger.error(f"Failed to get latest assignments: {e}")
return []

def get_latest_dispatches(self, limit: int = 10) -> List[Dict]:
"""Get latest dispatches"""
try:
with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()
cursor.execute(
"SELECT data FROM dispatches ORDER BY timestamp DESC LIMIT ?",
(limit,),
)
results = cursor.fetchall()
return [json.loads(row[0]) for row in results]
except Exception as e:
logger.error(f"Failed to get latest dispatches: {e}")
return []

def get_latest_planet_events(self, limit: int = 10) -> List[Dict]:
"""Get latest planet events"""
try:
with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()
cursor.execute(
"SELECT data FROM planet_events ORDER BY timestamp DESC LIMIT ?",
(limit,),
)
results = cursor.fetchall()
return [json.loads(row[0]) for row in results]
except Exception as e:
logger.error(f"Failed to get latest planet events: {e}")
return []
Loading