Files
mystuff_backend/API_DOCS.md
Lars Behrends 728ca893b1 Add API documentation and project README
Add comprehensive API_DOCS.md describing the Kyoo backend API (endpoints, request/response examples, image handling, authentication, error handling, CORS, logging) and a README.md with project overview, tech stack, quick start, API endpoints, data models, configuration and Docker instructions. Provides developers with usage examples, directory layout and troubleshooting steps for local deployment.
2026-04-12 03:00:17 +02:00

20 KiB

Kyoo Backend API Documentation

Base URL: http://localhost:6400/api

Content-Type: application/json


Table of Contents


Response Format

Success Response

{
  "success": true,
  "data": { ... }
}

Error Response

{
  "success": false,
  "error": "Error message"
}

Paginated Response

{
  "success": true,
  "data": {
    "items": [ ... ],
    "total": 100,
    "page": 1,
    "limit": 20,
    "totalPages": 5
  }
}

HTTP Status Codes

  • 200 - Success
  • 201 - Created
  • 400 - Bad Request
  • 404 - Not Found
  • 405 - Method Not Allowed
  • 500 - Internal Server Error

Authentication

Currently, the API does not require authentication. All endpoints are publicly accessible.


Endpoints

Root

Get API Information

Endpoint: GET /api

Description: Returns API version and available endpoints.

Response:

{
  "success": true,
  "message": "Media API v1.0",
  "endpoints": {
    "GET /api/docs": "Automatische API-Dokumentation",
    "GET /api/images/*": "Bilder abrufen",
    "GET /api/media": "Alle Medien abrufen",
    "GET /api/media/:id": "Ein Medium abrufen",
    "POST /api/media": "Neues Medium erstellen",
    "PUT /api/media/:id": "Medium aktualisieren",
    "DELETE /api/media/:id": "Medium löschen",
    "GET /api/cast": "Alle Cast-Mitglieder abrufen",
    "GET /api/cast/:id": "Cast-Mitglied abrufen",
    "GET /api/cast/:id/media": "Alle Medien eines Cast-Mitglieds abrufen",
    "POST /api/cast": "Neues Cast-Mitglied erstellen",
    "PUT /api/cast/:id": "Cast-Mitglied aktualisieren",
    "DELETE /api/cast/:id": "Cast-Mitglied löschen",
    "GET /api/settings": "Einstellungen abrufen",
    "PUT /api/settings": "Einstellungen aktualisieren"
  }
}

Documentation

Get Auto-Generated Documentation

Endpoint: GET /api/docs

Description: Returns automatically generated API documentation.

Response:

{
  "success": true,
  "data": { ... }
}

Media

Get All Media

Endpoint: GET /api/media

Query Parameters:

  • page (integer, optional) - Page number (default: 1)
  • limit (integer, optional) - Items per page (default: 20)
  • category (string, optional) - Filter by category (e.g., "movie", "tv", "music", "game")
  • type (string, optional) - Filter by type (e.g., "Movie", "TV", "Album", "Game")
  • search (string, optional) - Search in title and description

Example Request:

GET /api/media?page=1&limit=20&category=movie&search=action

Response:

{
  "success": true,
  "data": {
    "items": [
      {
        "id": 1,
        "title": "Movie Title",
        "cleanname": "movie-title",
        "year": 2024,
        "poster": "/images/movies/poster_xxx.webp",
        "banner": "/images/movies/banner_xxx.webp",
        "description": "Description text",
        "rating": 8.5,
        "category": "movie",
        "type": "Movie",
        "status": "released",
        "aspectRatio": "16:9",
        "runtime": 120,
        "director": "Director Name",
        "writer": "Writer Name",
        "source": "netflix",
        "releaseDate": "2024-01-01",
        "createdAt": "2024-01-01 00:00:00",
        "updatedAt": "2024-01-01 00:00:00"
      }
    ],
    "total": 100,
    "page": 1,
    "limit": 20,
    "totalPages": 5
  }
}

Get Single Media

Endpoint: GET /api/media/:id

