Skip to content

Commit

Permalink
Add GA support for redirect to embed (#81)
Browse files Browse the repository at this point in the history
  • Loading branch information
raymondjacobson authored Nov 11, 2021
1 parent 1c03762 commit b77de77
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 22 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"start:stage": "env-cmd -f .env.stage npm run spinup",
"start:prod": "env-cmd -f .env.prod npm run spinup",
"lint": "./node_modules/.bin/tslint 'src/**/*.ts'",
"lint-fix": "./node_modules/.bin/tslint 'src/**/*.ts' --fix",
"lint:fix": "./node_modules/.bin/tslint 'src/**/*.ts' --fix",
"test:stage": "env-cmd -f .env.stage jest",
"test:prod": "env-cmd -f .env.prod jest"
},
Expand Down
21 changes: 19 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,32 @@ router.get([
'/:handle/tracks',
'/:handle/playlists',
'/:handle/albums',
'/:handle/reposts',
'/:handle/collectibles',
'/:handle/reposts'
], (
req: express.Request,
res: express.Response) => {
getMetaTagsResponse(MetaTagFormat.User, req, res)
}
)

router.get([
'/:handle/collectibles/:collectibleId'
], (
req: express.Request,
res: express.Response) => {
getMetaTagsResponse(MetaTagFormat.Collectible, req, res)
}
)

router.get([
'/:handle/collectibles'
], (
req: express.Request,
res: express.Response) => {
getMetaTagsResponse(MetaTagFormat.Collectibles, req, res)
}
)

