633 lines
12 KiB
Markdown
633 lines
12 KiB
Markdown
# EU-Utility API Reference
|
|
|
|
**Version:** 2.2.0
|
|
**Last Updated:** 2026-02-15
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
EU-Utility provides a comprehensive three-tier API architecture:
|
|
|
|
| API | Purpose | Audience |
|
|
|-----|---------|----------|
|
|
| **PluginAPI** | Access core services | Plugin developers |
|
|
| **WidgetAPI** | Create overlay widgets | Widget developers |
|
|
| **ExternalAPI** | Third-party integrations | External apps, bots |
|
|
|
|
---
|
|
|
|
## PluginAPI
|
|
|
|
The PluginAPI provides access to all core EU-Utility services.
|
|
|
|
### Getting Started
|
|
|
|
```python
|
|
from core.api import get_api
|
|
|
|
class MyPlugin(BasePlugin):
|
|
def initialize(self):
|
|
self.api = get_api()
|
|
|
|
def on_event(self, event):
|
|
self.api.show_notification("Event", str(event))
|
|
```
|
|
|
|
### Services Available
|
|
|
|
#### Log Reader
|
|
```python
|
|
# Read recent log lines
|
|
lines = api.read_log_lines(100)
|
|
|
|
# Read since timestamp
|
|
recent = api.read_log_since(datetime.now() - timedelta(minutes=5))
|
|
```
|
|
|
|
#### Window Manager
|
|
```python
|
|
# Get EU window info
|
|
window = api.get_eu_window()
|
|
if window:
|
|
print(f"EU at {window['x']}, {window['y']}")
|
|
print(f"Size: {window['width']}x{window['height']}")
|
|
|
|
# Check focus
|
|
if api.is_eu_focused():
|
|
api.play_sound("alert.wav")
|
|
|
|
# Bring EU to front
|
|
api.bring_eu_to_front()
|
|
```
|
|
|
|
#### OCR Service
|
|
```python
|
|
# Check availability
|
|
if api.ocr_available():
|
|
# Read text from screen region
|
|
text = api.recognize_text((100, 100, 200, 50))
|
|
print(f"Found: {text}")
|
|
```
|
|
|
|
#### Screenshot
|
|
```python
|
|
# Capture screen
|
|
img = api.capture_screen((0, 0, 1920, 1080), "screenshot.png")
|
|
|
|
# Check availability
|
|
if api.screenshot_available():
|
|
img = api.capture_screen()
|
|
```
|
|
|
|
#### Nexus API (Item Database)
|
|
```python
|
|
# Search items
|
|
items = api.search_items("omegaton", limit=5)
|
|
for item in items:
|
|
print(f"{item['Name']}: {item['Value']} PED")
|
|
|
|
# Get item details
|
|
details = api.get_item_details(12345)
|
|
```
|
|
|
|
#### HTTP Client
|
|
```python
|
|
# GET request with caching
|
|
result = api.http_get("https://api.example.com/data", cache=True)
|
|
if result['success']:
|
|
data = result['data']
|
|
|
|
# POST request
|
|
result = api.http_post("https://api.example.com/save", {"key": "value"})
|
|
```
|
|
|
|
#### Audio
|
|
```python
|
|
# Play sound
|
|
api.play_sound("assets/sounds/alert.wav", volume=0.7)
|
|
|
|
# Simple beep
|
|
api.beep()
|
|
```
|
|
|
|
#### Notifications
|
|
```python
|
|
# Show toast
|
|
api.show_notification(
|
|
title="Loot Alert",
|
|
message="Found something valuable!",
|
|
duration=3000,
|
|
sound=True
|
|
)
|
|
```
|
|
|
|
#### Clipboard
|
|
```python
|
|
# Copy
|
|
api.copy_to_clipboard("TT: 100 PED")
|
|
|
|
# Paste
|
|
text = api.paste_from_clipboard()
|
|
```
|
|
|
|
#### Event Bus (Pub/Sub)
|
|
```python
|
|
# Subscribe to events
|
|
def on_loot(event):
|
|
print(f"Loot: {event.data}")
|
|
|
|
sub_id = api.subscribe("loot", on_loot)
|
|
|
|
# Publish event
|
|
api.publish("my_plugin.event", {"key": "value"})
|
|
|
|
# Unsubscribe
|
|
api.unsubscribe(sub_id)
|
|
```
|
|
|
|
#### Data Store
|
|
```python
|
|
# Store data
|
|
api.set_data("kill_count", 100)
|
|
|
|
# Retrieve data
|
|
count = api.get_data("kill_count", default=0)
|
|
|
|
# Delete
|
|
api.delete_data("kill_count")
|
|
```
|
|
|
|
#### Task Manager
|
|
```python
|
|
# Run in background
|
|
def heavy_work(data):
|
|
return process(data)
|
|
|
|
def on_done(result):
|
|
print(f"Done: {result}")
|
|
|
|
task_id = api.run_task(
|
|
heavy_work,
|
|
my_data,
|
|
callback=on_done
|
|
)
|
|
|
|
# Cancel task
|
|
api.cancel_task(task_id)
|
|
```
|
|
|
|
---
|
|
|
|
## WidgetAPI
|
|
|
|
The WidgetAPI manages overlay widgets - floating UI components.
|
|
|
|
### Getting Started
|
|
|
|
```python
|
|
from core.api import get_widget_api
|
|
|
|
widget_api = get_widget_api()
|
|
|
|
# Create widget
|
|
widget = widget_api.create_widget(
|
|
name="loot_tracker",
|
|
title="Loot Tracker",
|
|
size=(400, 300),
|
|
position=(100, 100)
|
|
)
|
|
|
|
widget.show()
|
|
```
|
|
|
|
### Widget Configuration
|
|
|
|
```python
|
|
from core.api import WidgetConfig, WidgetType
|
|
|
|
config = WidgetConfig(
|
|
name="my_widget",
|
|
title="My Widget",
|
|
widget_type=WidgetType.MINI,
|
|
size=(300, 200),
|
|
position=(100, 100),
|
|
opacity=0.95,
|
|
always_on_top=True,
|
|
locked=False,
|
|
resizable=True
|
|
)
|
|
```
|
|
|
|
### Widget Operations
|
|
|
|
```python
|
|
# Show/hide
|
|
widget.show()
|
|
widget.hide()
|
|
|
|
# Position
|
|
widget.move(500, 200)
|
|
x, y = widget.position
|
|
|
|
# Size
|
|
widget.resize(400, 300)
|
|
width, height = widget.size
|
|
|
|
# Opacity
|
|
widget.set_opacity(0.8)
|
|
|
|
# Lock/unlock (prevent dragging)
|
|
widget.set_locked(True)
|
|
|
|
# Minimize/restore
|
|
widget.minimize()
|
|
widget.restore()
|
|
|
|
# Close
|
|
widget.close()
|
|
```
|
|
|
|
### Widget Events
|
|
|
|
```python
|
|
# Handle events
|
|
widget.on('moved', lambda data: print(f"Moved to {data['x']}, {data['y']}"))
|
|
widget.on('resized', lambda data: print(f"Sized to {data['width']}x{data['height']}"))
|
|
widget.on('closing', lambda: print("Widget closing"))
|
|
widget.on('closed', lambda: print("Widget closed"))
|
|
widget.on('update', lambda data: print(f"Update: {data}"))
|
|
```
|
|
|
|
### Widget Management
|
|
|
|
```python
|
|
# Get widget
|
|
widget = widget_api.get_widget("loot_tracker")
|
|
|
|
# Show/hide specific widget
|
|
widget_api.show_widget("loot_tracker")
|
|
widget_api.hide_widget("loot_tracker")
|
|
|
|
# Close widget
|
|
widget_api.close_widget("loot_tracker")
|
|
|
|
# All widgets
|
|
widget_api.show_all_widgets()
|
|
widget_api.hide_all_widgets()
|
|
widget_api.close_all_widgets()
|
|
|
|
# Set all opacity
|
|
widget_api.set_all_opacity(0.8)
|
|
|
|
# Lock/unlock all
|
|
widget_api.lock_all()
|
|
widget_api.unlock_all()
|
|
```
|
|
|
|
### Layout Helpers
|
|
|
|
```python
|
|
# Arrange widgets
|
|
widget_api.arrange_widgets(layout="grid", spacing=10)
|
|
widget_api.arrange_widgets(layout="horizontal")
|
|
widget_api.arrange_widgets(layout="vertical")
|
|
widget_api.arrange_widgets(layout="cascade")
|
|
|
|
# Snap to grid
|
|
widget_api.snap_to_grid(grid_size=10)
|
|
```
|
|
|
|
### Widget Presets
|
|
|
|
```python
|
|
from core.api import WidgetConfig, WidgetType
|
|
|
|
# Register preset
|
|
preset = WidgetConfig(
|
|
name="preset",
|
|
title="Loot Tracker",
|
|
widget_type=WidgetType.MINI,
|
|
size=(250, 150),
|
|
opacity=0.9
|
|
)
|
|
|
|
widget_api.register_preset("loot_tracker", preset)
|
|
|
|
# Use preset
|
|
widget = widget_api.create_from_preset("loot_tracker", name="my_tracker")
|
|
```
|
|
|
|
### Persistence
|
|
|
|
```python
|
|
# Save all widget states
|
|
states = widget_api.save_all_states("widgets.json")
|
|
|
|
# Load states
|
|
widget_api.load_all_states("widgets.json")
|
|
```
|
|
|
|
---
|
|
|
|
## ExternalAPI
|
|
|
|
The ExternalAPI provides REST endpoints, webhooks, and third-party integrations.
|
|
|
|
### Getting Started
|
|
|
|
```python
|
|
from core.api import get_external_api
|
|
|
|
ext = get_external_api()
|
|
|
|
# Start server
|
|
ext.start_server(port=8080)
|
|
|
|
# Check status
|
|
print(ext.get_status())
|
|
```
|
|
|
|
### REST API Server
|
|
|
|
```python
|
|
# Start server with CORS
|
|
ext.start_server(
|
|
port=8080,
|
|
host="127.0.0.1",
|
|
cors_origins=["http://localhost:3000"]
|
|
)
|
|
|
|
# Stop server
|
|
ext.stop_server()
|
|
|
|
# Get URL
|
|
url = ext.get_url("api/v1/stats")
|
|
# Returns: http://127.0.0.1:8080/api/v1/stats
|
|
```
|
|
|
|
### API Endpoints
|
|
|
|
Using decorator:
|
|
```python
|
|
@ext.endpoint("stats", methods=["GET"])
|
|
def get_stats():
|
|
return {"kills": 100, "loot": "50 PED"}
|
|
|
|
@ext.endpoint("loot", methods=["POST"])
|
|
def record_loot(data):
|
|
save_loot(data)
|
|
return {"status": "saved"}
|
|
```
|
|
|
|
Programmatic:
|
|
```python
|
|
def get_stats(params):
|
|
return {"kills": 100}
|
|
|
|
ext.register_endpoint("stats", get_stats, methods=["GET"])
|
|
|
|
# Unregister
|
|
ext.unregister_endpoint("stats")
|
|
```
|
|
|
|
### Incoming Webhooks
|
|
|
|
```python
|
|
# Register webhook handler
|
|
def handle_discord(payload):
|
|
print(f"Discord: {payload}")
|
|
return {"status": "ok"}
|
|
|
|
ext.register_webhook(
|
|
name="discord",
|
|
handler=handle_discord,
|
|
secret="my_secret" # Optional HMAC verification
|
|
)
|
|
|
|
# Now POST to: http://localhost:8080/webhook/discord
|
|
```
|
|
|
|
With HMAC verification:
|
|
```python
|
|
import hmac
|
|
import hashlib
|
|
|
|
# Client side (Discord, etc.)
|
|
payload = {"event": "message"}
|
|
payload_str = json.dumps(payload, sort_keys=True)
|
|
signature = hmac.new(
|
|
secret.encode(),
|
|
payload_str.encode(),
|
|
hashlib.sha256
|
|
).hexdigest()
|
|
|
|
# Send with X-Signature header
|
|
headers = {'X-Signature': signature}
|
|
requests.post(url, json=payload, headers=headers)
|
|
```
|
|
|
|
### Outgoing Webhooks
|
|
|
|
```python
|
|
# POST to external webhook
|
|
result = ext.post_webhook(
|
|
"https://discord.com/api/webhooks/...",
|
|
{"content": "Hello from EU-Utility!"}
|
|
)
|
|
|
|
if result['success']:
|
|
print("Sent!")
|
|
else:
|
|
print(f"Error: {result['error']}")
|
|
```
|
|
|
|
### Authentication
|
|
|
|
```python
|
|
# Create API key
|
|
api_key = ext.create_api_key(
|
|
name="My Bot",
|
|
permissions=["read", "write"]
|
|
)
|
|
|
|
# Use in requests
|
|
headers = {'X-API-Key': api_key}
|
|
requests.get(url, headers=headers)
|
|
|
|
# Revoke
|
|
ext.revoke_api_key(api_key)
|
|
```
|
|
|
|
### IPC (Inter-Process Communication)
|
|
|
|
```python
|
|
# Register handler
|
|
def on_browser_message(data):
|
|
print(f"From browser: {data}")
|
|
|
|
ext.register_ipc_handler("browser", on_browser_message)
|
|
|
|
# Send message
|
|
ext.send_ipc("browser", {"action": "refresh"})
|
|
```
|
|
|
|
### File Watcher
|
|
|
|
```python
|
|
# Watch file for changes
|
|
def on_config_change():
|
|
print("Config changed!")
|
|
reload_config()
|
|
|
|
watch_id = ext.watch_file(
|
|
"config.json",
|
|
on_config_change,
|
|
interval=1.0
|
|
)
|
|
```
|
|
|
|
### Webhook History
|
|
|
|
```python
|
|
# Get recent webhook calls
|
|
history = ext.get_webhook_history(limit=10)
|
|
for entry in history:
|
|
print(f"{entry['name']}: {entry['timestamp']}")
|
|
```
|
|
|
|
### Server-Sent Events (SSE)
|
|
|
|
Clients can connect to `/events` for real-time updates:
|
|
|
|
```javascript
|
|
const evtSource = new EventSource("http://localhost:8080/events");
|
|
evtSource.addEventListener("message", (e) => {
|
|
console.log("Event:", JSON.parse(e.data));
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## Error Handling
|
|
|
|
All APIs provide specific exceptions:
|
|
|
|
```python
|
|
from core.api import (
|
|
PluginAPIError,
|
|
ServiceNotAvailableError,
|
|
ExternalAPIError,
|
|
WebhookError
|
|
)
|
|
|
|
try:
|
|
text = api.recognize_text((0, 0, 100, 100))
|
|
except ServiceNotAvailableError:
|
|
print("OCR not available")
|
|
except PluginAPIError as e:
|
|
print(f"API error: {e}")
|
|
```
|
|
|
|
---
|
|
|
|
## API Versions
|
|
|
|
| Version | Features |
|
|
|---------|----------|
|
|
| 2.0 | Initial PluginAPI |
|
|
| 2.1 | Added Activity Bar |
|
|
| 2.2 | Three-tier API (Plugin, Widget, External) |
|
|
|
|
---
|
|
|
|
## Examples
|
|
|
|
### Discord Integration
|
|
|
|
```python
|
|
from core.api import get_api, get_external_api
|
|
|
|
class DiscordPlugin(BasePlugin):
|
|
def initialize(self):
|
|
self.api = get_api()
|
|
self.ext = get_external_api()
|
|
|
|
# Start server
|
|
self.ext.start_server(port=8080)
|
|
|
|
# Register webhook
|
|
self.ext.register_webhook(
|
|
"loot",
|
|
self.handle_loot_webhook
|
|
)
|
|
|
|
# Subscribe to events
|
|
self.api.subscribe("loot", self.on_loot)
|
|
|
|
def on_loot(self, event):
|
|
# Send to Discord
|
|
self.ext.post_webhook(
|
|
self.discord_url,
|
|
{"content": f"Loot: {event.data}"}
|
|
)
|
|
|
|
def handle_loot_webhook(self, payload):
|
|
# Handle incoming Discord webhook
|
|
if payload.get('type') == 'command':
|
|
return self.process_command(payload)
|
|
return {"status": "ignored"}
|
|
```
|
|
|
|
### Custom Widget
|
|
|
|
```python
|
|
from core.api import get_api, get_widget_api
|
|
from PyQt6.QtWidgets import QLabel, QVBoxLayout, QWidget
|
|
|
|
class LootWidgetPlugin(BasePlugin):
|
|
def initialize(self):
|
|
self.api = get_api()
|
|
self.widget_api = get_widget_api()
|
|
|
|
# Create widget
|
|
self.widget = self.widget_api.create_widget(
|
|
name="loot_display",
|
|
title="Recent Loot",
|
|
size=(300, 200)
|
|
)
|
|
|
|
# Set content
|
|
content = QWidget()
|
|
layout = QVBoxLayout(content)
|
|
self.loot_label = QLabel("No loot yet")
|
|
layout.addWidget(self.loot_label)
|
|
|
|
self.widget.set_content(content)
|
|
|
|
# Subscribe to loot events
|
|
self.api.subscribe("loot", self.on_loot)
|
|
|
|
# Show widget
|
|
self.widget.show()
|
|
|
|
def on_loot(self, event):
|
|
self.loot_label.setText(f"Last: {event.data}")
|
|
self.widget.flash()
|
|
```
|
|
|
|
---
|
|
|
|
## See Also
|
|
|
|
- [API Cookbook](API_COOKBOOK.md) - Detailed recipes and patterns
|
|
- [Plugin Development Guide](PLUGIN_DEVELOPMENT.md) - Building plugins
|
|
- [Widget Guide](WIDGET_GUIDE.md) - Creating widgets
|
|
- [External Integration](EXTERNAL_INTEGRATION.md) - Third-party integrations
|
|
|
|
---
|
|
|
|
**Need Help?**
|
|
- Discord: https://discord.gg/clawd
|
|
- Issues: https://git.lemonlink.eu/impulsivefps/EU-Utility/issues
|