diff --git a/app/Services/StashSyncService.php b/app/Services/StashSyncService.php
index 3a9bddc..cf9b392 100644
--- a/app/Services/StashSyncService.php
+++ b/app/Services/StashSyncService.php
@@ -57,6 +57,45 @@ class StashSyncService extends BaseSyncService
$this->logProgress("Processed {$this->processedCount} Stash items");
}
+ /**
+ * Check if a scene should be ignored based on file paths and ignore patterns in config
+ */
+ private function shouldIgnoreScene(array $sceneData): bool
+ {
+ $config = $this->source['config'] ?? null;
+ if (empty($config)) {
+ return false;
+ }
+
+ $configData = json_decode($config, true);
+ if (json_last_error() !== JSON_ERROR_NONE) {
+ $this->logProgress('Invalid JSON in source config, skipping ignore check');
+ return false;
+ }
+
+ $ignorePaths = $configData['ignore_paths'] ?? [];
+ if (empty($ignorePaths) || !is_array($ignorePaths)) {
+ return false;
+ }
+
+ $files = $sceneData['files'] ?? [];
+ foreach ($files as $file) {
+ $filePath = $file['path'] ?? '';
+ if (empty($filePath)) {
+ continue;
+ }
+
+ foreach ($ignorePaths as $ignorePattern) {
+ if (stripos($filePath, $ignorePattern) !== false) {
+ $this->logProgress("Scene '{$sceneData['title']}' ignored due to file path containing: '{$ignorePattern}'");
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
private function syncScenes(): void
{
try {
@@ -91,6 +130,20 @@ class StashSyncService extends BaseSyncService
foreach ($scenes as $sceneData) {
try {
$this->logProgress("Processing scene: {$sceneData['title']} (ID: {$sceneData['id']})");
+
+ // Check if scene should be ignored based on file paths
+ if ($this->shouldIgnoreScene($sceneData)) {
+ $this->processedCount++; // Still count as processed
+ // Update progress for ignored items
+ $this->updateSyncLog($this->currentSyncLogId, 'running', [
+ 'processed_items' => $this->processedCount,
+ 'new_items' => $this->newCount,
+ 'updated_items' => $this->updatedCount,
+ 'message' => "Processed {$this->processedCount} of ~{$totalCount} scenes (ignored)"
+ ]);
+ continue;
+ }
+
$this->syncScene($sceneData);
$this->processedCount++;
@@ -210,6 +263,7 @@ class StashSyncService extends BaseSyncService
audio_codec
width
height
+ path
}
performers {
id
diff --git a/app/Services/XbvrSyncService.php b/app/Services/XbvrSyncService.php
index 256e30b..d92ecab 100644
--- a/app/Services/XbvrSyncService.php
+++ b/app/Services/XbvrSyncService.php
@@ -55,6 +55,7 @@ class XbvrSyncService extends BaseSyncService
foreach ($scenes as $sceneData) {
try {
$this->syncScene($sceneData);
+ $this->logProgress("Success Synced XBVR scene {$sceneData['id']}");
$this->processedCount++;
} catch (Exception $e) {
$this->logProgress("Error processing XBVR scene {$sceneData['id']}: " . $e->getMessage());
@@ -126,7 +127,7 @@ class XbvrSyncService extends BaseSyncService
}
// Add small delay to be respectful to the API
- usleep(100000); // 0.1 second delay
+ //usleep(100000); // 0.1 second delay
} catch (Exception $e) {
$this->logProgress("Error fetching details for video: " . $e->getMessage());
@@ -458,194 +459,44 @@ class XbvrSyncService extends BaseSyncService
return $actorData;
}
- // Try to fetch detailed actor information from XBVR/DeoVR API
- // XBVR might have actor detail endpoints, let's try a few possibilities
+ // XBVR/DeoVR API does not provide actor detail endpoints
+ // Skip API calls and use basic actor info only
+ $this->logProgress("XBVR does not provide actor details API, using basic info for: {$actorName}");
- $actorDetails = ['name' => $actorName];
-
- // Try different XBVR actor API endpoints
- $actorApiUrls = [
- "{$this->baseUrl}/api/actor/search/" . urlencode($actorName),
- "{$this->baseUrl}/actor/" . urlencode($actorName),
- "{$this->baseUrl}/api/actors?name=" . urlencode($actorName),
- ];
-
- foreach ($actorApiUrls as $apiUrl) {
- try {
- $this->logProgress("Trying to fetch actor details from: {$apiUrl}");
-
- $response = $this->httpClient->get($apiUrl, [
- 'timeout' => 10,
- 'connect_timeout' => 5
- ]);
-
- if ($response->getStatusCode() === 200) {
- $actorApiData = json_decode($response->getBody(), true);
-
- if (!empty($actorApiData)) {
- $this->logProgress("Successfully fetched actor details for: {$actorName}");
-
- // Merge API data with basic info
- $actorDetails = array_merge($actorDetails, $this->mapActorApiData($actorApiData));
- break;
- }
- }
- } catch (Exception $e) {
- // Continue to next API endpoint
- $this->logProgress("Actor API endpoint failed: {$apiUrl} - " . $e->getMessage());
- }
- }
-
- // If no detailed data found, try to scrape from web search or use basic info
- if (count($actorDetails) <= 1) {
- $this->logProgress("No detailed actor data found for {$actorName}, using basic info");
- $actorDetails = $this->scrapeActorInfo($actorName);
- }
-
- return $actorDetails;
+ return ['name' => $actorName];
}
- private function mapActorApiData(array $apiData): array
- {
- $mapped = [];
- // Handle different possible API response formats
- if (isset($apiData['actor'])) {
- $apiData = $apiData['actor'];
- }
-
- // Map common fields
- $fieldMappings = [
- 'id' => 'xbvr_id',
- 'name' => 'name',
- 'image' => 'image_path',
- 'thumbnail' => 'thumbnail_path',
- 'bio' => 'biography',
- 'biography' => 'biography',
- 'birthdate' => 'birth_date',
- 'age' => 'age',
- 'height' => 'height',
- 'weight' => 'weight',
- 'measurements' => 'measurements',
- 'nationality' => 'nationality',
- 'ethnicity' => 'ethnicity',
- 'eye_color' => 'eye_color',
- 'hair_color' => 'hair_color',
- 'tattoos' => 'tattoos',
- 'piercings' => 'piercings',
- 'aliases' => 'aliases',
- 'debut_year' => 'debut_year',
- 'retirement_year' => 'retirement_year',
- 'active' => 'active',
- 'website' => 'website',
- 'twitter' => 'twitter',
- 'instagram' => 'instagram',
- 'scene_count' => 'scene_count'
- ];
-
- foreach ($fieldMappings as $apiField => $localField) {
- if (isset($apiData[$apiField])) {
- $mapped[$localField] = $apiData[$apiField];
- }
- }
-
- return $mapped;
- }
-
- private function scrapeActorInfo(string $actorName): array
- {
- $actorInfo = ['name' => $actorName];
-
- // Try to get basic information from web scraping
- // This is a fallback when API doesn't provide details
-
- try {
- // Try to search for actor on common adult industry sites
- $searchUrls = [
- "https://www.adultempire.com/search.php?query=" . urlencode($actorName),
- "https://www.brazzers.com/search/" . urlencode($actorName) . "/",
- "https://www.naughtyamerica.com/search/" . urlencode($actorName),
- ];
-
- foreach ($searchUrls as $searchUrl) {
- try {
- $response = $this->httpClient->get($searchUrl, [
- 'timeout' => 5,
- 'headers' => [
- 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
- ]
- ]);
-
- if ($response->getStatusCode() === 200) {
- $html = $response->getBody()->getContents();
-
- // Basic HTML parsing to extract information
- $actorInfo = array_merge($actorInfo, $this->parseActorHtml($html, $actorName));
- break;
- }
- } catch (Exception $e) {
- continue;
- }
- }
- } catch (Exception $e) {
- $this->logProgress("Web scraping failed for {$actorName}: " . $e->getMessage());
- }
-
- return $actorInfo;
- }
-
- private function parseActorHtml(string $html, string $actorName): array
- {
- $info = [];
-
- // Very basic HTML parsing - look for common patterns
- // This is quite fragile and would need improvement for production use
-
- // Look for image URLs
- if (preg_match('/]+src=["\']([^"\']*?(?:actor|performer|model)[^"\']*?)["\'][^>]*>/i', $html, $matches)) {
- $info['image_path'] = $matches[1];
- }
-
- // Look for birthdate patterns
- if (preg_match('/(?:born|birthdate|birth).*?(\d{4}-\d{2}-\d{2}|\d{1,2}\/\d{1,2}\/\d{4})/i', $html, $matches)) {
- $info['birth_date'] = date('Y-m-d', strtotime($matches[1]));
- }
-
- // Look for age
- if (preg_match('/age.*?(\d+)/i', $html, $matches)) {
- $info['age'] = (int)$matches[1];
- }
-
- // Look for measurements
- if (preg_match('/measurements?.*?(\d+-\d+-\d+)/i', $html, $matches)) {
- $info['measurements'] = $matches[1];
- }
-
- // Look for height
- if (preg_match('/height.*?(\d+\'?\d*)/i', $html, $matches)) {
- $info['height'] = $matches[1];
- }
-
- return $info;
- }
private function getOrCreateActor(array $actorData): ?array
{
$name = $actorData['name'] ?? '';
if (empty($name)) return null;
- // Check if actor already exists by name or alias
+ // Check if actor already exists by name or alias
+ // First check by exact name
$stmt = $this->pdo->prepare("
SELECT id, name, thumbnail_path, metadata FROM actors
WHERE name = :name
- OR JSON_CONTAINS(metadata->'$.aliases', :name)
");
$stmt->execute(['name' => $name]);
$existingActor = $stmt->fetch(\PDO::FETCH_ASSOC);
- // If found by alias, log it for debugging
- if ($existingActor && $existingActor['name'] !== $name) {
- $this->logProgress("Found existing actor '{$existingActor['name']}' by alias '{$name}'");
+ // If not found by name, check aliases in PHP
+ if (!$existingActor) {
+ $stmt = $this->pdo->prepare("SELECT id, name, thumbnail_path, metadata FROM actors");
+ $stmt->execute();
+ $allActors = $stmt->fetchAll(\PDO::FETCH_ASSOC);
+
+ foreach ($allActors as $actor) {
+ $metadata = json_decode($actor['metadata'] ?? '{}', true);
+ $aliases = $metadata['aliases'] ?? [];
+ if (is_array($aliases) && in_array($name, $aliases)) {
+ $existingActor = $actor;
+ $this->logProgress("Found existing actor '{$actor['name']}' by alias '{$name}'");
+ break;
+ }
+ }
}
// Prepare metadata from XBVR actor data
diff --git a/resources/views/adult/index.twig b/resources/views/adult/index.twig
index fe09a84..f8b59dc 100644
--- a/resources/views/adult/index.twig
+++ b/resources/views/adult/index.twig
@@ -31,12 +31,12 @@
-
-