Path Parameters:

  • id (integer, required) - Media ID

Example Request:

GET /api/media/1

Response:

{
  "success": true,
  "data": {
    "id": 1,
    "title": "Movie Title",
    "cleanname": "movie-title",
    "year": 2024,
    "poster": "/images/movies/poster_xxx.webp",
    "banner": "/images/movies/banner_xxx.webp",
    "description": "Description text",
    "rating": 8.5,
    "category": "movie",
    "type": "Movie",
    "status": "released",
    "aspectRatio": "16:9",
    "runtime": 120,
    "director": "Director Name",
    "writer": "Writer Name",
    "source": "netflix",
    "releaseDate": "2024-01-01",
    "genres": ["Action", "Drama"],
    "tags": ["tag1", "tag2"],
    "studios": ["Studio1"],
    "staff": [
      {
        "id": 1,
        "name": "Actor Name",
        "photo": "/images/cast/photo_xxx.webp",
        "role": "Actor",
        "characterName": "Character",
        "characterImage": "/images/characters/char_xxx.webp"
      }
    ],
    "createdAt": "2024-01-01 00:00:00",
    "updatedAt": "2024-01-01 00:00:00"
  }
}

Create Media

Endpoint: POST /api/media

Request Body:

{
  "title": "Movie Title",
  "year": 2024,
  "poster": "base64_encoded_image_or_url",
  "banner": "base64_encoded_image_or_url",
  "description": "Description text",
  "rating": 8.5,
  "category": "movie",
  "type": "Movie",
  "status": "released",
  "aspectRatio": "16:9",
  "runtime": 120,
  "director": "Director Name",
  "writer": "Writer Name",
  "source": "netflix",
  "releaseDate": "2024-01-01",
  "genres": ["Action", "Drama"],
  "tags": ["tag1", "tag2"],
  "studios": ["Studio1"],
  "staff": [
    {
      "id": 1,
      "role": "Actor",
      "characterName": "Character",
      "characterImage": "base64_encoded_image_or_url"
    }
  ]
}

Note: If staff includes a cast member by name instead of id, the cast member will be automatically created if it doesn't exist.

Response (201 Created):

{
  "success": true,
  "data": {
    "id": 1
  }
}

Response (200 OK - if media already exists):

{
  "success": true,
  "data": {
    "id": 1,
    "message": "Media already exists"
  }
}

Update Media

Endpoint: PUT /api/media/:id

Path Parameters:

  • id (integer, required) - Media ID

Request Body: Same as create, but all fields are optional.

Response:

{
  "success": true,
  "data": {
    "id": 1
  }
}

Delete Media

Endpoint: DELETE /api/media/:id

Path Parameters:

  • id (integer, required) - Media ID

Response:

{
  "success": true,
  "message": "Media deleted successfully"
}

Series Episodes

Get All Episodes

Endpoint: GET /api/media/:id/episodes

Path Parameters:

  • id (integer, required) - Series media ID

Query Parameters:

  • season (integer, optional) - Filter by season number

Example Request:

GET /api/media/1/episodes?season=1

Response:

{
  "success": true,
  "data": {
    "items": [
      {
        "id": 1,
        "media_id": 1,
        "season": 1,
        "episode": 1,
        "title": "Episode Title",
        "overview": "Episode description",
        "airDate": "2024-01-01",
        "runtime": 45,
        "poster": "/images/episodes/poster_xxx.webp"
      }
    ]
  }
}

Get Single Episode

Endpoint: GET /api/media/:id/episodes/:episodeId

Path Parameters:

  • id (integer, required) - Series media ID
  • episodeId (integer, required) - Episode ID

Response:

{
  "success": true,
  "data": {
    "id": 1,
    "media_id": 1,
    "season": 1,
    "episode": 1,
    "title": "Episode Title",
    "overview": "Episode description",
    "airDate": "2024-01-01",
    "runtime": 45,
    "poster": "/images/episodes/poster_xxx.webp"
  }
}

Add Episode

Endpoint: POST /api/media/:id/episodes

Path Parameters:

  • id (integer, required) - Series media ID

