Remove obsolete test scripts and add new API controllers for dashboard and game management

- Deleted test scripts: test_jellyfin_execution.php, test_stash.php, test_xbvr.php, test_xbvr_sync.php, vite.config.js
- Added DashboardController for fetching dashboard statistics and recent activity
- Added GameController for managing games, including fetching all games, game details, and games by category
- Introduced various check scripts to validate database structures and data integrity for adult videos, games, gender data, posters, and TV show actors
This commit is contained in:
Lars Behrends
2026-01-18 01:42:03 +01:00
parent b728b0c72d
commit eb1ec1153d
29 changed files with 2685 additions and 2454 deletions

View File

@@ -230,7 +230,7 @@ class AdultVideo extends Model
*/
public function updateCastField(): bool
{
$actors = $this->actors();
$actors = $this->actors($this->id);
$actorNames = array_column($actors, 'name');
$castString = implode(', ', $actorNames);
@@ -239,6 +239,194 @@ class AdultVideo extends Model
]);
}
/**
* Find single adult video by ID with metadata processing
*/
public function find(int $id): ?array
{
$stmt = $this->pdo->prepare("
SELECT av.*, s.display_name as source_name
FROM adult_videos av
JOIN sources s ON av.source_id = s.id
WHERE av.id = :id
");
$stmt->execute(['id' => $id]);
$video = $stmt->fetch(\PDO::FETCH_ASSOC);
if (!$video) {
return null;
}
// Process metadata to extract additional fields
if (!empty($video['metadata'])) {
$metadata = json_decode($video['metadata'], true);
// Extract poster aspect ratio from metadata if available
if (!empty($metadata['poster_aspect_ratio'])) {
$video['poster_aspect_ratio'] = $metadata['poster_aspect_ratio'];
}
// Use local cover path if available, otherwise fall back to original URL
if (!empty($metadata['local_cover_path'])) {
$video['poster_url'] = $metadata['local_cover_path'];
} elseif (!empty($metadata['cover_url'])) {
$video['poster_url'] = $metadata['cover_url'];
}
// Add screenshot URL if available
if (!empty($metadata['screenshot_url'])) {
$video['screenshot_url'] = $metadata['screenshot_url'];
}
// Add actors data if available
if (!empty($metadata['actors'])) {
$video['actors'] = $metadata['actors'];
}
}
return $video;
}
/**
* Get all adult videos with filtering and pagination
*/
public function findAll(array $filters = [], int $limit = null, int $offset = 0): array
{
$sql = "
SELECT av.*, s.display_name as source_name
FROM adult_videos av
JOIN sources s ON av.source_id = s.id
";
$params = [];
$whereClauses = [];
// Search filter
if (!empty($filters['search'])) {
$whereClauses[] = "(av.title LIKE :search OR av.overview LIKE :search)";
$params['search'] = "%{$filters['search']}%";
}
// Genre filter
if (!empty($filters['genre'])) {
$whereClauses[] = "av.genre = :genre";
$params['genre'] = $filters['genre'];
}
// Year filter
if (!empty($filters['year'])) {
$whereClauses[] = "YEAR(av.release_date) = :year";
$params['year'] = $filters['year'];
}
// Source filter
if (!empty($filters['sources'])) {
$sources = is_array($filters['sources']) ? $filters['sources'] : [$filters['sources']];
$placeholders = [];
foreach ($sources as $index => $source) {
$placeholders[] = ":source_{$index}";
$params["source_{$index}"] = $source;
}
$whereClauses[] = "s.display_name IN (" . implode(',', $placeholders) . ")";
}
// Combine WHERE clauses
if (!empty($whereClauses)) {
$sql .= " WHERE " . implode(' AND ', $whereClauses);
}
// Add ordering and pagination
$sql .= " ORDER BY av.release_date DESC, av.title ASC";
if ($limit) {
$sql .= " LIMIT :limit OFFSET :offset";
$params['limit'] = $limit;
$params['offset'] = $offset;
}
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
$results = $stmt->fetchAll(\PDO::FETCH_ASSOC);
// Process metadata to extract additional fields
foreach ($results as &$video) {
if (!empty($video['metadata'])) {
$metadata = json_decode($video['metadata'], true);
// Extract poster aspect ratio from metadata if available
if (!empty($metadata['poster_aspect_ratio'])) {
$video['poster_aspect_ratio'] = $metadata['poster_aspect_ratio'];
}
// Use local cover path if available, otherwise fall back to original URL
if (!empty($metadata['local_cover_path'])) {
$video['poster_url'] = $metadata['local_cover_path'];
} elseif (!empty($metadata['cover_url'])) {
$video['poster_url'] = $metadata['cover_url'];
}
// Add actors data if available
if (!empty($metadata['actors'])) {
$video['actors'] = $metadata['actors'];
}
}
}
return $results;
}
/**
* Count adult videos with filters
*/
public function count(array $filters = []): int
{
$sql = "
SELECT COUNT(*) as total
FROM adult_videos av
JOIN sources s ON av.source_id = s.id
";
$params = [];
$whereClauses = [];
// Search filter
if (!empty($filters['search'])) {
$whereClauses[] = "(av.title LIKE :search OR av.overview LIKE :search)";
$params['search'] = "%{$filters['search']}%";
}
// Genre filter
if (!empty($filters['genre'])) {
$whereClauses[] = "av.genre = :genre";
$params['genre'] = $filters['genre'];
}
// Year filter
if (!empty($filters['year'])) {
$whereClauses[] = "YEAR(av.release_date) = :year";
$params['year'] = $filters['year'];
}
// Source filter
if (!empty($filters['sources'])) {
$sources = is_array($filters['sources']) ? $filters['sources'] : [$filters['sources']];
$placeholders = [];
foreach ($sources as $index => $source) {
$placeholders[] = ":source_{$index}";
$params["source_{$index}"] = $source;
}
$whereClauses[] = "s.display_name IN (" . implode(',', $placeholders) . ")";
}
// Combine WHERE clauses
if (!empty($whereClauses)) {
$sql .= " WHERE " . implode(' AND ', $whereClauses);
}
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
$result = $stmt->fetch(\PDO::FETCH_ASSOC);
return (int)$result['total'];
}
/**
* Get available genres for filtering
*/