diff --git a/unfurler/src/index.ts b/unfurler/src/index.ts
index 5db38324e..947ec7a8d 100644
--- a/unfurler/src/index.ts
+++ b/unfurler/src/index.ts
@@ -7,7 +7,7 @@ import { Cluster } from 'puppeteer-cluster';
import ReusablePage from './concurrency/ReusablePage';
import ReusableSSRPage from './concurrency/ReusableSSRPage';
import { parseLanguageUrl } from './language/lang';
-import { matchRoute } from './routes';
+import { matchRoute, networks } from './routes';
import nodejsPath from 'path';
import logger from './logger';
import { TimeoutError } from "puppeteer";
@@ -336,12 +336,18 @@ class Server {
const matchedRoute = matchRoute(this.network, path);
let ogImageUrl = config.SERVER.HOST + (matchedRoute.staticImg || matchedRoute.fallbackImg);
let ogTitle = 'The Mempool Open Source Project®';
+ let ogDescription = 'Explore the full Bitcoin ecosystem with mempool.space';
const canonical = this.canonicalHost + rawPath;
if (matchedRoute.render) {
ogImageUrl = `${config.SERVER.HOST}/render/${lang || 'en'}/preview${path}`;
ogTitle = `${this.network ? capitalize(this.network) + ' ' : ''}${matchedRoute.networkMode !== 'mainnet' ? capitalize(matchedRoute.networkMode) + ' ' : ''}${matchedRoute.title}`;
+ } else {
+ ogTitle = networks[this.network].title;
+ }
+ if (matchedRoute.description) {
+ ogDescription = matchedRoute.description;
}
return `
@@ -350,7 +356,7 @@ class Server {
${ogTitle}
-
+
@@ -360,7 +366,7 @@ class Server {
-
+
@@ -420,6 +426,9 @@ process.on('SIGTERM', async () => {
});
function capitalize(str) {
+ if (str === 'onbtc') {
+ return 'ONBTC';
+ }
if (str && str.length) {
return str[0].toUpperCase() + str.slice(1);
} else {
diff --git a/unfurler/src/routes.ts b/unfurler/src/routes.ts
index e7f3591e7..a00c9be4d 100644
--- a/unfurler/src/routes.ts
+++ b/unfurler/src/routes.ts
@@ -16,6 +16,7 @@ const agentSelector = function(_parsedURL: any) {
interface Match {
render: boolean;
title: string;
+ description: string;
fallbackImg: string;
staticImg?: string;
networkMode: string;
@@ -234,14 +235,18 @@ const routes = {
},
};
-const networks = {
+export const networks = {
bitcoin: {
+ title: 'The Mempool Open Source Project®',
+ description: 'Explore the full Bitcoin ecosystem with The Mempool Open Source Project®. See the real-time status of your transactions, get network info, and more.',
fallbackImg: '/resources/previews/mempool-space-preview.jpg',
routes: {
...routes // all routes supported
}
},
liquid: {
+ title: 'The Mempool Open Source Project®',
+ description: 'Explore the full Bitcoin ecosystem with The Mempool Open Source Project®. See Liquid transactions & assets, get network info, and more.',
fallbackImg: '/resources/liquid/liquid-network-preview.png',
routes: { // only block, address & tx routes supported
block: routes.block,
@@ -254,6 +259,8 @@ const networks = {
routes: {} // no routes supported
},
onbtc: {
+ title: 'National Bitcoin Office of El Salvador',
+ description: 'The National Bitcoin Office (ONBTC) of El Salvador under President @nayibbukele',
fallbackImg: '/resources/onbtc/onbtc-preview.jpg',
routes: { // only dynamic routes supported
block: routes.block,
@@ -277,6 +284,7 @@ export function matchRoute(network: string, path: string, matchFor: string = 're
const match: Match = {
render: false,
title: '',
+ description: '',
fallbackImg: '',
networkMode: 'mainnet'
}
@@ -292,6 +300,8 @@ export function matchRoute(network: string, path: string, matchFor: string = 're
let route = networks[network] || networks.bitcoin;
match.fallbackImg = route.fallbackImg;
+ match.title = route.title;
+ match.description = route.description;
// traverse the route tree until we run out of route or tree, or hit a renderable match
while (!route[matchFor] && route.routes && parts.length && route.routes[parts[0]]) {
@@ -300,6 +310,9 @@ export function matchRoute(network: string, path: string, matchFor: string = 're
if (route.fallbackImg) {
match.fallbackImg = route.fallbackImg;
}
+ if (route.description) {
+ match.description = route.description;
+ }
}
// enough route parts left for title & rendering
@@ -315,7 +328,7 @@ export function matchRoute(network: string, path: string, matchFor: string = 're
// apply the title function if present
if (route.getTitle && typeof route.getTitle === 'function') {
match.title = route.getTitle(parts);
- } else {
+ } else if (route.title) {
match.title = route.title;
}