Bluesky app fork with some witchin' additions 馃挮 witchsky.app
bluesky fork client
at main 72 lines 1.9 kB view raw
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}