mirror of
https://github.com/ceratic/MediaCollectorLibary.git
synced 2026-05-13 23:56:46 +02:00
297 lines
9.9 KiB
PHP
297 lines
9.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 App\Services\PlayniteSyncService;
|
|
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';
|
|
|
|
// Create a source entry for Playnite if it doesn't exist
|
|
$source = $this->getOrCreatePlayniteSource();
|
|
|
|
// Initialize the sync service with logging
|
|
$syncService = new PlayniteSyncService($this->pdo, $source);
|
|
|
|
try {
|
|
// Start the sync process (this will create a sync log entry)
|
|
$syncLogId = $syncService->startSync('import');
|
|
|
|
// Store the sync log ID in the session so we can update it later
|
|
$_SESSION['playnite_import']['sync_log_id'] = $syncLogId;
|
|
|
|
// Execute the import through the sync service
|
|
$importResult = $syncService->importGames($previewData['games'], $updateExisting);
|
|
|
|
// Get the log file path to show to the user
|
|
$logFilePath = $syncService->getLogFilePath();
|
|
|
|
// 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,
|
|
'log_file' => $logFilePath,
|
|
'sync_log_id' => $syncLogId
|
|
]);
|
|
|
|
} catch (\Exception $e) {
|
|
// Log the error
|
|
if (isset($syncService)) {
|
|
$syncService->logProgress("ERROR: " . $e->getMessage());
|
|
$logFilePath = $syncService->getLogFilePath();
|
|
}
|
|
|
|
// 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(),
|
|
'log_file' => $logFilePath ?? null,
|
|
'csrf_token' => $this->generateCSRFToken()
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get or create a source for Playnite
|
|
*/
|
|
private function getOrCreatePlayniteSource(): array
|
|
{
|
|
$stmt = $this->pdo->prepare("
|
|
SELECT id, name, display_name
|
|
FROM sources
|
|
WHERE name = 'playnite' OR display_name = 'Playnite'
|
|
LIMIT 1
|
|
");
|
|
$stmt->execute();
|
|
|
|
$source = $stmt->fetch(\PDO::FETCH_ASSOC);
|
|
|
|
if (!$source) {
|
|
$stmt = $this->pdo->prepare("
|
|
INSERT INTO sources (name, display_name, created_at, updated_at)
|
|
VALUES ('playnite', 'Playnite', NOW(), NOW())
|
|
");
|
|
$stmt->execute();
|
|
|
|
$source = [
|
|
'id' => $this->pdo->lastInsertId(),
|
|
'name' => 'playnite',
|
|
'display_name' => 'Playnite'
|
|
];
|
|
}
|
|
|
|
return $source;
|
|
}
|
|
|
|
/**
|
|
* 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';
|
|
}
|
|
}
|
|
}
|