Files
MediaCollectorLibary/app/Controllers/PlayniteImportController.php
Lars Behrends 218d0c28c0 impoort stuff!
2025-10-24 16:04:34 +02:00

240 lines
7.9 KiB
PHP

<?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';
}
}
}