Request Body:

{
  "season": 1,
  "episode": 1,
  "title": "Episode Title",
  "overview": "Episode description",
  "airDate": "2024-01-01",
  "runtime": 45,
  "poster": "base64_encoded_image_or_url"
}

Response (201 Created):

{
  "success": true,
  "data": {
    "id": 1
  }
}

Update Episode

Endpoint: PUT /api/media/:id/episodes/:episodeId

Path Parameters:

  • id (integer, required) - Series media ID
  • episodeId (integer, required) - Episode ID

Request Body: Same as add episode, but all fields are optional.

Response:

{
  "success": true,
  "data": {
    "id": 1
  }
}

Delete Episode

Endpoint: DELETE /api/media/:id/episodes/:episodeId

Path Parameters:

  • id (integer, required) - Series media ID
  • episodeId (integer, required) - Episode ID

Response:

{
  "success": true,
  "message": "Episode deleted successfully"
}

Music Tracks

Get All Tracks

Endpoint: GET /api/media/:id/tracks

Path Parameters:

  • id (integer, required) - Album media ID

Response:

{
  "success": true,
  "data": {
    "items": [
      {
        "id": 1,
        "media_id": 1,
        "track": 1,
        "title": "Track Title",
        "duration": 240,
        "artists": ["Artist1", "Artist2"]
      }
    ]
  }
}

Get Single Track

Endpoint: GET /api/media/:id/tracks/:trackId

Path Parameters:

  • id (integer, required) - Album media ID
  • trackId (integer, required) - Track ID

Response:

{
  "success": true,
  "data": {
    "id": 1,
    "media_id": 1,
    "track": 1,
    "title": "Track Title",
    "duration": 240,
    "artists": ["Artist1", "Artist2"]
  }
}

Add Track

Endpoint: POST /api/media/:id/tracks

Path Parameters:

  • id (integer, required) - Album media ID

Request Body:

{
  "track": 1,
  "title": "Track Title",
  "duration": 240,
  "artists": ["Artist1", "Artist2"]
}

Response (201 Created):

{
  "success": true,
  "data": {
    "id": 1
  }
}

Update Track

Endpoint: PUT /api/media/:id/tracks/:trackId

Path Parameters:

  • id (integer, required) - Album media ID
  • trackId (integer, required) - Track ID

Request Body: Same as add track, but all fields are optional.

Response:

{
  "success": true,
  "data": {
    "id": 1
  }
}

Delete Track

Endpoint: DELETE /api/media/:id/tracks/:trackId

Path Parameters:

  • id (integer, required) - Album media ID
  • trackId (integer, required) - Track ID

Response:

{
  "success": true,
  "message": "Track deleted successfully"
}

Cast

Get All Cast

Endpoint: GET /api/cast

Query Parameters:

  • page (integer, optional) - Page number (default: 1)
  • limit (integer, optional) - Items per page (default: 20)
  • search (string, optional) - Search by name

Example Request:

GET /api/cast?page=1&limit=20&search=john

Response:

{
  "success": true,
  "data": {
    "items": [
      {
        "id": 1,
        "name": "Actor Name",
        "cleanname": "actor-name",
        "photo": "/images/cast/photo_xxx.webp",
        "bio": "Biography text",
        "birthDate": "1990-01-01",
        "birthPlace": "City, Country",
        "occupations": ["Actor", "Director"],
        "filmography": [
          {
            "id": 1,
            "title": "Movie Title",
            "year": 2024,
            "poster": "/images/movies/poster_xxx.webp",
            "category": "movie",
            "type": "Movie",
            "role": "Actor",
            "characterName": "Character"
          }
        ],
        "media_types": ["movie", "tv"],
        "createdAt": "2024-01-01 00:00:00",
        "updatedAt": "2024-01-01 00:00:00"
      }
    ],
    "total": 100,
    "page": 1,
    "limit": 20
  }
}

Get Single Cast

Endpoint: GET /api/cast/:id

Path Parameters:

  • id (integer, required) - Cast ID

Response:

