Skip to content

Commit

Permalink
Replace peekalink with OpenGraph Ninja API (#157)
Browse files Browse the repository at this point in the history
* Replace peekalink with OpenGraph Ninja API

* Switch to url.href for OpenGraph call
  • Loading branch information
SSHari committed May 23, 2023
1 parent fbddb63 commit 9a46c6a
Show file tree
Hide file tree
Showing 7 changed files with 245 additions and 95 deletions.
4 changes: 1 addition & 3 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,7 @@ You should now be able to access your local JSON Hero server on [localhost:8787]
### Previewing URLs

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.

If you'd like to enable this functionality locally, signup for Peekalink and set the `PEEKALINK_API_KEY`
We currently use [OpenGraph Ninja](https://opengraph.ninja/) to power some of the Preview URL functionality.

### Deploying to Cloudflare

Expand Down
1 change: 0 additions & 1 deletion app/bindings.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@ declare global {
const SESSION_SECRET: string;
const GRAPH_JSON_API_KEY: string;
const GRAPH_JSON_COLLECTION: string;
const PEEKALINK_API_KEY: string;
const APIHERO_PROJECT_KEY: string;
}
68 changes: 1 addition & 67 deletions app/components/Preview/Types/PreviewHtml.tsx
Original file line number Diff line number Diff line change
@@ -1,78 +1,13 @@
import {
ArrowRightIcon,
CalendarIcon,
EyeIcon,
ThumbUpIcon,
} from "@heroicons/react/outline";
import { inferType } from "@jsonhero/json-infer-types";
import { Body } from "~/components/Primitives/Body";
import { Title } from "~/components/Primitives/Title";
import { formatNumber, formatValue } from "~/utilities/formatter";
import { PreviewBox } from "../PreviewBox";
import { PreviewProperties, PreviewProperty } from "../PreviewProperties";
import { PreviewHtml } from "./preview.types";
import { RetweetIcon } from "./RetweetIcon";

export type PreviewHtmlProps = {
info: PreviewHtml;
};

export function PreviewHtml({ info }: PreviewHtmlProps) {
const formatDate = (dateString: string): string => {
return formatValue(inferType(dateString)) ?? dateString;
};

const details = () => {
if (!info.details) {
return <></>;
}

switch (info.details.type) {
case "youtube": {
const properties: Array<PreviewProperty> = [
{
key: "likeCount",
title: formatNumber(info.details.likeCount),
icon: <ThumbUpIcon />,
},
{
key: "viewCount",
title: formatNumber(info.details.viewCount),
icon: <EyeIcon />,
},
{
key: "date",
title: formatDate(info.details.publishedAt),
icon: <CalendarIcon />,
},
];
return <PreviewProperties properties={properties} />;
}
case "twitter": {
const properties: Array<PreviewProperty> = [
{
key: "likeCount",
title: formatNumber(info.details.likesCount),
icon: <ThumbUpIcon />,
},
{
key: "retweetCount",
title: formatNumber(info.details.retweetCount),
icon: <RetweetIcon />,
},
{
key: "date",
title: formatDate(info.details.publishedAt),
icon: <CalendarIcon />,
},
];
return <PreviewProperties properties={properties} />;
}
}

return <></>;
};

return (
<PreviewBox link={info.url}>
<div>
Expand All @@ -88,10 +23,9 @@ export function PreviewHtml({ info }: PreviewHtmlProps) {
</div>
{info.image && (
<div>
<img className="block" src={info.image?.url} alt="" />
<img className="block" src={info.image?.url} alt={info.image?.alt} />
</div>
)}
{details()}
</PreviewBox>
);
}
221 changes: 219 additions & 2 deletions app/components/Preview/Types/preview.types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,223 @@ declare type TwitterLinkDetails = {

declare type ImageAssetDetails = {
url: string;
width: number;
height: number;
alt?: string;
width?: number;
height?: number;
};

/* OpenGraph Ninja Types */
// Types adapted from https://github.com/opengraphninja/react/blob/main/src/types.d.ts
type OpenGraphMedia = {
height: string | null;
type: string | null;
url: string;
width: string | null;
};

type OpenGraphTwitterImage = {
height: string | null;
alt: string | null;
url: string;
width: string | null;
};

type OpenGraphTwitterPlayer = {
height: string | null;
stream: string | null;
url: string;
width: string | null;
};

type OpenGraphMusicSong = {
url: string;
track: string | null;
disc: string | null;
};

type OpenGraphDetails = {
alAndroidAppName?: string;
alAndroidClass?: string;
alAndroidPackage?: string;
alAndroidUrl?: string;
alIosAppName?: string;
alIosAppStoreId?: string;
alIosUrl?: string;
alIpadAppName?: string;
alIpadAppStoreId?: string;
alIpadUrl?: string;
alIphoneAppName?: string;
alIphoneAppStoreId?: string;
alIphoneUrl?: string;
alWebShouldFallback?: string;
alWebUrl?: string;
alWindowsAppId?: string;
alWindowsAppName?: string;
alWindowsPhoneAppId?: string;
alWindowsPhoneAppName?: string;
alWindowsPhoneUrl?: string;
alWindowsUniversalAppId?: string;
alWindowsUniversalAppName?: string;
alWindowsUniversalUrl?: string;
alWindowsUrl?: string;
articleAuthor?: string;
articleExpirationTime?: string;
articleModifiedTime?: string;
articlePublishedTime?: string;
articlePublisher?: string;
articleSection?: string;
articleTag?: string;
author?: string;
bookAuthor?: string;
bookCanonicalName?: string;
bookIsbn?: string;
bookReleaseDate?: string;
booksBook?: string;
booksRatingScale?: string;
booksRatingValue?: string;
bookTag?: string;
businessContactDataCountryName?: string;
businessContactDataLocality?: string;
businessContactDataPostalCode?: string;
businessContactDataRegion?: string;
businessContactDataStreetAddress?: string;
dcContributor?: string;
dcCoverage?: string;
dcCreator?: string;
dcDate?: string;
dcDateCreated?: string;
dcDateIssued?: string;
dcDescription?: string;
dcFormatMedia?: string;
dcFormatSize?: string;
dcIdentifier?: string;
dcLanguage?: string;
dcPublisher?: string;
dcRelation?: string;
dcRights?: string;
dcSource?: string;
dcSubject?: string;
dcTitle?: string;
dcType?: string;
modifiedTime?: string;
musicAlbum?: string | string[];
musicAlbumDisc?: string;
musicAlbumTrack?: string;
musicAlbumUrl?: string;
musicCreator?: string | string[];
musicDuration?: string;
musicMusician?: string | string[];
musicReleaseDate?: string;
musicSong?: OpenGraphMusicSong;
musicSongDisc?: string | string[];
musicSongTrack?: string | string[];
musicSongUrl?: string | string[];
ogArticleAuthor?: string;
ogArticleExpirationTime?: string;
ogArticleModifiedTime?: string;
ogArticlePublishedTime?: string;
ogArticlePublisher?: string;
ogArticleSection?: string;
ogArticleTag?: string;
ogAudio?: string;
ogAudioSecureURL?: string;
ogAudioType?: string;
ogAudioURL?: string;
ogAvailability?: string;
ogDate?: string;
ogDescription?: string;
ogDeterminer?: string;
ogImage?: OpenGraphMedia | OpenGraphMedia[];
ogImageHeight?: string | string[];
ogImageSecureURL?: string | string[];
ogImageType?: string | string[];
ogImageURL?: string | string[];
ogImageWidth?: string | string[];
ogLocale?: string;
ogLocaleAlternate?: string;
ogLogo?: string;
ogPriceAmount?: string;
ogPriceCurrency?: string;
ogProductAvailability?: string;
ogProductCondition?: string;
ogProductPriceAmount?: string;
ogProductPriceCurrency?: string;
ogProductRetailerItemId?: string;
ogSiteName?: string;
ogTitle?: string;
ogType?: string;
ogUrl?: string;
ogVideo?: OpenGraphMedia | OpenGraphMedia[];
ogVideoActorId?: string | string[];
ogVideoHeight?: string | string[];
ogVideoSecureURL?: string | string[];
ogVideoType?: string | string[];
ogVideoWidth?: string | string[];
placeLocationLatitude?: string;
placeLocationLongitude?: string;
profileFirstName?: string;
profileGender?: string;
profileLastName?: string;
profileUsername?: string;
publishedTime?: string;
releaseDate?: string;
restaurantContactInfoCountryName?: string;
restaurantContactInfoEmail?: string;
restaurantContactInfoLocality?: string;
restaurantContactInfoPhoneNumber?: string;
restaurantContactInfoPostalCode?: string;
restaurantContactInfoRegion?: string;
restaurantContactInfoStreetAddress?: string;
restaurantContactInfoWebsite?: string;
restaurantMenu?: string;
restaurantRestaurant?: string;
restaurantSection?: string;
restaurantVariationPriceAmount?: string;
restaurantVariationPriceCurrency?: string;
twitterAppIdGooglePlay?: string;
twitterAppIdiPad?: string;
twitterAppIdiPhone?: string;
twitterAppNameGooglePlay?: string;
twitterAppNameiPad?: string;
twitterAppNameiPhone?: string;
twitterAppUrlGooglePlay?: string;
twitterAppUrliPad?: string;
twitterAppUrliPhone?: string;
twitterCard?: string;
twitterCreator?: string;
twitterCreatorId?: string;
twitterDescription?: string;
twitterImage?: OpenGraphTwitterImage | OpenGraphTwitterImage[];
twitterImageAlt?: string | string[];
twitterImageHeight?: string | string[];
twitterImageSrc?: string | string[];
twitterImageWidth?: string | string[];
twitterPlayer?: OpenGraphTwitterPlayer | OpenGraphTwitterPlayer[];
twitterPlayerHeight?: string | string[];
twitterPlayerStream?: string | string[];
twitterPlayerStreamContentType?: string | string[];
twitterPlayerWidth?: string | string[];
twitterSite?: string;
twitterSiteId?: string;
twitterTitle?: string;
twitterUrl?: string;
updatedTime?: string;
favicon?: string;
[key: string]: any;
};

export type OpenGraphPreviewData = {
hostname: string;
requestUrl: string;
title: string;
description: string;
image?: {
url: string;
alt?: string;
};
details: Details;
};

export type OpenGraphPreviewDataError = {
error: string;
};
Loading

0 comments on commit 9a46c6a

Please sign in to comment.