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.
1113 lines
20 KiB
Markdown
1113 lines
20 KiB
Markdown
# Kyoo Backend API Documentation
|
|
|
|
**Base URL**: `http://localhost:6400/api`
|
|
|
|
**Content-Type**: `application/json`
|
|
|
|
---
|
|
|
|
## Table of Contents
|
|
|
|
- [Response Format](#response-format)
|
|
- [Authentication](#authentication)
|
|
- [Endpoints](#endpoints)
|
|
- [Root](#root)
|
|
- [Documentation](#documentation)
|
|
- [Media](#media)
|
|
- [Series Episodes](#series-episodes)
|
|
- [Music Tracks](#music-tracks)
|
|
- [Cast](#cast)
|
|
- [Adult Cast](#adult-cast)
|
|
- [Images](#images)
|
|
- [Settings](#settings)
|
|
|
|
---
|
|
|
|
## Response Format
|
|
|
|
### Success Response
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": { ... }
|
|
}
|
|
```
|
|
|
|
### Error Response
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": "Error message"
|
|
}
|
|
```
|
|
|
|
### Paginated Response
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```bash
|
|
GET /api/media?page=1&limit=20&category=movie&search=action
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```bash
|
|
GET /api/media/1
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"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):
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"id": 1
|
|
}
|
|
}
|
|
```
|
|
|
|
**Response** (200 OK - if media already exists):
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"id": 1
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Delete Media
|
|
|
|
**Endpoint**: `DELETE /api/media/:id`
|
|
|
|
**Path Parameters**:
|
|
- `id` (integer, required) - Media ID
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```bash
|
|
GET /api/media/1/episodes?season=1
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"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):
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"track": 1,
|
|
"title": "Track Title",
|
|
"duration": 240,
|
|
"artists": ["Artist1", "Artist2"]
|
|
}
|
|
```
|
|
|
|
**Response** (201 Created):
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```bash
|
|
GET /api/cast?page=1&limit=20&search=john
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"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):
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"id": 1
|
|
}
|
|
}
|
|
```
|
|
|
|
**Response** (200 OK - if cast already exists):
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"id": 1
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Delete Cast
|
|
|
|
**Endpoint**: `DELETE /api/cast/:id`
|
|
|
|
**Path Parameters**:
|
|
- `id` (integer, required) - Cast ID
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```bash
|
|
GET /api/cast/adult?page=1&limit=20ðnicity=Asian
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"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):
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```json
|
|
{
|
|
"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**:
|
|
```bash
|
|
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**:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"id": 1,
|
|
"key": "value",
|
|
"updatedAt": "2024-01-01 00:00:00"
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Update Settings
|
|
|
|
**Endpoint**: `PUT /api/settings`
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"key": "value"
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"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
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": "Invalid JSON"
|
|
}
|
|
```
|
|
|
|
#### 404 Not Found
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": "Media not found"
|
|
}
|
|
```
|
|
|
|
#### 405 Method Not Allowed
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": "Method not allowed"
|
|
}
|
|
```
|
|
|
|
#### 500 Internal Server Error
|
|
```json
|
|
{
|
|
"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`
|