返回 presentation-ai
unsplash.ts
根目录 / src / app / _actions / apps / image-studio / unsplash.ts
1 "use server";
2
3 import { getImageFromUnsplash as getSingleUnsplashImage } from "@/app/_actions/image/unsplash";
4 import { env } from "@/env";
5 import { requireOptionalIntegration } from "@/lib/env/optional-integrations";
6
7 type UnsplashImageResult = {
8 url: string;
9 thumb?: string;
10 author?: string;
11 username?: string;
12 downloadLocation?: string;
13 link?: string;
14 };
15
16 interface UnsplashImage {
17 urls: {
18 regular: string;
19 thumb: string;
20 };
21 user: {
22 name: string;
23 username: string;
24 };
25 links: {
26 download_location: string;
27 html: string;
28 };
29 }
30
31 interface UnsplashResponse {
32 results: UnsplashImage[];
33 }
34
35 type UnsplashTrendingImage = UnsplashImage;
36
37 export async function searchUnsplashImages(
38 query: string,
39 perPage = 30,
40 page = 1,
41 ): Promise<{ success: boolean; images?: UnsplashImageResult[]; error?: string }> {
42 const unsplashConfig = requireOptionalIntegration({
43 integration: "Unsplash",
44 envVar: "UNSPLASH_ACCESS_KEY",
45 value: env.UNSPLASH_ACCESS_KEY,
46 feature: "Unsplash image search",
47 });
48
49 if (!unsplashConfig.ok) {
50 return {
51 success: false,
52 error: unsplashConfig.error,
53 };
54 }
55
56 try {
57 const response = await fetch(
58 `https://api.unsplash.com/search/photos?query=${encodeURIComponent(query)}&page=${page}&per_page=${perPage}`,
59 {
60 headers: {
61 Authorization: `Client-ID ${unsplashConfig.value}`,
62 },
63 },
64 );
65
66 if (!response.ok) {
67 throw new Error(`Unsplash API error: ${response.status}`);
68 }
69
70 const data = (await response.json()) as UnsplashResponse;
71
72 return {
73 success: true,
74 images: data.results.map((image) => ({
75 url: image.urls.regular,
76 thumb: image.urls.thumb,
77 author: image.user.name,
78 username: image.user.username,
79 downloadLocation: image.links.download_location,
80 link: image.links.html,
81 })),
82 };
83 } catch (error) {
84 console.error("Unsplash search failed:", error);
85 return {
86 success: false,
87 error:
88 error instanceof Error ? error.message : "Failed to search Unsplash",
89 };
90 }
91 }
92
93 export async function triggerUnsplashDownload(downloadLocation: string) {
94 const unsplashConfig = requireOptionalIntegration({
95 integration: "Unsplash",
96 envVar: "UNSPLASH_ACCESS_KEY",
97 value: env.UNSPLASH_ACCESS_KEY,
98 feature: "Unsplash download tracking",
99 });
100
101 if (!unsplashConfig.ok) {
102 return { success: false };
103 }
104
105 try {
106 await fetch(downloadLocation, {
107 headers: {
108 Authorization: `Client-ID ${unsplashConfig.value}`,
109 },
110 });
111 return { success: true };
112 } catch (error) {
113 console.error("Unsplash download trigger failed:", error);
114 return { success: false };
115 }
116 }
117
118 export async function getTrendingUnsplashImages(
119 perPage = 30,
120 page = 1,
121 ): Promise<{ success: boolean; images?: UnsplashImageResult[]; error?: string }> {
122 const unsplashConfig = requireOptionalIntegration({
123 integration: "Unsplash",
124 envVar: "UNSPLASH_ACCESS_KEY",
125 value: env.UNSPLASH_ACCESS_KEY,
126 feature: "Unsplash image search",
127 });
128
129 if (!unsplashConfig.ok) {
130 return {
131 success: false,
132 error: unsplashConfig.error,
133 };
134 }
135
136 try {
137 const params = new URLSearchParams({
138 order_by: "popular",
139 page: String(page),
140 per_page: String(perPage),
141 });
142 const response = await fetch(
143 `https://api.unsplash.com/photos?${params.toString()}`,
144 {
145 headers: {
146 Authorization: `Client-ID ${unsplashConfig.value}`,
147 },
148 },
149 );
150
151 if (!response.ok) {
152 throw new Error(`Unsplash API error: ${response.status}`);
153 }
154
155 const data = (await response.json()) as UnsplashTrendingImage[];
156
157 return {
158 success: true,
159 images: data.map((image) => ({
160 url: image.urls.regular,
161 thumb: image.urls.thumb,
162 author: image.user.name,
163 username: image.user.username,
164 downloadLocation: image.links.download_location,
165 link: image.links.html,
166 })),
167 };
168 } catch (error) {
169 console.error("Unsplash trending search failed:", error);
170 return {
171 success: false,
172 error:
173 error instanceof Error
174 ? error.message
175 : "Failed to load trending Unsplash images",
176 };
177 }
178 }
179
180 export async function getImageFromUnsplash(
181 query: string,
182 layoutType?: string,
183 ) {
184 return getSingleUnsplashImage(query, layoutType as never);
185 }
186
186 lines TYPESCRIPT