mirror of
https://github.com/ceratic/MediaCollectorLibary.git
synced 2026-05-13 23:56:46 +02:00
tada
This commit is contained in:
@@ -132,26 +132,65 @@ class AdminController extends Controller
|
|||||||
|
|
||||||
private function startSync(array $source, string $syncType): int
|
private function startSync(array $source, string $syncType): int
|
||||||
{
|
{
|
||||||
// Create appropriate sync service based on source type
|
// Create sync log entry first
|
||||||
switch ($source['name']) {
|
$syncLogId = $this->createSyncLog($source, $syncType);
|
||||||
case 'steam':
|
|
||||||
$syncService = new SteamSyncService($this->pdo, $source);
|
// Start sync in background process
|
||||||
break;
|
$this->startBackgroundSync($source['id'], $syncType, $syncLogId);
|
||||||
case 'jellyfin':
|
|
||||||
$syncService = new JellyfinSyncService($this->pdo, $source);
|
return $syncLogId;
|
||||||
break;
|
|
||||||
case 'stash':
|
|
||||||
$syncService = new StashSyncService($this->pdo, $source);
|
|
||||||
break;
|
|
||||||
case 'adult':
|
|
||||||
$syncService = new AdultSyncService($this->pdo, $source);
|
|
||||||
break;
|
|
||||||
case 'xbvr':
|
|
||||||
$syncService = new XbvrSyncService($this->pdo, $source);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start sync (this would typically be queued in production)
|
private function createSyncLog(array $source, string $syncType): int
|
||||||
return $syncService->startSync($syncType);
|
{
|
||||||
|
$data = [
|
||||||
|
'source_id' => $source['id'],
|
||||||
|
'sync_type' => $syncType,
|
||||||
|
'status' => 'started',
|
||||||
|
'total_items' => 0,
|
||||||
|
'processed_items' => 0,
|
||||||
|
'new_items' => 0,
|
||||||
|
'updated_items' => 0,
|
||||||
|
'deleted_items' => 0,
|
||||||
|
'started_at' => date('Y-m-d H:i:s')
|
||||||
|
];
|
||||||
|
|
||||||
|
$columns = array_keys($data);
|
||||||
|
$placeholders = array_map(fn($col) => ":$col", $columns);
|
||||||
|
$sql = "INSERT INTO sync_logs (" . implode(', ', $columns) . ") VALUES (" . implode(', ', $placeholders) . ")";
|
||||||
|
|
||||||
|
$stmt = $this->pdo->prepare($sql);
|
||||||
|
$stmt->execute($data);
|
||||||
|
|
||||||
|
return (int) $this->pdo->lastInsertId();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function startBackgroundSync(int $sourceId, string $syncType, int $syncLogId): void
|
||||||
|
{
|
||||||
|
$scriptPath = __DIR__ . '/../../sync-runner.php';
|
||||||
|
$command = sprintf(
|
||||||
|
'php %s %d %s %d > /dev/null 2>&1 &',
|
||||||
|
escapeshellarg($scriptPath),
|
||||||
|
$sourceId,
|
||||||
|
escapeshellarg($syncType),
|
||||||
|
$syncLogId
|
||||||
|
);
|
||||||
|
|
||||||
|
// Execute the command in background
|
||||||
|
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
|
||||||
|
// Windows
|
||||||
|
pclose(popen('start /B ' . $command, 'r'));
|
||||||
|
} else {
|
||||||
|
// Unix-like systems
|
||||||
|
exec($command);
|
||||||
|
}
|
||||||
|
|
||||||
|
// */
|
||||||
|
// Update sync log to indicate it's running (this will be updated again by the script)
|
||||||
|
$syncLogModel = new SyncLog($this->pdo);
|
||||||
|
$syncLogModel->update($syncLogId, [
|
||||||
|
'status' => 'running',
|
||||||
|
'message' => 'Sync process starting in background'
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,14 +6,26 @@
|
|||||||
<title>{{ title }} - Media Collector</title>
|
<title>{{ title }} - Media Collector</title>
|
||||||
<!-- Bootstrap CSS CDN -->
|
<!-- Bootstrap CSS CDN -->
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<!-- In the head section of app.twig -->
|
||||||
{% if app_env == 'production' %}
|
{% if app_env == 'production' %}
|
||||||
<link rel="stylesheet" href="{{ base_url() }}/build/assets/app-{{ manifest['resources/js/app.js'].file|replace({'.js': '.css'}) }}">
|
{% if manifest['resources/css/app.css'] is defined %}
|
||||||
|
<link rel="stylesheet" href="{{ base_url() }}/build/assets/{{ manifest['resources/css/app.css'].file }}">
|
||||||
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<link rel="stylesheet" href="{{ base_url() }}/app.css">
|
<link rel="stylesheet" href="{{ base_url() }}/public/css/app.css">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<!-- Favicon -->
|
<!-- Favicon -->
|
||||||
<link rel="icon" type="image/svg+xml" href="{{ base_url() }}/favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="{{ base_url() }}/favicon.svg">
|
||||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
|
<!-- In the head section -->
|
||||||
|
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||||
|
<!-- Before closing </head> tag -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
{% if app_env == 'production' and manifest['resources/js/app.js'] is defined %}
|
||||||
|
<script type="module" src="{{ base_url() }}/build/assets/{{ manifest['resources/js/app.js'].file }}"></script>
|
||||||
|
{% else %}
|
||||||
|
<script type="module" src="{{ base_url() }}/resources/js/app.js"></script>
|
||||||
|
{% endif %}
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-light">
|
<body class="bg-light">
|
||||||
<!-- Navigation -->
|
<!-- Navigation -->
|
||||||
@@ -88,15 +100,5 @@
|
|||||||
<main class="container-fluid py-4">
|
<main class="container-fluid py-4">
|
||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<!-- Scripts -->
|
|
||||||
{% if app_env == 'production' %}
|
|
||||||
<script type="module" src="{{ base_url() }}/build/assets/{{ manifest['resources/js/app.js'].file }}"></script>
|
|
||||||
{% else %}
|
|
||||||
<script type="module" src="{{ base_url() }}/resources/js/app.js"></script>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Bootstrap JS -->
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
3
run_migrations.bat
Normal file
3
run_migrations.bat
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
@echo off
|
||||||
|
cd /d "%~dp0"
|
||||||
|
php run_migrations.php
|
||||||
165
sync-runner.php
Normal file
165
sync-runner.php
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__ . '/vendor/autoload.php';
|
||||||
|
|
||||||
|
// Load helper functions
|
||||||
|
require_once __DIR__ . '/app/helpers.php';
|
||||||
|
|
||||||
|
// Load environment variables
|
||||||
|
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
|
||||||
|
$dotenv->load();
|
||||||
|
|
||||||
|
// Load database configuration
|
||||||
|
$dbConfig = require __DIR__ . '/config/database.php';
|
||||||
|
\App\Database\Database::setConfig($dbConfig);
|
||||||
|
|
||||||
|
// Initialize database
|
||||||
|
try {
|
||||||
|
$pdo = \App\Database\Database::getInstance();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo "Database connection failed: " . $e->getMessage() . "\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Get command line arguments
|
||||||
|
$args = $argv;
|
||||||
|
array_shift($args); // Remove script name
|
||||||
|
|
||||||
|
if (count($args) < 3) {
|
||||||
|
echo "Usage: php sync-runner.php <source_id> <sync_type> <sync_log_id> [--no-output]\n";
|
||||||
|
echo "Example: php sync-runner.php 1 full 123\n";
|
||||||
|
echo "Example: php sync-runner.php 2 incremental 124 --no-output\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sourceId = (int) $args[0];
|
||||||
|
$syncType = $args[1];
|
||||||
|
$syncLogId = (int) $args[2];
|
||||||
|
$noOutput = in_array('--no-output', $args);
|
||||||
|
|
||||||
|
// Initialize PDO connection
|
||||||
|
try {
|
||||||
|
$pdo = \App\Database\Database::getInstance();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo "Database connection failed: " . $e->getMessage() . "\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get source information
|
||||||
|
$sourceModel = new Source($pdo);
|
||||||
|
$source = $sourceModel->find($sourceId);
|
||||||
|
|
||||||
|
if (!$source) {
|
||||||
|
echo "Source with ID {$sourceId} not found.\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert source array to expected format for sync services
|
||||||
|
$sourceData = [
|
||||||
|
'id' => $source['id'],
|
||||||
|
'name' => $source['name'],
|
||||||
|
'display_name' => $source['display_name'],
|
||||||
|
'api_url' => $source['api_url'],
|
||||||
|
'api_key' => $source['api_key'],
|
||||||
|
'config' => $source['config'],
|
||||||
|
'is_active' => $source['is_active'],
|
||||||
|
'last_sync_at' => $source['last_sync_at']
|
||||||
|
];
|
||||||
|
|
||||||
|
// Validate sync type
|
||||||
|
if ($source['name'] === 'jellyfin') {
|
||||||
|
$validSyncTypes = ['full', 'incremental', 'all', 'movies', 'tvshows'];
|
||||||
|
if (!in_array($syncType, $validSyncTypes)) {
|
||||||
|
echo "Invalid sync type for Jellyfin source. Valid types: " . implode(', ', $validSyncTypes) . "\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$validSyncTypes = ['full', 'incremental'];
|
||||||
|
if (!in_array($syncType, $validSyncTypes)) {
|
||||||
|
echo "Invalid sync type. Valid types: " . implode(', ', $validSyncTypes) . "\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create appropriate sync service based on source type
|
||||||
|
$syncService = null;
|
||||||
|
switch ($source['name']) {
|
||||||
|
case 'steam':
|
||||||
|
$syncService = new SteamSyncService($pdo, $sourceData);
|
||||||
|
break;
|
||||||
|
case 'jellyfin':
|
||||||
|
$syncService = new JellyfinSyncService($pdo, $sourceData);
|
||||||
|
break;
|
||||||
|
case 'stash':
|
||||||
|
$syncService = new StashSyncService($pdo, $sourceData);
|
||||||
|
break;
|
||||||
|
case 'adult':
|
||||||
|
$syncService = new AdultSyncService($pdo, $sourceData);
|
||||||
|
break;
|
||||||
|
case 'xbvr':
|
||||||
|
$syncService = new XbvrSyncService($pdo, $sourceData);
|
||||||
|
break;
|
||||||
|
case 'exophase':
|
||||||
|
$syncService = new ExophaseSyncService($pdo, $sourceData);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
echo "Unsupported source type: " . $source['name'] . "\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$noOutput) {
|
||||||
|
echo "Starting {$syncType} sync for source: " . ($source['display_name'] ?? $source['name']) . "\n";
|
||||||
|
echo "Source ID: {$sourceId}\n";
|
||||||
|
echo "Sync Type: {$syncType}\n";
|
||||||
|
echo "Sync Log ID: {$syncLogId}\n";
|
||||||
|
echo "Timestamp: " . date('Y-m-d H:i:s') . "\n";
|
||||||
|
echo "----------------------------------------\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update sync log to running status first
|
||||||
|
$syncLogModel = new SyncLog($pdo);
|
||||||
|
$syncLogModel->update($syncLogId, [
|
||||||
|
'status' => 'running',
|
||||||
|
'message' => 'Sync process started in background'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Execute the sync
|
||||||
|
try {
|
||||||
|
$syncLogId = $syncService->startSync($syncType);
|
||||||
|
|
||||||
|
if (!$noOutput) {
|
||||||
|
echo "Sync started with log ID: {$syncLogId}\n";
|
||||||
|
echo "Monitor progress at: /admin/sync/status/{$syncLogId}\n";
|
||||||
|
echo "Sync completed successfully.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
if (!$noOutput) {
|
||||||
|
echo "ERROR: Sync failed - " . $e->getMessage() . "\n";
|
||||||
|
echo "File: " . $e->getFile() . ":" . $e->getLine() . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update sync log as failed
|
||||||
|
$syncLogModel->update($syncLogId, [
|
||||||
|
'status' => 'failed',
|
||||||
|
'completed_at' => date('Y-m-d H:i:s'),
|
||||||
|
'message' => $e->getMessage(),
|
||||||
|
'errors' => json_encode([
|
||||||
|
$e->getMessage(),
|
||||||
|
"File: " . $e->getFile() . ":" . $e->getLine()
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user