Files
mystuff_backend/api
Lars Behrends eeff824701 Add Jellyfin mappings and optimize cast queries
Performance and settings updates:

- Add a new jellyfin_library_mappings column to the settings table and wire it into the Settings model (update handling and default value). This enables storing Jellyfin library mappings in settings.
- Optimize Cast::list by loading all cast filmography in a single joined query and grouping results per cast to avoid N+1 queries.
- Remove per-item cast/staff loading in Media model to avoid repeated queries during list/search operations.
- Remove game-specific enrichment from MediaController search to stop extra game info lookups during search responses.

These changes reduce repeated DB calls and centralize Jellyfin mapping storage.
2026-04-12 02:07:59 +02:00
..

PHP Media API

Eine schnelle und zuverlässige PHP-API für die Verwaltung von Medieninhalten mit vollständigen CRUD-Operationen.

Architektur

Die API ist in MVC-ähnliche Struktur aufgeteilt für bessere Wartbarkeit und Erweiterbarkeit:

  • index.php (35 Zeilen) - Entry Point und Request-Handling
  • Router.php - Routing-Logik
  • controllers/ - Controller für HTTP-Requests
    • MediaController.php
    • CastController.php
  • models/ - Datenbank-Modelle
    • BaseModel.php - Abstrakte Basisklasse mit CRUD-Methoden
    • Media.php - Media Model mit Relationen
    • Cast.php - Cast Model mit Filmographie
    • AdultCast.php - Erweitertes Cast Model für Adult-Actors
    • MediaType.php - Abstrakte Basisklasse für Medientypen
    • Movie.php - Movie-spezifische Logik
    • Series.php - Series-spezifische Logik
    • Music.php - Music-spezifische Logik
    • Game.php - Game-spezifische Logik
    • Console.php - Console-spezifische Logik
    • Adult.php - Adult-spezifische Logik
  • database.php - Datenbankverbindung und Tabellen-Erstellung
  • config.php - Konfiguration
  • services/ - Services für Hilfsfunktionen
    • DocumentationService.php - Automatische API-Dokumentation

Installation

  1. Stelle sicher, dass PHP und SQLite installiert sind
  2. Die Datenbank wird automatisch beim ersten Aufruf erstellt
  3. Konfiguriere deinen Webserver (Apache/nginx) so, dass er auf den api-Ordner zeigt

Automatische API-Dokumentation

Die API verfügt über eine automatische Dokumentation, die sich dynamisch aus den Controllern und Modellen generiert:

  • GET /api/docs - Vollständige API-Dokumentation als JSON

Die Dokumentation scannt alle Controller und Modelle und extrahiert:

  • Alle verfügbaren Endpunkte
  • HTTP-Methoden
  • Parameter und deren Typen
  • Rückgabewerte
  • Beschreibungen aus PHPDoc-Kommentaren

Erweiterung der Dokumentation: Füge einfach PHPDoc-Kommentare zu deinen Controller-Methoden hinzu:

/**
 * Create a new media item
 * @param array $data Media data
 * @return array Created media ID
 */
private function create() {
    // ...
}

Die Dokumentation wird automatisch beim nächsten Aufruf aktualisiert.

Endpunkte

Media-Endpunkte

  • GET /api/media - Alle Medien abrufen (mit Filterung und Pagination)
  • GET /api/media/:id - Ein spezifisches Medium abrufen
  • POST /api/media - Neues Medium erstellen
  • PUT /api/media/:id - Medium aktualisieren
  • DELETE /api/media/:id - Medium löschen

Episoden-Endpunkte (für Series)

  • GET /api/media/:id/episodes - Alle Episoden einer Serie abrufen
  • GET /api/media/:id/episodes?season=1 - Episoden einer bestimmten Staffel abrufen
  • GET /api/media/:id/episodes/:episodeId - Einzelne Episode abrufen
  • POST /api/media/:id/episodes - Neue Episode zur Serie hinzufügen
  • PUT /api/media/:id/episodes/:episodeId - Episode aktualisieren
  • DELETE /api/media/:id/episodes/:episodeId - Episode löschen

Tracks-Endpunkte (für Music/Alben)

  • GET /api/media/:id/tracks - Alle Tracks eines Albums abrufen
  • GET /api/media/:id/tracks/:trackId - Einzelnen Track abrufen
  • POST /api/media/:id/tracks - Neuen Track zum Album hinzufügen
  • PUT /api/media/:id/tracks/:trackId - Track aktualisieren
  • DELETE /api/media/:id/tracks/:trackId - Track löschen

Cast/Staff-Endpunkte

  • GET /api/cast - Alle Cast-Mitglieder abrufen
  • GET /api/cast/:id - Ein spezifisches Cast-Mitglied abrufen (mit Filmographie)
  • GET /api/cast/:id/media - Alle Medien eines Cast-Mitglieds abrufen
  • POST /api/cast - Neues Cast-Mitglied erstellen (Stammdaten)
  • PUT /api/cast/:id - Cast-Mitglied aktualisieren
  • DELETE /api/cast/:id - Cast-Mitglied löschen

