2020-02-22 03:39:15 +01:00
|
|
|
import getUrls from 'get-urls'
|
|
|
|
import { execPipe, asyncFilter, asyncMap, map, take, filter, asyncFlatMap, toArray } from 'iter-tools'
|
|
|
|
import { share } from '/routes.js'
|
2020-01-20 03:26:18 +01:00
|
|
|
|
2020-02-29 17:48:57 +01:00
|
|
|
const intersection = (xs, ys) => xs.filter(x => ys.includes(x))
|
|
|
|
const difference = (xs, ys) => xs.filter(x => !ys.includes(x))
|
|
|
|
const symmetricDifference = (xs, ys) => [...difference(xs, ys), ...difference(ys, xs)]
|
|
|
|
|
2020-01-20 03:26:18 +01:00
|
|
|
export const tap = f => x => {
|
|
|
|
f(x)
|
|
|
|
return x
|
|
|
|
}
|
|
|
|
|
|
|
|
export const defer = () => {
|
|
|
|
let resolve
|
|
|
|
let reject
|
|
|
|
|
|
|
|
const promise = new Promise((res, rej) => {
|
|
|
|
resolve = res
|
|
|
|
reject = rej
|
|
|
|
})
|
|
|
|
|
|
|
|
return { resolve, reject, promise }
|
|
|
|
}
|
|
|
|
|
2020-02-22 03:39:15 +01:00
|
|
|
export const queue = () => {
|
|
|
|
const deferred = defer()
|
|
|
|
let promise = deferred.promise
|
2020-01-20 03:26:18 +01:00
|
|
|
|
2020-02-22 03:39:15 +01:00
|
|
|
const enqueue = f => {
|
|
|
|
promise = promise.then(tap(f))
|
2020-02-24 23:18:51 +01:00
|
|
|
return promise
|
2020-01-20 03:26:18 +01:00
|
|
|
}
|
|
|
|
|
2020-02-22 03:39:15 +01:00
|
|
|
return { enqueue, run: deferred.resolve }
|
2020-01-20 03:26:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
export const secondsToElapsedTime = (seconds) => {
|
|
|
|
const parts = [
|
|
|
|
Math.floor(seconds / 3600),
|
|
|
|
Math.floor(seconds / 60) % 60,
|
|
|
|
Math.floor(seconds) % 60
|
|
|
|
]
|
|
|
|
|
|
|
|
return parts
|
|
|
|
.filter((value, index) => value > 0 || index > 0)
|
|
|
|
.map(value => value < 10 ? '0' + value : value)
|
|
|
|
.join(':')
|
|
|
|
}
|
|
|
|
|
2020-02-22 03:39:15 +01:00
|
|
|
export async function* tracksIterator(refererGenerator, cache) {
|
|
|
|
const notKnow = (values) => {
|
2020-02-16 17:02:39 +01:00
|
|
|
if (cache.has(values)) {
|
|
|
|
console.log(`Drop already processed ${values.join(':')}`)
|
2020-02-22 03:39:15 +01:00
|
|
|
return false
|
2020-02-16 17:02:39 +01:00
|
|
|
} else {
|
|
|
|
cache.add(values)
|
2020-02-22 03:39:15 +01:00
|
|
|
return true
|
2020-02-15 23:12:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-22 03:39:15 +01:00
|
|
|
try {
|
|
|
|
yield* execPipe(
|
|
|
|
refererGenerator,
|
|
|
|
asyncFilter(({ credentials: { domain, id } }) => notKnow(['referer', 'mastodon', domain, id])),
|
|
|
|
asyncFlatMap(referer => {
|
|
|
|
return execPipe(
|
|
|
|
referer.content,
|
|
|
|
getUrls,
|
|
|
|
map(url => {
|
|
|
|
const { hostname, pathname, searchParams } = new URL(url)
|
|
|
|
|
|
|
|
if (['youtube.com', 'm.youtube.com', 'music.youtube.com'].includes(hostname) && searchParams.has('v')) {
|
|
|
|
return { url, credentials: { type: 'youtube', id: searchParams.get('v') } }
|
|
|
|
} else if (hostname === 'youtu.be') {
|
|
|
|
return { url, credentials: { type: 'youtube', id: pathname.substring(1) } }
|
|
|
|
} else {
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
filter(media => media !== null),
|
|
|
|
map(({ url, credentials }) => ({ referer, mediaUrl: url, mediaCredentials: credentials })),
|
|
|
|
take(1),
|
|
|
|
toArray
|
|
|
|
)
|
|
|
|
}),
|
|
|
|
asyncFilter(({ mediaCredentials: { id }}) => notKnow(['media', 'youtube', id])),
|
|
|
|
asyncMap(async ({ referer, mediaUrl, mediaCredentials }) => {
|
|
|
|
const metadata = await fetchMetadata(mediaCredentials)
|
|
|
|
|
|
|
|
return {
|
|
|
|
shareUrl: `${location.origin}${share.reverse({ domain: referer.credentials.domain, id: referer.credentials.id })}`,
|
|
|
|
referer,
|
|
|
|
media: {
|
|
|
|
title: metadata.title,
|
|
|
|
url: mediaUrl,
|
2020-02-24 23:18:51 +01:00
|
|
|
cover: `https://img.youtube.com/vi/${mediaCredentials.id}/mqdefault.jpg`,
|
2020-02-22 03:39:15 +01:00
|
|
|
credentials: mediaCredentials
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
)
|
|
|
|
} finally {
|
|
|
|
refererGenerator.return()
|
2020-01-20 03:26:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-22 03:39:15 +01:00
|
|
|
const fetchMetadata = (credentials) => {
|
|
|
|
return fetch(`https://noembed.com/embed?url=https://www.youtube.com/watch?v=${credentials.id}`)
|
|
|
|
.then(response => response.json())
|
2020-01-20 03:26:18 +01:00
|
|
|
}
|