Skip to content

Commit

Permalink
Get IPFS images statically, if not available, get from IPFS gateway
Browse files Browse the repository at this point in the history
  • Loading branch information
yuetloo committed Jul 6, 2024
1 parent 6c248ad commit da1257f
Show file tree
Hide file tree
Showing 18 changed files with 2,830 additions and 75 deletions.
10 changes: 5 additions & 5 deletions contracts/tasks/runners/exportImages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
*/

import { task } from 'hardhat/config'
import { FetchRequest } from 'ethers'
import { isPathExist, makeDirectory } from '../../utils/misc'
import { getIpfsContent } from '@clrfund/common'
import fs from 'fs'

/**
Expand All @@ -31,11 +31,11 @@ async function download({
ipfsHash: string
outputDir: string
}) {
const url = new URL(`ipfs/${ipfsHash}`, gateway)
const req = new FetchRequest(url.href)
const res = await req.send()
if (!ipfsHash) return

const res = await getIpfsContent(ipfsHash, gateway)
if (res.hasBody()) {
console.log('Downloading', ipfsHash)
console.log('Downloaded', ipfsHash)
fs.writeFileSync(`${outputDir}/${ipfsHash}`, res.body)
}
}
Expand Down
38 changes: 15 additions & 23 deletions vue-app/src/api/projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ export interface LeaderboardProject {
id: string // Address or another ID depending on registry implementation
name: string
index: number
bannerImageUrl?: string
thumbnailImageUrl?: string
imageUrl?: string
bannerImageHash?: string
thumbnailImageHash?: string
allocatedAmount: bigint
votes: bigint
donation: bigint
Expand All @@ -39,9 +38,8 @@ export interface Project {
websiteUrl?: string
twitterUrl?: string
discordUrl?: string
bannerImageUrl?: string
thumbnailImageUrl?: string
imageUrl?: string // TODO remove
bannerImageHash?: string
thumbnailImageHash?: string
index: number
isHidden: boolean // Hidden from the list (does not participate in round)
isLocked: boolean // Visible, but contributions are not allowed
Expand Down Expand Up @@ -134,17 +132,13 @@ export async function getProjectByIndex(
metadata = {}
}

const thumbnailImageUrl = metadata.thumbnailImageHash
? `${ipfsGatewayUrl}/ipfs/${metadata.thumbnailImageHash}`
: `${ipfsGatewayUrl}/ipfs/${metadata.imageUrl}`

return {
id: recipient.id,
address: recipient.recipientAddress || '',
name: metadata.name,
description: metadata.description,
tagline: metadata.tagline,
thumbnailImageUrl,
thumbnailImageHash: metadata.thumbnailImageHash || metadata.imageHash,
index: recipient.recipientIndex,
}
}
Expand Down Expand Up @@ -182,12 +176,12 @@ export async function getRecipientIdByHash(transactionHash: string): Promise<str
}

export function toLeaderboardProject(project: any): LeaderboardProject {
const imageUrl = `${ipfsGatewayUrl}/ipfs/${project.metadata.imageHash || project.metadata.thumbnailImageHash}`
return {
id: project.id,
name: project.name,
index: getNumber(project.recipientIndex),
imageUrl,
thumbnailImageHash: project.metadata.thumbnailImageHash || project.metadata.imageHash,
bannerImageHash: project.metadata.bannerImageHash,
allocatedAmount: BigInt(project.allocatedAmount || '0'),
votes: BigInt(project.tallyResult || '0'),
donation: BigInt(project.spentVoiceCredits || '0'),
Expand All @@ -207,10 +201,8 @@ export async function getLeaderboardProject(
const project = data.projects.find(project => project.id === projectId)

const metadata = project.metadata
const thumbnailHash = metadata.thumbnailImageHash || metadata.imageHash
const thumbnailImageUrl = thumbnailHash ? `${ipfsGatewayUrl}/ipfs/${thumbnailHash}` : undefined
const bannerHash = metadata.bannerImageHash || metadata.imageHash
const bannerImageUrl = bannerHash ? `${ipfsGatewayUrl}/ipfs/${bannerHash}` : undefined
const thumbnailImageHash = metadata.thumbnailImageHash || metadata.imageHash
const bannerImageHash = metadata.bannerImageHash || metadata.imageHash

return {
id: project.id,
Expand All @@ -228,8 +220,8 @@ export async function getLeaderboardProject(
websiteUrl: metadata.websiteUrl,
twitterUrl: metadata.twitterUrl,
discordUrl: metadata.discordUrl,
thumbnailImageUrl,
bannerImageUrl,
thumbnailImageHash,
bannerImageHash,
index: project.recipientIndex,
isHidden: false, // always show leaderboard project
isLocked: true, // Visible, but contributions are not allowed
Expand All @@ -254,8 +246,8 @@ export function formToProjectInterface(data: RecipientApplicationData): Project
websiteUrl: links.website,
twitterUrl: links.twitter,
discordUrl: links.discord,
bannerImageUrl: `${ipfsGatewayUrl}/ipfs/${image.bannerHash}`,
thumbnailImageUrl: `${ipfsGatewayUrl}/ipfs/${image.thumbnailHash}`,
bannerImageHash: image.bannerHash,
thumbnailImageHash: image.thumbnailHash,
index: 0,
isHidden: false,
isLocked: true,
Expand Down Expand Up @@ -284,8 +276,8 @@ export function staticDataToProjectInterface(project: any): Project {
websiteUrl: project.metadata.websiteUrl,
twitterUrl: project.metadata.twitterUrl,
discordUrl: project.discordUrl,
bannerImageUrl: `${ipfsGatewayUrl}/ipfs/${project.metadata.bannerImageHash}`,
thumbnailImageUrl: `${ipfsGatewayUrl}/ipfs/${project.metadata.thumbnailImageHash}`,
bannerImageHash: project.metadata.bannerImageHash,
thumbnailImageHash: project.metadata.thumbnailImageHash,
index: project.recipientIndex,
isHidden: project.state !== 'Accepted',
isLocked: false,
Expand Down
4 changes: 2 additions & 2 deletions vue-app/src/api/recipient-registry-kleros.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function decodeTcrItemData(
address: string
name: string
description: string
imageUrl: string
imageHash: string
} {
// Disable console.error to ignore parser errors
/* eslint-disable no-console */
Expand All @@ -52,7 +52,7 @@ function decodeTcrItemData(
address: decodedMetadata[1] as string,
name: decodedMetadata[0] as string,
description: decodedMetadata[3] as string,
imageUrl: `${ipfsGatewayUrl}${decodedMetadata[2]}`,
imageHash: decodedMetadata[2] as string,
}
}