Adult-Actor Endpunkte (erweiterte Cast-Infos)

  • GET /api/cast/adult - Alle Adult-Actors mit spezifischen Infos abrufen
  • GET /api/cast/adult?ethnicity=Caucasian&hair_color=Blonde - Adult-Actors filtern
  • GET /api/cast/:id/adult - Adult-Actor mit spezifischen Infos abrufen
  • POST /api/cast/adult - Neuen Adult-Actor mit spezifischen Infos erstellen
  • PUT /api/cast/:id/adult - Adult-Actor und spezifische Infos aktualisieren
  • DELETE /api/cast/:id/adult - Spezifische Adult-Infos löschen

Query-Parameter

Media-Filter

  • category - Filter nach Kategorie (Movies, Anime, Music, etc.)
  • type - Filter nach Typ (Movie, TV, Album, etc.)
  • search - Suche in Titel und Beschreibung
  • page - Seitenzahl (Standard: 1)
  • limit - Ergebnisse pro Seite (Standard: 20)

Cast-Filter

  • search - Suche nach Name
  • page - Seitenzahl
  • limit - Ergebnisse pro Seite

Beispiele

Neues Medium erstellen

curl -X POST http://localhost/api/media \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Inception",
    "year": "2010",
    "category": "Movies",
    "type": "Movie",
    "description": "Ein Dieb...",
    "rating": 8.8,
    "genres": ["Sci-Fi", "Action"],
    "director": "Christopher Nolan",
    "staff": [
      {
        "id": 1,
        "role": "Actor",
        "characterName": "Cobb"
      },
      {
        "name": "Marion Cotillard",
        "role": "Actor",
        "characterName": "Mal",
        "photo": "https://example.com/photo.jpg"
      }
    ]
  }'

Neues Cast-Mitglied erstellen

curl -X POST http://localhost/api/cast \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Leonardo DiCaprio",
    "photo": "https://example.com/photo.jpg",
    "bio": "Amerikanischer Schauspieler",
    "birthDate": "1974-11-11",
    "birthPlace": "Los Angeles",
    "occupations": ["Actor", "Producer"]
  }'

Alle Medien eines Cast-Mitglieds abrufen

curl http://localhost/api/cast/1/media

Serie mit Episoden erstellen

curl -X POST http://localhost/api/media \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Breaking Bad",
    "year": "2008",
    "category": "Movies",
    "type": "TV",
    "description": "Ein Chemielehrer...",
    "genres": ["Drama", "Crime"],
    "episodes": [
      {
        "season": 1,
        "episode_number": 1,
        "title": "Pilot",
        "description": "Erste Episode",
        "air_date": "2008-01-20",
        "duration": 58
      },
      {
        "season": 1,
        "episode_number": 2,
        "title": "Cat's in the Bag...",
        "duration": 48
      }
    ]
  }'

Episode zu einer Serie hinzufügen

curl -X POST http://localhost/api/media/1/episodes \
  -H "Content-Type: application/json" \
  -d '{
    "season": 2,
    "episode_number": 1,
    "title": "Seven Thirty-Seven",
    "duration": 47
  }'

Episoden einer Staffel abrufen

curl "http://localhost/api/media/1/episodes?season=1"

Album mit Tracklist erstellen

curl -X POST http://localhost/api/media \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Dark Side of the Moon",
    "year": "1973",
    "category": "Music",
    "type": "Album",
    "artist": "Pink Floyd",
    "genres": ["Progressive Rock"],
    "tracks": [
      {
        "track_number": 1,
        "title": "Speak to Me",
        "duration": 90
      },
      {
        "track_number": 2,
        "title": "Breathe",
        "duration": 274
      }
    ]
  }'

Track zu einem Album hinzufügen

curl -X POST http://localhost/api/media/2/tracks \
  -H "Content-Type: application/json" \
  -d '{
    "track_number": 3,
    "title": "On the Run",
    "duration": 225
  }'

Adult-Actor mit spezifischen Infos erstellen

curl -X POST http://localhost/api/cast/adult \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Jane Doe",
    "photo": "https://example.com/photo.jpg",
    "bio": "Adult actress",
    "birthDate": "1995-05-15",
    "birthPlace": "Los Angeles",
    "occupations": ["Adult Actress", "Model"],
    "adult_specifics": {
      "bust_size": "34",
      "cup_size": "D",
      "waist_size": "24",
      "hip_size": "34",
      "height": 170,
      "weight": 55,
      "hair_color": "Blonde",
      "eye_color": "Blue",
      "ethnicity": "Caucasian",
      "tattoos": "None",
      "piercings": "Ears",
      "measurements": "34D-24-34",
      "shoe_size": "38"
    }
  }'

