From 299ca889cd5f29a0fdd7d5cebbcd8fe36649a0e2 Mon Sep 17 00:00:00 2001 From: samuelmaddock Date: Tue, 7 Jul 2020 22:53:59 -0400 Subject: [PATCH] feat: add media item favicons --- .../src/assets/icons/favicon-default.svg | 1 + .../src/components/media/Media.css | 10 ++-- .../src/components/media/MediaItem.tsx | 19 +++++++ .../src/lobby/actions/media-request.ts | 3 +- .../src/lobby/reducers/mediaPlayer.ts | 3 ++ .../src/media/middleware/html.ts | 52 +++++++++++++++++-- packages/metastream-app/src/media/types.ts | 3 ++ 7 files changed, 81 insertions(+), 10 deletions(-) create mode 100644 packages/metastream-app/src/assets/icons/favicon-default.svg diff --git a/packages/metastream-app/src/assets/icons/favicon-default.svg b/packages/metastream-app/src/assets/icons/favicon-default.svg new file mode 100644 index 00000000..93e8b330 --- /dev/null +++ b/packages/metastream-app/src/assets/icons/favicon-default.svg @@ -0,0 +1 @@ + diff --git a/packages/metastream-app/src/components/media/Media.css b/packages/metastream-app/src/components/media/Media.css index f22bcf60..29629f1e 100644 --- a/packages/metastream-app/src/components/media/Media.css +++ b/packages/metastream-app/src/components/media/Media.css @@ -16,14 +16,12 @@ justify-content: space-between; } -/* .top { - +.favicon { + align-self: center; + margin-right: 0.5rem; + width: 1.25rem; } -.bottom { - -} */ - .title { composes: single-line from '~styles/text.css'; flex: 1 1 100%; diff --git a/packages/metastream-app/src/components/media/MediaItem.tsx b/packages/metastream-app/src/components/media/MediaItem.tsx index 9fc92dfd..583937a2 100644 --- a/packages/metastream-app/src/components/media/MediaItem.tsx +++ b/packages/metastream-app/src/components/media/MediaItem.tsx @@ -4,6 +4,9 @@ import styles from './Media.css' import { formatMs } from 'utils/time' import { IconButton } from '../common/button' +import { assetUrl } from 'utils/appUrl' + +const DEFAULT_FAVICON = assetUrl('icons/favicon-default.svg') interface IProps { media: IMediaItem @@ -24,8 +27,24 @@ export class MediaItem extends Component { render(): JSX.Element | null { const { media } = this.props + let hostname + + try { + hostname = new URL(media.url).hostname + } catch {} + return (
+ { + if (e.target && (e.target as any).tagName === 'IMG') { + ;(e.target as any).src = DEFAULT_FAVICON + } + }} + />
{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 {