Skip to content

Commit 9a46c6a

Browse files
authored
Replace peekalink with OpenGraph Ninja API (#157)
* Replace peekalink with OpenGraph Ninja API * Switch to url.href for OpenGraph call
1 parent fbddb63 commit 9a46c6a

File tree

7 files changed

+245
-95
lines changed

7 files changed

+245
-95
lines changed

DEVELOPMENT.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,7 @@ You should now be able to access your local JSON Hero server on [localhost:8787]
7676
7777
### Previewing URLs
7878

79-
We currently use [Peekalink](https://www.peekalink.io) to power some of the Preview URL functionality. This feature is disabled unless there is a valid `PEEKALINK_API_KEY` environment variable set in your `.env` file created above.
80-
81-
If you'd like to enable this functionality locally, signup for Peekalink and set the `PEEKALINK_API_KEY`
79+
We currently use [OpenGraph Ninja](https://opengraph.ninja/) to power some of the Preview URL functionality.
8280

8381
### Deploying to Cloudflare
8482

app/bindings.d.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,5 @@ declare global {
55
const SESSION_SECRET: string;
66
const GRAPH_JSON_API_KEY: string;
77
const GRAPH_JSON_COLLECTION: string;
8-
const PEEKALINK_API_KEY: string;
98
const APIHERO_PROJECT_KEY: string;
109
}
Lines changed: 1 addition & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,13 @@
1-
import {
2-
ArrowRightIcon,
3-
CalendarIcon,
4-
EyeIcon,
5-
ThumbUpIcon,
6-
} from "@heroicons/react/outline";
7-
import { inferType } from "@jsonhero/json-infer-types";
81
import { Body } from "~/components/Primitives/Body";
92
import { Title } from "~/components/Primitives/Title";
10-
import { formatNumber, formatValue } from "~/utilities/formatter";
113
import { PreviewBox } from "../PreviewBox";
12-
import { PreviewProperties, PreviewProperty } from "../PreviewProperties";
134
import { PreviewHtml } from "./preview.types";
14-
import { RetweetIcon } from "./RetweetIcon";
155

166
export type PreviewHtmlProps = {
177
info: PreviewHtml;
188
};
199

2010
export function PreviewHtml({ info }: PreviewHtmlProps) {
21-
const formatDate = (dateString: string): string => {
22-
return formatValue(inferType(dateString)) ?? dateString;
23-
};
24-
25-
const details = () => {
26-
if (!info.details) {
27-
return <></>;
28-
}
29-
30-
switch (info.details.type) {
31-
case "youtube": {
32-
const properties: Array<PreviewProperty> = [
33-
{
34-
key: "likeCount",
35-
title: formatNumber(info.details.likeCount),
36-
icon: <ThumbUpIcon />,
37-
},
38-
{
39-
key: "viewCount",
40-
title: formatNumber(info.details.viewCount),
41-
icon: <EyeIcon />,
42-
},
43-
{
44-
key: "date",
45-
title: formatDate(info.details.publishedAt),
46-
icon: <CalendarIcon />,
47-
},
48-
];
49-
return <PreviewProperties properties={properties} />;
50-
}
51-
case "twitter": {
52-
const properties: Array<PreviewProperty> = [
53-
{
54-
key: "likeCount",
55-
title: formatNumber(info.details.likesCount),
56-
icon: <ThumbUpIcon />,
57-
},
58-
{
59-
key: "retweetCount",
60-
title: formatNumber(info.details.retweetCount),
61-
icon: <RetweetIcon />,
62-
},
63-
{
64-
key: "date",
65-
title: formatDate(info.details.publishedAt),
66-
icon: <CalendarIcon />,
67-
},
68-
];
69-
return <PreviewProperties properties={properties} />;
70-
}
71-
}
72-
73-
return <></>;
74-
};
75-
7611
return (
7712
<PreviewBox link={info.url}>
7813
<div>
@@ -88,10 +23,9 @@ export function PreviewHtml({ info }: PreviewHtmlProps) {
8823
</div>
8924
{info.image && (
9025
<div>
91-
<img className="block" src={info.image?.url} alt="" />
26+
<img className="block" src={info.image?.url} alt={info.image?.alt} />
9227
</div>
9328
)}
94-
{details()}
9529
</PreviewBox>
9630
);
9731
}

app/components/Preview/Types/preview.types.d.ts

Lines changed: 219 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,223 @@ declare type TwitterLinkDetails = {
5656

5757
declare type ImageAssetDetails = {
5858
url: string;
59-
width: number;
60-
height: number;
59+
alt?: string;
60+
width?: number;
61+
height?: number;
62+
};
63+
64+
/* OpenGraph Ninja Types */
65+
// Types adapted from https://github.com/opengraphninja/react/blob/main/src/types.d.ts
66+
type OpenGraphMedia = {
67+
height: string | null;
68+
type: string | null;
69+
url: string;
70+
width: string | null;
71+
};
72+
73+
type OpenGraphTwitterImage = {
74+
height: string | null;
75+
alt: string | null;
76+
url: string;
77+
width: string | null;
78+
};
79+
80+
type OpenGraphTwitterPlayer = {
81+
height: string | null;
82+
stream: string | null;
83+
url: string;
84+
width: string | null;
85+
};
86+
87+
type OpenGraphMusicSong = {
88+
url: string;
89+
track: string | null;
90+
disc: string | null;
91+
};
92+
93+
type OpenGraphDetails = {
94+
alAndroidAppName?: string;
95+
alAndroidClass?: string;
96+
alAndroidPackage?: string;
97+
alAndroidUrl?: string;
98+
alIosAppName?: string;
99+
alIosAppStoreId?: string;
100+
alIosUrl?: string;
101+
alIpadAppName?: string;
102+
alIpadAppStoreId?: string;
103+
alIpadUrl?: string;
104+
alIphoneAppName?: string;
105+
alIphoneAppStoreId?: string;
106+
alIphoneUrl?: string;
107+
alWebShouldFallback?: string;
108+
alWebUrl?: string;
109+
alWindowsAppId?: string;
110+
alWindowsAppName?: string;
111+
alWindowsPhoneAppId?: string;
112+
alWindowsPhoneAppName?: string;
113+
alWindowsPhoneUrl?: string;
114+
alWindowsUniversalAppId?: string;
115+
alWindowsUniversalAppName?: string;
116+
alWindowsUniversalUrl?: string;
117+
alWindowsUrl?: string;
118+
articleAuthor?: string;
119+
articleExpirationTime?: string;
120+
articleModifiedTime?: string;
121+
articlePublishedTime?: string;
122+
articlePublisher?: string;
123+
articleSection?: string;
124+
articleTag?: string;
125+
author?: string;
126+
bookAuthor?: string;
127+
bookCanonicalName?: string;
128+
bookIsbn?: string;
129+
bookReleaseDate?: string;
130+
booksBook?: string;
131+
booksRatingScale?: string;
132+
booksRatingValue?: string;
133+
bookTag?: string;
134+
businessContactDataCountryName?: string;
135+
businessContactDataLocality?: string;
136+
businessContactDataPostalCode?: string;
137+
businessContactDataRegion?: string;
138+
businessContactDataStreetAddress?: string;
139+
dcContributor?: string;
140+
dcCoverage?: string;
141+
dcCreator?: string;
142+
dcDate?: string;
143+
dcDateCreated?: string;
144+
dcDateIssued?: string;
145+
dcDescription?: string;
146+
dcFormatMedia?: string;
147+
dcFormatSize?: string;
148+
dcIdentifier?: string;
149+
dcLanguage?: string;
150+
dcPublisher?: string;
151+
dcRelation?: string;
152+
dcRights?: string;
153+
dcSource?: string;
154+
dcSubject?: string;
155+
dcTitle?: string;
156+
dcType?: string;
157+
modifiedTime?: string;
158+
musicAlbum?: string | string[];
159+
musicAlbumDisc?: string;
160+
musicAlbumTrack?: string;
161+
musicAlbumUrl?: string;
162+
musicCreator?: string | string[];
163+
musicDuration?: string;
164+
musicMusician?: string | string[];
165+
musicReleaseDate?: string;
166+
musicSong?: OpenGraphMusicSong;
167+
musicSongDisc?: string | string[];
168+
musicSongTrack?: string | string[];
169+
musicSongUrl?: string | string[];
170+
ogArticleAuthor?: string;
171+
ogArticleExpirationTime?: string;
172+
ogArticleModifiedTime?: string;
173+
ogArticlePublishedTime?: string;
174+
ogArticlePublisher?: string;
175+
ogArticleSection?: string;
176+
ogArticleTag?: string;
177+
ogAudio?: string;
178+
ogAudioSecureURL?: string;
179+
ogAudioType?: string;
180+
ogAudioURL?: string;
181+
ogAvailability?: string;
182+
ogDate?: string;
183+
ogDescription?: string;
184+
ogDeterminer?: string;
185+
ogImage?: OpenGraphMedia | OpenGraphMedia[];
186+
ogImageHeight?: string | string[];
187+
ogImageSecureURL?: string | string[];
188+
ogImageType?: string | string[];
189+
ogImageURL?: string | string[];
190+
ogImageWidth?: string | string[];
191+
ogLocale?: string;
192+
ogLocaleAlternate?: string;
193+
ogLogo?: string;
194+
ogPriceAmount?: string;
195+
ogPriceCurrency?: string;
196+
ogProductAvailability?: string;
197+
ogProductCondition?: string;
198+
ogProductPriceAmount?: string;
199+
ogProductPriceCurrency?: string;
200+
ogProductRetailerItemId?: string;
201+
ogSiteName?: string;
202+
ogTitle?: string;
203+
ogType?: string;
204+
ogUrl?: string;
205+
ogVideo?: OpenGraphMedia | OpenGraphMedia[];
206+
ogVideoActorId?: string | string[];
207+
ogVideoHeight?: string | string[];
208+
ogVideoSecureURL?: string | string[];
209+
ogVideoType?: string | string[];
210+
ogVideoWidth?: string | string[];
211+
placeLocationLatitude?: string;
212+
placeLocationLongitude?: string;
213+
profileFirstName?: string;
214+
profileGender?: string;
215+
profileLastName?: string;
216+
profileUsername?: string;
217+
publishedTime?: string;
218+
releaseDate?: string;
219+
restaurantContactInfoCountryName?: string;
220+
restaurantContactInfoEmail?: string;
221+
restaurantContactInfoLocality?: string;
222+
restaurantContactInfoPhoneNumber?: string;
223+
restaurantContactInfoPostalCode?: string;
224+
restaurantContactInfoRegion?: string;
225+
restaurantContactInfoStreetAddress?: string;
226+
restaurantContactInfoWebsite?: string;
227+
restaurantMenu?: string;
228+
restaurantRestaurant?: string;
229+
restaurantSection?: string;
230+
restaurantVariationPriceAmount?: string;
231+
restaurantVariationPriceCurrency?: string;
232+
twitterAppIdGooglePlay?: string;
233+
twitterAppIdiPad?: string;
234+
twitterAppIdiPhone?: string;
235+
twitterAppNameGooglePlay?: string;
236+
twitterAppNameiPad?: string;
237+
twitterAppNameiPhone?: string;
238+
twitterAppUrlGooglePlay?: string;
239+
twitterAppUrliPad?: string;
240+
twitterAppUrliPhone?: string;
241+
twitterCard?: string;
242+
twitterCreator?: string;
243+
twitterCreatorId?: string;
244+
twitterDescription?: string;
245+
twitterImage?: OpenGraphTwitterImage | OpenGraphTwitterImage[];
246+
twitterImageAlt?: string | string[];
247+
twitterImageHeight?: string | string[];
248+
twitterImageSrc?: string | string[];
249+
twitterImageWidth?: string | string[];
250+
twitterPlayer?: OpenGraphTwitterPlayer | OpenGraphTwitterPlayer[];
251+
twitterPlayerHeight?: string | string[];
252+
twitterPlayerStream?: string | string[];
253+
twitterPlayerStreamContentType?: string | string[];
254+
twitterPlayerWidth?: string | string[];
255+
twitterSite?: string;
256+
twitterSiteId?: string;
257+
twitterTitle?: string;
258+
twitterUrl?: string;
259+
updatedTime?: string;
260+
favicon?: string;
261+
[key: string]: any;
262+
};
263+
264+
export type OpenGraphPreviewData = {
265+
hostname: string;
266+
requestUrl: string;
267+
title: string;
268+
description: string;
269+
image?: {
270+
url: string;
271+
alt?: string;
272+
};
273+
details: Details;
274+
};
275+
276+
export type OpenGraphPreviewDataError = {
277+
error: string;
61278
};

0 commit comments

Comments
 (0)