Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

feat(plex user auth): Use the built in plex user auth instead of server token #43

Merged
merged 8 commits into from
Jan 20, 2025
12 changes: 2 additions & 10 deletions Compose/frontend/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,6 @@ events {}

http {
include mime.types;
types {
text/html html;
text/css css;
application/javascript js mjs;
image/png png;
image/jpeg jpeg jpg;
application/json json;
}
server {
listen 80;

Expand All @@ -20,7 +12,7 @@ http {

# Reverse proxy for the API
location /api/ {
proxy_pass http://${TUNEBOX_URL}:8000;
proxy_pass http://${TUNEBOX_URL};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
Expand All @@ -29,7 +21,7 @@ http {

# Reverse proxy for WebSocket connections
location /ws {
proxy_pass http://${TUNEBOX_URL}:8000;
proxy_pass http://${TUNEBOX_URL};
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,11 @@ TuneBox is built with the following technologies:
3. Create a .env file in the root directory and configure it with your Plex server details. The .env file
should look like this (where CLIENT_NAME is according to your Plex client):
```bash
PLEX_BASE_URL=your_plex_server_ip # Example: https:/192.0.2.0:32400
PLEX_TOKEN=your_plex_token
PLEX_USERNAME=usernamehere
PLEX_PASSWORD=passwordhere
PLEX_SERVER_NAME=plex-server
CLIENT_NAME=Macbook Pro Personal
REDIS_URL=redis://localhost:6379
REDIS_URL=redis://redis:6379
TUNEBOX_URL=localhost:8000 # or DNS name or IP address of your Tunebox host
4. Create a frontend/.env file and configure it with. Unfortunately Vite requires us to use a separate .env file
inside the frontend directory
Expand Down
5 changes: 3 additions & 2 deletions backend/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
class Settings(BaseSettings):
"""Define the settings we need."""

plex_base_url: str
plex_token: str
plex_username: str
plex_password: str
plex_server_name: str
client_name: str
redis_url: str
tunebox_url: str
Expand Down
21 changes: 21 additions & 0 deletions backend/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""Custom exceptions for the backend application."""


class PlexConnectionError(Exception):
"""Exception raised for Plex connection errors.

Attributes:
original_error (Optional[Exception]): The original exception that caused this error
"""

default_message = "Failed to connect to Plex server"

def __init__(self, original_error: Exception | None = None) -> None:
"""Initialize the PlexConnectionError.

Args:
original_error (Optional[Exception], optional): The original exception that caused this error.
Defaults to None.
"""
self.original_error = original_error
super().__init__(self.default_message)
29 changes: 23 additions & 6 deletions backend/services/plex.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

import asyncio
import logging
from functools import lru_cache

import requests
import urllib3
from fastapi import HTTPException
from plexapi.exceptions import PlexApiException
from plexapi.server import PlexServer
from plexapi.myplex import MyPlexAccount

from backend.config import settings
from backend.exceptions import PlexConnectionError
from backend.services.redis import cache_data, get_cached_data, get_redis_queue, remove_from_redis_queue
from backend.utils import TrackTimeTracker, milliseconds_to_seconds

Expand All @@ -23,15 +25,27 @@
playback_active = False


@lru_cache
def get_plex_connection():
"""Establish a connection to the Plex server.
"""Establish a connection to the Plex server via MyPlexAccount.

Returns:
A PlexServer instance to run our API calls against.
"""
session = requests.Session()
session.verify = False
return PlexServer(settings.plex_base_url, settings.plex_token, session=session)
try:
session = requests.Session()
session.verify = False

# Connect to Plex via MyPlexAccount
account = MyPlexAccount(username=settings.plex_username, password=settings.plex_password)

# Get the specific server by its name
plex_server = account.resource(settings.plex_server_name).connect()
logger.info("Connected to Plex server %s", plex_server)
except Exception as e:
raise PlexConnectionError(original_error=e) from e
else:
return plex_server


def calculate_playback_state(session):
Expand Down Expand Up @@ -401,7 +415,10 @@ def fetch_art(item_id: int, item_type: str):
if not item.thumb:
raise HTTPException(status_code=404, detail=f"No image available for this {item_type}.")

image_url = f"{settings.plex_base_url}{item.thumb}?X-Plex-Token={settings.plex_token}"
# Get the server URL and token from the established connection
server_url = plex.baseurl
token = plex.token
image_url = f"{server_url}{item.thumb}?X-Plex-Token={token}"

# ruff: noqa: S501
response = requests.get(image_url, stream=True, verify=False, timeout=5)
Expand Down
5 changes: 3 additions & 2 deletions backend/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
from plexapi.audio import Track

mock_env = {
"PLEX_BASE_URL": "http://fake-plex:32400",
"PLEX_TOKEN": "fake-token",
"PLEX_USERNAME": "testuser",
"PLEX_PASSWORD": "testpassword",
"PLEX_SERVER_NAME": "plexserver",
"CLIENT_NAME": "test-client",
"REDIS_URL": "redis://fake-redis:6379",
"TUNEBOX_URL": "http://fake-tunebox:8000",
Expand Down
4 changes: 4 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ services:
dockerfile: Compose/frontend/Dockerfile
ports:
- "80:80"
environment:
- TUNEBOX_URL=${TUNEBOX_URL}
volumes:
- ./frontend/.env:/app/.env
depends_on:
- backend

Expand Down
Loading