Expand Down
18 changes: 6 additions & 12 deletions vue-app/src/api/recipient-registry-optimistic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ export enum RequestStatus {
interface RecipientMetadata {
name: string
description: string
imageUrl: string
thumbnailImageUrl: string
imageHash: string
thumbnailImageHash: string
}

export interface Request {
Expand Down Expand Up @@ -155,10 +155,8 @@ export async function getRequests(registryInfo: RegistryInfo, registryAddress: s
metadata = {
name,
description,
imageUrl: `${ipfsGatewayUrl}/ipfs/${imageHash}`,
thumbnailImageUrl: thumbnailImageHash
? `${ipfsGatewayUrl}/ipfs/${thumbnailImageHash}`
: `${ipfsGatewayUrl}/ipfs/${imageHash}`,
imageHash: imageHash,
thumbnailImageHash: thumbnailImageHash,
}
}

Expand Down Expand Up @@ -213,9 +211,6 @@ function decodeProject(recipient: Partial<Recipient>): Project {

const metadata = JSON.parse(recipient.recipientMetadata || '')

// imageUrl is the legacy form property - fall back to this if bannerImageHash or thumbnailImageHash don't exist
const imageUrl = `${ipfsGatewayUrl}/ipfs/${metadata.imageHash}`

let requester
if (recipient.requester) {
requester = recipient.requester
Expand All @@ -227,7 +222,6 @@ function decodeProject(recipient: Partial<Recipient>): Project {
requester,
name: metadata.name,
description: metadata.description,
imageUrl,
// Only unregistered project can have invalid index 0
index: 0,
isHidden: false,
Expand All @@ -246,8 +240,8 @@ function decodeProject(recipient: Partial<Recipient>): Project {
websiteUrl: metadata.websiteUrl,
twitterUrl: metadata.twitterUrl,
discordUrl: metadata.discordUrl,
bannerImageUrl: metadata.bannerImageHash ? `${ipfsGatewayUrl}/ipfs/${metadata.bannerImageHash}` : imageUrl,
thumbnailImageUrl: metadata.thumbnailImageHash ? `${ipfsGatewayUrl}/ipfs/${metadata.thumbnailImageHash}` : imageUrl,
bannerImageHash: metadata.bannerImageHash || metadata.imageHash,
thumbnailImageHash: metadata.thumbnailImageHash || metadata.imageHash,
}
}

Expand Down
4 changes: 2 additions & 2 deletions vue-app/src/api/recipient-registry-simple.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ function decodeRecipientAdded(event: EventLog): Project {
websiteUrl: metadata.websiteUrl,
twitterUrl: metadata.twitterUrl,
discordUrl: metadata.discordUrl,
bannerImageUrl: `${ipfsGatewayUrl}/ipfs/${metadata.bannerImageHash}`,
thumbnailImageUrl: `${ipfsGatewayUrl}/ipfs/${metadata.thumbnailImageHash}`,
bannerImageHash: metadata.bannerImageHash,
thumbnailImageHash: metadata.thumbnailImageHash,
index: getNumber(args._index),
isHidden: false,
isLocked: false,
Expand Down
1 change: 1 addition & 0 deletions vue-app/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ declare module '@vue/runtime-core' {
Info: typeof import('./components/Info.vue')['default']
InputButton: typeof import('./components/InputButton.vue')['default']
IpfsCopyWidget: typeof import('./components/IpfsCopyWidget.vue')['default']
IpfsImage: typeof import('./components/IpfsImage.vue')['default']
IpfsImageUpload: typeof import('./components/IpfsImageUpload.vue')['default']
LayoutSteps: typeof import('./components/LayoutSteps.vue')['default']
LeaderboardDetailView: typeof import('./components/LeaderboardDetailView.vue')['default']
Expand Down
2 changes: 1 addition & 1 deletion vue-app/src/components/CartItems.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
>
<div class="project">
<links :to="{ name: 'project', params: { id: item.id } }">
<img class="project-image" :src="item.thumbnailImageUrl" :alt="item.name" />
<ipfs-image class="project-image" :src="item.thumbnailImageHash" :alt="item.name" />
</links>
<links class="project-name" :to="{ name: 'project', params: { id: item.id } }">
{{ item.name }}
Expand Down
25 changes: 25 additions & 0 deletions vue-app/src/components/IpfsImage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<template>
<img v-if="isStaticImageBroken" :src="imageSrc" :alt="alt" :class="class" />
<img v-else :src="staticImageSrc" :alt="alt" @error="handleBrokenStaticImage" :class="class" />
</template>

<script setup lang="ts">
import { getIpfsUrl, getStaticAssetsUrlByIpfsHash } from '@/utils/url'
interface Props {
class?: string
src?: string
alt: string
}
const isStaticImageBroken = ref(false)
const props = defineProps<Props>()
const staticImageSrc = computed(() => getStaticAssetsUrlByIpfsHash(props.src) || '')
const imageSrc = computed(() => getIpfsUrl(props.src) || '')
function handleBrokenStaticImage() {
isStaticImageBroken.value = true
}
</script>
11 changes: 2 additions & 9 deletions vue-app/src/components/LeaderboardSimpleView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
</div>
</div>
<div class="desktop project-image">
<img v-if="projectImageUrl" :src="projectImageUrl" :alt="project.name" />
<ipfs-image :src="project.thumbnailImageHash" :alt="project.name" />
</div>
<div class="project-name">
{{ project.name }}
Expand All @@ -49,6 +49,7 @@
import type { LeaderboardProject } from '@/api/projects'
import type { RoundInfo } from '@/api/round'
import { formatAmount } from '@/utils/amounts'
import { getStaticAssetsUrlByIpfsHash, getIpfsUrl } from '@/utils/url'
interface Props {
project: LeaderboardProject
Expand Down Expand Up @@ -79,14 +80,6 @@ function formatAllocationAmount(amount?: bigint): string {
return amount ? formatAmount(amount, tokenDecimals, null, 0) : '0'
}
const projectImageUrl = computed(() => {
if (typeof props.project.imageUrl !== 'undefined') {
return props.project.imageUrl
}
return null
})
const tokenSymbol = computed(() => {
return props.round.nativeTokenSymbol
})
Expand Down
13 changes: 2 additions & 11 deletions vue-app/src/components/ProjectListItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<div>
<links :to="projectRoute">
<div class="project-image">
<img :src="projectImageUrl || ''" :alt="project.name" />
<ipfs-image :src="props.project.bannerImageHash || ''" :alt="project.name" />
<div v-if="project.category" class="tag">
{{ $t(categoryLocaleKey(project.category)) }}
</div>
Expand Down Expand Up @@ -37,6 +37,7 @@ import { useRoute, type RouteLocationRaw } from 'vue-router'
import { useAppStore } from '@/stores'
import { storeToRefs } from 'pinia'
import { isActiveApp } from '@/api/core'
import IpfsImage from './IpfsImage.vue'
const route = useRoute()
const appStore = useAppStore()
Expand All @@ -55,16 +56,6 @@ const descriptionHtml = computed<string>(() => {
return markdown.renderInline(props.project.description)
})
const projectImageUrl = computed<string | null>(() => {
if (typeof props.project.bannerImageUrl !== 'undefined') {
return props.project.bannerImageUrl
}
if (typeof props.project.imageUrl !== 'undefined') {
return props.project.imageUrl
}
return null
})
const inCart = computed<boolean>(() => {
const index = appStore.cart.findIndex((item: CartItem) => {
// Ignore cleared items
Expand Down
2 changes: 1 addition & 1 deletion vue-app/src/components/ProjectProfile.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div v-if="project" class="project-page">
<info v-if="previewMode" class="info" :message="$t('projectProfile.info1')" />
<img v-if="previewMode" class="project-image" :src="project.bannerImageUrl" :alt="project.name" />
<ipfs-image v-if="previewMode" class="project-image" :src="project.bannerImageHash" :alt="project.name" />
<div class="about">
<h1 class="project-name" :title="addressName" :project-index="project.index">
<links v-if="klerosCurateUrl" :to="klerosCurateUrl">{{ project.name }}</links>
Expand Down
Loading

0 comments on commit da1257f

Please sign in to comment.