mirror of
https://github.com/ceratic/MediaCollectorLibary.git
synced 2026-05-13 23:56:46 +02:00
actor fetching :)
Stash / ADultVideoAPI
This commit is contained in:
@@ -149,35 +149,135 @@ class ActorController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
// Handle image upload
|
||||
// Handle image upload/download
|
||||
$thumbnailPath = $actor['thumbnail_path']; // Keep existing by default
|
||||
if (!empty($uploadedFiles['thumbnail']) && $uploadedFiles['thumbnail']->getError() === UPLOAD_ERR_OK) {
|
||||
$uploadedFile = $uploadedFiles['thumbnail'];
|
||||
$imageSource = $data['image_source'] ?? 'upload';
|
||||
|
||||
// Validate file type
|
||||
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
|
||||
if (!in_array($uploadedFile->getClientMediaType(), $allowedTypes)) {
|
||||
return $this->view->render($response, 'actor/edit.twig', [
|
||||
'title' => 'Edit Actor',
|
||||
'actor' => $actor,
|
||||
'metadata' => $metadata,
|
||||
'error' => 'Invalid image type. Only JPEG, PNG, GIF, and WebP are allowed.'
|
||||
]);
|
||||
if ($imageSource === 'upload') {
|
||||
// Handle file upload
|
||||
if (!empty($uploadedFiles['thumbnail']) && $uploadedFiles['thumbnail']->getError() === UPLOAD_ERR_OK) {
|
||||
$uploadedFile = $uploadedFiles['thumbnail'];
|
||||
|
||||
// Validate file type
|
||||
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
|
||||
if (!in_array($uploadedFile->getClientMediaType(), $allowedTypes)) {
|
||||
return $this->view->render($response, 'actor/edit.twig', [
|
||||
'title' => 'Edit Actor',
|
||||
'actor' => $actor,
|
||||
'metadata' => $metadata,
|
||||
'error' => 'Invalid image type. Only JPEG, PNG, GIF, and WebP are allowed.'
|
||||
]);
|
||||
}
|
||||
|
||||
// Generate filename and move file
|
||||
$extension = pathinfo($uploadedFile->getClientFilename(), PATHINFO_EXTENSION);
|
||||
$filename = 'actor_' . $actorId . '_' . time() . '.' . $extension;
|
||||
$uploadPath = __DIR__ . '/../../public/images/actors/' . $filename;
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
$uploadDir = dirname($uploadPath);
|
||||
if (!is_dir($uploadDir)) {
|
||||
mkdir($uploadDir, 0755, true);
|
||||
}
|
||||
|
||||
$uploadedFile->moveTo($uploadPath);
|
||||
$thumbnailPath = '/images/actors/' . $filename;
|
||||
}
|
||||
} elseif ($imageSource === 'url') {
|
||||
// Handle URL download
|
||||
$imageUrl = trim($data['thumbnail_url'] ?? '');
|
||||
if (!empty($imageUrl)) {
|
||||
// Validate URL
|
||||
if (!filter_var($imageUrl, FILTER_VALIDATE_URL)) {
|
||||
return $this->view->render($response, 'actor/edit.twig', [
|
||||
'title' => 'Edit Actor',
|
||||
'actor' => $actor,
|
||||
'metadata' => $metadata,
|
||||
'error' => 'Invalid image URL provided.'
|
||||
]);
|
||||
}
|
||||
|
||||
// Generate filename and move file
|
||||
$extension = pathinfo($uploadedFile->getClientFilename(), PATHINFO_EXTENSION);
|
||||
$filename = 'actor_' . $actorId . '_' . time() . '.' . $extension;
|
||||
$uploadPath = __DIR__ . '/../../public/images/actors/' . $filename;
|
||||
try {
|
||||
// Download image from URL
|
||||
$imageData = file_get_contents($imageUrl);
|
||||
if ($imageData === false) {
|
||||
return $this->view->render($response, 'actor/edit.twig', [
|
||||
'title' => 'Edit Actor',
|
||||
'actor' => $actor,
|
||||
'metadata' => $metadata,
|
||||
'error' => 'Failed to download image from the provided URL.'
|
||||
]);
|
||||
}
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
$uploadDir = dirname($uploadPath);
|
||||
if (!is_dir($uploadDir)) {
|
||||
mkdir($uploadDir, 0755, true);
|
||||
// Get image info to validate type and determine extension
|
||||
$imageInfo = getimagesizefromstring($imageData);
|
||||
if (!$imageInfo) {
|
||||
return $this->view->render($response, 'actor/edit.twig', [
|
||||
'title' => 'Edit Actor',
|
||||
'actor' => $actor,
|
||||
'metadata' => $metadata,
|
||||
'error' => 'The URL does not point to a valid image.'
|
||||
]);
|
||||
}
|
||||
|
||||
// Validate MIME type
|
||||
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
|
||||
if (!in_array($imageInfo['mime'], $allowedTypes)) {
|
||||
return $this->view->render($response, 'actor/edit.twig', [
|
||||
'title' => 'Edit Actor',
|
||||
'actor' => $actor,
|
||||
'metadata' => $metadata,
|
||||
'error' => 'Invalid image type. Only JPEG, PNG, GIF, and WebP are allowed.'
|
||||
]);
|
||||
}
|
||||
|
||||
// Determine extension from MIME type
|
||||
$extension = '';
|
||||
switch ($imageInfo['mime']) {
|
||||
case 'image/jpeg':
|
||||
$extension = 'jpg';
|
||||
break;
|
||||
case 'image/png':
|
||||
$extension = 'png';
|
||||
break;
|
||||
case 'image/gif':
|
||||
$extension = 'gif';
|
||||
break;
|
||||
case 'image/webp':
|
||||
$extension = 'webp';
|
||||
break;
|
||||
}
|
||||
|
||||
// Generate filename and save file
|
||||
$filename = 'actor_' . $actorId . '_' . time() . '.' . $extension;
|
||||
$uploadPath = __DIR__ . '/../../public/images/actors/' . $filename;
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
$uploadDir = dirname($uploadPath);
|
||||
if (!is_dir($uploadDir)) {
|
||||
mkdir($uploadDir, 0755, true);
|
||||
}
|
||||
|
||||
// Save the downloaded image
|
||||
if (file_put_contents($uploadPath, $imageData) === false) {
|
||||
return $this->view->render($response, 'actor/edit.twig', [
|
||||
'title' => 'Edit Actor',
|
||||
'actor' => $actor,
|
||||
'metadata' => $metadata,
|
||||
'error' => 'Failed to save the downloaded image.'
|
||||
]);
|
||||
}
|
||||
|
||||
$thumbnailPath = '/images/actors/' . $filename;
|
||||
} catch (Exception $e) {
|
||||
return $this->view->render($response, 'actor/edit.twig', [
|
||||
'title' => 'Edit Actor',
|
||||
'actor' => $actor,
|
||||
'metadata' => $metadata,
|
||||
'error' => 'Error downloading image: ' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$uploadedFile->moveTo($uploadPath);
|
||||
$thumbnailPath = '/images/actors/' . $filename;
|
||||
}
|
||||
|
||||
// Prepare metadata
|
||||
@@ -246,13 +346,156 @@ class ActorController extends Controller
|
||||
'metadata' => $metadata
|
||||
]);
|
||||
}
|
||||
public function fetchStashData(Request $request, Response $response, $args)
|
||||
{
|
||||
ini_set('memory_limit', '2G');
|
||||
|
||||
try {
|
||||
// Parse JSON body for API requests
|
||||
$rawBody = $request->getBody()->getContents();
|
||||
$data = json_decode($rawBody, true);
|
||||
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
return $this->jsonResponse($response->withStatus(400), [
|
||||
'error' => 'Invalid JSON in request body'
|
||||
]);
|
||||
}
|
||||
|
||||
$query = trim($data['query'] ?? '');
|
||||
|
||||
if (empty($query)) {
|
||||
return $this->jsonResponse($response->withStatus(400), [
|
||||
'error' => 'Missing required parameter: query'
|
||||
]);
|
||||
}
|
||||
|
||||
// Get Stash configuration from database
|
||||
$stmt = $this->pdo->prepare('SELECT * FROM sources WHERE name = ?');
|
||||
$stmt->execute(['stash']);
|
||||
$stashSource = $stmt->fetch(\PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$stashSource) {
|
||||
return $this->jsonResponse($response->withStatus(500), [
|
||||
'error' => 'Stash source not configured in database'
|
||||
]);
|
||||
}
|
||||
|
||||
$stashUrl = trim($stashSource['api_url'] ?? '');
|
||||
$stashApiKey = trim($stashSource['api_key'] ?? '');
|
||||
|
||||
if (empty($stashUrl)) {
|
||||
return $this->jsonResponse($response->withStatus(500), [
|
||||
'error' => 'Stash API URL not configured'
|
||||
]);
|
||||
}
|
||||
|
||||
// Create HTTP client for Stash API
|
||||
$client = new \GuzzleHttp\Client([
|
||||
'timeout' => 30,
|
||||
'verify' => false,
|
||||
'headers' => [
|
||||
'User-Agent' => 'MediaCollector/1.0',
|
||||
'ApiKey' => $stashApiKey,
|
||||
'Content-Type' => 'application/json'
|
||||
]
|
||||
]);
|
||||
|
||||
// Build GraphQL query to search for performers
|
||||
$graphqlQuery = '
|
||||
query FindPerformers($filter: FindFilterType) {
|
||||
findPerformers(filter: $filter) {
|
||||
performers {
|
||||
id
|
||||
name
|
||||
disambiguation
|
||||
url
|
||||
gender
|
||||
birthdate
|
||||
ethnicity
|
||||
country
|
||||
eye_color
|
||||
height_cm
|
||||
measurements
|
||||
fake_tits
|
||||
penis_length
|
||||
circumcised
|
||||
career_length
|
||||
tattoos
|
||||
piercings
|
||||
alias_list
|
||||
favorite
|
||||
ignore_auto_tag
|
||||
created_at
|
||||
updated_at
|
||||
details
|
||||
death_date
|
||||
hair_color
|
||||
weight
|
||||
image_path
|
||||
scene_count
|
||||
}
|
||||
count
|
||||
}
|
||||
}
|
||||
';
|
||||
|
||||
$variables = [
|
||||
'filter' => [
|
||||
'q' => $query,
|
||||
'per_page' => 10, // Limit results
|
||||
'sort' => 'name',
|
||||
'direction' => 'ASC'
|
||||
]
|
||||
];
|
||||
|
||||
// Make the API call
|
||||
$apiResponse = $client->post(rtrim($stashUrl, '/') . '/graphql', [
|
||||
'json' => [
|
||||
'query' => $graphqlQuery,
|
||||
'variables' => $variables
|
||||
]
|
||||
]);
|
||||
|
||||
$result = json_decode($apiResponse->getBody(), true);
|
||||
|
||||
if (!isset($result['data']['findPerformers']['performers'])) {
|
||||
return $this->jsonResponse($response, [
|
||||
'performers' => [],
|
||||
'message' => 'No performers found'
|
||||
]);
|
||||
}
|
||||
|
||||
$performers = $result['data']['findPerformers']['performers'];
|
||||
|
||||
return $this->jsonResponse($response, [
|
||||
'performers' => $performers,
|
||||
'count' => count($performers),
|
||||
'stash_url' => $stashUrl
|
||||
]);
|
||||
|
||||
} catch (\GuzzleHttp\Exception\RequestException $e) {
|
||||
$errorMessage = 'Failed to connect to Stash server';
|
||||
if ($e->hasResponse()) {
|
||||
$statusCode = $e->getResponse()->getStatusCode();
|
||||
$errorMessage .= ": HTTP {$statusCode}";
|
||||
}
|
||||
return $this->jsonResponse($response->withStatus(500), [
|
||||
'error' => $errorMessage
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return $this->jsonResponse($response->withStatus(500), [
|
||||
'error' => 'Internal server error: ' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function index(Request $request, Response $response, $args)
|
||||
{
|
||||
$queryParams = $request->getQueryParams();
|
||||
|
||||
// Get pagination parameters
|
||||
$page = max(1, (int)($queryParams['page'] ?? 1));
|
||||
$perPage = max(12, min(100, (int)($queryParams['per_page'] ?? 24)));
|
||||
$perPage = max(12, min(100, (int)($queryParams['per_page'] ?? 48)));
|
||||
|
||||
// Get search parameters
|
||||
$search = trim($queryParams['search'] ?? '');
|
||||
@@ -367,9 +610,51 @@ class ActorController extends Controller
|
||||
$orderBy = $sortMap[$sort] ?? 'total_media_count DESC, a.name ASC';
|
||||
$sql .= " ORDER BY {$orderBy}";
|
||||
|
||||
// Get total count for pagination
|
||||
$countSql = str_replace('SELECT a.id, a.name, a.thumbnail_path,', 'SELECT COUNT(*) as count,', $sql);
|
||||
$countSql = preg_replace('/ORDER BY.*$/', '', $countSql);
|
||||
// Get total count for pagination - use a subquery to count the results
|
||||
$countSql = "
|
||||
SELECT COUNT(*) as count FROM (
|
||||
SELECT a.id,
|
||||
COALESCE(adult_counts.adult_video_count, 0) as adult_video_count,
|
||||
COALESCE(movie_counts.movie_count, 0) as movie_count,
|
||||
COALESCE(tv_counts.tv_show_count, 0) as tv_show_count
|
||||
FROM actors a
|
||||
LEFT JOIN (
|
||||
SELECT actor_id, COUNT(DISTINCT adult_video_id) as adult_video_count
|
||||
FROM actor_adult_video
|
||||
GROUP BY actor_id
|
||||
) adult_counts ON a.id = adult_counts.actor_id
|
||||
LEFT JOIN (
|
||||
SELECT actor_id, COUNT(DISTINCT movie_id) as movie_count
|
||||
FROM actor_movie
|
||||
GROUP BY actor_id
|
||||
) movie_counts ON a.id = movie_counts.actor_id
|
||||
LEFT JOIN (
|
||||
SELECT actor_id, COUNT(DISTINCT tv_show_id) as tv_show_count
|
||||
FROM (
|
||||
SELECT actor_id, tv_show_id FROM actor_tv_show
|
||||
UNION
|
||||
SELECT ate.actor_id, te.tv_show_id
|
||||
FROM actor_tv_episode ate
|
||||
JOIN tv_episodes te ON ate.tv_episode_id = te.id
|
||||
) combined_tv
|
||||
GROUP BY actor_id
|
||||
) tv_counts ON a.id = tv_counts.actor_id
|
||||
";
|
||||
|
||||
// Add search filter
|
||||
if (!empty($whereClauses)) {
|
||||
$countSql .= ' WHERE ' . implode(' AND ', $whereClauses);
|
||||
}
|
||||
|
||||
$countSql .= " GROUP BY a.id";
|
||||
|
||||
// Add HAVING clause for filters
|
||||
if (!empty($havingClauses)) {
|
||||
$countSql .= ' HAVING ' . implode(' AND ', $havingClauses);
|
||||
}
|
||||
|
||||
$countSql .= ") as filtered_actors";
|
||||
|
||||
$countStmt = $this->pdo->prepare($countSql);
|
||||
foreach ($params as $key => $value) {
|
||||
$countStmt->bindValue($key, $value);
|
||||
|
||||
Reference in New Issue
Block a user