mirror of
https://github.com/ceratic/MediaCollectorLibary.git
synced 2026-05-13 23:56:46 +02:00
i dont know
This commit is contained in:
@@ -790,7 +790,7 @@ class JellyfinSyncService extends BaseSyncService
|
||||
|
||||
try {
|
||||
// Create images directory structure if it doesn't exist
|
||||
$imagesDir = "public/images/{$type}";
|
||||
$imagesDir = __DIR__ . "/../../storage/images/{$type}";
|
||||
if (!is_dir($imagesDir)) {
|
||||
if (!mkdir($imagesDir, 0755, true)) {
|
||||
$this->logProgress("Warning: Could not create images directory: {$imagesDir}");
|
||||
|
||||
313
app/Services/LocalSyncService.php
Normal file
313
app/Services/LocalSyncService.php
Normal file
@@ -0,0 +1,313 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\MediaItem;
|
||||
use App\Models\SyncLog;
|
||||
use Exception;
|
||||
use RecursiveDirectoryIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
use SplFileInfo;
|
||||
|
||||
class LocalSyncService extends BaseSyncService implements SyncServiceInterface
|
||||
{
|
||||
protected string $sourceType = 'local';
|
||||
|
||||
/**
|
||||
* @var array Supported file extensions for each media type
|
||||
*/
|
||||
protected array $supportedExtensions = [
|
||||
'movies' => ['mp4', 'mkv', 'avi', 'mov', 'wmv', 'flv', 'm4v', 'mpg', 'mpeg'],
|
||||
'tv_shows' => ['mp4', 'mkv', 'avi', 'mov', 'wmv', 'flv', 'm4v', 'mpg', 'mpeg'],
|
||||
'music' => ['mp3', 'flac', 'wav', 'aac', 'ogg', 'm4a'],
|
||||
'games' => ['iso', 'rom', 'nsp', 'xci', 'rvz', 'ciso', 'gcm', 'wbfs'],
|
||||
'books' => ['epub', 'mobi', 'pdf', 'azw', 'azw3', 'djvu'],
|
||||
'pictures' => ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'tiff', 'raw']
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function sync($source, string $type = 'full', callable $progressCallback = null): array
|
||||
{
|
||||
$this->source = $source;
|
||||
$this->sourceId = $source['id'] ?? null;
|
||||
|
||||
if (!$this->sourceId) {
|
||||
throw new Exception('Source ID is required for sync');
|
||||
}
|
||||
|
||||
try {
|
||||
$this->logProgress("Starting {$type} sync for local source: " . ($source['name'] ?? 'Unknown'));
|
||||
|
||||
$path = $source['path'] ?? null;
|
||||
if (empty($path) || !is_dir($path)) {
|
||||
throw new Exception("Invalid or inaccessible source path: {$path}");
|
||||
}
|
||||
|
||||
// Determine the media type from the source configuration
|
||||
$mediaType = $this->determineMediaType($source);
|
||||
|
||||
// Get all files from the source directory recursively
|
||||
$files = $this->scanDirectory($path, $mediaType);
|
||||
$this->logProgress(sprintf('Found %d files to process', count($files)));
|
||||
|
||||
// Get existing media items from the database
|
||||
$existingItems = $this->getExistingMediaItems($mediaType);
|
||||
$this->logProgress(sprintf('Found %d existing items in database', count($existingItems)));
|
||||
|
||||
$result = [
|
||||
'total_items' => count($files),
|
||||
'processed_items' => 0,
|
||||
'new_items' => 0,
|
||||
'updated_items' => 0,
|
||||
'deleted_items' => 0,
|
||||
'errors' => []
|
||||
];
|
||||
|
||||
// Process each file
|
||||
foreach ($files as $filePath => $fileInfo) {
|
||||
try {
|
||||
$relativePath = $this->getRelativePath($path, $filePath);
|
||||
$fileKey = $this->generateFileKey($relativePath, $fileInfo);
|
||||
|
||||
if (isset($existingItems[$fileKey])) {
|
||||
// Update existing item if needed
|
||||
$item = $existingItems[$fileKey];
|
||||
$updated = $this->updateMediaItem($item, $filePath, $fileInfo, $mediaType);
|
||||
|
||||
if ($updated) {
|
||||
$result['updated_items']++;
|
||||
$this->logProgress("Updated: {$relativePath}");
|
||||
}
|
||||
|
||||
// Remove from existing items to track deletions
|
||||
unset($existingItems[$fileKey]);
|
||||
} else {
|
||||
// Add new item
|
||||
$this->createMediaItem($filePath, $fileInfo, $mediaType, $relativePath);
|
||||
$result['new_items']++;
|
||||
$this->logProgress("Added: {$relativePath}");
|
||||
}
|
||||
|
||||
$result['processed_items']++;
|
||||
|
||||
// Update progress
|
||||
if ($progressCallback) {
|
||||
$progress = (int)(($result['processed_items'] / $result['total_items']) * 100);
|
||||
$progressCallback($progress, "Processing: {$relativePath}");
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$errorMsg = "Error processing {$filePath}: " . $e->getMessage();
|
||||
$this->logProgress($errorMsg, 'ERROR');
|
||||
$result['errors'][] = $errorMsg;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle deleted files
|
||||
if ($type === 'full' && !empty($existingItems)) {
|
||||
foreach ($existingItems as $item) {
|
||||
try {
|
||||
$this->deleteMediaItem($item, $mediaType);
|
||||
$result['deleted_items']++;
|
||||
$this->logProgress("Deleted: {$item['file_path']}");
|
||||
} catch (\Exception $e) {
|
||||
$errorMsg = "Error deleting {$item['file_path']}: " . $e->getMessage();
|
||||
$this->logProgress($errorMsg, 'ERROR');
|
||||
$result['errors'][] = $errorMsg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->logProgress("Sync completed successfully");
|
||||
|
||||
return array_merge($result, [
|
||||
'success' => true,
|
||||
'message' => 'Sync completed successfully',
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$errorMsg = 'Sync failed: ' . $e->getMessage();
|
||||
$this->logProgress($errorMsg, 'ERROR');
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => $errorMsg,
|
||||
'errors' => [$errorMsg]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getSupportedTypes(): array
|
||||
{
|
||||
return ['local', 'file'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the media type from the source configuration
|
||||
*/
|
||||
protected function determineMediaType(array $source): string
|
||||
{
|
||||
// First check if media_type is explicitly set in the source config
|
||||
if (!empty($source['media_type'])) {
|
||||
return strtolower($source['media_type']);
|
||||
}
|
||||
|
||||
// Otherwise, try to guess from the path or name
|
||||
$path = strtolower($source['path'] ?? '');
|
||||
$name = strtolower($source['name'] ?? '');
|
||||
|
||||
foreach (array_keys($this->supportedExtensions) as $type) {
|
||||
if (strpos($path, $type) !== false || strpos($name, $type) !== false) {
|
||||
return $type;
|
||||
}
|
||||
}
|
||||
|
||||
// Default to 'other' if we can't determine the type
|
||||
return 'other';
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan a directory recursively for media files
|
||||
*/
|
||||
protected function scanDirectory(string $path, string $mediaType): array
|
||||
{
|
||||
$files = [];
|
||||
$extensions = $this->supportedExtensions[$mediaType] ?? [];
|
||||
|
||||
$iterator = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS),
|
||||
RecursiveIteratorIterator::SELF_FIRST
|
||||
);
|
||||
|
||||
/** @var SplFileInfo $file */
|
||||
foreach ($iterator as $file) {
|
||||
if ($file->isFile()) {
|
||||
$ext = strtolower($file->getExtension());
|
||||
|
||||
// If we have specific extensions for this media type, filter by them
|
||||
if (!empty($extensions) && !in_array($ext, $extensions)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$files[$file->getPathname()] = [
|
||||
'size' => $file->getSize(),
|
||||
'modified' => $file->getMTime(),
|
||||
'extension' => $ext,
|
||||
'path' => $file->getPathname(),
|
||||
'filename' => $file->getFilename()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get existing media items from the database
|
||||
*/
|
||||
protected function getExistingMediaItems(string $mediaType): array
|
||||
{
|
||||
$mediaItem = new MediaItem($this->pdo);
|
||||
$items = $mediaItem->where('source_id', $this->sourceId)
|
||||
->where('media_type', $mediaType)
|
||||
->get();
|
||||
|
||||
$result = [];
|
||||
foreach ($items as $item) {
|
||||
$result[$item['file_key']] = $item;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a unique key for a file
|
||||
*/
|
||||
protected function generateFileKey(string $relativePath, array $fileInfo): string
|
||||
{
|
||||
return md5($relativePath . $fileInfo['size'] . $fileInfo['modified']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the relative path from the base path
|
||||
*/
|
||||
protected function getRelativePath(string $basePath, string $filePath): string
|
||||
{
|
||||
return ltrim(str_replace('\\', '/', substr($filePath, strlen($basePath))), '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new media item in the database
|
||||
*/
|
||||
protected function createMediaItem(string $filePath, array $fileInfo, string $mediaType, string $relativePath): void
|
||||
{
|
||||
$mediaItem = new MediaItem($this->pdo);
|
||||
|
||||
$data = [
|
||||
'source_id' => $this->sourceId,
|
||||
'media_type' => $mediaType,
|
||||
'file_path' => $relativePath,
|
||||
'file_name' => $fileInfo['filename'],
|
||||
'file_size' => $fileInfo['size'],
|
||||
'file_modified' => date('Y-m-d H:i:s', $fileInfo['modified']),
|
||||
'file_extension' => $fileInfo['extension'],
|
||||
'file_key' => $this->generateFileKey($relativePath, $fileInfo),
|
||||
'metadata' => json_encode([
|
||||
'original_path' => $filePath,
|
||||
'imported_at' => date('Y-m-d H:i:s')
|
||||
]),
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s')
|
||||
];
|
||||
|
||||
$mediaItem->create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing media item if needed
|
||||
*/
|
||||
protected function updateMediaItem(array $item, string $filePath, array $fileInfo, string $mediaType): bool
|
||||
{
|
||||
$needsUpdate = false;
|
||||
$updates = [];
|
||||
|
||||
// Check if file has been modified
|
||||
if ($item['file_size'] != $fileInfo['size'] ||
|
||||
$item['file_modified'] != date('Y-m-d H:i:s', $fileInfo['modified'])) {
|
||||
|
||||
$updates = [
|
||||
'file_size' => $fileInfo['size'],
|
||||
'file_modified' => date('Y-m-d H:i:s', $fileInfo['modified']),
|
||||
'updated_at' => date('Y-m-d H:i:s')
|
||||
];
|
||||
$needsUpdate = true;
|
||||
}
|
||||
|
||||
// Update metadata if needed
|
||||
$metadata = json_decode($item['metadata'] ?? '{}', true);
|
||||
$metadata['last_checked'] = date('Y-m-d H:i:s');
|
||||
$updates['metadata'] = json_encode($metadata);
|
||||
|
||||
if ($needsUpdate) {
|
||||
$mediaItem = new MediaItem($this->pdo);
|
||||
$mediaItem->update($item['id'], $updates);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a media item from the database
|
||||
*/
|
||||
protected function deleteMediaItem(array $item, string $mediaType): void
|
||||
{
|
||||
$mediaItem = new MediaItem($this->pdo);
|
||||
$mediaItem->delete($item['id']);
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ class StashSyncService extends BaseSyncService
|
||||
'verify' => false // Disable SSL verification for problematic servers
|
||||
]);
|
||||
|
||||
$this->imageDownloader = new ImageDownloader('public/images', $this->apiKey);
|
||||
$this->imageDownloader = new ImageDownloader(__DIR__ . '/../../storage/images', $this->apiKey);
|
||||
}
|
||||
|
||||
protected function executeSync(string $syncType): void
|
||||
|
||||
23
app/Services/SyncServiceInterface.php
Normal file
23
app/Services/SyncServiceInterface.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
interface SyncServiceInterface
|
||||
{
|
||||
/**
|
||||
* Synchronize media from the source
|
||||
*
|
||||
* @param array $source The source configuration
|
||||
* @param string $type Sync type (full, scan, update)
|
||||
* @param callable $progressCallback Callback for progress updates
|
||||
* @return array Result of the sync operation
|
||||
*/
|
||||
public function sync($source, string $type = 'full', callable $progressCallback = null): array;
|
||||
|
||||
/**
|
||||
* Get the supported source types
|
||||
*
|
||||
* @return array Array of supported source types
|
||||
*/
|
||||
public function getSupportedTypes(): array;
|
||||
}
|
||||
@@ -30,7 +30,7 @@ class XbvrSyncService extends BaseSyncService
|
||||
]
|
||||
]);
|
||||
|
||||
$this->imageDownloader = new ImageDownloader('public/images');
|
||||
$this->imageDownloader = new ImageDownloader(__DIR__ . '/../../storage/images');
|
||||
}
|
||||
|
||||
protected function executeSync(string $syncType): void
|
||||
|
||||
Reference in New Issue
Block a user