Skip to content

Commit

Permalink
Add imageType (#149)
Browse files Browse the repository at this point in the history
Also:

- Pass NFT metadata to imageProxy()
- Remove image proxy from examples
- Update fetchWrapper yarn.lock
  • Loading branch information
bpierre authored Aug 16, 2021
1 parent f920644 commit 4c834df
Show file tree
Hide file tree
Showing 17 changed files with 82 additions and 48 deletions.
28 changes: 16 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,37 +74,40 @@ The useNft() hook requires two arguments: the NFT `contract` address, and its to
The returned value is an object containing information about the loading state:

```tsx
const result = useNft("0xd07dc4262bcdbf85190c01c996b4c06a461d2430", "90473")
const { status, loading, error, reload, nft } = useNft("0xd07dc4262bcdbf85190c01c996b4c06a461d2430", "90473")

// one of "error", "loading" and "done"
result.status
status

// same as status === "loading"
result.loading
loading

// undefined or Error instance when status === "error"
result.error
error

// call this function to retry in case of error
result.reload
reload

// nft is undefined when status !== "done"
result.nft
nft

// name of the NFT (or empty string)
result.nft.name
nft.name

// description of the NFT (or empty string)
result.nft.description
nft.description

// image / media URL of the NFT (or empty string)
result.nft.image
nft.image

// the type of media: "image", "video" or "unknown"
nft.imageType

// current owner of the NFT (or empty string)
result.nft.owner
nft.owner

// url of the json containing the NFT's metadata
result.nft.metadataUrl
nft.metadataUrl
```

As TypeScript type:
Expand All @@ -118,6 +121,7 @@ type NftResult = {
nft?: {
description: string
image: string
imageType: "image" | "video" | "unknown"
name: string
owner: string
metadataUrl?: string
Expand Down Expand Up @@ -185,7 +189,7 @@ Allows to proxy the image URL. This is useful to optimize (compress / resize) th
Default value:

```js
function imageProxy(url) {
function imageProxy(url, metadata) {
return url
}
```
Expand Down
8 changes: 1 addition & 7 deletions examples/ethereum/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,14 @@ import NoEthereum from "./NoEthereum"
import nfts from "../../nfts"
import useEthereum from "./use-ethereum"

const imageProxy = (url: string) =>
`https://ik.imagekit.io/p/${encodeURIComponent(url)}?tr=n-card`
const jsonProxy = (url: string) =>
`https://api.allorigins.win/raw?url=${encodeURIComponent(url)}`

function App() {
const ethereum = useEthereum()
const connected = ethereum?.isConnected()
return (
<NftProvider
fetcher={["ethereum", { ethereum }]}
imageProxy={imageProxy}
jsonProxy={jsonProxy}
>
<NftProvider fetcher={["ethereum", { ethereum }]} jsonProxy={jsonProxy}>
<Base>{connected ? <NftGrid nfts={nfts} /> : <NoEthereum />}</Base>
</NftProvider>
)
Expand Down
8 changes: 1 addition & 7 deletions examples/ethers/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,12 @@ const ethersConfig = {
provider: getDefaultProvider("homestead"),
}

const imageProxy = (url: string) =>
`https://ik.imagekit.io/p/${encodeURIComponent(url)}?tr=n-card`
const jsonProxy = (url: string) =>
`https://api.allorigins.win/raw?url=${encodeURIComponent(url)}`

function App() {
return (
<NftProvider
fetcher={["ethers", ethersConfig]}
imageProxy={imageProxy}
jsonProxy={jsonProxy}
>
<NftProvider fetcher={["ethers", ethersConfig]} jsonProxy={jsonProxy}>
<Base>
<NftGrid nfts={nfts} />
</Base>
Expand Down
10 changes: 5 additions & 5 deletions examples/fetchWrapper/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9287,14 +9287,14 @@ resolve@^2.0.0-next.3:
languageName: node
linkType: hard

"swr@npm:^1.0.0-beta.6":
version: 1.0.0-beta.6
resolution: "swr@npm:1.0.0-beta.6"
"swr@npm:^1.0.0-beta.10":
version: 1.0.0-beta.10
resolution: "swr@npm:1.0.0-beta.10"
dependencies:
dequal: 2.0.2
peerDependencies:
react: ^16.11.0 || ^17.0.0
checksum: b67113b40001be62389195341b0eb7ad10fdcb4d724166228781ba22a99f26f1d2d0a9f2b2252f7bc8695e500376390b1e552b0e3581d8ba1e9328a580318cfc
checksum: 6895e0bc2d849cfb805857fa1f8dbb792136b9bb5177e401f21b0e96e41b2e427de289ee820d4d75850b500e50d8695d89985cf8ea164a5db0e38f45e57bffb8
languageName: node
linkType: hard

Expand Down Expand Up @@ -9740,7 +9740,7 @@ resolve@^2.0.0-next.3:
version: 0.0.0-use.local
resolution: "use-nft@portal:../..::locator=fetchwrapper%40workspace%3A."
dependencies:
swr: ^1.0.0-beta.6
swr: ^1.0.0-beta.10
peerDependencies:
react: ">=17"
languageName: node
Expand Down
2 changes: 1 addition & 1 deletion src/fetchers/ethereum/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ function addProxyImage(
imageProxy: ImageProxyFn
): NftMetadata {
return metadata.image.startsWith("http")
? { ...metadata, image: imageProxy(metadata.image) }
? { ...metadata, image: imageProxy(metadata.image, metadata) }
: metadata
}

Expand Down
11 changes: 9 additions & 2 deletions src/fetchers/ethereum/standard-nft.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ import type { Address, FetchContext, NftMetadata } from "../../types"
import type { EthereumFetcherConfig, EthereumProviderEip1193 } from "./types"

import { fetchMetadata } from "../shared/fetch-metadata"
import { MultipleErrors, normalizeTokenUrl, promiseAny } from "../../utils"
import {
MultipleErrors,
normalizeTokenUrl,
promiseAny,
urlExtensionType,
} from "../../utils"
import {
decodeAddress,
decodeString,
Expand Down Expand Up @@ -50,10 +55,12 @@ export async function fetchStandardNftContractData(
])

const metadata = await fetchMetadata(metadataUrl, fetchContext)
const imageType = urlExtensionType(metadata.image)

return {
...metadata,
owner,
imageType,
metadataUrl,
owner,
}
}
2 changes: 1 addition & 1 deletion src/fetchers/ethers/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ function addProxyImage(
imageProxy: ImageProxyFn
): NftMetadata {
return metadata.image.startsWith("http")
? { ...metadata, image: imageProxy(metadata.image) }
? { ...metadata, image: imageProxy(metadata.image, metadata) }
: metadata
}

Expand Down
11 changes: 9 additions & 2 deletions src/fetchers/ethers/standard-nft.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import type { Address, FetchContext, NftMetadata } from "../../types"
import type { EthersFetcherConfig } from "./types"

import { fetchMetadata } from "../shared/fetch-metadata"
import { MultipleErrors, normalizeTokenUrl, promiseAny } from "../../utils"
import {
MultipleErrors,
normalizeTokenUrl,
promiseAny,
urlExtensionType,
} from "../../utils"

const ABI = [
// ERC-721
Expand Down Expand Up @@ -55,10 +60,12 @@ export async function fetchStandardNftContractData(
])

const metadata = await fetchMetadata(metadataUrl, fetchContext)
const imageType = urlExtensionType(metadata.image)

return {
...metadata,
owner,
imageType,
metadataUrl,
owner,
}
}
6 changes: 4 additions & 2 deletions src/fetchers/shared/cryptokitties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ export async function cryptoKittiesMetadata(
bio: string
image_url: string
}
const image = data?.image_url ?? ""
return {
description: data?.bio ?? "−",
image: data?.image_url ?? "",
image,
imageType: image ? "image" : "unknown",
metadataUrl,
name: data?.name ?? "Unknown",
owner: "",
metadataUrl,
}
}

Expand Down
1 change: 1 addition & 0 deletions src/fetchers/shared/cryptopunks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export function cryptoPunksMetadata(index: string): NftMetadata {
return {
description: CRYPTOPUNKS_DESCRIPTION,
image: `https://www.larvalabs.com/cryptopunks/cryptopunk${index}.png`,
imageType: "image",
metadataUrl: "",
name: `CryptoPunk ${index}`,
owner: "",
Expand Down
4 changes: 3 additions & 1 deletion src/fetchers/shared/decentraland-estate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,12 @@ export async function decentralandEstateMetadata(
}

const nft = data?.nfts?.[0]
const image = nft?.image ?? ""

return {
description: nft?.estate?.data?.description ?? "−",
image: nft?.image ?? "",
image,
imageType: image ? "image" : "unknown",
metadataUrl: "",
name: nft?.name ?? "Unknown",
owner: nft?.owner?.address ?? "",
Expand Down
6 changes: 4 additions & 2 deletions src/fetchers/shared/decentraland-parcel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,13 @@ export async function decentralandParcelMetadata(

const nft = data?.nfts?.[0]
const parcel = nft?.parcel
const image = nft?.image ?? ""

return {
description: parcel?.data?.description ?? "-",
image: nft?.image ?? "",
metadataUrl: '',
image,
imageType: image ? "image" : "unknown",
metadataUrl: "",
name: nft?.name ?? `Parcel ${parcel?.x},${parcel?.y}`,
owner: nft?.owner?.address ?? "",
}
Expand Down
1 change: 1 addition & 0 deletions src/fetchers/shared/mooncats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export async function moonCatsMetadata(
`The (unofficial) wrapped version of MoonCats Rescue. ` +
`Original cat ID: ${catId}.`,
image,
imageType: image ? "image" : "unknown",
metadataUrl: "",
name: `Wrapped MoonCat #${tokenId}`,
owner: "",
Expand Down
5 changes: 3 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ export type NftResult = NftResultLoading | NftResultError | NftResultDone
export type NftMetadata = {
description: string
image: string
imageType: "image" | "video" | "unknown"
metadataUrl: string
name: string
owner: Address
metadataUrl: string
}

export type NftJsonMetadata = {
Expand Down Expand Up @@ -70,7 +71,7 @@ export type FetcherDeclaration =

export type FetcherProp = Fetcher<unknown> | FetcherDeclaration

export type ImageProxyFn = (url: string) => string
export type ImageProxyFn = (url: string, metadata: NftMetadata) => string
export type JsonProxyFn = (url: string) => string
export type IpfsUrlFn = (cid: string, path?: string) => string

Expand Down
10 changes: 10 additions & 0 deletions src/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -261,3 +261,13 @@ export class MultipleErrors extends Error {
this.errors = errors
}
}

const IMAGE_EXT_RE = /\.(?:png|svg|jpg|jepg|gif|webp|jxl|avif)$/
const VIDEO_EXT_RE = /\.(?:mp4|mov|webm|ogv)$/

// Guess a file type from the extension used in a URL
export function urlExtensionType(url: string): NftMetadata["imageType"] {
if (IMAGE_EXT_RE.test(url)) return "image"
if (VIDEO_EXT_RE.test(url)) return "video"
return "unknown"
}
13 changes: 11 additions & 2 deletions test/utils.test.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import {
fetchImage,
ipfsUrlFromString,
identity,
ipfsUrlDefault,
ipfsUrlFromString,
isAddress,
identity,
normalizeImageUrl,
normalizeNftMetadata,
normalizeNiftyGatewayUrl,
normalizeOpenSeaUrl,
normalizeTokenUrl,
parseNftUrl,
urlExtensionType,
} from "../src/utils"

const IPFS_HASH_1 =
Expand Down Expand Up @@ -187,3 +188,11 @@ describe("normalizeNftMetadata()", () => {
})
})
})

describe("urlExtensionType()", () => {
it("guesses the asset type from the URL", () => {
expect(urlExtensionType("something.jpg")).toBe("image")
expect(urlExtensionType("something.mov")).toBe("video")
expect(urlExtensionType("something.xyz")).toBe("unknown")
})
})
4 changes: 2 additions & 2 deletions website/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ const fetcher = [
},
]

const imageProxy = (url: string) =>
url.endsWith(".mp4")
const imageProxy = (url: string, metadata: NftMetadata) =>
metadata.imageType === "video"
? url
: `https://ik.imagekit.io/p/${encodeURIComponent(url)}?tr=n-card`

Expand Down

0 comments on commit 4c834df

Please sign in to comment.