init: initial commit

This commit is contained in:
Strix 2025-04-09 23:59:52 +02:00
commit d4496a2eda
8 changed files with 120 additions and 0 deletions

2
.dockerignore Normal file
View file

@ -0,0 +1,2 @@
.env
__pycache__/

7
.env.example Normal file
View file

@ -0,0 +1,7 @@
EXPORTER_PORT=8000
SCRAPE_INTERVAL=30
# twitch
TWITCH_CLIENT_ID=
TWITCH_CLIENT_SECRET=
TWITCH_CHANNELS=ikiznear

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
__pycache__/
.env

9
Dockerfile Normal file
View file

@ -0,0 +1,9 @@
FROM python:3.11-slim
WORKDIR /app
COPY . /app
RUN pip install -r requirements.txt
EXPOSE 8000
CMD ["python", "main.py"]

37
main.py Normal file
View file

@ -0,0 +1,37 @@
import os
import importlib.util
import time
from prometheus_client import start_http_server
from dotenv import load_dotenv
load_dotenv()
def load_stat_modules(path='stats'):
modules = []
for filename in os.listdir(path):
if filename.endswith(".py") and filename != "__init__.py":
module_name = filename[:-3]
filepath = os.path.join(path, filename)
spec = importlib.util.spec_from_file_location(module_name, filepath)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
if hasattr(module, 'update'):
modules.append(module)
return modules
if __name__ == '__main__':
port = int(os.getenv("EXPORTER_PORT", "8000"))
print(f"Starting exporter on port {port}...")
start_http_server(port)
modules = load_stat_modules()
while True:
for mod in modules:
try:
mod.update()
except Exception as e:
print(f"Error in {mod.__name__}: {e}")
time.sleep(int(os.getenv("SCRAPE_INTERVAL", "30")))

3
requirements.txt Normal file
View file

@ -0,0 +1,3 @@
prometheus_client
requests
python-dotenv

0
stats/__init__.py Normal file
View file

60
stats/twitch_stats.py Normal file
View file

@ -0,0 +1,60 @@
from prometheus_client import Gauge
import requests
import os
import time
# Load env vars
TWITCH_CLIENT_ID = os.getenv("TWITCH_CLIENT_ID")
TWITCH_CLIENT_SECRET = os.getenv("TWITCH_CLIENT_SECRET")
CHANNELS = os.getenv("TWITCH_CHANNELS", "").split(",")
# Metric definition
live_status = Gauge('twitch_stream_live', 'Is the stream live?', ['channel'])
_token_cache = {
"access_token": None,
"expires_at": 0
}
print("[twitch] Client ID:", TWITCH_CLIENT_ID)
print("[twitch] Client Secret:", TWITCH_CLIENT_SECRET)
print("[twitch] Channels:", CHANNELS)
def get_token():
if time.time() < _token_cache["expires_at"] - 60:
return _token_cache["access_token"]
response = requests.post("https://id.twitch.tv/oauth2/token", data={
"client_id": TWITCH_CLIENT_ID,
"client_secret": TWITCH_CLIENT_SECRET,
"grant_type": "client_credentials"
})
# Print the response for debugging
print(f"[twitch] Response: {response.json()}")
data = response.json()
# Check for errors in the response
if "access_token" not in data:
raise ValueError(f"Error getting token: {data}")
_token_cache["access_token"] = data["access_token"]
_token_cache["expires_at"] = time.time() + data["expires_in"]
return _token_cache["access_token"]
headers = {
'Client-ID': TWITCH_CLIENT_ID,
'Authorization': f'Bearer {get_token()}'
}
def update():
for channel in CHANNELS:
url = f'https://api.twitch.tv/helix/streams?user_login={channel}'
try:
response = requests.get(url, headers=headers)
data = response.json()
is_live = int(bool(data.get('data')))
live_status.labels(channel=channel).set(is_live)
except Exception as e:
print(f"[twitch] Error checking {channel}: {e}")