gifs and query params
This commit is contained in:
parent
0d2a2c7258
commit
0dc5b19bd8
10047
assets/openapi.json
Normal file
10047
assets/openapi.json
Normal file
File diff suppressed because it is too large
Load Diff
13137
assets/schemas.json
13137
assets/schemas.json
File diff suppressed because it is too large
Load Diff
@ -202,6 +202,19 @@ function apiRoutes() {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (route.query) {
|
||||||
|
// map to array
|
||||||
|
const query = Object.entries(route.query).map(([k, v]) => ({
|
||||||
|
name: k,
|
||||||
|
in: "query",
|
||||||
|
required: v.required,
|
||||||
|
schema: { type: v.type },
|
||||||
|
description: v.description,
|
||||||
|
}));
|
||||||
|
|
||||||
|
obj.parameters = [...(obj.parameters || []), ...query];
|
||||||
|
}
|
||||||
|
|
||||||
obj.tags = [...(obj.tags || []), getTag(p)].unique();
|
obj.tags = [...(obj.tags || []), getTag(p)].unique();
|
||||||
|
|
||||||
specification.paths[path] = {
|
specification.paths[path] = {
|
||||||
|
@ -16,34 +16,63 @@
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
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 fetch from "node-fetch";
|
||||||
import ProxyAgent from "proxy-agent";
|
import ProxyAgent from "proxy-agent";
|
||||||
import { route } from "@spacebar/api";
|
|
||||||
import { getGifApiKey, parseGifResult } from "./trending";
|
import { getGifApiKey, parseGifResult } from "./trending";
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
router.get("/", route({}), async (req: Request, res: Response) => {
|
router.get(
|
||||||
// TODO: Custom providers
|
"/",
|
||||||
const { q, media_format, locale } = req.query;
|
route({
|
||||||
|
query: {
|
||||||
const apiKey = getGifApiKey();
|
q: {
|
||||||
|
type: "string",
|
||||||
const agent = new ProxyAgent();
|
required: true,
|
||||||
|
description: "Search query",
|
||||||
const response = await fetch(
|
},
|
||||||
`https://g.tenor.com/v1/search?q=${q}&media_format=${media_format}&locale=${locale}&key=${apiKey}`,
|
media_format: {
|
||||||
{
|
type: "string",
|
||||||
agent,
|
description: "Media format",
|
||||||
method: "get",
|
values: Object.keys(TenorMediaTypes).filter((key) =>
|
||||||
headers: { "Content-Type": "application/json" },
|
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 { results } = await response.json();
|
const apiKey = getGifApiKey();
|
||||||
|
|
||||||
res.json(results.map(parseGifResult)).status(200);
|
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 { results } = await response.json();
|
||||||
|
|
||||||
|
res.json(results.map(parseGifResult)).status(200);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
@ -16,34 +16,58 @@
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
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 fetch from "node-fetch";
|
||||||
import ProxyAgent from "proxy-agent";
|
import ProxyAgent from "proxy-agent";
|
||||||
import { route } from "@spacebar/api";
|
|
||||||
import { getGifApiKey, parseGifResult } from "./trending";
|
import { getGifApiKey, parseGifResult } from "./trending";
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
router.get("/", route({}), async (req: Request, res: Response) => {
|
router.get(
|
||||||
// TODO: Custom providers
|
"/",
|
||||||
const { media_format, locale } = req.query;
|
route({
|
||||||
|
query: {
|
||||||
const apiKey = getGifApiKey();
|
media_format: {
|
||||||
|
type: "string",
|
||||||
const agent = new ProxyAgent();
|
description: "Media format",
|
||||||
|
values: Object.keys(TenorMediaTypes).filter((key) =>
|
||||||
const response = await fetch(
|
isNaN(Number(key)),
|
||||||
`https://g.tenor.com/v1/trending?media_format=${media_format}&locale=${locale}&key=${apiKey}`,
|
),
|
||||||
{
|
},
|
||||||
agent,
|
locale: {
|
||||||
method: "get",
|
type: "string",
|
||||||
headers: { "Content-Type": "application/json" },
|
description: "Locale",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
);
|
responses: {
|
||||||
|
200: {
|
||||||
|
body: "TenorGifsResponse",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
async (req: Request, res: Response) => {
|
||||||
|
// TODO: Custom providers
|
||||||
|
const { media_format, locale } = req.query;
|
||||||
|
|
||||||
const { results } = await response.json();
|
const apiKey = getGifApiKey();
|
||||||
|
|
||||||
res.json(results.map(parseGifResult)).status(200);
|
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 { results } = await response.json();
|
||||||
|
|
||||||
|
res.json(results.map(parseGifResult)).status(200);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
@ -16,66 +16,21 @@
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Router, Response, Request } from "express";
|
import { route } from "@spacebar/api";
|
||||||
|
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 fetch from "node-fetch";
|
||||||
import ProxyAgent from "proxy-agent";
|
import ProxyAgent from "proxy-agent";
|
||||||
import { route } from "@spacebar/api";
|
|
||||||
import { Config } from "@spacebar/util";
|
|
||||||
import { HTTPError } from "lambert-server";
|
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
// TODO: Move somewhere else
|
export function parseGifResult(result: TenorGif) {
|
||||||
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) {
|
|
||||||
return {
|
return {
|
||||||
id: result.id,
|
id: result.id,
|
||||||
title: result.title,
|
title: result.title,
|
||||||
@ -97,45 +52,63 @@ export function getGifApiKey() {
|
|||||||
return apiKey;
|
return apiKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
router.get("/", route({}), async (req: Request, res: Response) => {
|
router.get(
|
||||||
// TODO: Custom providers
|
"/",
|
||||||
// TODO: return gifs as mp4
|
route({
|
||||||
// const { media_format, locale } = req.query;
|
query: {
|
||||||
const { locale } = req.query;
|
locale: {
|
||||||
|
type: "string",
|
||||||
const apiKey = getGifApiKey();
|
description: "Locale",
|
||||||
|
|
||||||
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(
|
responses: {
|
||||||
`https://g.tenor.com/v1/trending?locale=${locale}&key=${apiKey}`,
|
200: {
|
||||||
{
|
body: "TenorTrendingResponse",
|
||||||
agent,
|
|
||||||
method: "get",
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
},
|
},
|
||||||
),
|
},
|
||||||
]);
|
}),
|
||||||
|
async (req: Request, res: Response) => {
|
||||||
|
// TODO: Custom providers
|
||||||
|
// TODO: return gifs as mp4
|
||||||
|
// const { media_format, locale } = req.query;
|
||||||
|
const { locale } = req.query;
|
||||||
|
|
||||||
const { tags } = (await responseSource.json()) as TENOR_CATEGORIES_RESULTS;
|
const apiKey = getGifApiKey();
|
||||||
const { results } = (await trendGifSource.json()) as TENOR_TRENDING_RESULTS;
|
|
||||||
|
|
||||||
res.json({
|
const agent = new ProxyAgent();
|
||||||
categories: tags.map((x) => ({
|
|
||||||
name: x.searchterm,
|
const [responseSource, trendGifSource] = await Promise.all([
|
||||||
src: x.image,
|
fetch(
|
||||||
})),
|
`https://g.tenor.com/v1/categories?locale=${locale}&key=${apiKey}`,
|
||||||
gifs: [parseGifResult(results[0])],
|
{
|
||||||
}).status(200);
|
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;
|
export default router;
|
||||||
|
@ -62,6 +62,14 @@ export interface RouteOptions {
|
|||||||
event?: EVENT | EVENT[];
|
event?: EVENT | EVENT[];
|
||||||
summary?: string;
|
summary?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
query?: {
|
||||||
|
[key: string]: {
|
||||||
|
type: string;
|
||||||
|
required?: boolean;
|
||||||
|
description?: string;
|
||||||
|
values?: string[];
|
||||||
|
};
|
||||||
|
};
|
||||||
// test?: {
|
// test?: {
|
||||||
// response?: RouteResponse;
|
// response?: RouteResponse;
|
||||||
// body?: unknown;
|
// body?: unknown;
|
||||||
|
72
src/util/schemas/responses/Tenor.ts
Normal file
72
src/util/schemas/responses/Tenor.ts
Normal file
@ -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[];
|
@ -13,6 +13,7 @@ export * from "./GatewayBotResponse";
|
|||||||
export * from "./GatewayResponse";
|
export * from "./GatewayResponse";
|
||||||
export * from "./GenerateRegistrationTokensResponse";
|
export * from "./GenerateRegistrationTokensResponse";
|
||||||
export * from "./LocationMetadataResponse";
|
export * from "./LocationMetadataResponse";
|
||||||
|
export * from "./Tenor";
|
||||||
export * from "./TokenResponse";
|
export * from "./TokenResponse";
|
||||||
export * from "./UserProfileResponse";
|
export * from "./UserProfileResponse";
|
||||||
export * from "./UserRelationsResponse";
|
export * from "./UserRelationsResponse";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user