Adult-Actors nach Ethnie filtern

curl "http://localhost/api/cast/adult?ethnicity=Caucasian&hair_color=Blonde"

Medien abrufen mit Filter

curl "http://localhost/api/media?category=Movies&search=inception"

Medium aktualisieren

curl -X PUT http://localhost/api/media/1 \
  -H "Content-Type: application/json" \
  -d '{"rating": 9.0}'

Medium löschen

curl -X DELETE http://localhost/api/media/1

Datenstruktur

Media-Objekt

{
  "id": 1,
  "title": "Titel",
  "year": "2024",
  "poster": "URL",
  "banner": "URL",
  "description": "Beschreibung",
  "rating": 8.5,
  "category": "Movies",
  "type": "Movie",
  "genres": ["Action", "Drama"],
  "tags": ["tag1", "tag2"],
  "studios": ["Studio1"],
  "runtime": 120,
  "director": "Regisseur",
  "createdAt": "2024-01-01T00:00:00Z",
  "updatedAt": "2024-01-01T00:00:00Z"
}

Cast-Objekt (Stammdaten)

{
  "id": 1,
  "name": "Name",
  "photo": "URL",
  "bio": "Biografie",
  "birthDate": "1990-01-01",
  "birthPlace": "Ort",
  "occupations": ["Actor", "Producer"],
  "filmography": [
    {
      "id": 1,
      "title": "Film Titel",
      "year": "2020",
      "role": "Actor",
      "characterName": "Charakter"
    }
  ]
}

Cast-Zuordnung in Media

{
  "staff": [
    {
      "id": 1,
      "role": "Actor",
      "characterName": "Cobb",
      "characterImage": "URL"
    },
    {
      "name": "Neuer Schauspieler",
      "role": "Actor",
      "characterName": "Charakter"
    }
  ]
}

Episode-Objekt

{
  "id": 1,
  "media_id": 1,
  "season": 1,
  "episode_number": 1,
  "title": "Pilot",
  "description": "Beschreibung der Episode",
  "air_date": "2008-01-20",
  "duration": 58,
  "thumbnail": "URL"
}

Track-Objekt

{
  "id": 1,
  "media_id": 2,
  "track_number": 1,
  "title": "Speak to Me",
  "duration": 90,
  "artist": "Pink Floyd"
}

Adult-Specifics Objekt

{
  "id": 1,
  "cast_id": 1,
  "bust_size": "34",
  "cup_size": "D",
  "waist_size": "24",
  "hip_size": "34",
  "height": 170,
  "weight": 55,
  "hair_color": "Blonde",
  "eye_color": "Blue",
  "ethnicity": "Caucasian",
  "tattoos": "None",
  "piercings": "Ears",
  "measurements": "34D-24-34",
  "shoe_size": "38"
}

Features

  • Vollständige CRUD-Operationen
  • SQLite-Datenbank (keine zusätzliche Konfiguration nötig)
  • JSON-basierte API
  • CORS-Unterstützung
  • Filterung und Suche
  • Pagination
  • Automatische Datenbank-Erstellung
  • Relationale Daten (Genres, Tags, Studios, Cast)
  • n:m Beziehung zwischen Cast und Media (Cast-Mitglied nur einmal anlegen, mehreren Medien zuordnen)
  • Automatische Cast-Erkennung anhand Name beim Media-Upload
  • Filmographie für jedes Cast-Mitglied
  • Modularer Aufbau mit MVC-ähnlicher Struktur
  • Typ-spezifische Modelle (Movie, Series, Music, Game, Console, Adult)
  • Erweiterbare Architektur für neue Medientypen
  • Episoden und Staffeln für Serien
  • Tracklisten für Musikalben
  • Typ-spezifische Endpunkte für Episoden und Tracks
  • Adult-Actors mit erweiterten Informationen (Maße, Aussehen, etc.)
  • Filterung von Adult-Actors nach Ethnie, Haarfarbe, etc.
  • Automatische API-Dokumentation via GET /api/docs
  • Dynamische Dokumentation aus PHPDoc-Kommentaren

Erweiterung für neue Medientypen

Um einen neuen Medientyp hinzuzufügen:

  1. Neue Klasse in models/ erstellen, die von MediaType erbt:
<?php
require_once __DIR__ . '/MediaType.php';

class Book extends MediaType {
    protected function getType() {
        return 'Book';
    }
    
    protected function getTypeSpecificFields() {
        return ['author', 'isbn', 'pages'];
    }
    
    protected function validateTypeSpecificFields($data) {
        // Typ-spezifische Validierung
    }
}
  1. Controller im Router registrieren (optional)
  2. Datenbank-Tabelle in database.php hinzufügen falls nötig