1
0
mirror of https://git.sr.ht/~cadence/cloudtube synced 2024-12-22 13:07:00 +00:00

Add local fetch option

This commit is contained in:
Cadence Ember 2020-10-26 20:29:05 +13:00
parent f78ee4ff0f
commit 9a890574d5
No known key found for this signature in database
GPG Key ID: BC1C2C61CF521B17
7 changed files with 107 additions and 45 deletions

View File

@ -37,9 +37,8 @@ module.exports = [
if (isNaN(provided)) data[key] = null
else data[key] = +provided
} else if (setting.type === "boolean") {
if (provided === "true") data[key] = true
else if (provided === "false") data[key] = false
else data[key] = null
if (provided === "1") data[key] = 1
else data[key] = 0
} else {
throw new Error("Unsupported setting type: "+setting.type)
}

View File

@ -35,41 +35,34 @@ function formatOrder(format) {
return -total
}
module.exports = [
{
route: "/watch", methods: ["GET"], code: async ({req, url}) => {
const id = url.searchParams.get("v")
const user = getUser(req)
const settings = user.getSettingsOrDefaults()
const instanceOrigin = settings.instance
const outURL = `${instanceOrigin}/api/v1/videos/${id}`
try {
const video = await fetch(outURL).then(res => res.json())
if (!video) throw new Error("The instance returned null.")
if (video.error) throw new InstanceError(video.error, video.identifier)
// video data additional processing
for (const format of video.formatStreams.concat(video.adaptiveFormats)) {
if (!format.second__height && format.resolution) format.second__height = +format.resolution.slice(0, -1)
if (!format.second__order) format.second__order = formatOrder(format)
}
for (const rec of video.recommendedVideos) {
if (!rec.second__lengthText && rec.lengthSeconds > 0) {
rec.second__lengthText = converters.lengthSecondsToLengthText(rec.lengthSeconds)
}
}
const subscribed = user.isSubscribed(video.authorId)
return render(200, "pug/video.pug", {video, subscribed, instanceOrigin})
} catch (e) {
let message = pug.render("pre= error", {error: e.stack || e.toString()})
if (e instanceof fetch.FetchError) {
const template = `
async function renderVideo(videoPromise, {user, id, instanceOrigin}) {
try {
const video = await videoPromise
if (!video) throw new Error("The instance returned null.")
if (video.error) throw new InstanceError(video.error, video.identifier)
// video data additional processing
for (const format of video.formatStreams.concat(video.adaptiveFormats)) {
if (!format.second__height && format.resolution) format.second__height = +format.resolution.slice(0, -1)
if (!format.second__order) format.second__order = formatOrder(format)
}
for (const rec of video.recommendedVideos) {
if (!rec.second__lengthText && rec.lengthSeconds > 0) {
rec.second__lengthText = converters.lengthSecondsToLengthText(rec.lengthSeconds)
}
}
const subscribed = user.isSubscribed(video.authorId)
return render(200, "pug/video.pug", {video, subscribed, instanceOrigin})
} catch (e) {
let message = pug.render("pre= error", {error: e.stack || e.toString()})
if (e instanceof fetch.FetchError) {
const template = `
p The selected instance, #[code= instanceOrigin], did not respond correctly.
p Requested URL: #[a(href=url)= url]
`
message = pug.render(template, {instanceOrigin, url: outURL})
} else if (e instanceof InstanceError) {
if (e.identifier === "RATE_LIMITED_BY_YOUTUBE") {
const template = `
message = pug.render(template, {instanceOrigin, url: outURL})
} else if (e instanceof InstanceError) {
if (e.identifier === "RATE_LIMITED_BY_YOUTUBE") {
const template = `
.blocked-explanation
img(src="/static/images/instance-blocked.svg" width=552 height=96)
.rows
@ -96,18 +89,40 @@ p.
p.
This situation #[em will] be improved in the future!
`
message = pug.render(template, {instanceOrigin})
} else {
const template = `
message = pug.render(template, {instanceOrigin})
} else {
const template = `
p #[strong= error.message]
if error.identifier
p #[code= error.identifier]
p That error was generated by #[code= instanceOrigin].
`
message = pug.render(template, {instanceOrigin, error: e})
}
message = pug.render(template, {instanceOrigin, error: e})
}
}
return render(500, "pug/video.pug", {video: {videoId: id}, error: true, message})
}
}
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 (!settings.local) {
const instanceOrigin = settings.instance
const outURL = `${instanceOrigin}/api/v1/videos/${id}`
const videoPromise = fetch(outURL).then(res => res.json())
return renderVideo(videoPromise, {user, id, instanceOrigin})
} else {
return render(200, "pug/local-video.pug", {id})
}
return render(500, "pug/video.pug", {video: {videoId: id}, error: true, message})
} else { // req.method === "POST"
const video = JSON.parse(new URLSearchParams(body.toString()).get("video"))
const videoPromise = Promise.resolve(video)
return renderVideo(videoPromise, {user})
}
}
}

View File

@ -0,0 +1,18 @@
import {q} from "./elemjs/elemjs.js"
const status = q("#status")
const form = q("#form")
const data = q("#video-data")
fetch(`http://localhost:3000/api/v1/videos/${id}`).then(res => res.json()).then(root => {
if (root.error) throw new Error(root)
data.value = JSON.stringify(root)
form.submit()
status.textContent = "Submitting..."
}).catch(e => {
if (e.message.includes("NetworkError")) {
status.textContent = "Connection failed. Make sure you're running your own instance locally."
} else {
status.innerText = e.toString()
}
})

16
pug/local-video.pug Normal file
View File

@ -0,0 +1,16 @@
extends includes/layout
include includes/video-list-item
include includes/subscribe-button
block head
title Fetching... - CloudTube
script(type="module" src=getStaticURL("html", "/static/js/local-video.js"))
script const id = !{JSON.stringify(id)}
block content
main.video-error-page
h2 Fetching video
p#status Waiting...
form(method="post")#form.local-video-form
input(type="hidden" name="video")#video-data

View File

@ -20,7 +20,7 @@ mixin select(id, description, disabled, options)
label.description(for=id)= description
select(id=id name=id disabled=disabled).border-look
each option in options
option(value=option.value selected=(option.value === settings[id]))= option.text
option(value=option.value selected=(option.value == settings[id]))= option.text
block head
title Settings - CloudTube
@ -38,9 +38,14 @@ block content
])
+select("save_history", "Watch history", false, [
{value: "", text: "Don't save"},
{value: "yes", text: "Save"}
{value: "0", text: "Don't save"},
{value: "1", text: "Save"}
])
+select("local", "Fetch videos", false, [
{value: "0", text: "Remote instance"},
{value: "1", text: "Locally"}
])
.save-settings
button.border-look Save
button.border-look Save

View File

@ -7,6 +7,10 @@ const constants = {
save_history: {
type: "boolean",
default: false
},
local: {
type: "boolean",
default: false
}
},

View File

@ -23,6 +23,11 @@ const deltas = [
function() {
db.prepare("ALTER TABLE Channels ADD COLUMN refreshed INTEGER")
.run()
},
// 2: Settings +local
function() {
db.prepare("ALTER TABLE Settings ADD COLUMN local INTEGER DEFAULT 0")
.run()
}
]