diff --git a/apps/admin/src/components/MediaLibrary.tsx b/apps/admin/src/components/MediaLibrary.tsx
index a499817..a4aee21 100644
--- a/apps/admin/src/components/MediaLibrary.tsx
+++ b/apps/admin/src/components/MediaLibrary.tsx
@@ -21,9 +21,6 @@ type StockPhoto = {
html: string;
};
};
- links: {
- download_location: string;
- };
width: number;
height: number;
};
@@ -198,7 +195,6 @@ export default function MediaLibrary({
body: JSON.stringify({
photoId: photo.id,
downloadUrl: photo.urls.regular,
- downloadLocation: photo.links.download_location,
photographer: photo.user.name,
photographerUrl: photo.user.links.html,
}),
@@ -298,7 +294,7 @@ export default function MediaLibrary({
{!stockLoading && stockPhotos.length === 0 && !stockQuery && (
- Enter a search term to find free stock photos from Unsplash.
+ Enter a search term to find free stock photos from Pexels.
)}
@@ -309,7 +305,7 @@ export default function MediaLibrary({
- Photo by {photo.user.name}
+ Photo by {photo.user.name}
{photo.width} × {photo.height}
diff --git a/apps/api/src/routes/stock-photos.routes.ts b/apps/api/src/routes/stock-photos.routes.ts
index 0f1519d..3479a3a 100644
--- a/apps/api/src/routes/stock-photos.routes.ts
+++ b/apps/api/src/routes/stock-photos.routes.ts
@@ -4,11 +4,11 @@ import crypto from 'crypto';
const router = express.Router();
-const UNSPLASH_ACCESS_KEY = process.env.UNSPLASH_ACCESS_KEY;
+const PEXELS_API_KEY = process.env.PEXELS_API_KEY;
/**
* GET /api/stock-photos/search
- * Search Unsplash for stock photos
+ * Search Pexels for stock photos
*/
router.get('/search', async (req, res) => {
try {
@@ -18,21 +18,47 @@ router.get('/search', async (req, res) => {
return res.status(400).json({ error: 'query parameter is required' });
}
- if (!UNSPLASH_ACCESS_KEY) {
- return res.status(500).json({ error: 'Unsplash API key not configured' });
+ if (!PEXELS_API_KEY) {
+ return res.status(500).json({ error: 'Pexels API key not configured' });
}
- const unsplashUrl = `https://api.unsplash.com/search/photos?query=${encodeURIComponent(query)}&per_page=${per_page}&client_id=${UNSPLASH_ACCESS_KEY}`;
+ const pexelsUrl = `https://api.pexels.com/v1/search?query=${encodeURIComponent(query)}&per_page=${per_page}`;
- const response = await fetch(unsplashUrl);
+ const response = await fetch(pexelsUrl, {
+ headers: {
+ 'Authorization': PEXELS_API_KEY,
+ },
+ });
if (!response.ok) {
- throw new Error(`Unsplash API error: ${response.status}`);
+ throw new Error(`Pexels API error: ${response.status}`);
}
const data = await response.json();
- res.json(data);
+ // Transform Pexels response to match expected format
+ const transformedData = {
+ results: data.photos?.map((photo: any) => ({
+ id: String(photo.id),
+ urls: {
+ small: photo.src.small,
+ regular: photo.src.large,
+ full: photo.src.original,
+ },
+ alt_description: photo.alt || null,
+ user: {
+ name: photo.photographer,
+ links: {
+ html: photo.photographer_url,
+ },
+ },
+ width: photo.width,
+ height: photo.height,
+ })) || [],
+ total: data.total_results || 0,
+ };
+
+ res.json(transformedData);
} catch (err: any) {
console.error('[Stock Photos] Search error:', err);
res.status(500).json({
@@ -48,31 +74,18 @@ router.get('/search', async (req, res) => {
*/
router.post('/import', async (req, res) => {
try {
- const { photoId, downloadUrl, downloadLocation, photographer, photographerUrl } = req.body;
+ const { photoId, downloadUrl, photographer, photographerUrl } = req.body;
if (!photoId || !downloadUrl) {
return res.status(400).json({ error: 'photoId and downloadUrl are required' });
}
- if (!UNSPLASH_ACCESS_KEY) {
- return res.status(500).json({ error: 'Unsplash API key not configured' });
+ if (!PEXELS_API_KEY) {
+ return res.status(500).json({ error: 'Pexels API key not configured' });
}
console.log('[Stock Photos] Importing photo:', photoId);
- // Trigger download tracking (required by Unsplash API guidelines)
- if (downloadLocation) {
- try {
- await fetch(downloadLocation, {
- headers: {
- 'Authorization': `Client-ID ${UNSPLASH_ACCESS_KEY}`,
- },
- });
- } catch (err) {
- console.warn('[Stock Photos] Failed to track download:', err);
- }
- }
-
// Download the image
const imageResponse = await fetch(downloadUrl);
@@ -93,7 +106,7 @@ router.post('/import', async (req, res) => {
// Generate unique filename
const timestamp = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
const randomId = crypto.randomBytes(8).toString('hex');
- const filename = `unsplash-${photoId}-${randomId}.${ext}`;
+ const filename = `pexels-${photoId}-${randomId}.${ext}`;
const key = `images/${timestamp}/${filename}`;
// Upload to S3
diff --git a/docker-compose.yml b/docker-compose.yml
index 20a2c60..33e4367 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -49,6 +49,9 @@ services:
S3_ACCESS_KEY: ${S3_ACCESS_KEY}
S3_SECRET_KEY: ${S3_SECRET_KEY}
S3_ENDPOINT: ${S3_ENDPOINT}
+ INFISICAL_TOKEN: ${INFISICAL_TOKEN}
+ INFISICAL_SITE_URL: ${INFISICAL_SITE_URL}
+ PEXELS_API_KEY: ${PEXELS_API_KEY}
depends_on:
mysql:
condition: service_healthy