From 1925d6043575668f0eb92c03c4e26ef597808ab6 Mon Sep 17 00:00:00 2001 From: Raymond Jacobson Date: Mon, 7 Aug 2023 01:41:57 -0700 Subject: [PATCH 1/3] First pass at working SEO --- packages/web/scripts/workers-site/index.js | 152 ++++++++++++++++++++- 1 file changed, 147 insertions(+), 5 deletions(-) diff --git a/packages/web/scripts/workers-site/index.js b/packages/web/scripts/workers-site/index.js index 977b580b2a..f76cd7d73a 100644 --- a/packages/web/scripts/workers-site/index.js +++ b/packages/web/scripts/workers-site/index.js @@ -1,7 +1,28 @@ import { getAssetFromKV, mapRequestToAsset } from '@cloudflare/kv-asset-handler' +/* globals GA, GA_ACCESS_TOKEN, SITEMAP */ + const DEBUG = false +const routes = [ + { pattern: /^\/([^/]+)$/, name: 'user', keys: ['handle'] }, + { + pattern: /^\/([^/]+)\/([^/]+)$/, + name: 'track', + keys: ['handle', 'title'] + }, + { + pattern: /^\/([^/]+)\/playlist\/([^/]+)$/, + name: 'playlist', + keys: ['handle', 'title'] + }, + { + pattern: /^\/([^/]+)\/album\/([^/]+)$/, + name: 'album', + keys: ['handle', 'title'] + } +] + addEventListener('fetch', (event) => { try { event.respondWith(handleEvent(event)) @@ -17,17 +38,95 @@ addEventListener('fetch', (event) => { } }) +function matchRoute(input) { + for (const route of routes) { + const match = route.pattern.exec(input) + if (match) { + const result = { name: route.name, params: {} } + route.keys.forEach((key, index) => { + result.params[key] = match[index + 1] + }) + return result + } + } + return null +} + function checkIsBot(val) { if (!val) { return false } - const botTest = new RegExp( - 'altavista|baiduspider|bingbot|discordbot|duckduckbot|facebookexternalhit|gigabot|ia_archiver|linkbot|linkedinbot|msnbot|nextgensearchbot|reaper|slackbot|snap url preview service|telegrambot|twitterbot|whatsapp|whatsup|yahoo|yandex|yeti|yodaobot|zend|zoominfobot|embedly', - 'i' - ) + const botTest = + /altavista|baiduspider|bingbot|discordbot|duckduckbot|facebookexternalhit|gigabot|ia_archiver|linkbot|linkedinbot|msnbot|nextgensearchbot|reaper|slackbot|snap url preview service|telegrambot|twitterbot|whatsapp|whatsup|yahoo|yandex|yeti|yodaobot|zend|zoominfobot|embedly/i return botTest.test(val) } +async function getMetadata(pathname) { + const discoveryNode = 'https://discoveryprovider.audius.co' + let discoveryRequestPath + const route = matchRoute(pathname) + switch (route.name) { + case 'user': { + const { handle } = route.params + discoveryRequestPath = `v1/users/handle/${handle}` + break + } + case 'track': { + const { handle, title } = route.params + discoveryRequestPath = `v1/tracks?handle=${handle}&slug=${title}` + break + } + case 'playlist': { + const { handle, title } = route.params + discoveryRequestPath = `v1/full/playlists/by_permalink/${handle}/${title}` + break + } + case 'album': { + const { handle, title } = route.params + discoveryRequestPath = `v1/full/playlists/by_permalink/${handle}/${title}` + break + } + default: + return null + } + try { + const res = await fetch(`${discoveryNode}/${discoveryRequestPath}`) + if (res.status !== 200) { + throw new Error(res.status) + } + const json = res.json() + return { metadata: json, name: route.name } + } catch (e) { + return null + } +} + +async function injectHead(asset, { title, description, image, permalink }) { + const canonicalUrl = `https://audius.co/${permalink}` + const tags = ` + ${title} + + + + + + + + + + + + + +` + + if (typeof asset === 'string' && asset.includes('')) { + asset = asset.replace('', tags + '') + } + + return asset +} + async function handleEvent(event) { const url = new URL(event.request.url) const { pathname, search, hash } = url @@ -82,7 +181,50 @@ async function handleEvent(event) { } } - return await getAssetFromKV(event, options) + const asset = await getAssetFromKV(event, options) + let modifiedAsset + const { metadata, name } = await getMetadata(pathname) + switch (name) { + case 'user': { + modifiedAsset = injectHead(asset, { + title: `${metadata.data.name} (@${metadata.data.name})`, + description: metadata.data.bio || '', + image: metadata.data.profile_picture['1000x1000'] || '', + permalink: metadata.data.handle + }) + break + } + case 'track': { + modifiedAsset = injectHead(asset, { + title: `${metadata.data.title} by ${metadata.user.name}`, + description: metadata.data.description || '', + image: metadata.data.artwork['1000x1000'] || '', + permalink: metadata.data.permalink + }) + break + } + case 'playlist': { + modifiedAsset = injectHead(asset, { + title: `${metadata.data.playlist_name} by ${metadata.user.name}`, + description: metadata.data.description || '', + image: metadata.data.artwork['1000x1000'] || '', + permalink: metadata.data.permalink + }) + break + } + case 'album': { + modifiedAsset = injectHead(asset, { + title: `${metadata.data.playlist_name} by ${metadata.user.name}`, + description: metadata.data.description || '', + image: metadata.data.artwork['1000x1000'] || '', + permalink: metadata.data.permalink + }) + break + } + default: + return null + } + return modifiedAsset } catch (e) { return new Response(e.message || e.toString(), { status: 500 }) } From 28f0ab6df0d800812087c9b906b55a0db800b7aa Mon Sep 17 00:00:00 2001 From: Raymond Jacobson Date: Tue, 8 Aug 2023 00:14:42 -0700 Subject: [PATCH 2/3] [C-2941] Add "SSR"-like tag generation fro SEO --- packages/web/.gitignore | 1 + packages/web/public/index.html | 20 +-- packages/web/scripts/workers-site/index.js | 184 +++++++++++++-------- packages/web/wrangler.toml | 6 + 4 files changed, 127 insertions(+), 84 deletions(-) diff --git a/packages/web/.gitignore b/packages/web/.gitignore index 1dc3a0a926..fb10386350 100644 --- a/packages/web/.gitignore +++ b/packages/web/.gitignore @@ -14,6 +14,7 @@ /coverage # build +/sourcemaps /build /build-development /build-demo diff --git a/packages/web/public/index.html b/packages/web/public/index.html index 2cb32cc0c9..065d0008fc 100644 --- a/packages/web/public/index.html +++ b/packages/web/public/index.html @@ -21,22 +21,13 @@ - - - - - + - - - - - - - + + @@ -46,8 +37,6 @@ src="%PUBLIC_URL%/scripts/web3.min.js" > - Audius - +