mirror of
https://github.com/ceratic/MediaCollectorLibary.git
synced 2026-05-13 23:56:46 +02:00
first commit
This commit is contained in:
129
app/Controllers/AdminController.php
Normal file
129
app/Controllers/AdminController.php
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use App\Models\Source;
|
||||
use App\Models\SyncLog;
|
||||
use App\Services\SteamSyncService;
|
||||
use App\Services\JellyfinSyncService;
|
||||
use App\Services\StashSyncService;
|
||||
use App\Services\XbvrSyncService;
|
||||
use App\Services\AdultSyncService;
|
||||
use App\Services\ExophaseSyncService;
|
||||
use PDO;
|
||||
use Slim\Views\Twig;
|
||||
|
||||
class AdminController extends Controller
|
||||
{
|
||||
private PDO $pdo;
|
||||
|
||||
public function __construct(PDO $pdo, Twig $view)
|
||||
{
|
||||
parent::__construct($view);
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
|
||||
public function index(Request $request, Response $response, $args)
|
||||
{
|
||||
$sourceModel = new Source($this->pdo);
|
||||
$sources = $sourceModel->findAll();
|
||||
|
||||
$syncLogModel = new SyncLog($this->pdo);
|
||||
$recentSyncs = SyncLog::getRecent($this->pdo, 10);
|
||||
|
||||
return $this->view->render($response, 'admin/index.twig', [
|
||||
'title' => 'Admin Dashboard',
|
||||
'sources' => $sources,
|
||||
'recent_syncs' => $recentSyncs
|
||||
]);
|
||||
}
|
||||
|
||||
public function syncSource(Request $request, Response $response, $args)
|
||||
{
|
||||
$sourceId = $args['id'];
|
||||
$syncType = $request->getQueryParams()['type'] ?? 'full';
|
||||
|
||||
$sourceModel = new Source($this->pdo);
|
||||
$source = $sourceModel->find($sourceId);
|
||||
|
||||
if (!$source) {
|
||||
return $response->withStatus(404)->withHeader('Content-Type', 'application/json');
|
||||
}
|
||||
|
||||
// Start sync in background (simplified - in production you'd use queues)
|
||||
$syncLogId = $this->startSync($source, $syncType);
|
||||
|
||||
return $this->json($response, [
|
||||
'success' => true,
|
||||
'sync_log_id' => $syncLogId,
|
||||
'message' => 'Sync started successfully'
|
||||
]);
|
||||
}
|
||||
|
||||
public function syncStatus(Request $request, Response $response, $args)
|
||||
{
|
||||
$syncLogId = $args['id'];
|
||||
|
||||
$syncLogModel = new SyncLog($this->pdo);
|
||||
$syncLog = $syncLogModel->find($syncLogId);
|
||||
|
||||
if (!$syncLog) {
|
||||
return $response->withStatus(404)->withHeader('Content-Type', 'application/json');
|
||||
}
|
||||
|
||||
return $this->json($response, [
|
||||
'id' => $syncLog['id'],
|
||||
'status' => $syncLog['status'],
|
||||
'sync_type' => $syncLog['sync_type'],
|
||||
'total_items' => $syncLog['total_items'],
|
||||
'processed_items' => $syncLog['processed_items'],
|
||||
'new_items' => $syncLog['new_items'],
|
||||
'updated_items' => $syncLog['updated_items'],
|
||||
'deleted_items' => $syncLog['deleted_items'],
|
||||
'started_at' => $syncLog['started_at'],
|
||||
'completed_at' => $syncLog['completed_at'],
|
||||
'message' => $syncLog['message'],
|
||||
'errors' => $syncLog['errors'] ? json_decode($syncLog['errors'], true) : []
|
||||
]);
|
||||
}
|
||||
|
||||
public function sources(Request $request, Response $response, $args)
|
||||
{
|
||||
$sourceModel = new Source($this->pdo);
|
||||
$sources = $sourceModel->findAll();
|
||||
|
||||
return $this->view->render($response, 'admin/sources.twig', [
|
||||
'title' => 'Source Management',
|
||||
'sources' => $sources
|
||||
]);
|
||||
}
|
||||
|
||||
private function startSync(array $source, string $syncType): int
|
||||
{
|
||||
// Create appropriate sync service based on source type
|
||||
switch ($source['name']) {
|
||||
case 'steam':
|
||||
$syncService = new SteamSyncService($this->pdo, $source);
|
||||
break;
|
||||
case 'jellyfin':
|
||||
$syncService = new JellyfinSyncService($this->pdo, $source);
|
||||
break;
|
||||
case 'stash':
|
||||
$syncService = new StashSyncService($this->pdo, $source);
|
||||
break;
|
||||
case 'adult':
|
||||
$syncService = new AdultSyncService($this->pdo, $source);
|
||||
break;
|
||||
case 'exophase':
|
||||
$syncService = new ExophaseSyncService($this->pdo, $source);
|
||||
break;
|
||||
default:
|
||||
throw new \Exception('Unsupported source type: ' . $source['name']);
|
||||
}
|
||||
|
||||
// Start sync (this would typically be queued in production)
|
||||
return $syncService->startSync($syncType);
|
||||
}
|
||||
}
|
||||
99
app/Controllers/AdultController.php
Normal file
99
app/Controllers/AdultController.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use App\Models\AdultVideo;
|
||||
use Slim\Views\Twig;
|
||||
|
||||
class AdultController extends Controller
|
||||
{
|
||||
private \PDO $pdo;
|
||||
|
||||
public function __construct(\PDO $pdo, Twig $view)
|
||||
{
|
||||
parent::__construct($view);
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
|
||||
public function index(Request $request, Response $response, $args)
|
||||
{
|
||||
$queryParams = $request->getQueryParams();
|
||||
|
||||
// Get pagination parameters
|
||||
$page = max(1, (int)($queryParams['page'] ?? 1));
|
||||
$perPage = max(12, min(100, (int)($queryParams['per_page'] ?? 24)));
|
||||
|
||||
// Get search parameters
|
||||
$search = trim($queryParams['search'] ?? '');
|
||||
|
||||
// Get view mode
|
||||
$viewMode = $queryParams['view'] ?? 'grid'; // grid, list, covers
|
||||
|
||||
// Get adult videos with pagination and search
|
||||
$adultVideos = AdultVideo::getAllWithPagination($this->pdo, $page, $perPage, $search);
|
||||
|
||||
// Get total count for pagination
|
||||
$totalCount = AdultVideo::getTotalCount($this->pdo, $search);
|
||||
|
||||
// Calculate pagination info
|
||||
$totalPages = ceil($totalCount / $perPage);
|
||||
$hasNextPage = $page < $totalPages;
|
||||
$hasPrevPage = $page > 1;
|
||||
|
||||
return $this->view->render($response, 'adult/index.twig', [
|
||||
'title' => 'Adult Videos',
|
||||
'movies' => $adultVideos, // Keep same variable name for template compatibility
|
||||
'pagination' => [
|
||||
'current_page' => $page,
|
||||
'per_page' => $perPage,
|
||||
'total_pages' => $totalPages,
|
||||
'total_items' => $totalCount,
|
||||
'has_next' => $hasNextPage,
|
||||
'has_prev' => $hasPrevPage,
|
||||
'next_page' => $page + 1,
|
||||
'prev_page' => $page - 1
|
||||
],
|
||||
'search' => $search,
|
||||
'view_mode' => $viewMode,
|
||||
'view_modes' => ['grid', 'list', 'covers']
|
||||
]);
|
||||
}
|
||||
|
||||
public function show(Request $request, Response $response, $args)
|
||||
{
|
||||
$adultVideoId = (int) $args['id'];
|
||||
|
||||
// Get adult video details
|
||||
$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' => $adultVideoId]);
|
||||
$adultVideo = $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$adultVideo) {
|
||||
return $response->withStatus(404);
|
||||
}
|
||||
|
||||
// Decode metadata for display
|
||||
$metadata = json_decode($adultVideo['metadata'], true);
|
||||
|
||||
return $this->view->render($response, 'adult/show.twig', [
|
||||
'title' => $adultVideo['title'],
|
||||
'movie' => $adultVideo, // Keep same variable name for template compatibility
|
||||
'metadata' => $metadata
|
||||
]);
|
||||
}
|
||||
|
||||
private function getAdultSourceId(): ?int
|
||||
{
|
||||
$stmt = $this->pdo->prepare("SELECT id FROM sources WHERE name = 'adult' LIMIT 1");
|
||||
$stmt->execute();
|
||||
$result = $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||
return $result ? (int) $result['id'] : null;
|
||||
}
|
||||
}
|
||||
76
app/Controllers/AuthController.php
Normal file
76
app/Controllers/AuthController.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use App\Services\AuthService;
|
||||
use Slim\Views\Twig;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
private AuthService $auth;
|
||||
|
||||
public function __construct(AuthService $auth, Twig $view)
|
||||
{
|
||||
parent::__construct($view);
|
||||
$this->auth = $auth;
|
||||
}
|
||||
|
||||
public function showLogin(Request $request, Response $response, $args)
|
||||
{
|
||||
// If already logged in, redirect to dashboard
|
||||
if ($this->auth->isLoggedIn()) {
|
||||
return $response->withStatus(302)->withHeader('Location', '/');
|
||||
}
|
||||
|
||||
return $this->view->render($response, 'auth/login.twig', [
|
||||
'title' => 'Login',
|
||||
'csrf_token' => $this->auth->generateCSRFToken()
|
||||
]);
|
||||
}
|
||||
|
||||
public function login(Request $request, Response $response, $args)
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
$username = $data['username'] ?? '';
|
||||
$password = $data['password'] ?? '';
|
||||
$csrfToken = $data['csrf_token'] ?? '';
|
||||
|
||||
// Verify CSRF token
|
||||
if (!$this->auth->verifyCSRFToken($csrfToken)) {
|
||||
return $this->view->render($response->withStatus(400), 'auth/login.twig', [
|
||||
'title' => 'Login',
|
||||
'error' => 'Invalid CSRF token',
|
||||
'csrf_token' => $this->auth->generateCSRFToken()
|
||||
]);
|
||||
}
|
||||
|
||||
// Validate input
|
||||
if (empty($username) || empty($password)) {
|
||||
return $this->view->render($response->withStatus(400), 'auth/login.twig', [
|
||||
'title' => 'Login',
|
||||
'error' => 'Username and password are required',
|
||||
'csrf_token' => $this->auth->generateCSRFToken()
|
||||
]);
|
||||
}
|
||||
|
||||
// Attempt login
|
||||
if ($this->auth->login($username, $password, $_SERVER['REMOTE_ADDR'] ?? null)) {
|
||||
return $response->withStatus(302)->withHeader('Location', '/');
|
||||
}
|
||||
|
||||
// Login failed
|
||||
return $this->view->render($response->withStatus(401), 'auth/login.twig', [
|
||||
'title' => 'Login',
|
||||
'error' => 'Invalid username or password',
|
||||
'csrf_token' => $this->auth->generateCSRFToken()
|
||||
]);
|
||||
}
|
||||
|
||||
public function logout(Request $request, Response $response, $args)
|
||||
{
|
||||
$this->auth->logout();
|
||||
return $response->withStatus(302)->withHeader('Location', '/login');
|
||||
}
|
||||
}
|
||||
25
app/Controllers/Controller.php
Normal file
25
app/Controllers/Controller.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Slim\Views\Twig;
|
||||
|
||||
abstract class Controller
|
||||
{
|
||||
protected $view;
|
||||
|
||||
public function __construct(Twig $view)
|
||||
{
|
||||
$this->view = $view;
|
||||
}
|
||||
|
||||
protected function json(Response $response, $data, int $status = 200): Response
|
||||
{
|
||||
$response->getBody()->write(json_encode($data));
|
||||
return $response
|
||||
->withHeader('Content-Type', 'application/json')
|
||||
->withStatus($status);
|
||||
}
|
||||
}
|
||||
82
app/Controllers/DashboardController.php
Normal file
82
app/Controllers/DashboardController.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use App\Models\Game;
|
||||
use App\Models\Movie;
|
||||
use App\Models\TvShow;
|
||||
use App\Models\MusicArtist;
|
||||
use App\Models\SyncLog;
|
||||
use Slim\Views\Twig;
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
public function __construct(Twig $view)
|
||||
{
|
||||
parent::__construct($view);
|
||||
}
|
||||
|
||||
public function index(Request $request, Response $response, $args)
|
||||
{
|
||||
$pdo = $this->view->getEnvironment()->getGlobals()['pdo'] ?? null;
|
||||
|
||||
if (!$pdo) {
|
||||
return $this->view->render($response, 'dashboard/index.twig', [
|
||||
'title' => 'Dashboard',
|
||||
'stats' => [
|
||||
'total_media' => 0,
|
||||
'total_games' => 0,
|
||||
'total_movies' => 0,
|
||||
'total_tv_shows' => 0,
|
||||
'total_episodes' => 0,
|
||||
'total_music' => 0,
|
||||
],
|
||||
'error' => 'Database connection not available'
|
||||
]);
|
||||
}
|
||||
|
||||
// Get statistics from models
|
||||
$gameStats = Game::getStats($pdo);
|
||||
$movieStats = Movie::getStats($pdo);
|
||||
$tvShowStats = TvShow::getStats($pdo);
|
||||
$musicStats = MusicArtist::getStats($pdo);
|
||||
$syncStats = SyncLog::getStats($pdo);
|
||||
|
||||
// Get recent activity
|
||||
$recentGames = Game::getRecent($pdo, 5);
|
||||
$recentMovies = Movie::getRecent($pdo, 5);
|
||||
$recentSyncs = SyncLog::getRecent($pdo, 5);
|
||||
|
||||
// Calculate total media count
|
||||
$totalMedia = ($gameStats['total_games'] ?? 0) +
|
||||
($movieStats['total_movies'] ?? 0) +
|
||||
($tvShowStats['total_shows'] ?? 0) +
|
||||
($musicStats['total_artists'] ?? 0);
|
||||
|
||||
$stats = [
|
||||
'total_media' => $totalMedia,
|
||||
'total_games' => $gameStats['total_games'] ?? 0,
|
||||
'total_movies' => $movieStats['total_movies'] ?? 0,
|
||||
'total_tv_shows' => $tvShowStats['total_shows'] ?? 0,
|
||||
'total_episodes' => $tvShowStats['total_episodes'] ?? 0,
|
||||
'total_music' => $musicStats['total_artists'] ?? 0,
|
||||
'total_playtime' => $gameStats['total_playtime'] ?? 0,
|
||||
'watched_movies' => $movieStats['watched_movies'] ?? 0,
|
||||
'favorite_games' => $gameStats['favorite_games'] ?? 0,
|
||||
'favorite_movies' => $movieStats['favorite_movies'] ?? 0,
|
||||
'favorite_shows' => $tvShowStats['favorite_shows'] ?? 0,
|
||||
'favorite_music' => $musicStats['favorite_artists'] ?? 0,
|
||||
];
|
||||
|
||||
return $this->view->render($response, 'dashboard/index.twig', [
|
||||
'title' => 'Dashboard',
|
||||
'stats' => $stats,
|
||||
'recent_games' => $recentGames,
|
||||
'recent_movies' => $recentMovies,
|
||||
'recent_syncs' => $recentSyncs,
|
||||
'sync_stats' => $syncStats
|
||||
]);
|
||||
}
|
||||
}
|
||||
95
app/Controllers/GameController.php
Normal file
95
app/Controllers/GameController.php
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use App\Models\Game;
|
||||
use Slim\Views\Twig;
|
||||
|
||||
class GameController extends Controller
|
||||
{
|
||||
private \PDO $pdo;
|
||||
|
||||
public function __construct(\PDO $pdo, Twig $view)
|
||||
{
|
||||
parent::__construct($view);
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
|
||||
public function index(Request $request, Response $response, $args)
|
||||
{
|
||||
$queryParams = $request->getQueryParams();
|
||||
|
||||
// Get pagination parameters
|
||||
$page = max(1, (int)($queryParams['page'] ?? 1));
|
||||
$perPage = max(12, min(100, (int)($queryParams['per_page'] ?? 24)));
|
||||
|
||||
// Get search parameters
|
||||
$search = trim($queryParams['search'] ?? '');
|
||||
|
||||
// Get view mode
|
||||
$viewMode = $queryParams['view'] ?? 'grid'; // grid, list, covers
|
||||
|
||||
// Get games with pagination and search
|
||||
$games = Game::getGroupedGamesWithPagination($this->pdo, $page, $perPage, $search);
|
||||
|
||||
// Get total count for pagination
|
||||
$totalCount = Game::getTotalCount($this->pdo, $search);
|
||||
|
||||
// Calculate pagination info
|
||||
$totalPages = ceil($totalCount / $perPage);
|
||||
$hasNextPage = $page < $totalPages;
|
||||
$hasPrevPage = $page > 1;
|
||||
|
||||
return $this->view->render($response, 'games/index.twig', [
|
||||
'title' => 'Games',
|
||||
'games' => $games,
|
||||
'pagination' => [
|
||||
'current_page' => $page,
|
||||
'per_page' => $perPage,
|
||||
'total_pages' => $totalPages,
|
||||
'total_items' => $totalCount,
|
||||
'has_next' => $hasNextPage,
|
||||
'has_prev' => $hasPrevPage,
|
||||
'next_page' => $page + 1,
|
||||
'prev_page' => $page - 1
|
||||
],
|
||||
'search' => $search,
|
||||
'view_mode' => $viewMode,
|
||||
'view_modes' => ['grid', 'list', 'covers']
|
||||
]);
|
||||
}
|
||||
|
||||
public function show(Request $request, Response $response, $args)
|
||||
{
|
||||
$gameKey = $args['game_key'];
|
||||
|
||||
// Find the main game entry (could be any platform version)
|
||||
$stmt = $this->pdo->prepare("
|
||||
SELECT g.*, s.display_name as source_name
|
||||
FROM games g
|
||||
JOIN sources s ON g.source_id = s.id
|
||||
WHERE g.game_key = :game_key
|
||||
LIMIT 1
|
||||
");
|
||||
$stmt->execute(['game_key' => $gameKey]);
|
||||
$mainGame = $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$mainGame) {
|
||||
return $response->withStatus(404);
|
||||
}
|
||||
|
||||
// Get all platform versions
|
||||
$gameModel = new Game($this->pdo);
|
||||
$gameModel->id = $mainGame['id'];
|
||||
$gameModel->game_key = $mainGame['game_key'];
|
||||
$platformVersions = $gameModel->getPlatformVersions();
|
||||
|
||||
return $this->view->render($response, 'games/show.twig', [
|
||||
'title' => $mainGame['title'],
|
||||
'main_game' => $mainGame,
|
||||
'platform_versions' => $platformVersions
|
||||
]);
|
||||
}
|
||||
}
|
||||
91
app/Controllers/MovieController.php
Normal file
91
app/Controllers/MovieController.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use App\Models\Movie;
|
||||
use Slim\Views\Twig;
|
||||
|
||||
class MovieController extends Controller
|
||||
{
|
||||
private \PDO $pdo;
|
||||
|
||||
public function __construct(\PDO $pdo, Twig $view)
|
||||
{
|
||||
parent::__construct($view);
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
|
||||
public function index(Request $request, Response $response, $args)
|
||||
{
|
||||
$queryParams = $request->getQueryParams();
|
||||
|
||||
// Get pagination parameters
|
||||
$page = max(1, (int)($queryParams['page'] ?? 1));
|
||||
$perPage = max(12, min(100, (int)($queryParams['per_page'] ?? 24)));
|
||||
|
||||
// Get search parameters
|
||||
$search = trim($queryParams['search'] ?? '');
|
||||
|
||||
// Get view mode
|
||||
$viewMode = $queryParams['view'] ?? 'grid'; // grid, list, covers
|
||||
|
||||
// Get movies with pagination and search
|
||||
$movies = Movie::getAllWithPagination($this->pdo, $page, $perPage, $search);
|
||||
|
||||
// Get total count for pagination
|
||||
$totalCount = Movie::getTotalCount($this->pdo, $search);
|
||||
|
||||
// Calculate pagination info
|
||||
$totalPages = ceil($totalCount / $perPage);
|
||||
$hasNextPage = $page < $totalPages;
|
||||
$hasPrevPage = $page > 1;
|
||||
|
||||
return $this->view->render($response, 'movies/index.twig', [
|
||||
'title' => 'Movies',
|
||||
'movies' => $movies,
|
||||
'pagination' => [
|
||||
'current_page' => $page,
|
||||
'per_page' => $perPage,
|
||||
'total_pages' => $totalPages,
|
||||
'total_items' => $totalCount,
|
||||
'has_next' => $hasNextPage,
|
||||
'has_prev' => $hasPrevPage,
|
||||
'next_page' => $page + 1,
|
||||
'prev_page' => $page - 1
|
||||
],
|
||||
'search' => $search,
|
||||
'view_mode' => $viewMode,
|
||||
'view_modes' => ['grid', 'list', 'covers']
|
||||
]);
|
||||
}
|
||||
|
||||
public function show(Request $request, Response $response, $args)
|
||||
{
|
||||
$movieId = (int) $args['id'];
|
||||
|
||||
// Get movie details
|
||||
$stmt = $this->pdo->prepare("
|
||||
SELECT m.*, s.display_name as source_name
|
||||
FROM movies m
|
||||
JOIN sources s ON m.source_id = s.id
|
||||
WHERE m.id = :id
|
||||
");
|
||||
$stmt->execute(['id' => $movieId]);
|
||||
$movie = $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$movie) {
|
||||
return $response->withStatus(404);
|
||||
}
|
||||
|
||||
// Decode metadata for display
|
||||
$metadata = json_decode($movie['metadata'], true);
|
||||
|
||||
return $this->view->render($response, 'movies/show.twig', [
|
||||
'title' => $movie['title'],
|
||||
'movie' => $movie,
|
||||
'metadata' => $metadata
|
||||
]);
|
||||
}
|
||||
}
|
||||
72
app/Controllers/MusicController.php
Normal file
72
app/Controllers/MusicController.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Slim\Views\Twig;
|
||||
|
||||
class MusicController extends Controller
|
||||
{
|
||||
private \PDO $pdo;
|
||||
|
||||
public function __construct(\PDO $pdo, Twig $view)
|
||||
{
|
||||
parent::__construct($view);
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
|
||||
public function index(Request $request, Response $response, $args)
|
||||
{
|
||||
$queryParams = $request->getQueryParams();
|
||||
|
||||
// Get pagination parameters
|
||||
$page = max(1, (int)($queryParams['page'] ?? 1));
|
||||
$perPage = max(12, min(100, (int)($queryParams['per_page'] ?? 24)));
|
||||
|
||||
// Get search parameters
|
||||
$search = trim($queryParams['search'] ?? '');
|
||||
|
||||
// Get view mode
|
||||
$viewMode = $queryParams['view'] ?? 'grid'; // grid, list, covers
|
||||
|
||||
// For now, return empty arrays since Music isn't implemented yet
|
||||
$music = [];
|
||||
$totalCount = 0;
|
||||
|
||||
// Calculate pagination info
|
||||
$totalPages = 0;
|
||||
$hasNextPage = false;
|
||||
$hasPrevPage = false;
|
||||
|
||||
return $this->view->render($response, 'music/index.twig', [
|
||||
'title' => 'Music',
|
||||
'music' => $music,
|
||||
'pagination' => [
|
||||
'current_page' => $page,
|
||||
'per_page' => $perPage,
|
||||
'total_pages' => $totalPages,
|
||||
'total_items' => $totalCount,
|
||||
'has_next' => $hasNextPage,
|
||||
'has_prev' => $hasPrevPage,
|
||||
'next_page' => $page + 1,
|
||||
'prev_page' => $page - 1
|
||||
],
|
||||
'search' => $search,
|
||||
'view_mode' => $viewMode,
|
||||
'view_modes' => ['grid', 'list', 'covers']
|
||||
]);
|
||||
}
|
||||
|
||||
public function show(Request $request, Response $response, $args)
|
||||
{
|
||||
$musicId = (int) $args['id'];
|
||||
|
||||
// For now, return a placeholder since Music isn't implemented yet
|
||||
return $this->view->render($response, 'music/show.twig', [
|
||||
'title' => 'Music Details',
|
||||
'music' => ['id' => $musicId, 'title' => 'Coming Soon'],
|
||||
'message' => 'Music details page is not yet implemented.'
|
||||
]);
|
||||
}
|
||||
}
|
||||
68
app/Controllers/SearchController.php
Normal file
68
app/Controllers/SearchController.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Slim\Views\Twig;
|
||||
|
||||
class SearchController extends Controller
|
||||
{
|
||||
private \PDO $pdo;
|
||||
|
||||
public function __construct(\PDO $pdo, Twig $view)
|
||||
{
|
||||
parent::__construct($view);
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
|
||||
public function index(Request $request, Response $response, $args)
|
||||
{
|
||||
$queryParams = $request->getQueryParams();
|
||||
$search = trim($queryParams['q'] ?? '');
|
||||
|
||||
if (empty($search)) {
|
||||
return $this->view->render($response, 'search/index.twig', [
|
||||
'title' => 'Search',
|
||||
'search' => $search,
|
||||
'results' => []
|
||||
]);
|
||||
}
|
||||
|
||||
// Search across different media types
|
||||
$results = [];
|
||||
|
||||
// Search movies (including adult videos)
|
||||
$movieStmt = $this->pdo->prepare("
|
||||
SELECT m.*, s.display_name as source_name, 'movie' as type
|
||||
FROM movies m
|
||||
JOIN sources s ON m.source_id = s.id
|
||||
WHERE (m.title LIKE :search OR m.overview LIKE :search)
|
||||
ORDER BY m.title
|
||||
LIMIT 20
|
||||
");
|
||||
$searchParam = "%{$search}%";
|
||||
$movieStmt->bindParam(':search', $searchParam, \PDO::PARAM_STR);
|
||||
$movieStmt->execute();
|
||||
$results['movies'] = $movieStmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||
|
||||
// Search games
|
||||
$gameStmt = $this->pdo->prepare("
|
||||
SELECT g.*, s.display_name as source_name, 'game' as type
|
||||
FROM games g
|
||||
JOIN sources s ON g.source_id = s.id
|
||||
WHERE (g.name LIKE :search OR g.description LIKE :search)
|
||||
ORDER BY g.name
|
||||
LIMIT 20
|
||||
");
|
||||
$gameStmt->bindParam(':search', $searchParam, \PDO::PARAM_STR);
|
||||
$gameStmt->execute();
|
||||
$results['games'] = $gameStmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||
|
||||
return $this->view->render($response, 'search/index.twig', [
|
||||
'title' => 'Search Results',
|
||||
'search' => $search,
|
||||
'results' => $results
|
||||
]);
|
||||
}
|
||||
}
|
||||
72
app/Controllers/TvShowController.php
Normal file
72
app/Controllers/TvShowController.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Slim\Views\Twig;
|
||||
|
||||
class TvShowController extends Controller
|
||||
{
|
||||
private \PDO $pdo;
|
||||
|
||||
public function __construct(\PDO $pdo, Twig $view)
|
||||
{
|
||||
parent::__construct($view);
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
|
||||
public function index(Request $request, Response $response, $args)
|
||||
{
|
||||
$queryParams = $request->getQueryParams();
|
||||
|
||||
// Get pagination parameters
|
||||
$page = max(1, (int)($queryParams['page'] ?? 1));
|
||||
$perPage = max(12, min(100, (int)($queryParams['per_page'] ?? 24)));
|
||||
|
||||
// Get search parameters
|
||||
$search = trim($queryParams['search'] ?? '');
|
||||
|
||||
// Get view mode
|
||||
$viewMode = $queryParams['view'] ?? 'grid'; // grid, list, covers
|
||||
|
||||
// For now, return empty arrays since TV Shows aren't implemented yet
|
||||
$tvshows = [];
|
||||
$totalCount = 0;
|
||||
|
||||
// Calculate pagination info
|
||||
$totalPages = 0;
|
||||
$hasNextPage = false;
|
||||
$hasPrevPage = false;
|
||||
|
||||
return $this->view->render($response, 'tvshows/index.twig', [
|
||||
'title' => 'TV Shows',
|
||||
'tvshows' => $tvshows,
|
||||
'pagination' => [
|
||||
'current_page' => $page,
|
||||
'per_page' => $perPage,
|
||||
'total_pages' => $totalPages,
|
||||
'total_items' => $totalCount,
|
||||
'has_next' => $hasNextPage,
|
||||
'has_prev' => $hasPrevPage,
|
||||
'next_page' => $page + 1,
|
||||
'prev_page' => $page - 1
|
||||
],
|
||||
'search' => $search,
|
||||
'view_mode' => $viewMode,
|
||||
'view_modes' => ['grid', 'list', 'covers']
|
||||
]);
|
||||
}
|
||||
|
||||
public function show(Request $request, Response $response, $args)
|
||||
{
|
||||
$tvShowId = (int) $args['id'];
|
||||
|
||||
// For now, return a placeholder since TV Shows aren't implemented yet
|
||||
return $this->view->render($response, 'tvshows/show.twig', [
|
||||
'title' => 'TV Show Details',
|
||||
'tvshow' => ['id' => $tvShowId, 'title' => 'Coming Soon'],
|
||||
'message' => 'TV show details page is not yet implemented.'
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user