summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/api/routes/gifs/search.ts65
-rw-r--r--src/api/routes/gifs/trending-gifs.ts60
-rw-r--r--src/api/routes/gifs/trending.ts159
-rw-r--r--src/api/util/handlers/route.ts8
-rw-r--r--src/util/schemas/responses/Tenor.ts72
-rw-r--r--src/util/schemas/responses/index.ts1
6 files changed, 236 insertions, 129 deletions
diff --git a/src/api/routes/gifs/search.ts b/src/api/routes/gifs/search.ts
index fb99374b..b51bba37 100644
--- a/src/api/routes/gifs/search.ts
+++ b/src/api/routes/gifs/search.ts
@@ -16,34 +16,63 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-import { Router, Response, Request } from "express";
+import { route } from "@spacebar/api";
+import { TenorMediaTypes } from "@spacebar/util";
+import { Request, Response, Router } from "express";
 import fetch from "node-fetch";
 import ProxyAgent from "proxy-agent";
-import { route } from "@spacebar/api";
 import { getGifApiKey, parseGifResult } from "./trending";
 
 const router = Router();
 
-router.get("/", route({}), async (req: Request, res: Response) => {
-	// TODO: Custom providers
-	const { q, media_format, locale } = req.query;
+router.get(
+	"/",
+	route({
+		query: {
+			q: {
+				type: "string",
+				required: true,
+				description: "Search query",
+			},
+			media_format: {
+				type: "string",
+				description: "Media format",
+				values: Object.keys(TenorMediaTypes).filter((key) =>
+					isNaN(Number(key)),
+				),
+			},
+			locale: {
+				type: "string",
+				description: "Locale",
+			},
+		},
+		responses: {
+			200: {
+				body: "TenorGifsResponse",
+			},
+		},
+	}),
+	async (req: Request, res: Response) => {
+		// TODO: Custom providers
+		const { q, media_format, locale } = req.query;
 
-	const apiKey = getGifApiKey();
+		const apiKey = getGifApiKey();
 
-	const agent = new ProxyAgent();
+		const agent = new ProxyAgent();
 
-	const response = await fetch(
-		`https://g.tenor.com/v1/search?q=${q}&media_format=${media_format}&locale=${locale}&key=${apiKey}`,
-		{
-			agent,
-			method: "get",
-			headers: { "Content-Type": "application/json" },
-		},
-	);
+		const response = await fetch(
+			`https://g.tenor.com/v1/search?q=${q}&media_format=${media_format}&locale=${locale}&key=${apiKey}`,
+			{
+				agent,
+				method: "get",
+				headers: { "Content-Type": "application/json" },
+			},
+		);
 
-	const { results } = await response.json();
+		const { results } = await response.json();
 
-	res.json(results.map(parseGifResult)).status(200);
-});
+		res.json(results.map(parseGifResult)).status(200);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/gifs/trending-gifs.ts b/src/api/routes/gifs/trending-gifs.ts
index 238a2abd..899250cf 100644
--- a/src/api/routes/gifs/trending-gifs.ts
+++ b/src/api/routes/gifs/trending-gifs.ts
@@ -16,34 +16,58 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-import { Router, Response, Request } from "express";
+import { route } from "@spacebar/api";
+import { TenorMediaTypes } from "@spacebar/util";
+import { Request, Response, Router } from "express";
 import fetch from "node-fetch";
 import ProxyAgent from "proxy-agent";
-import { route } from "@spacebar/api";
 import { getGifApiKey, parseGifResult } from "./trending";
 
 const router = Router();
 
-router.get("/", route({}), async (req: Request, res: Response) => {
-	// TODO: Custom providers
-	const { media_format, locale } = req.query;
+router.get(
+	"/",
+	route({
+		query: {
+			media_format: {
+				type: "string",
+				description: "Media format",
+				values: Object.keys(TenorMediaTypes).filter((key) =>
+					isNaN(Number(key)),
+				),
+			},
+			locale: {
+				type: "string",
+				description: "Locale",
+			},
+		},
+		responses: {
+			200: {
+				body: "TenorGifsResponse",
+			},
+		},
+	}),
+	async (req: Request, res: Response) => {
+		// TODO: Custom providers
+		const { media_format, locale } = req.query;
 
-	const apiKey = getGifApiKey();
+		const apiKey = getGifApiKey();
 
-	const agent = new ProxyAgent();
+		const agent = new ProxyAgent();
 
-	const response = await fetch(
-		`https://g.tenor.com/v1/trending?media_format=${media_format}&locale=${locale}&key=${apiKey}`,
-		{
-			agent,
-			method: "get",
-			headers: { "Content-Type": "application/json" },
-		},
-	);
+		const response = await fetch(
+			`https://g.tenor.com/v1/trending?media_format=${media_format}&locale=${locale}&key=${apiKey}`,
+			{
+				agent,
+				method: "get",
+				headers: { "Content-Type": "application/json" },
+			},
+		);
 
-	const { results } = await response.json();
+		const { results } = await response.json();
 
-	res.json(results.map(parseGifResult)).status(200);
-});
+		res.json(results.map(parseGifResult)).status(200);
+	},
+);
 
 export default router;
diff --git a/src/api/routes/gifs/trending.ts b/src/api/routes/gifs/trending.ts
index 5cccdb2d..3c2ab6ab 100644
--- a/src/api/routes/gifs/trending.ts
+++ b/src/api/routes/gifs/trending.ts
@@ -16,66 +16,21 @@
 	along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-import { Router, Response, Request } from "express";
-import fetch from "node-fetch";
-import ProxyAgent from "proxy-agent";
 import { route } from "@spacebar/api";
-import { Config } from "@spacebar/util";
+import {
+	Config,
+	TenorCategoriesResults,
+	TenorGif,
+	TenorTrendingResults,
+} from "@spacebar/util";
+import { Request, Response, Router } from "express";
 import { HTTPError } from "lambert-server";
+import fetch from "node-fetch";
+import ProxyAgent from "proxy-agent";
 
 const router = Router();
 
-// TODO: Move somewhere else
-enum TENOR_GIF_TYPES {
-	gif,
-	mediumgif,
-	tinygif,
-	nanogif,
-	mp4,
-	loopedmp4,
-	tinymp4,
-	nanomp4,
-	webm,
-	tinywebm,
-	nanowebm,
-}
-
-type TENOR_MEDIA = {
-	preview: string;
-	url: string;
-	dims: number[];
-	size: number;
-};
-
-type TENOR_GIF = {
-	created: number;
-	hasaudio: boolean;
-	id: string;
-	media: { [type in keyof typeof TENOR_GIF_TYPES]: TENOR_MEDIA }[];
-	tags: string[];
-	title: string;
-	itemurl: string;
-	hascaption: boolean;
-	url: string;
-};
-
-type TENOR_CATEGORY = {
-	searchterm: string;
-	path: string;
-	image: string;
-	name: string;
-};
-
-type TENOR_CATEGORIES_RESULTS = {
-	tags: TENOR_CATEGORY[];
-};
-
-type TENOR_TRENDING_RESULTS = {
-	next: string;
-	results: TENOR_GIF[];
-};
-
-export function parseGifResult(result: TENOR_GIF) {
+export function parseGifResult(result: TenorGif) {
 	return {
 		id: result.id,
 		title: result.title,
@@ -97,45 +52,63 @@ export function getGifApiKey() {
 	return apiKey;
 }
 
-router.get("/", route({}), async (req: Request, res: Response) => {
-	// TODO: Custom providers
-	// TODO: return gifs as mp4
-	// const { media_format, locale } = req.query;
-	const { locale } = req.query;
-
-	const apiKey = getGifApiKey();
-
-	const agent = new ProxyAgent();
-
-	const [responseSource, trendGifSource] = await Promise.all([
-		fetch(
-			`https://g.tenor.com/v1/categories?locale=${locale}&key=${apiKey}`,
-			{
-				agent,
-				method: "get",
-				headers: { "Content-Type": "application/json" },
+router.get(
+	"/",
+	route({
+		query: {
+			locale: {
+				type: "string",
+				description: "Locale",
 			},
-		),
-		fetch(
-			`https://g.tenor.com/v1/trending?locale=${locale}&key=${apiKey}`,
-			{
-				agent,
-				method: "get",
-				headers: { "Content-Type": "application/json" },
+		},
+		responses: {
+			200: {
+				body: "TenorTrendingResponse",
 			},
-		),
-	]);
-
-	const { tags } = (await responseSource.json()) as TENOR_CATEGORIES_RESULTS;
-	const { results } = (await trendGifSource.json()) as TENOR_TRENDING_RESULTS;
-
-	res.json({
-		categories: tags.map((x) => ({
-			name: x.searchterm,
-			src: x.image,
-		})),
-		gifs: [parseGifResult(results[0])],
-	}).status(200);
-});
+		},
+	}),
+	async (req: Request, res: Response) => {
+		// TODO: Custom providers
+		// TODO: return gifs as mp4
+		// const { media_format, locale } = req.query;
+		const { locale } = req.query;
+
+		const apiKey = getGifApiKey();
+
+		const agent = new ProxyAgent();
+
+		const [responseSource, trendGifSource] = await Promise.all([
+			fetch(
+				`https://g.tenor.com/v1/categories?locale=${locale}&key=${apiKey}`,
+				{
+					agent,
+					method: "get",
+					headers: { "Content-Type": "application/json" },
+				},
+			),
+			fetch(
+				`https://g.tenor.com/v1/trending?locale=${locale}&key=${apiKey}`,
+				{
+					agent,
+					method: "get",
+					headers: { "Content-Type": "application/json" },
+				},
+			),
+		]);
+
+		const { tags } =
+			(await responseSource.json()) as TenorCategoriesResults;
+		const { results } =
+			(await trendGifSource.json()) as TenorTrendingResults;
+
+		res.json({
+			categories: tags.map((x) => ({
+				name: x.searchterm,
+				src: x.image,
+			})),
+			gifs: [parseGifResult(results[0])],
+		}).status(200);
+	},
+);
 
 export default router;
diff --git a/src/api/util/handlers/route.ts b/src/api/util/handlers/route.ts
index 331ac0c2..2416b73f 100644
--- a/src/api/util/handlers/route.ts
+++ b/src/api/util/handlers/route.ts
@@ -62,6 +62,14 @@ export interface RouteOptions {
 	event?: EVENT | EVENT[];
 	summary?: string;
 	description?: string;
+	query?: {
+		[key: string]: {
+			type: string;
+			required?: boolean;
+			description?: string;
+			values?: string[];
+		};
+	};
 	// test?: {
 	// 	response?: RouteResponse;
 	// 	body?: unknown;
diff --git a/src/util/schemas/responses/Tenor.ts b/src/util/schemas/responses/Tenor.ts
new file mode 100644
index 00000000..9dddf9d0
--- /dev/null
+++ b/src/util/schemas/responses/Tenor.ts
@@ -0,0 +1,72 @@
+export enum TenorMediaTypes {
+	gif,
+	mediumgif,
+	tinygif,
+	nanogif,
+	mp4,
+	loopedmp4,
+	tinymp4,
+	nanomp4,
+	webm,
+	tinywebm,
+	nanowebm,
+}
+
+export type TenorMedia = {
+	preview: string;
+	url: string;
+	dims: number[];
+	size: number;
+};
+
+export type TenorGif = {
+	created: number;
+	hasaudio: boolean;
+	id: string;
+	media: { [type in keyof typeof TenorMediaTypes]: TenorMedia }[];
+	tags: string[];
+	title: string;
+	itemurl: string;
+	hascaption: boolean;
+	url: string;
+};
+
+export type TenorCategory = {
+	searchterm: string;
+	path: string;
+	image: string;
+	name: string;
+};
+
+export type TenorCategoriesResults = {
+	tags: TenorCategory[];
+};
+
+export type TenorTrendingResults = {
+	next: string;
+	results: TenorGif[];
+	locale: string;
+};
+
+export type TenorSearchResults = {
+	next: string;
+	results: TenorGif[];
+};
+
+export interface TenorGifResponse {
+	id: string;
+	title: string;
+	url: string;
+	src: string;
+	gif_src: string;
+	width: number;
+	height: number;
+	preview: string;
+}
+
+export interface TenorTrendingResponse {
+	categories: TenorCategoriesResults;
+	gifs: TenorGifResponse[];
+}
+
+export type TenorGifsResponse = TenorGifResponse[];
diff --git a/src/util/schemas/responses/index.ts b/src/util/schemas/responses/index.ts
index 49e8053b..30949f7f 100644
--- a/src/util/schemas/responses/index.ts
+++ b/src/util/schemas/responses/index.ts
@@ -13,6 +13,7 @@ export * from "./GatewayBotResponse";
 export * from "./GatewayResponse";
 export * from "./GenerateRegistrationTokensResponse";
 export * from "./LocationMetadataResponse";
+export * from "./Tenor";
 export * from "./TokenResponse";
 export * from "./UserProfileResponse";
 export * from "./UserRelationsResponse";