Skip to content

Commit bdbf539

Browse files
committed
Add fetch embed module & test
1 parent a586347 commit bdbf539

File tree

5 files changed

+190
-0
lines changed

5 files changed

+190
-0
lines changed

deno.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"license": "MIT",
1212
"tasks": {
1313
"build": "deno run -A ./scripts/build_npm.ts",
14+
"eval": "deno run --allow-net scripts/eval.ts",
1415
"sync": "deno run --allow-net --allow-write --allow-read scripts/sync.ts"
1516
},
1617
"imports": {

mod.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
// mod.ts
22

3+
import extractWithDiscovery from './utils/auto_discovery.ts'
4+
import fetchEmbed from './utils/fetch_embed.ts'
5+
36
export {
47
find as findProvider,
58
has as hasProvider,

scripts/eval.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env deno run --allow-net
2+
3+
const url = Deno.args[0];
4+
console.log(url)

tests/feed_embed_test.ts

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
// feed_embed_test.ts
2+
3+
import { assertEquals, assertRejects } from "https://deno.land/std/testing/asserts.ts";
4+
import { mockFetch, resetFetch } from "jsr:@c4spar/mock-fetch";
5+
import { isObject, hasProperty } from "jsr:@ndaidong/bellajs";
6+
7+
import { getEndpoint } from '../utils/provider.ts'
8+
9+
import fetchEmbed from '../utils/fetch_embed.ts'
10+
11+
const parseUrl = (url: string): any => {
12+
const re = new URL(url)
13+
return {
14+
baseUrl: `${re.protocol}//${re.host}`,
15+
path: re.pathname,
16+
}
17+
}
18+
19+
Deno.test("test if fetchEmbed() works correctly", async (t) => {
20+
const cases = [
21+
{
22+
input: {
23+
url: 'https://youtu.be/iQzwqZgr8Hc',
24+
file: './tests/test_data/youtube.json',
25+
},
26+
expected: {
27+
provider_name: 'YouTube',
28+
type: 'video',
29+
},
30+
},
31+
{
32+
input: {
33+
url: 'https://twitter.com/ndaidong/status/1173592062878314497',
34+
file: './tests/test_data/twitter.json',
35+
},
36+
expected: {
37+
provider_name: 'Twitter',
38+
type: 'rich',
39+
},
40+
},
41+
{
42+
input: {
43+
url: 'https://twitter.com/ndaidong/status/1173592062878314497?theme=dark',
44+
file: './tests/test_data/twitter-dark.json',
45+
},
46+
expected: {
47+
provider_name: 'Twitter',
48+
type: 'rich',
49+
},
50+
},
51+
{
52+
input: {
53+
url: 'https://www.facebook.com/facebook/videos/10153231379946729/',
54+
params: {
55+
access_token: '845078789498971|8ff3ab4ddd45b8f018b35c4fb7edac62',
56+
},
57+
file: './tests/test_data/facebook.json',
58+
},
59+
expected: {
60+
provider_name: 'Facebook',
61+
type: 'video',
62+
},
63+
},
64+
{
65+
input: {
66+
url: 'http://farm4.static.flickr.com/3123/2341623661_7c99f48bbf_m.jpg',
67+
file: './tests/test_data/flickr-default.json',
68+
},
69+
expected: {
70+
provider_name: 'Flickr',
71+
type: 'photo',
72+
maxwidth: 1024,
73+
maxheight: 683,
74+
},
75+
},
76+
{
77+
input: {
78+
url: 'http://farm4.static.flickr.com/3123/2341623661_7c99f48bbf_m.jpg',
79+
params: {
80+
maxwidth: 800,
81+
maxheight: 400,
82+
},
83+
file: './tests/test_data/flickr-sizelimit.json',
84+
},
85+
expected: {
86+
provider_name: 'Flickr',
87+
type: 'photo',
88+
maxwidth: 800,
89+
maxheight: 400,
90+
},
91+
},
92+
];
93+
94+
for (const ucase of cases) {
95+
const { input, expected } = ucase;
96+
const { url, file: mockFile } = input;
97+
const params: any = input.params || {}
98+
await t.step(`check fetchEmbed("${url}")`, async () => {
99+
const endpoint = getEndpoint(url) || ''
100+
const { baseUrl, path } = parseUrl(endpoint)
101+
102+
const queries = new URLSearchParams({
103+
url,
104+
format: 'json',
105+
...params,
106+
})
107+
108+
const target = `${endpoint}?${queries.toString()}`;
109+
console.log(target)
110+
111+
const fakeJson = await Deno.readTextFile(mockFile);
112+
mockFetch(target, {
113+
body: fakeJson,
114+
headers: {
115+
'Content-Type': 'application/json',
116+
}
117+
});
118+
119+
const maxwidth: number = Number(params.maxwidth || 0)
120+
const maxheight: number = Number(params.maxheight || 0)
121+
122+
const result = await fetchEmbed(url, { maxwidth, maxheight }, endpoint);
123+
assertEquals(isObject(result), true);
124+
assertEquals(result.provider_name, expected.provider_name)
125+
assertEquals(result.type, expected.type)
126+
127+
resetFetch();
128+
});
129+
}
130+
});

utils/fetch_embed.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// fetch_embed.ts
2+
3+
import { getJson, FetchOptions } from './retrieve.ts';
4+
import { getDomain } from './linker.ts';
5+
6+
const isFacebookGraphDependent = (url: string): boolean => {
7+
return getDomain(url) === 'graph.facebook.com';
8+
}
9+
10+
const getFacebookGraphToken = (): string => {
11+
const env = Deno.env.toObject();
12+
const appId = env.FACEBOOK_APP_ID;
13+
const clientToken = env.FACEBOOK_CLIENT_TOKEN;
14+
return `${appId}|${clientToken}`;
15+
}
16+
17+
interface Params {
18+
[key: string]: string | number | undefined;
19+
}
20+
21+
export default async (
22+
url: string,
23+
params: Params = {},
24+
endpoint: string = '',
25+
options: FetchOptions = {}
26+
): Promise<any> => {
27+
const query: Params = {
28+
url,
29+
format: 'json',
30+
...params,
31+
};
32+
33+
const maxwidth: number = Number(query.maxwidth || 0)
34+
const maxheight: number = Number(query.maxheight || 0)
35+
36+
if (maxwidth <= 0) {
37+
delete query.maxwidth;
38+
}
39+
if (maxheight <= 0) {
40+
delete query.maxheight;
41+
}
42+
43+
if (isFacebookGraphDependent(endpoint)) {
44+
query.access_token = getFacebookGraphToken();
45+
}
46+
47+
const queryParams = new URLSearchParams(query as Record<string, string>).toString();
48+
const link = `${endpoint}?${queryParams}`;
49+
const body = await getJson(link, options);
50+
body.method = 'provider-api';
51+
return body;
52+
}

0 commit comments

Comments
 (0)