1
0
mirror of https://git.sr.ht/~cadence/cloudtube synced 2024-11-14 04:17:29 +00:00
cloudtube/utils/converters.js

101 lines
2.9 KiB
JavaScript
Raw Normal View History

function timeToPastText(timestamp) {
const difference = Date.now() - timestamp
return [
["year", 365 * 24 * 60 * 60 * 1000],
["month", 30 * 24 * 60 * 60 * 1000],
["week", 7 * 24 * 60 * 60 * 1000],
["day", 24 * 60 * 60 * 1000],
["hour", 60 * 60 * 1000],
["minute", 60 * 1000],
["second", 1 * 1000]
2021-01-13 11:55:03 +00:00
].reduce((acc, /** @type {[string, number]} */ [unitName, unitValue]) => {
if (acc) return acc
if (difference > unitValue) {
const number = Math.floor(difference / unitValue)
const pluralUnit = unitName + (number == 1 ? "" : "s")
return `${number} ${pluralUnit} ago`
}
}, null) || "just now"
}
2020-10-06 10:43:44 +00:00
function lengthSecondsToLengthText(seconds) {
2021-01-13 11:55:03 +00:00
let parts = [Math.floor(seconds/3600), Math.floor(seconds/60)%60, seconds%60]
if (parts[0] === 0) parts = parts.slice(1)
return parts.map((x, i) => i === 0 ? x : (x+"").padStart(2, "0")).join(":")
2020-10-06 10:43:44 +00:00
}
/**
* Second and Invidious don't return quite the same data. This
* function normalises them so that all the useful properties are
* available no matter the kind of instance. The video is modified
* in-place.
*
* Changes:
* - second__lengthText is added, may be [hh:]mm:ss or "LIVE"
* - publishedText may be changed to "Live now"
*/
function normaliseVideoInfo(video) {
if (!video.second__lengthText && video.lengthSeconds > 0) {
video.second__lengthText = lengthSecondsToLengthText(video.lengthSeconds)
}
if (!video.second__lengthText && video.lengthSeconds === 0) {
video.second__lengthText = "LIVE"
video.liveNow = true
}
if (video.publishedText === "0 seconds ago") {
video.publishedText = "Live now"
}
}
/**
* 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 = ""
if (!t || t.length > 10) { // don't parse missing values, don't parse 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
2020-10-06 10:43:44 +00:00
module.exports.lengthSecondsToLengthText = lengthSecondsToLengthText
module.exports.normaliseVideoInfo = normaliseVideoInfo
module.exports.tToMediaFragment = tToMediaFragment