{
  "success": true,
  "data": {
    "id": 1,
    "name": "Actor Name",
    "cleanname": "actor-name",
    "photo": "/images/cast/photo_xxx.webp",
    "bio": "Biography text",
    "birthDate": "1990-01-01",
    "birthPlace": "City, Country",
    "occupations": ["Actor", "Director"],
    "filmography": [
      {
        "id": 1,
        "title": "Movie Title",
        "year": 2024,
        "poster": "/images/movies/poster_xxx.webp",
        "category": "movie",
        "type": "Movie",
        "role": "Actor",
        "characterName": "Character"
      }
    ],
    "adult_specifics": {
      "id": 1,
      "cast_id": 1,
      "ethnicity": "Asian",
      "hair_color": "Black",
      "eye_color": "Brown",
      "height": 170,
      "weight": 60
    },
    "createdAt": "2024-01-01 00:00:00",
    "updatedAt": "2024-01-01 00:00:00"
  }
}

Get Cast Media

Endpoint: GET /api/cast/:id/media

Path Parameters:

  • id (integer, required) - Cast ID

Response:

{
  "success": true,
  "data": {
    "items": [
      {
        "id": 1,
        "title": "Movie Title",
        "year": 2024,
        "poster": "/images/movies/poster_xxx.webp",
        "category": "movie",
        "type": "Movie",
        "role": "Actor",
        "characterName": "Character"
      }
    ]
  }
}

Create Cast

Endpoint: POST /api/cast

Request Body:

{
  "name": "Actor Name",
  "photo": "base64_encoded_image_or_url",
  "bio": "Biography text",
  "birthDate": "1990-01-01",
  "birthPlace": "City, Country",
  "occupations": ["Actor", "Director"]
}

Response (201 Created):

{
  "success": true,
  "data": {
    "id": 1
  }
}

Response (200 OK - if cast already exists):

{
  "success": true,
  "data": {
    "id": 1,
    "message": "Cast already exists"
  }
}

Update Cast

Endpoint: PUT /api/cast/:id

Path Parameters:

  • id (integer, required) - Cast ID

Request Body: Same as create, but all fields are optional.

Response:

{
  "success": true,
  "data": {
    "id": 1
  }
}

Delete Cast

Endpoint: DELETE /api/cast/:id

Path Parameters:

  • id (integer, required) - Cast ID

Response:

{
  "success": true,
  "message": "Cast member deleted successfully"
}

Adult Cast

Get All Adult Cast

Endpoint: GET /api/cast/adult

Query Parameters:

  • page (integer, optional) - Page number (default: 1)
  • limit (integer, optional) - Items per page (default: 20)
  • search (string, optional) - Search by name
  • ethnicity (string, optional) - Filter by ethnicity
  • hair_color (string, optional) - Filter by hair color

Example Request:

GET /api/cast/adult?page=1&limit=20&ethnicity=Asian

Response:

{
  "success": true,
  "data": {
    "items": [
      {
        "id": 1,
        "name": "Actor Name",
        "cleanname": "actor-name",
        "photo": "/images/cast/photo_xxx.webp",
        "bio": "Biography text",
        "birthDate": "1990-01-01",
        "birthPlace": "City, Country",
        "ethnicity": "Asian",
        "hair_color": "Black",
        "eye_color": "Brown",
        "height": 170,
        "weight": 60,
        "createdAt": "2024-01-01 00:00:00",
        "updatedAt": "2024-01-01 00:00:00"
      }
    ],
    "total": 100,
    "page": 1,
    "limit": 20
  }
}

Get Single Adult Cast

Endpoint: GET /api/cast/adult/:id

Path Parameters:

  • id (integer, required) - Cast ID

Response:

{
  "success": true,
  "data": {
    "id": 1,
    "name": "Actor Name",
    "cleanname": "actor-name",
    "photo": "/images/cast/photo_xxx.webp",
    "bio": "Biography text",
    "birthDate": "1990-01-01",
    "birthPlace": "City, Country",
    "ethnicity": "Asian",
    "hair_color": "Black",
    "eye_color": "Brown",
    "height": 170,
    "weight": 60,
    "createdAt": "2024-01-01 00:00:00",
    "updatedAt": "2024-01-01 00:00:00"
  }
}

