Support t parameter using media fragments

This commit is contained in:
Cadence Ember 2021-01-14 00:55:31 +13:00
parent 36f33b9f7e
commit bb4816c4b3
No known key found for this signature in database
GPG Key ID: BC1C2C61CF521B17
3 changed files with 56 additions and 4 deletions

View File

@ -122,20 +122,23 @@ module.exports = [
route: "/watch", methods: ["GET", "POST"], upload: true, code: async ({req, url, body}) => {
const user = getUser(req)
const settings = user.getSettingsOrDefaults()
if (req.method === "GET") {
const id = url.searchParams.get("v")
if (req.method === "GET") {
const t = url.searchParams.get("t")
let mediaFragment = converters.tToMediaFragment(t)
if (!settings.local) {
const instanceOrigin = settings.instance
const outURL = `${instanceOrigin}/api/v1/videos/${id}`
const videoPromise = request(outURL).then(res => res.json())
return renderVideo(videoPromise, {user, id, instanceOrigin})
return renderVideo(videoPromise, {user, id, instanceOrigin}, {mediaFragment})
} else {
return render(200, "pug/local-video.pug", {id})
}
} else { // req.method === "POST"
const video = JSON.parse(new URLSearchParams(body.toString()).get("video"))
const videoPromise = Promise.resolve(video)
return renderVideo(videoPromise, {user})
const instanceOrigin = "http://localhost:3000"
return renderVideo(videoPromise, {user, id, instanceOrigin})
}
}
}

View File

@ -22,7 +22,7 @@ block content
- const format = sortedFormatStreams[0]
if format
video(controls preload="auto" poster=`/vi/${video.videoId}/maxresdefault.jpg` width=format.second__width height=format.second__height data-itag=format.itag)#video.video
source(src=format.url type=format.type)
source(src=format.url+mediaFragment type=format.type)
else
video(src="")#video.video
.stream-notice The server provided no playback streams.

View File

@ -47,6 +47,55 @@ function normaliseVideoInfo(video) {
}
}
/**
* YT supports a time parameter t in these possible formats:
* - [digits] -> seconds
* - ([digits]:)?[digits]:[digits] -> hours?, minutes, seconds
* - ([digits]h)?([digits]m)?([digits]s)? -> hours?, minutes?, seconds
*
* Try our best to get something suitable out. Fail by returning empty
* string, meaning nothing suitable was recognised.
*/
function tToMediaFragment(t) {
let resolved = ""
console.log(t)
if (!t || t.length > 10) { // don't parse missing values, don't pass too long strings
// skip processing
} else if (t.match(/^[0-9.,]+$/)) {
resolved = t
} else if (t.includes(":")) {
resolved = t.split(":").map(s => s.padStart(2, "0")).join(":") // need to pad each to length 2 for npt
} else if (t.match(/[hms]/)) {
let buffer = ""
let sum = 0
const multipliers = new Map([
["h", 60*60],
["m", 60],
["s", 1]
])
for (const char of t) {
console.log(char)
if (char.match(/[0-9]/)) {
buffer += char
} else if (char.match(/[hms]/)) {
sum += +buffer * multipliers.get(char)
buffer = ""
} else {
buffer = ""
}
}
resolved = String(sum)
}
if (resolved) {
return "#t=npt:" + resolved
} else {
return ""
}
}
module.exports.timeToPastText = timeToPastText
module.exports.lengthSecondsToLengthText = lengthSecondsToLengthText
module.exports.normaliseVideoInfo = normaliseVideoInfo
module.exports.tToMediaFragment = tToMediaFragment