Skip to content

Commit 142470c

Browse files
committed
fix: use optimized droposal videos for playback
1 parent 8e274a7 commit 142470c

5 files changed

Lines changed: 119 additions & 3 deletions

File tree

src/app/[locale]/droposals/[id]/page.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { DroposalSupporters } from "@/components/droposals/detail/DroposalSuppor
1313
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
1414
import { Separator } from "@/components/ui/separator";
1515
import { BASE_URL, DAO_ADDRESSES } from "@/lib/config";
16+
import { resolveDroposalPlaybackUrl } from "@/lib/droposal-media";
1617
import { decodeDroposalParams, formatDroposalForTable, isDroposal } from "@/lib/droposal-utils";
1718
import { ipfsToHttp } from "@/lib/ipfs";
1819
import { DROPOSALS_MINIAPP_EMBED_CONFIG } from "@/lib/miniapp-config";
@@ -236,7 +237,9 @@ export default async function DroposalDetailPage({
236237
}
237238

238239
const mediaImage = decoded?.imageURI ? ipfsToHttp(decoded.imageURI) : undefined;
239-
const mediaAnimation = decoded?.animationURI ? ipfsToHttp(decoded.animationURI) : undefined;
240+
const mediaAnimation = decoded?.animationURI
241+
? resolveDroposalPlaybackUrl(decoded.animationURI)
242+
: undefined;
240243
const priceEth = decoded?.saleConfig?.publicSalePrice
241244
? formatEther(decoded.saleConfig.publicSalePrice)
242245
: "0";

src/app/api/droposal-embed/[id]/route.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { NextResponse } from "next/server";
22
import { formatEther } from "viem";
33
import { DAO_ADDRESSES } from "@/lib/config";
4+
import { resolveDroposalPlaybackUrl } from "@/lib/droposal-media";
45
import { decodeDroposalParams, isDroposal } from "@/lib/droposal-utils";
56
import { ipfsToHttp } from "@/lib/ipfs";
67
import { subgraphQuery } from "@/lib/subgraph";
@@ -59,7 +60,9 @@ export async function GET(_req: Request, { params }: { params: Promise<{ id: str
5960
}
6061

6162
const mediaImage = decoded?.imageURI ? ipfsToHttp(decoded.imageURI) : undefined;
62-
const mediaAnimation = decoded?.animationURI ? ipfsToHttp(decoded.animationURI) : undefined;
63+
const mediaAnimation = decoded?.animationURI
64+
? resolveDroposalPlaybackUrl(decoded.animationURI)
65+
: undefined;
6366
const priceEth = decoded?.saleConfig?.publicSalePrice
6467
? formatEther(decoded.saleConfig.publicSalePrice)
6568
: "0";

src/lib/droposal-media.test.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { describe, expect, it } from "vitest";
2+
import {
3+
OPTIMIZED_DROPOSAL_VIDEO_CID_BY_ORIGINAL_CID,
4+
resolveDroposalPlaybackUrl,
5+
} from "@/lib/droposal-media";
6+
7+
const ORIGINAL_CID = "QmbHbVzFTNSFpFUXHyKBrtGfJ3era6SpkQBjEEpzapeNex";
8+
const OPTIMIZED_CID = OPTIMIZED_DROPOSAL_VIDEO_CID_BY_ORIGINAL_CID[ORIGINAL_CID];
9+
const OPTIMIZED_URL = `https://ipfs.skatehive.app/ipfs/${OPTIMIZED_CID}`;
10+
11+
describe("resolveDroposalPlaybackUrl", () => {
12+
it.each([
13+
[
14+
"Qmak7m8x3ckbkM8YrghZRWm7zBqSUiYoCySdJ6bEwKuDRX",
15+
"bafybeid4f7v6yez2ibuay4kbmiuky44tph3gn32rnczkcmvno6nbjd7ykm",
16+
],
17+
[
18+
"QmVF2BjJvA2MnjWuuNbUEAbMuzQD8JFks83TR6MdSgNY2e",
19+
"bafybeiazfjbov4ag7t6h7d77s2mokjsvz2dxyixogm7l5ptbrrg6qjxn7e",
20+
],
21+
])("uses the optimized Gnars Droposal video for %s", (originalCid, optimizedCid) => {
22+
expect(resolveDroposalPlaybackUrl(`ipfs://${originalCid}`)).toBe(
23+
`https://ipfs.skatehive.app/ipfs/${optimizedCid}`,
24+
);
25+
});
26+
27+
it("replaces a mapped ipfs URI with its optimized CID", () => {
28+
expect(resolveDroposalPlaybackUrl(`ipfs://${ORIGINAL_CID}`)).toBe(OPTIMIZED_URL);
29+
});
30+
31+
it("replaces a mapped gateway URL with its optimized CID", () => {
32+
expect(resolveDroposalPlaybackUrl(`https://example.com/ipfs/${ORIGINAL_CID}`)).toBe(
33+
OPTIMIZED_URL,
34+
);
35+
});
36+
37+
it("keeps unmapped ipfs CIDs on the normal gateway path", () => {
38+
const cid = "QmUnmappedCidForDroposalPlayback";
39+
expect(resolveDroposalPlaybackUrl(`ipfs://${cid}`)).toBe(
40+
`https://magic.decentralized-content.com/ipfs/${cid}`,
41+
);
42+
});
43+
44+
it("leaves non-IPFS HTTPS URLs unchanged", () => {
45+
const url = "https://example.com/video.mp4";
46+
expect(resolveDroposalPlaybackUrl(url)).toBe(url);
47+
});
48+
49+
it("extracts an exact CID before a subpath, query, or fragment", () => {
50+
expect(
51+
resolveDroposalPlaybackUrl(
52+
`https://example.com/ipfs/${ORIGINAL_CID}/video.mp4?download=1#preview`,
53+
),
54+
).toBe(OPTIMIZED_URL);
55+
});
56+
57+
it("does not mutate the original URI", () => {
58+
const originalUri = `ipfs://${ORIGINAL_CID}`;
59+
resolveDroposalPlaybackUrl(originalUri);
60+
expect(originalUri).toBe(`ipfs://${ORIGINAL_CID}`);
61+
});
62+
});

src/lib/droposal-media.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { ipfsToHttp } from "@/lib/ipfs";
2+
3+
const SKATEHIVE_IPFS_GATEWAY = "https://ipfs.skatehive.app/ipfs";
4+
5+
export const OPTIMIZED_DROPOSAL_VIDEO_CID_BY_ORIGINAL_CID = {
6+
Qmak7m8x3ckbkM8YrghZRWm7zBqSUiYoCySdJ6bEwKuDRX:
7+
"bafybeid4f7v6yez2ibuay4kbmiuky44tph3gn32rnczkcmvno6nbjd7ykm",
8+
QmVF2BjJvA2MnjWuuNbUEAbMuzQD8JFks83TR6MdSgNY2e:
9+
"bafybeiazfjbov4ag7t6h7d77s2mokjsvz2dxyixogm7l5ptbrrg6qjxn7e",
10+
QmbHbVzFTNSFpFUXHyKBrtGfJ3era6SpkQBjEEpzapeNex:
11+
"bafybeibohdmwemv2gdgegiqi3jhajo3z2ejz5o7q7rynkvi7wiihvl245u",
12+
Qmcj9mcaXkiNU8s3KCY9JMVAhacFJZvUXngYbPVx44R8uG:
13+
"bafybeidkmzaygivag7xekzmvtohkkbqwt7zud6lxqwtkt35hdvbaptpn3u",
14+
QmfQydzfV5i3JgQ4SDQ3XXkBy4mDBufAJjD596NxPvwMfs:
15+
"bafybeifdwbkhaugqjjlhkiiqza2h7i2k5srhkfakyvbsio3ppf2s7mqleu",
16+
QmTu1QGDSQzrJAULeiKNGVxpEbiTw5Z6FDonNyrQ3H7bZ7:
17+
"bafybeicfqryhrlawk4uhgopnstld77sm2ddqykrqs3tz4fwfwaju3llt2e",
18+
} as const satisfies Readonly<Record<string, string>>;
19+
20+
type OptimizedDroposalSourceCid = keyof typeof OPTIMIZED_DROPOSAL_VIDEO_CID_BY_ORIGINAL_CID;
21+
22+
function extractIpfsCid(uri: string): string | undefined {
23+
const trimmedUri = uri.trim();
24+
const ipfsPath = trimmedUri.startsWith("ipfs://")
25+
? trimmedUri.slice("ipfs://".length)
26+
: trimmedUri.includes("/ipfs/")
27+
? trimmedUri.split("/ipfs/")[1]
28+
: undefined;
29+
30+
return ipfsPath?.split(/[/?#]/, 1)[0] || undefined;
31+
}
32+
33+
function hasOptimizedDroposalVideo(cid: string): cid is OptimizedDroposalSourceCid {
34+
return cid in OPTIMIZED_DROPOSAL_VIDEO_CID_BY_ORIGINAL_CID;
35+
}
36+
37+
export function resolveDroposalPlaybackUrl(animationUri: string): string {
38+
const originalCid = extractIpfsCid(animationUri);
39+
if (!originalCid || !hasOptimizedDroposalVideo(originalCid)) {
40+
return ipfsToHttp(animationUri);
41+
}
42+
43+
const optimizedCid = OPTIMIZED_DROPOSAL_VIDEO_CID_BY_ORIGINAL_CID[originalCid];
44+
return `${SKATEHIVE_IPFS_GATEWAY}/${optimizedCid}`;
45+
}

src/services/droposals.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { cache } from "react";
22
import { createPublicClient, formatEther, http } from "viem";
33
import { base } from "viem/chains";
44
import { DAO_ADDRESSES, DROPOSAL_TARGET } from "@/lib/config";
5+
import { resolveDroposalPlaybackUrl } from "@/lib/droposal-media";
56
import { decodeDroposalParams, isDroposal } from "@/lib/droposal-utils";
67
import { ipfsToHttp } from "@/lib/ipfs";
78
import { subgraphQuery } from "@/lib/subgraph";
@@ -95,7 +96,9 @@ function mapDroposalItems(proposals: ProposalData[]): DroposalListItem[] {
9596

9697
const decoded = calldatas[i] ? decodeDroposalParams(calldatas[i]!) : null;
9798
const bannerImage = decoded?.imageURI ? ipfsToHttp(decoded.imageURI) : undefined;
98-
const animationUrl = decoded?.animationURI ? ipfsToHttp(decoded.animationURI) : undefined;
99+
const animationUrl = decoded?.animationURI
100+
? resolveDroposalPlaybackUrl(decoded.animationURI)
101+
: undefined;
99102
const priceEth =
100103
decoded?.saleConfig?.publicSalePrice !== undefined
101104
? formatEther(decoded.saleConfig.publicSalePrice)

0 commit comments

Comments
 (0)