Initial project scaffold for a PHP Media API including routing, controllers, models and services under api/ (Router, Media/Cast/Image/Settings controllers, models, database/bootstrap files and automatic docs service). Adds Docker support (Dockerfile, docker-compose.yml, DOCKER_README.md, php-custom.ini), .htaccess for pretty URLs, API documentation and example payloads (API_EXAMPLES.md, api/README.md, api_examples/*.json), image handling service and logging, plus a comprehensive .gitignore. This commit provides a runnable development environment and example requests to get the API up and tested quickly.
389 lines
13 KiB
PHP
389 lines
13 KiB
PHP
<?php
|
|
require_once __DIR__ . '/config.php';
|
|
|
|
class Database {
|
|
private $pdo;
|
|
|
|
public function __construct() {
|
|
try {
|
|
$dsn = 'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME . ';charset=utf8mb4';
|
|
$this->pdo = new PDO($dsn, DB_USER, DB_PASS);
|
|
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
$this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
|
|
$this->initializeTables();
|
|
} catch (PDOException $e) {
|
|
http_response_code(500);
|
|
echo json_encode(['success' => false, 'error' => 'Database connection failed: ' . $e->getMessage()]);
|
|
exit;
|
|
}
|
|
}
|
|
|
|
private function initializeTables() {
|
|
// Media-Tabelle
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS media (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
title TEXT NOT NULL,
|
|
cleanname TEXT,
|
|
year TEXT,
|
|
poster TEXT,
|
|
banner TEXT,
|
|
description TEXT,
|
|
rating FLOAT,
|
|
category TEXT,
|
|
type TEXT,
|
|
status TEXT,
|
|
aspectRatio TEXT,
|
|
runtime INT,
|
|
director TEXT,
|
|
writer TEXT,
|
|
releaseDate TEXT,
|
|
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
)
|
|
");
|
|
|
|
// cleanname Feld zu bestehender Tabelle hinzufügen, falls nicht vorhanden
|
|
try {
|
|
$this->pdo->exec("ALTER TABLE media ADD COLUMN cleanname TEXT");
|
|
} catch (Exception $e) {
|
|
// Feld existiert bereits
|
|
}
|
|
|
|
// Index für cleanname erstellen
|
|
try {
|
|
$this->pdo->exec("CREATE INDEX idx_media_cleanname ON media(cleanname)");
|
|
} catch (Exception $e) {
|
|
// Index existiert bereits
|
|
}
|
|
|
|
// Genres-Tabelle
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS genres (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
media_id INT,
|
|
genre TEXT,
|
|
FOREIGN KEY (media_id) REFERENCES media(id) ON DELETE CASCADE
|
|
)
|
|
");
|
|
|
|
// Tags-Tabelle
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS tags (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
media_id INT,
|
|
tag TEXT,
|
|
FOREIGN KEY (media_id) REFERENCES media(id) ON DELETE CASCADE
|
|
)
|
|
");
|
|
|
|
// Studios-Tabelle
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS studios (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
media_id INT,
|
|
studio TEXT,
|
|
FOREIGN KEY (media_id) REFERENCES media(id) ON DELETE CASCADE
|
|
)
|
|
");
|
|
|
|
// Cast/Staff-Tabelle (Stammdaten - ohne media_id)
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS cast_staff (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
cleanname TEXT,
|
|
photo TEXT,
|
|
bio TEXT,
|
|
birthDate TEXT,
|
|
birthPlace TEXT,
|
|
createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
)
|
|
");
|
|
|
|
// cleanname Feld zu bestehender Tabelle hinzufügen, falls nicht vorhanden
|
|
try {
|
|
$this->pdo->exec("ALTER TABLE cast_staff ADD COLUMN cleanname TEXT");
|
|
} catch (Exception $e) {
|
|
// Feld existiert bereits
|
|
}
|
|
|
|
// Index für cleanname erstellen
|
|
try {
|
|
$this->pdo->exec("CREATE INDEX idx_cast_staff_cleanname ON cast_staff(cleanname)");
|
|
} catch (Exception $e) {
|
|
// Index existiert bereits
|
|
}
|
|
|
|
// n:m Beziehung zwischen Media und Cast
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS media_cast (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
media_id INT,
|
|
cast_id INT,
|
|
role TEXT,
|
|
characterName TEXT,
|
|
characterImage TEXT,
|
|
FOREIGN KEY (media_id) REFERENCES media(id) ON DELETE CASCADE,
|
|
FOREIGN KEY (cast_id) REFERENCES cast_staff(id) ON DELETE CASCADE
|
|
)
|
|
");
|
|
|
|
// Occupations-Tabelle
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS occupations (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
cast_id INT,
|
|
occupation TEXT,
|
|
FOREIGN KEY (cast_id) REFERENCES cast_staff(id) ON DELETE CASCADE
|
|
)
|
|
");
|
|
|
|
// Episodes-Tabelle (für Series)
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS episodes (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
media_id INT,
|
|
season INT,
|
|
episode_number INT,
|
|
title TEXT,
|
|
description TEXT,
|
|
air_date TEXT,
|
|
duration INT,
|
|
thumbnail TEXT,
|
|
FOREIGN KEY (media_id) REFERENCES media(id) ON DELETE CASCADE
|
|
)
|
|
");
|
|
|
|
// Tracks-Tabelle (für Music/Albums)
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS tracks (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
media_id INT,
|
|
track_number INT,
|
|
title TEXT,
|
|
duration INT,
|
|
artist TEXT,
|
|
FOREIGN KEY (media_id) REFERENCES media(id) ON DELETE CASCADE
|
|
)
|
|
");
|
|
|
|
// Adult-spezifische Cast-Infos
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS adult_cast_specifics (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
cast_id INT UNIQUE,
|
|
bust_size TEXT,
|
|
cup_size TEXT,
|
|
waist_size TEXT,
|
|
hip_size TEXT,
|
|
height INT,
|
|
weight INT,
|
|
hair_color TEXT,
|
|
eye_color TEXT,
|
|
ethnicity TEXT,
|
|
tattoos TEXT,
|
|
piercings TEXT,
|
|
measurements TEXT,
|
|
shoe_size TEXT,
|
|
FOREIGN KEY (cast_id) REFERENCES cast_staff(id) ON DELETE CASCADE
|
|
)
|
|
");
|
|
|
|
// Media-Games Tabelle (1:1 Relation zu media für spiel-spezifische Daten)
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS media_games (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
media_id INT UNIQUE,
|
|
sortingName TEXT,
|
|
notes TEXT,
|
|
completionStatus TEXT,
|
|
source TEXT,
|
|
gameId TEXT,
|
|
pluginId TEXT,
|
|
isInstalled BOOLEAN DEFAULT 0,
|
|
installDirectory TEXT,
|
|
installSize BIGINT DEFAULT 0,
|
|
hidden BOOLEAN DEFAULT 0,
|
|
favorite BOOLEAN DEFAULT 0,
|
|
playCount INT DEFAULT 0,
|
|
lastActivity TIMESTAMP NULL,
|
|
added TIMESTAMP NULL,
|
|
modified TIMESTAMP NULL,
|
|
communityScore INT DEFAULT 0,
|
|
criticScore INT DEFAULT 0,
|
|
userScore INT DEFAULT 0,
|
|
hasIcon BOOLEAN DEFAULT 0,
|
|
hasCover BOOLEAN DEFAULT 0,
|
|
hasBackground BOOLEAN DEFAULT 0,
|
|
version TEXT,
|
|
playtime INT DEFAULT 0,
|
|
FOREIGN KEY (media_id) REFERENCES media(id) ON DELETE CASCADE
|
|
)
|
|
");
|
|
|
|
// Achievements-Tabelle (für Games - referenziert media_games)
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS achievements (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
media_game_id INT,
|
|
name TEXT NOT NULL,
|
|
description TEXT,
|
|
icon TEXT,
|
|
unlocked BOOLEAN DEFAULT 0,
|
|
unlocked_date TIMESTAMP NULL,
|
|
FOREIGN KEY (media_game_id) REFERENCES media_games(id) ON DELETE CASCADE
|
|
)
|
|
");
|
|
|
|
// Game Categories-Tabelle
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS game_categories (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
media_game_id INT,
|
|
category TEXT,
|
|
FOREIGN KEY (media_game_id) REFERENCES media_games(id) ON DELETE CASCADE
|
|
)
|
|
");
|
|
|
|
// Game Features-Tabelle
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS game_features (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
media_game_id INT,
|
|
feature TEXT,
|
|
FOREIGN KEY (media_game_id) REFERENCES media_games(id) ON DELETE CASCADE
|
|
)
|
|
");
|
|
|
|
// Game Platforms-Tabelle
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS game_platforms (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
media_game_id INT,
|
|
platform TEXT,
|
|
FOREIGN KEY (media_game_id) REFERENCES media_games(id) ON DELETE CASCADE
|
|
)
|
|
");
|
|
|
|
// Game Developers-Tabelle
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS game_developers (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
media_game_id INT,
|
|
developer TEXT,
|
|
FOREIGN KEY (media_game_id) REFERENCES media_games(id) ON DELETE CASCADE
|
|
)
|
|
");
|
|
|
|
// Game Publishers-Tabelle
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS game_publishers (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
media_game_id INT,
|
|
publisher TEXT,
|
|
FOREIGN KEY (media_game_id) REFERENCES media_games(id) ON DELETE CASCADE
|
|
)
|
|
");
|
|
|
|
// Game Series-Tabelle
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS game_series (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
media_game_id INT,
|
|
series TEXT,
|
|
FOREIGN KEY (media_game_id) REFERENCES media_games(id) ON DELETE CASCADE
|
|
)
|
|
");
|
|
|
|
// Game Age Ratings-Tabelle
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS game_age_ratings (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
media_game_id INT,
|
|
age_rating TEXT,
|
|
FOREIGN KEY (media_game_id) REFERENCES media_games(id) ON DELETE CASCADE
|
|
)
|
|
");
|
|
|
|
// Game Regions-Tabelle
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS game_regions (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
media_game_id INT,
|
|
region TEXT,
|
|
FOREIGN KEY (media_game_id) REFERENCES media_games(id) ON DELETE CASCADE
|
|
)
|
|
");
|
|
|
|
// Game Links-Tabelle (mit name und url)
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS game_links (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
media_game_id INT,
|
|
name TEXT,
|
|
url TEXT,
|
|
FOREIGN KEY (media_game_id) REFERENCES media_games(id) ON DELETE CASCADE
|
|
)
|
|
");
|
|
|
|
// API Logs-Tabelle
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS api_logs (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
type TEXT NOT NULL,
|
|
method TEXT,
|
|
path TEXT,
|
|
params JSON,
|
|
body JSON,
|
|
status_code INT,
|
|
response JSON,
|
|
error TEXT,
|
|
INDEX idx_timestamp (timestamp),
|
|
INDEX idx_type (type)
|
|
)
|
|
");
|
|
|
|
// Settings-Tabelle
|
|
$this->pdo->exec("
|
|
CREATE TABLE IF NOT EXISTS settings (
|
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
enabled_categories JSON,
|
|
items_per_page INT DEFAULT 20,
|
|
default_view TEXT DEFAULT 'grid',
|
|
show_adult_content BOOLEAN DEFAULT 0,
|
|
auto_play_trailers BOOLEAN DEFAULT 0,
|
|
language TEXT DEFAULT 'en',
|
|
theme TEXT DEFAULT 'system',
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
)
|
|
");
|
|
|
|
// Bestehende Einträge mit cleanname aktualisieren
|
|
$this->updateExistingCleanNames();
|
|
}
|
|
|
|
private function updateExistingCleanNames() {
|
|
// Media cleanname aktualisieren
|
|
$this->pdo->exec("
|
|
UPDATE media
|
|
SET cleanname = LOWER(REPLACE(REPLACE(REPLACE(REPLACE(title, ' ', '-'), '.', '-'), ',', '-'), '--', '-'))
|
|
WHERE cleanname IS NULL OR cleanname = ''
|
|
");
|
|
|
|
// Cast cleanname aktualisieren
|
|
$this->pdo->exec("
|
|
UPDATE cast_staff
|
|
SET cleanname = LOWER(REPLACE(REPLACE(REPLACE(REPLACE(name, ' ', '-'), '.', '-'), ',', '-'), '--', '-'))
|
|
WHERE cleanname IS NULL OR cleanname = ''
|
|
");
|
|
}
|
|
|
|
public function getConnection() {
|
|
return $this->pdo;
|
|
}
|
|
}
|