2020-01-09 20:31:12 +01:00
|
|
|
import getUrls from 'get-urls'
|
2020-01-10 03:02:46 +01:00
|
|
|
import { pipe, asyncFilter, asyncMap, asyncTap, asyncTake } from 'iter-tools'
|
|
|
|
|
|
|
|
export async function* statusesStreaming() {
|
|
|
|
let { statuses, nextLink, previousLink } = await fetchTimeline('https://eldritch.cafe/api/v1/timelines/tag/np')
|
|
|
|
|
|
|
|
yield* statuses
|
|
|
|
|
|
|
|
while (nextLink) {
|
|
|
|
const a = await fetchTimeline(nextLink)
|
|
|
|
|
|
|
|
nextLink = a.nextLink
|
|
|
|
yield* a.statuses
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export const statusesToEntries = pipe(
|
|
|
|
asyncMap(status => ({ status, urls: Array.from(getUrls(status.content)).filter(isSupportedUrl) })),
|
|
|
|
asyncFilter(entry => entry.urls.length > 0),
|
|
|
|
asyncMap(async ({ status, urls }) => {
|
|
|
|
const [url] = urls
|
|
|
|
const id = getYoutubeVideoId(url)
|
|
|
|
|
|
|
|
const tags = intersection(status.tags.map(tag => tag.name), [
|
|
|
|
'np',
|
|
|
|
'nowplaying',
|
|
|
|
'tootradio',
|
|
|
|
'pouetradio'
|
|
|
|
])
|
|
|
|
|
|
|
|
const metadata = await fetchYoutubeMetadata(id)
|
|
|
|
|
|
|
|
return { status, url, id, tags, metadata }
|
|
|
|
}),
|
|
|
|
asyncTake(20)
|
|
|
|
)
|
|
|
|
|
|
|
|
function fetchYoutubeMetadata(id) {
|
|
|
|
return fetch(`https://noembed.com/embed?url=https://www.youtube.com/watch?v=${id}`)
|
|
|
|
.then(response => response.json())
|
|
|
|
|
|
|
|
}
|
2020-01-07 19:23:49 +01:00
|
|
|
|
2020-01-09 20:31:12 +01:00
|
|
|
export function isSupportedUrl(urlAsString) {
|
|
|
|
const url = new URL(urlAsString)
|
|
|
|
|
|
|
|
const hosts = [
|
|
|
|
'youtube.com',
|
|
|
|
'music.youtube.host'
|
|
|
|
]
|
|
|
|
|
|
|
|
return hosts.includes(url.hostname) && url.searchParams.has('v')
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getYoutubeVideoId(urlAsString) {
|
|
|
|
return new URL(urlAsString).searchParams.get('v')
|
2020-01-07 19:23:49 +01:00
|
|
|
}
|
|
|
|
|
2020-01-09 02:26:13 +01:00
|
|
|
export function intersection(xs, ys) {
|
2020-01-07 19:23:49 +01:00
|
|
|
return xs.filter(x => ys.includes(x));
|
2020-01-09 20:31:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
export async function fetchTimeline(url) {
|
|
|
|
const urlBuilder = new URL(url)
|
|
|
|
urlBuilder.searchParams.set('limit', 40)
|
|
|
|
|
|
|
|
const response = await fetch(url)
|
|
|
|
const statuses = await response.json()
|
|
|
|
const { next, previous } = parseLinkHeader(response.headers.get('link'))
|
|
|
|
|
|
|
|
return { statuses, nextLink: next, previousLink: previous }
|
|
|
|
}
|
|
|
|
|
|
|
|
const LINK_RE = /<(.+?)>; rel="(\w+)"/gi
|
|
|
|
|
|
|
|
export function parseLinkHeader(link) {
|
|
|
|
const links = {}
|
|
|
|
|
|
|
|
for (const [ , url, name ] of link.matchAll(LINK_RE)) {
|
|
|
|
links[name] = url
|
|
|
|
}
|
|
|
|
|
|
|
|
return links
|
2020-01-07 19:23:49 +01:00
|
|
|
}
|