{media.title}
diff --git a/packages/metastream-app/src/lobby/actions/media-request.ts b/packages/metastream-app/src/lobby/actions/media-request.ts
index 0f1864ed..437d465a 100644
--- a/packages/metastream-app/src/lobby/actions/media-request.ts
+++ b/packages/metastream-app/src/lobby/actions/media-request.ts
@@ -140,7 +140,8 @@ const requestMedia = (opts: MediaRequestOptions): RpcThunk
+ $('title')
+ .text()
+ .trim()
+
+/** Prefer non-ico icons. */
+const sortIcons = (a: CheerioElement, b: CheerioElement) => {
+ const aIco = a.attribs.href.includes('.ico')
+ const bIco = b.attribs.href.includes('.ico')
+
+ if (aIco && !bIco) return 1
+ if (!aIco && bIco) return -1
+ return 0
+}
+
+const parseFavicon = (ctx: IMediaContext, $: CheerioStatic) => {
+ const icons = Array.from($('head link')).filter(icon => {
+ const rel = new Set((icon.attribs.rel || '').split(' '))
+ if (!rel.has('icon')) return false
+ return true
+ })
+
+ if (icons.length === 0) return
+
+ icons.sort(sortIcons)
+
+ const icon = icons[0]
+ let url
+
+ try {
+ url = new URL(icon.attribs.href).href
+ } catch {}
+
+ if (!url) {
+ try {
+ url = new URL(`${ctx.req.url.origin}${icon.attribs.href}`).href
+ } catch {}
+ }
+
+ return url
+}
+
const mware: IMediaMiddleware = {
match({ protocol }) {
return protocol === 'http:' || protocol === 'https:'
@@ -35,8 +77,12 @@ const mware: IMediaMiddleware = {
ctx.state.body = text
const $ = (ctx.state.$ = load(text))
- // prettier-ignore
- ctx.res.title = $('title').text().trim() || ctx.res.title
+ try {
+ ctx.res.title = parseTitle($) || ctx.res.title
+ ctx.res.favicon = parseFavicon(ctx, $)
+ } catch (e) {
+ console.error(e)
+ }
return next()
}
diff --git a/packages/metastream-app/src/media/types.ts b/packages/metastream-app/src/media/types.ts
index b0c54f6c..d05a3f90 100644
--- a/packages/metastream-app/src/media/types.ts
+++ b/packages/metastream-app/src/media/types.ts
@@ -56,6 +56,9 @@ export interface IMediaResponse {
/** Milliseconds */
startTime?: number
+
+ /** Website favicon URL. */
+ favicon?: string
}
export interface IMediaContext {