router.get('/:handle/:title/remixes', (
req: express.Request,
res: express.Response) => {
Expand Down
14 changes: 3 additions & 11 deletions src/servlets/bedtime/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Collectible, FetchNFTClient } from '@audius/fetch-nft'
import { Collectible } from '@audius/fetch-nft'
import express from 'express'

import libs from '../../libs'
import { nftClient } from '../utils/fetchNft'
import { decodeHashId, encodeHashId } from '../utils/hashids'
import {
getCollection,
Expand All @@ -18,15 +19,6 @@ import { BedtimeFormat, GetCollectionResponse, GetTracksResponse, TrackResponse
// Error Messages
const DELETED_MESSAGE = 'DELETED'

const nftClient = new FetchNFTClient({
openSeaConfig: {
apiEndpoint: process.env.OPENSEA_ENDPOINT
},
solanaConfig: {
rpcEndpoint: process.env.SOLANA_RPC_ENDPOINT
}
})

const getTrackMetadata = async (trackId: number, ownerId: number | null): Promise<GetTracksResponse> => {
try {
if (shouldRedirectTrack(trackId)) return Promise.reject(new Error(DELETED_MESSAGE))
Expand Down Expand Up @@ -227,7 +219,7 @@ export const getBedtimeResponse = async (
return
}

parsedOwnerId = parseInt(ownerId, 10)
parsedOwnerId = parseInt(ownerId as string, 10)
}

try {
Expand Down
4 changes: 2 additions & 2 deletions src/servlets/ipfs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const makeBuildPath = (name: string) =>
router.get('/update_build', async (
req: express.Request,
res: express.Response) => {
const { site }: { site: buildType } = req.query
const site = req.query.site as buildType
try {
if (!BUILD_URLS) {
res.status(500).send(`Build URLS not specified`)
Expand Down Expand Up @@ -83,7 +83,7 @@ router.get('/update_build', async (
router.get('/pin_build', async (
req: express.Request,
res: express.Response) => {
const { site }: { site: buildType } = req.query
const site = req.query.site as buildType
const buildUrl = BUILD_URLS[site]!
const buildFileName = buildUrl.split('/').slice(-1)[0].replace('.zip', '')
try {
Expand Down
118 changes: 117 additions & 1 deletion src/servlets/metaTags/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { Collectible, FetchNFTClient } from '@audius/fetch-nft'
import express from 'express'
import fs from 'fs'
import handlebars from 'handlebars'
import path from 'path'

import libs from '../../libs'
import { getHash } from '../bedtime/helpers'
import { DEFAULT_IMAGE_URL } from '../utils/constants'
import { nftClient } from '../utils/fetchNft'
import { formatDate, formatSeconds } from '../utils/format'
import { encodeHashId } from '../utils/hashids'
import {
formatGateway,
getCollection,
Expand All @@ -24,6 +29,14 @@ const getEmbedUrl = (type: Playable, id: number, ownerId: number) => {
return `${E.PUBLIC_URL}/embed/${type}?id=${id}&ownerId=${ownerId}&flavor=card&twitter=true`
}

const getCollectiblesEmbedUrl = (handle: string) => {
return `${E.PUBLIC_URL}/embed/${handle}/collectibles`
}

const getCollectibleEmbedUrl = (handle: string, collectibleId: string) => {
return `${E.PUBLIC_URL}/embed/${handle}/collectibles/${collectibleId}`
}

/** Routes */

const template = handlebars.compile(
Expand Down Expand Up @@ -129,6 +142,100 @@ const getUserContext = async (handle: string): Promise<Context> => {
}
}

const getCollectiblesContext = async (handle: string, canEmbed: boolean): Promise<Context> => {
if (!handle) return getDefaultContext()
try {
const user = await getUserByHandle(handle)
const gateway = formatGateway(user.creator_node_endpoint, user.user_id)

const profilePicture = user.profile_picture_sizes
? `${user.profile_picture_sizes}/1000x1000.jpg`
: user.profile_picture

const infoText = user.track_count > 0
? `Listen to ${user.name} on Audius`
: `Follow ${user.name} on Audius`

return {
format: MetaTagFormat.Collectibles,
title: `${user.name}'s Collectibles`,
description: `A collection of NFT collectibles owned and created by ${user.name}`,
additionalSEOHint: infoText,
image: getImageUrl(profilePicture, gateway),
embed: canEmbed,
embedUrl: getCollectiblesEmbedUrl(user.handle)
}
} catch (e) {
console.error(e)
return getDefaultContext()
}
}

const getCollectibleContext = async (handle: string, collectibleId: string, canEmbed: boolean): Promise<Context> => {
if (!handle) return getDefaultContext()
try {
const user = await getUserByHandle(handle)
const gateway = formatGateway(user.creator_node_endpoint, user.user_id)

const profilePicture = user.profile_picture_sizes
? `${user.profile_picture_sizes}/1000x1000.jpg`
: user.profile_picture

const infoText = user.track_count > 0
? `Listen to ${user.name} on Audius`
: `Follow ${user.name} on Audius`

const dp = libs.discoveryProvider.discoveryProviderEndpoint
const encodedUserId = encodeHashId(user.user_id)
const res = await fetch(`${dp}/v1/users/associated_wallets?id=${encodedUserId}`)
const { data: walletData } = await res.json()

// Get collectibles for user wallets
const resp = await nftClient.getCollectibles({
ethWallets: walletData.wallets,
solWallets: walletData.sol_wallets
})

let foundCol: Collectible
if (collectibleId) {
const ethValues: Collectible[][] = Object.values(resp.ethCollectibles)
const solValues: Collectible[][] = Object.values(resp.solCollectibles)
const collectibles = [
...ethValues.reduce((acc, vals) => [...acc, ...vals], []),
...solValues.reduce((acc, vals) => [...acc, ...vals], []),
]

foundCol = collectibles.find((col) => getHash(col.id) === collectibleId)
}

if (foundCol) {
return {
format: MetaTagFormat.Collectibles,
title: foundCol.name,
description: foundCol.description,
additionalSEOHint: infoText,
image: foundCol.frameUrl,
embed: canEmbed,
embedUrl: getCollectibleEmbedUrl(user.handle, collectibleId)
}
}

return {
format: MetaTagFormat.Collectibles,
title: `${user.name}'s Collectibles`,
description: `A collection of NFT collectibles owned and created by ${user.name}`,
additionalSEOHint: infoText,
image: getImageUrl(profilePicture, gateway),
embed: canEmbed,
embedUrl: getCollectiblesEmbedUrl(user.handle)
}

} catch (e) {
console.error(e)
return getDefaultContext()
}
}

const getRemixesContext = async (handle: string, slug: string): Promise<Context> => {
if (!handle || !slug) return getDefaultContext()
try {
Expand Down Expand Up @@ -207,7 +314,8 @@ const getResponse = async (
const {
title,
handle,
type
type,
collectibleId
} = req.params
const userAgent = req.get('User-Agent') || ''
const canEmbed = CAN_EMBED_USER_AGENT_REGEX.test(userAgent.toLowerCase())
Expand Down Expand Up @@ -240,6 +348,14 @@ const getResponse = async (
console.log('get explore', req.path, userAgent)
context = await getExploreContext(type)
break
case MetaTagFormat.Collectibles:
console.log('get collectibles', req.path, userAgent)
context = await getCollectiblesContext(handle, canEmbed)
break
case MetaTagFormat.Collectible:
console.log('get collectible', req.path, userAgent)
context = await getCollectibleContext(handle, collectibleId, canEmbed)
break
case MetaTagFormat.Error:
default:
console.log('get default', req.path, userAgent)
Expand Down
2 changes: 2 additions & 0 deletions src/servlets/metaTags/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export enum MetaTagFormat {
Remixes,
Upload,
Explore,
Collectibles,
Collectible,
Error
}

Expand Down
8 changes: 3 additions & 5 deletions src/servlets/proxy/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,8 @@ router.get('/', async (
expressRes: express.Response
) => {
try {
const {
url,
replace
} = req.query
const url = req.query.url as string
const replace = req.query.replace as string

if (!url) throw new Error('No url provided')
if (!replace) throw new Error('No replace json provided')
Expand Down Expand Up @@ -93,7 +91,7 @@ router.get('/simple', async (
req: express.Request,
res: express.Response
) => {
const { url } = req.query
const url = req.query.url as string
const newReq = https.request(decodeURI(url), (newRes: any) => {
const headers = {
'Access-Control-Allow-Method': '*',
Expand Down
10 changes: 10 additions & 0 deletions src/servlets/utils/fetchNft.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { FetchNFTClient } from '@audius/fetch-nft'

export const nftClient = new FetchNFTClient({
openSeaConfig: {
apiEndpoint: process.env.OPENSEA_ENDPOINT
},
solanaConfig: {
rpcEndpoint: process.env.SOLANA_RPC_ENDPOINT
}
})

0 comments on commit b77de77

Please sign in to comment.