Create Adult Cast

Endpoint: POST /api/cast/adult

Request Body:

{
  "name": "Actor Name",
  "photo": "base64_encoded_image_or_url",
  "bio": "Biography text",
  "birthDate": "1990-01-01",
  "birthPlace": "City, Country",
  "ethnicity": "Asian",
  "hair_color": "Black",
  "eye_color": "Brown",
  "height": 170,
  "weight": 60
}

Response (201 Created):

{
  "success": true,
  "data": {
    "id": 1
  }
}

Update Adult Cast

Endpoint: PUT /api/cast/adult/:id

Path Parameters:

  • id (integer, required) - Cast ID

Request Body: Same as create, but all fields are optional.

Response:

{
  "success": true,
  "data": {
    "id": 1
  }
}

Delete Adult Cast Specifics

Endpoint: DELETE /api/cast/adult/:id

Path Parameters:

  • id (integer, required) - Cast ID

Note: This only deletes the adult-specific attributes, not the cast member itself.

Response:

{
  "success": true,
  "message": "Adult specifics deleted successfully"
}

Images

Serve Image

Endpoint: GET /api/images/*

Description: Serves images directly from the storage. Images are organized by type (movies, games, cast, etc.).

Example Requests:

GET /api/images/movies/poster_xxx.webp
GET /api/images/cast/photo_xxx.webp
GET /api/images/episodes/poster_xxx.webp

Response: Binary image data (WebP format)


Settings

Get Settings

Endpoint: GET /api/settings

Description: Retrieves application settings.

Response:

{
  "success": true,
  "data": {
    "id": 1,
    "key": "value",
    "updatedAt": "2024-01-01 00:00:00"
  }
}

Update Settings

Endpoint: PUT /api/settings

Request Body:

{
  "key": "value"
}

Response:

{
  "success": true,
  "data": {
    "id": 1,
    "key": "value",
    "updatedAt": "2024-01-01 00:00:00"
  }
}

Image Handling

Image Formats

Images can be provided in two ways:

  1. Base64-encoded string: The API will automatically decode and save the image
  2. URL: The API will store the URL as-is

Image Storage

Images are stored in the following structure:

/images/
├── movies/
│   ├── poster_*.webp
│   └── banner_*.webp
├── games/
│   ├── poster_*.webp
│   └── banner_*.webp
├── cast/
│   └── photo_*.webp
├── characters/
│   └── char_*.webp
└── episodes/
    └── poster_*.webp

Image Processing

  • All images are automatically converted to WebP format
  • Old images are deleted when updating
  • Images are served directly via the /api/images/* endpoint

Search & Filtering

Clean Names

The API uses "clean names" for deduplication. A clean name is generated from the title/name by:

  • Converting to lowercase
  • Replacing special characters with hyphens
  • Removing leading/trailing hyphens
  • Replacing multiple consecutive hyphens with a single hyphen

Example: "The Dark Knight" → "the-dark-knight"

Deduplication

When creating media or cast members:

  • The API checks if an item with the same clean name already exists
  • If it exists, the existing ID is returned with a 200 status
  • If it doesn't exist, a new item is created with a 201 status

Error Handling

Common Errors

400 Bad Request

{
  "success": false,
  "error": "Invalid JSON"
}

404 Not Found

{
  "success": false,
  "error": "Media not found"
}

405 Method Not Allowed

{
  "success": false,
  "error": "Method not allowed"
}

500 Internal Server Error

{
  "success": false,
  "error": "Error message"
}

CORS

The API supports CORS with the following headers:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type

Rate Limiting

Currently, there is no rate limiting implemented.


Logging

API logging can be enabled by setting the API_LOGGING_ENABLED environment variable to true.

Logs are written to:

  • API requests/responses: /var/www/html/logs/api.log
  • PHP errors: /var/www/html/logs/php_error.log