mirror of
https://github.com/ceratic/MediaCollectorLibary.git
synced 2026-05-13 23:56:46 +02:00
xbvr sync
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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('/<img[^>]+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
|
||||
|
||||
Reference in New Issue
Block a user