Files
Matirx-Manager/main.py
2025-12-08 12:42:02 +00:00

117 lines
4.1 KiB
Python

from fastapi import FastAPI, HTTPException, BackgroundTasks, Request
from pydantic import BaseModel
from bot import MatrixBot
import asyncio
from contextlib import asynccontextmanager
import logging
import sys
# Configure logging to output to stdout
logging.basicConfig(
stream=sys.stdout,
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger("matrix_manager")
bot = MatrixBot()
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup
logger.info("Starting up Matrix Manager Service...")
try:
await bot.login()
logger.info("Bot logged in successfully.")
except Exception as e:
logger.error(f"Failed to login bot: {e}")
yield
# Shutdown
logger.info("Shutting down Matrix Manager Service...")
await bot.close()
app = FastAPI(lifespan=lifespan)
class Notification(BaseModel):
service_name: str
content: str
room_id: str | None = None
level: str = "info"
class JellyfinPayload(BaseModel):
notification_type: str
item_type: str
name: str
series_name: str | None = None
season: int | None = None
episode: int | None = None
year: int | None = None
overview: str | None = None
room_id: str | None = None
@app.post("/notify")
async def send_notification(notification: Notification, background_tasks: BackgroundTasks):
"""
Send a notification to a Matrix room.
"""
logger.info(f"Received notification request from service: {notification.service_name}")
try:
# Format the message to include the service name
# Plain text fallback
plain_message = f"[{notification.service_name}]\n{notification.content}"
# HTML message
html_message = f"<b>[{notification.service_name}]</b><br>{notification.content}"
# We can send it in background to not block the API response
logger.info(f"Queueing message for room_id: {notification.room_id or 'Default'}")
background_tasks.add_task(bot.send_message, plain_message, html_message, notification.room_id)
return {"status": "queued"}
except Exception as e:
logger.error(f"Error in send_notification: {e}")
raise HTTPException(status_code=500, detail=str(e))
@app.post("/jellyfin")
async def receive_jellyfin_webhook(payload: JellyfinPayload, background_tasks: BackgroundTasks):
"""
Receive webhook from Jellyfin and forward to Matrix.
"""
logger.info(f"Received Jellyfin webhook. Type: {payload.notification_type}, Item: {payload.item_type}")
try:
if payload.notification_type != "ItemAdded":
logger.info("Ignored Jellyfin event (not ItemAdded)")
return {"status": "ignored", "reason": "Not an ItemAdded event"}
# content construction
content = ""
if payload.item_type == "Movie":
content = f"New Movie: {payload.name}"
if payload.year:
content += f" ({payload.year})"
if payload.overview:
content += f"\n{payload.overview}"
elif payload.item_type == "Episode":
show = payload.series_name or "Unknown Series"
s = f"S{payload.season:02d}" if payload.season is not None else "S??"
e = f"E{payload.episode:02d}" if payload.episode is not None else "E??"
content = f"New Episode: {show} - {s}{e} - {payload.name}"
else:
# Fallback for Series, Season, etc.
content = f"New {payload.item_type}: {payload.name}"
plain_message = f"[Jellyfin]\n{content}"
html_message = f"<b>[Jellyfin]</b><br>{content.replace(chr(10), '<br>')}"
logger.info(f"Queueing Jellyfin message for room_id: {payload.room_id or 'Default'}")
background_tasks.add_task(bot.send_message, plain_message, html_message, payload.room_id)
return {"status": "queued"}
except Exception as e:
logger.error(f"Error in receive_jellyfin_webhook: {e}")
raise HTTPException(status_code=500, detail=str(e))
@app.get("/health")
async def health_check():
logger.info("Health check requested")
return {"status": "ok"}