1
0
mirror of https://git.sr.ht/~cadence/cloudtube synced 2024-11-22 15:47:30 +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 if (isNaN(provided)) data[key] = null
else data[key] = +provided else data[key] = +provided
} else if (setting.type === "boolean") { } else if (setting.type === "boolean") {
if (provided === "true") data[key] = true if (provided === "1") data[key] = 1
else if (provided === "false") data[key] = false else data[key] = 0
else data[key] = null
} else { } else {
throw new Error("Unsupported setting type: "+setting.type) throw new Error("Unsupported setting type: "+setting.type)
} }

View File

@ -35,41 +35,34 @@ function formatOrder(format) {
return -total return -total
} }
module.exports = [ async function renderVideo(videoPromise, {user, id, instanceOrigin}) {
{ try {
route: "/watch", methods: ["GET"], code: async ({req, url}) => { const video = await videoPromise
const id = url.searchParams.get("v") if (!video) throw new Error("The instance returned null.")
const user = getUser(req) if (video.error) throw new InstanceError(video.error, video.identifier)
const settings = user.getSettingsOrDefaults() // video data additional processing
const instanceOrigin = settings.instance for (const format of video.formatStreams.concat(video.adaptiveFormats)) {
const outURL = `${instanceOrigin}/api/v1/videos/${id}` if (!format.second__height && format.resolution) format.second__height = +format.resolution.slice(0, -1)
try { if (!format.second__order) format.second__order = formatOrder(format)
const video = await fetch(outURL).then(res => res.json()) }
if (!video) throw new Error("The instance returned null.") for (const rec of video.recommendedVideos) {
if (video.error) throw new InstanceError(video.error, video.identifier) if (!rec.second__lengthText && rec.lengthSeconds > 0) {
// video data additional processing rec.second__lengthText = converters.lengthSecondsToLengthText(rec.lengthSeconds)
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) const subscribed = user.isSubscribed(video.authorId)
} return render(200, "pug/video.pug", {video, subscribed, instanceOrigin})
for (const rec of video.recommendedVideos) { } catch (e) {
if (!rec.second__lengthText && rec.lengthSeconds > 0) { let message = pug.render("pre= error", {error: e.stack || e.toString()})
rec.second__lengthText = converters.lengthSecondsToLengthText(rec.lengthSeconds) if (e instanceof fetch.FetchError) {
} const template = `
}
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 The selected instance, #[code= instanceOrigin], did not respond correctly.
p Requested URL: #[a(href=url)= url] p Requested URL: #[a(href=url)= url]
` `
message = pug.render(template, {instanceOrigin, url: outURL}) message = pug.render(template, {instanceOrigin, url: outURL})
} else if (e instanceof InstanceError) { } else if (e instanceof InstanceError) {
if (e.identifier === "RATE_LIMITED_BY_YOUTUBE") { if (e.identifier === "RATE_LIMITED_BY_YOUTUBE") {
const template = ` const template = `
.blocked-explanation .blocked-explanation
img(src="/static/images/instance-blocked.svg" width=552 height=96) img(src="/static/images/instance-blocked.svg" width=552 height=96)
.rows .rows
@ -96,18 +89,40 @@ p.
p. p.
This situation #[em will] be improved in the future! This situation #[em will] be improved in the future!
` `
message = pug.render(template, {instanceOrigin}) message = pug.render(template, {instanceOrigin})
} else { } else {
const template = ` const template = `
p #[strong= error.message] p #[strong= error.message]
if error.identifier if error.identifier
p #[code= error.identifier] p #[code= error.identifier]
p That error was generated by #[code= instanceOrigin]. 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 label.description(for=id)= description
select(id=id name=id disabled=disabled).border-look select(id=id name=id disabled=disabled).border-look
each option in options 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 block head
title Settings - CloudTube title Settings - CloudTube
@ -38,8 +38,13 @@ block content
]) ])
+select("save_history", "Watch history", false, [ +select("save_history", "Watch history", false, [
{value: "", text: "Don't save"}, {value: "0", text: "Don't save"},
{value: "yes", text: "Save"} {value: "1", text: "Save"}
])
+select("local", "Fetch videos", false, [
{value: "0", text: "Remote instance"},
{value: "1", text: "Locally"}
]) ])
.save-settings .save-settings

View File

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

View File

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