208 lines
6.7 KiB
Python
208 lines
6.7 KiB
Python
|
|
"""
|
||
|
|
Wiki Configuration Manager - Fetches post templates and titles from subreddit wiki
|
||
|
|
"""
|
||
|
|
|
||
|
|
import time
|
||
|
|
import json
|
||
|
|
import re
|
||
|
|
import yaml
|
||
|
|
from typing import Dict, Optional, Tuple
|
||
|
|
|
||
|
|
# Cache TTL in seconds (refresh wiki config every 30 minutes)
|
||
|
|
WIKI_CACHE_TTL = 1800
|
||
|
|
WIKI_PAGE_NAME = "minecraft_update_bot"
|
||
|
|
|
||
|
|
|
||
|
|
class WikiConfig:
|
||
|
|
"""Manages post configurations loaded from subreddit wiki."""
|
||
|
|
|
||
|
|
def __init__(self):
|
||
|
|
self.configs: Dict[str, Dict[str, str]] = {}
|
||
|
|
self.default_config: Dict[str, str] = {"title": "", "body": ""}
|
||
|
|
self.last_updated = 0
|
||
|
|
self.reddit = None
|
||
|
|
self.subreddit_name = None
|
||
|
|
|
||
|
|
def init(self, reddit, subreddit_name: str):
|
||
|
|
"""Initialize the wiki config manager."""
|
||
|
|
self.reddit = reddit
|
||
|
|
self.subreddit_name = subreddit_name
|
||
|
|
|
||
|
|
def should_refresh(self) -> bool:
|
||
|
|
"""Check if cache has expired."""
|
||
|
|
return (time.time() - self.last_updated) >= WIKI_CACHE_TTL
|
||
|
|
|
||
|
|
def fetch_from_wiki(self) -> bool:
|
||
|
|
"""
|
||
|
|
Fetch post configurations from subreddit wiki.
|
||
|
|
|
||
|
|
Wiki page format (YAML):
|
||
|
|
```yaml
|
||
|
|
release:
|
||
|
|
title: "Minecraft {version} Released!"
|
||
|
|
body: |
|
||
|
|
# Minecraft {version} Released
|
||
|
|
A new version of Minecraft is available!
|
||
|
|
|
||
|
|
**Version:** {version}
|
||
|
|
**Date:** {release_date}
|
||
|
|
|
||
|
|
Get it now at [minecraft.net](https://minecraft.net)
|
||
|
|
|
||
|
|
snapshot:
|
||
|
|
title: "Minecraft {version} Snapshot Available"
|
||
|
|
body: |
|
||
|
|
# Minecraft {version} Snapshot
|
||
|
|
A new snapshot is available for testing!
|
||
|
|
|
||
|
|
**Version:** {version}
|
||
|
|
**Date:** {release_date}
|
||
|
|
|
||
|
|
Try it in the launcher!
|
||
|
|
|
||
|
|
default:
|
||
|
|
title: "Minecraft {version} ({type})"
|
||
|
|
body: |
|
||
|
|
New {type}: {version}
|
||
|
|
Released: {release_date}
|
||
|
|
```
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
True if successful, False otherwise
|
||
|
|
"""
|
||
|
|
try:
|
||
|
|
subreddit = self.reddit.subreddit(self.subreddit_name)
|
||
|
|
wiki_page = subreddit.wiki[WIKI_PAGE_NAME]
|
||
|
|
content = wiki_page.content_md
|
||
|
|
|
||
|
|
self.configs = self._parse_yaml_content(content)
|
||
|
|
self.last_updated = time.time()
|
||
|
|
|
||
|
|
if self.configs:
|
||
|
|
print(f"[WIKI_CONFIG] ✓ Loaded {len(self.configs)} configuration(s)")
|
||
|
|
for release_type in self.configs:
|
||
|
|
print(f" - {release_type}")
|
||
|
|
return True
|
||
|
|
else:
|
||
|
|
print("[WIKI_CONFIG] ⚠ No configurations found in wiki")
|
||
|
|
return False
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
print(f"[WIKI_CONFIG] ✗ Error fetching wiki: {e}")
|
||
|
|
return False
|
||
|
|
|
||
|
|
def _parse_yaml_content(self, content: str) -> Dict[str, Dict[str, str]]:
|
||
|
|
"""
|
||
|
|
Parse YAML content into configuration dict.
|
||
|
|
|
||
|
|
Expected format:
|
||
|
|
```yaml
|
||
|
|
release:
|
||
|
|
title: "Minecraft {version} Released!"
|
||
|
|
body: |
|
||
|
|
Multi-line post body
|
||
|
|
with {placeholders}
|
||
|
|
|
||
|
|
snapshot:
|
||
|
|
title: "Minecraft {version} Snapshot"
|
||
|
|
body: |
|
||
|
|
Snapshot post body
|
||
|
|
```
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Dict mapping release_type -> {"title": str, "body": str}
|
||
|
|
"""
|
||
|
|
try:
|
||
|
|
data = yaml.safe_load(content)
|
||
|
|
|
||
|
|
if not isinstance(data, dict):
|
||
|
|
print("[WIKI_CONFIG] ✗ Wiki content is not valid YAML dictionary")
|
||
|
|
return {}
|
||
|
|
|
||
|
|
configs = {}
|
||
|
|
for release_type, config in data.items():
|
||
|
|
if isinstance(config, dict):
|
||
|
|
if "title" in config and "body" in config:
|
||
|
|
configs[release_type.lower()] = {
|
||
|
|
"title": str(config["title"]),
|
||
|
|
"body": str(config["body"])
|
||
|
|
}
|
||
|
|
else:
|
||
|
|
print(f"[WIKI_CONFIG] ⚠ Missing 'title' or 'body' for {release_type}")
|
||
|
|
|
||
|
|
return configs
|
||
|
|
|
||
|
|
except yaml.YAMLError as e:
|
||
|
|
print(f"[WIKI_CONFIG] ✗ YAML parsing error: {e}")
|
||
|
|
return {}
|
||
|
|
|
||
|
|
def get_config(self, release_type: str, refresh: bool = False) -> Tuple[str, str]:
|
||
|
|
"""
|
||
|
|
Get title and body template for a release type.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
release_type: Type like "release" or "snapshot"
|
||
|
|
refresh: Force refresh from wiki
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Tuple of (title_template, body_template)
|
||
|
|
"""
|
||
|
|
# Refresh if needed
|
||
|
|
if refresh or self.should_refresh() or not self.configs:
|
||
|
|
self.fetch_from_wiki()
|
||
|
|
|
||
|
|
# Get config for this type, fall back to any available config
|
||
|
|
if release_type in self.configs:
|
||
|
|
config = self.configs[release_type]
|
||
|
|
return config["title"], config["body"]
|
||
|
|
|
||
|
|
# Try generic "default" config
|
||
|
|
if "default" in self.configs:
|
||
|
|
config = self.configs["default"]
|
||
|
|
return config["title"], config["body"]
|
||
|
|
|
||
|
|
# Fall back to hardcoded defaults
|
||
|
|
default_title = "Minecraft {version} Released!"
|
||
|
|
default_body = """# Minecraft {version}
|
||
|
|
|
||
|
|
A new version is available!
|
||
|
|
|
||
|
|
**Version:** {version}
|
||
|
|
**Released:** {release_date}
|
||
|
|
|
||
|
|
Get it at [minecraft.net](https://minecraft.net)"""
|
||
|
|
|
||
|
|
return default_title, default_body
|
||
|
|
|
||
|
|
def format_post(self, release_type: str, version: str, release_date: str) -> Tuple[str, str]:
|
||
|
|
"""
|
||
|
|
Get formatted post title and body for a version.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
release_type: Type like "release" or "snapshot"
|
||
|
|
version: Version string like "1.21"
|
||
|
|
release_date: Formatted date string
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Tuple of (formatted_title, formatted_body)
|
||
|
|
"""
|
||
|
|
title_template, body_template = self.get_config(release_type)
|
||
|
|
|
||
|
|
# Format with available placeholders
|
||
|
|
format_dict = {
|
||
|
|
"version": version,
|
||
|
|
"release_date": release_date,
|
||
|
|
"type": release_type
|
||
|
|
}
|
||
|
|
|
||
|
|
try:
|
||
|
|
formatted_title = title_template.format(**format_dict)
|
||
|
|
formatted_body = body_template.format(**format_dict)
|
||
|
|
return formatted_title, formatted_body
|
||
|
|
except KeyError as e:
|
||
|
|
print(f"[WIKI_CONFIG] ✗ Unknown placeholder in template: {e}")
|
||
|
|
# Fall back to defaults
|
||
|
|
formatted_title = f"Minecraft {version} ({release_type})"
|
||
|
|
formatted_body = f"New {release_type}: {version}\nReleased: {release_date}"
|
||
|
|
return formatted_title, formatted_body
|