Bluesky app fork with some witchin' additions 馃挮
witchsky.app
bluesky
fork
client
1import {type I18n} from '@lingui/core'
2import {plural} from '@lingui/core/macro'
3import psl from 'psl'
4
5export function displayDuration(i18n: I18n, durationInMinutes: number) {
6 const roundedDurationInMinutes = Math.round(durationInMinutes)
7 const hours = Math.floor(roundedDurationInMinutes / 60)
8 const minutes = roundedDurationInMinutes % 60
9 const minutesString = i18n._(
10 plural(minutes, {one: '# minute', other: '# minutes'}),
11 )
12 return hours > 0
13 ? i18n._(
14 minutes > 0
15 ? plural(hours, {
16 one: `# hour ${minutesString}`,
17 other: `# hours ${minutesString}`,
18 })
19 : plural(hours, {
20 one: '# hour',
21 other: '# hours',
22 }),
23 )
24 : minutesString
25}
26
27const serviceUrlToNameMap: Record<string, string> = {
28 'twitch.tv': 'Twitch',
29 'youtube.com': 'YouTube',
30 'nba.com': 'NBA',
31 'nba.smart.link': 'nba.smart.link',
32 'espn.com': 'ESPN',
33 'stream.place': 'Streamplace',
34 'skylight.social': 'Skylight',
35 'bluecast.app': 'Bluecast',
36}
37
38export function getLiveServiceNames(domains: Set<string>) {
39 const names = Array.from(
40 new Set(
41 Array.from(domains.values())
42 .map(d => sanitizeLiveNowHost(d))
43 .map(d => serviceUrlToNameMap[d] || d),
44 ),
45 )
46 return {
47 names,
48 formatted: names.join(', '),
49 }
50}
51
52export function sanitizeLiveNowHost(hostname: string) {
53 // special case this one
54 if (hostname === 'nba.smart.link') {
55 return hostname
56 }
57 const parsed = psl.parse(hostname)
58 if (parsed.error || !parsed.listed || !parsed.domain) {
59 // fall back to dumb version
60 return hostname.replace(/^www\./, '')
61 }
62 return parsed.domain
63}
64
65/**
66 * Extracts the apex domain from a given URL, for use when matching allowed
67 * Live Now hosts.
68 */
69export function getLiveNowHost(url: string) {
70 const {hostname} = new URL(url)
71 return sanitizeLiveNowHost(hostname)
72}