mirror of
https://github.com/ceratic/MediaCollectorLibary.git
synced 2026-05-13 23:56:46 +02:00
impoort stuff!
This commit is contained in:
@@ -3,18 +3,19 @@
|
||||
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)
|
||||
protected $auth;
|
||||
|
||||
public function __construct(Twig $view, $auth = null)
|
||||
{
|
||||
$this->view = $view;
|
||||
$this->auth = $auth;
|
||||
}
|
||||
|
||||
|
||||
protected function json(Response $response, $data, int $status = 200): Response
|
||||
{
|
||||
$response->getBody()->write(json_encode($data));
|
||||
@@ -22,4 +23,122 @@ abstract class Controller
|
||||
->withHeader('Content-Type', 'application/json')
|
||||
->withStatus($status);
|
||||
}
|
||||
|
||||
protected function jsonResponse(Response $response, $data, int $status = 200): Response
|
||||
{
|
||||
return $this->json($response, $data, $status);
|
||||
}
|
||||
|
||||
protected function withRedirect(Response $response, string $url): Response
|
||||
{
|
||||
return $response->withStatus(302)->withHeader('Location', $url);
|
||||
}
|
||||
|
||||
protected function generateCSRFToken(): string
|
||||
{
|
||||
if ($this->auth && method_exists($this->auth, 'generateCSRFToken')) {
|
||||
return $this->auth->generateCSRFToken();
|
||||
}
|
||||
|
||||
// Fallback for when auth service is not available
|
||||
if (!isset($_SESSION['csrf_token'])) {
|
||||
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
||||
}
|
||||
return $_SESSION['csrf_token'];
|
||||
}
|
||||
|
||||
protected function verifyCSRFToken(string $token): bool
|
||||
{
|
||||
if ($this->auth && method_exists($this->auth, 'verifyCSRFToken')) {
|
||||
return $this->auth->verifyCSRFToken($token);
|
||||
}
|
||||
|
||||
// Fallback for when auth service is not available
|
||||
return isset($_SESSION['csrf_token']) && $_SESSION['csrf_token'] === $token;
|
||||
}
|
||||
|
||||
protected function getRoutePath(string $routeName, array $data = [], array $queryParams = []): string
|
||||
{
|
||||
// Simple implementation matching the path_for function in templates
|
||||
$basePath = '';
|
||||
|
||||
// Handle common route patterns
|
||||
switch ($routeName) {
|
||||
case 'home':
|
||||
$basePath = '/';
|
||||
break;
|
||||
case 'games.index':
|
||||
$basePath = '/media/games';
|
||||
break;
|
||||
case 'games.show':
|
||||
$basePath = '/media/games/' . ($data['game_key'] ?? '');
|
||||
break;
|
||||
case 'movies.index':
|
||||
$basePath = '/media/movies';
|
||||
break;
|
||||
case 'tvshows.index':
|
||||
$basePath = '/media/tv-shows';
|
||||
break;
|
||||
case 'music.index':
|
||||
$basePath = '/media/music';
|
||||
break;
|
||||
case 'admin.index':
|
||||
$basePath = '/admin';
|
||||
break;
|
||||
case 'admin.playnite.import':
|
||||
$basePath = '/admin/playnite/import';
|
||||
break;
|
||||
case 'admin.playnite.upload':
|
||||
$basePath = '/admin/playnite/import';
|
||||
break;
|
||||
case 'admin.settings':
|
||||
$basePath = '/admin/settings';
|
||||
break;
|
||||
case 'admin.sources':
|
||||
$basePath = '/admin/sources';
|
||||
break;
|
||||
case 'admin.sync':
|
||||
$basePath = '/admin/sync/' . ($data['id'] ?? '');
|
||||
break;
|
||||
case 'auth.login':
|
||||
$basePath = '/login';
|
||||
break;
|
||||
case 'auth.logout':
|
||||
$basePath = '/logout';
|
||||
break;
|
||||
case 'movies.show':
|
||||
$basePath = '/media/movies/' . ($data['id'] ?? '');
|
||||
break;
|
||||
case 'tvshows.show':
|
||||
$basePath = '/media/tv-shows/' . ($data['id'] ?? '');
|
||||
break;
|
||||
case 'music.show':
|
||||
$basePath = '/media/music/' . ($data['id'] ?? '');
|
||||
break;
|
||||
case 'adult.index':
|
||||
$basePath = '/media/adult';
|
||||
break;
|
||||
case 'adult.show':
|
||||
$basePath = '/media/adult/' . ($data['id'] ?? '');
|
||||
break;
|
||||
case 'actors.index':
|
||||
$basePath = '/media/actors';
|
||||
break;
|
||||
case 'actors.show':
|
||||
$basePath = '/media/actors/' . ($data['id'] ?? '');
|
||||
break;
|
||||
case 'search.index':
|
||||
$basePath = '/search';
|
||||
break;
|
||||
default:
|
||||
$basePath = '/' . str_replace('.', '/', $routeName);
|
||||
}
|
||||
|
||||
// Add query parameters
|
||||
if (!empty($queryParams)) {
|
||||
$basePath .= '?' . http_build_query($queryParams);
|
||||
}
|
||||
|
||||
return $basePath;
|
||||
}
|
||||
}
|
||||
|
||||
239
app/Controllers/PlayniteImportController.php
Normal file
239
app/Controllers/PlayniteImportController.php
Normal file
@@ -0,0 +1,239 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use App\Services\PlayniteImportService;
|
||||
use Slim\Views\Twig;
|
||||
|
||||
class PlayniteImportController extends Controller
|
||||
{
|
||||
private \PDO $pdo;
|
||||
private PlayniteImportService $importService;
|
||||
protected $auth;
|
||||
|
||||
public function __construct(\PDO $pdo, Twig $view, $auth = null)
|
||||
{
|
||||
parent::__construct($view, $auth);
|
||||
$this->pdo = $pdo;
|
||||
$this->importService = new PlayniteImportService($pdo);
|
||||
$this->auth = $auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the import form
|
||||
*/
|
||||
public function showImport(Request $request, Response $response, $args)
|
||||
{
|
||||
return $this->view->render($response, 'admin/playnite/import.twig', [
|
||||
'title' => 'Import Playnite Games',
|
||||
'csrf_token' => $this->generateCSRFToken()
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle file upload and preview
|
||||
*/
|
||||
public function upload(Request $request, Response $response, $args)
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
$csrfToken = $data['csrf_token'] ?? '';
|
||||
|
||||
// Verify CSRF token
|
||||
if (!$this->verifyCSRFToken($csrfToken)) {
|
||||
return $this->view->render($response->withStatus(400), 'admin/playnite/import.twig', [
|
||||
'title' => 'Import Playnite Games',
|
||||
'error' => 'Invalid CSRF token',
|
||||
'csrf_token' => $this->generateCSRFToken()
|
||||
]);
|
||||
}
|
||||
|
||||
$uploadedFiles = $request->getUploadedFiles();
|
||||
|
||||
if (empty($uploadedFiles['playnite_file'])) {
|
||||
return $this->view->render($response->withStatus(400), 'admin/playnite/import.twig', [
|
||||
'title' => 'Import Playnite Games',
|
||||
'error' => 'No file uploaded',
|
||||
'csrf_token' => $this->generateCSRFToken()
|
||||
]);
|
||||
}
|
||||
|
||||
$file = $uploadedFiles['playnite_file'];
|
||||
|
||||
// Validate file
|
||||
if ($file->getError() !== UPLOAD_ERR_OK) {
|
||||
return $this->view->render($response->withStatus(400), 'admin/playnite/import.twig', [
|
||||
'title' => 'Import Playnite Games',
|
||||
'error' => 'Upload error: ' . $this->getUploadErrorMessage($file->getError()),
|
||||
'csrf_token' => $this->generateCSRFToken()
|
||||
]);
|
||||
}
|
||||
|
||||
// Check file type
|
||||
$filename = $file->getClientFilename();
|
||||
$extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
|
||||
|
||||
if (!in_array($extension, ['json'])) {
|
||||
return $this->view->render($response->withStatus(400), 'admin/playnite/import.twig', [
|
||||
'title' => 'Import Playnite Games',
|
||||
'error' => 'Only JSON files are supported',
|
||||
'csrf_token' => $this->generateCSRFToken()
|
||||
]);
|
||||
}
|
||||
|
||||
// Move uploaded file to temp location
|
||||
$tempPath = sys_get_temp_dir() . '/playnite_import_' . uniqid() . '.json';
|
||||
$file->moveTo($tempPath);
|
||||
|
||||
try {
|
||||
// Parse and validate the file
|
||||
$result = $this->importService->parsePlayniteFile($tempPath);
|
||||
|
||||
// Store the temp file path and results in session for the confirmation step
|
||||
$_SESSION['playnite_import'] = [
|
||||
'temp_file' => $tempPath,
|
||||
'preview_data' => $result
|
||||
];
|
||||
|
||||
return $this->view->render($response, 'admin/playnite/preview.twig', [
|
||||
'title' => 'Preview Playnite Import',
|
||||
'preview' => $result,
|
||||
'filename' => $filename
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
// Clean up temp file
|
||||
if (file_exists($tempPath)) {
|
||||
unlink($tempPath);
|
||||
}
|
||||
|
||||
return $this->view->render($response->withStatus(400), 'admin/playnite/import.twig', [
|
||||
'title' => 'Import Playnite Games',
|
||||
'error' => 'Error parsing file: ' . $e->getMessage(),
|
||||
'csrf_token' => $this->generateCSRFToken()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm and execute the import
|
||||
*/
|
||||
public function confirm(Request $request, Response $response, $args)
|
||||
{
|
||||
if (!isset($_SESSION['playnite_import'])) {
|
||||
return $response->withRedirect($this->getRoutePath('admin.playnite.import'));
|
||||
}
|
||||
|
||||
$importData = $_SESSION['playnite_import'];
|
||||
$tempPath = $importData['temp_file'];
|
||||
$previewData = $importData['preview_data'];
|
||||
|
||||
// Get import options from form
|
||||
$queryParams = $request->getQueryParams();
|
||||
$updateExisting = ($queryParams['update_existing'] ?? 'false') === 'true';
|
||||
|
||||
try {
|
||||
// Execute the import
|
||||
$importResult = $this->importService->importGames($previewData['games'], $updateExisting);
|
||||
|
||||
// Clean up temp file
|
||||
if (file_exists($tempPath)) {
|
||||
unlink($tempPath);
|
||||
}
|
||||
|
||||
// Clear session data
|
||||
unset($_SESSION['playnite_import']);
|
||||
|
||||
return $this->view->render($response, 'admin/playnite/result.twig', [
|
||||
'title' => 'Import Complete',
|
||||
'import_result' => $importResult,
|
||||
'preview_data' => $previewData
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
// Clean up temp file
|
||||
if (file_exists($tempPath)) {
|
||||
unlink($tempPath);
|
||||
}
|
||||
|
||||
// Clear session data
|
||||
unset($_SESSION['playnite_import']);
|
||||
|
||||
return $this->view->render($response->withStatus(500), 'admin/playnite/import.twig', [
|
||||
'title' => 'Import Playnite Games',
|
||||
'error' => 'Import failed: ' . $e->getMessage(),
|
||||
'csrf_token' => $this->generateCSRFToken()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the import (cleanup)
|
||||
*/
|
||||
public function cancel(Request $request, Response $response, $args)
|
||||
{
|
||||
if (isset($_SESSION['playnite_import'])) {
|
||||
$tempPath = $_SESSION['playnite_import']['temp_file'];
|
||||
if (file_exists($tempPath)) {
|
||||
unlink($tempPath);
|
||||
}
|
||||
unset($_SESSION['playnite_import']);
|
||||
}
|
||||
|
||||
return $response->withRedirect($this->getRoutePath('admin.playnite.import'));
|
||||
}
|
||||
|
||||
/**
|
||||
* API endpoint for programmatic imports
|
||||
*/
|
||||
public function apiImport(Request $request, Response $response, $args)
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
if (!isset($data['games']) || !is_array($data['games'])) {
|
||||
return $this->jsonResponse($response->withStatus(400), [
|
||||
'error' => 'Games data is required'
|
||||
]);
|
||||
}
|
||||
|
||||
try {
|
||||
$importResult = $this->importService->importGames($data['games'], $data['update_existing'] ?? true);
|
||||
|
||||
return $this->jsonResponse($response, [
|
||||
'success' => true,
|
||||
'result' => $importResult
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return $this->jsonResponse($response->withStatus(500), [
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get upload error message
|
||||
*/
|
||||
private function getUploadErrorMessage(int $errorCode): string
|
||||
{
|
||||
switch ($errorCode) {
|
||||
case UPLOAD_ERR_INI_SIZE:
|
||||
return 'File too large (exceeds server limit)';
|
||||
case UPLOAD_ERR_FORM_SIZE:
|
||||
return 'File too large (exceeds form limit)';
|
||||
case UPLOAD_ERR_PARTIAL:
|
||||
return 'File only partially uploaded';
|
||||
case UPLOAD_ERR_NO_FILE:
|
||||
return 'No file uploaded';
|
||||
case UPLOAD_ERR_NO_TMP_DIR:
|
||||
return 'No temporary directory';
|
||||
case UPLOAD_ERR_CANT_WRITE:
|
||||
return 'Cannot write to disk';
|
||||
case UPLOAD_ERR_EXTENSION:
|
||||
return 'File upload stopped by extension';
|
||||
default:
|
||||
return 'Unknown upload error';
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user