const express = require("express"), path = require("path"), fs = require("fs"), ytjs = require('youtubei.js') const PORT = process.env.PORT || 8080 var app = express() var resources = path.join(__dirname, 'resources') var staticpath = path.join(__dirname, 'static') app.listen(PORT, () => { console.log("SimpleTube is now listening on port " + PORT) }) app.use(express.static(staticpath)) var thumbCount = 0 // Proxy images through thumbor instances that alternate to prevent: // 1. Direct communication with Youtube Services // 2. Getting rate limited // 3. Gathering too much data from one source // more thumbor instances will be added var thumborInstances = [ "https://thumbor-production-0e82.up.railway.app/", "https://enormous-book-production.up.railway.app/", "https://unusual-back-production.up.railway.app/", "https://axiomatic-hair-production.up.railway.app/" ] function getThumbor() { thumbCount += 1 return thumborInstances[thumbCount % thumborInstances.length] + "unsafe" } function searchResultToHTML(results) { var videosHTML = "

Videos:

" var channelsHTML = "

Channels:

" var addedHTML = "" for (let index = 0; index < results.length; index++) { const result = results[index].content || results[index]; try { if (result && result.type == "Video" && result.published && result.duration.text != "N/A" && result.thumbnails && result.author.thumbnails) { if (!result.description_snippet) { if (result.snippets) { result.description_snippet = result.snippets[0].text.runs[0] } else { result.description_snippet = {text: ''} } } videosHTML += `
${result.author.name}
` } else if (result.type == "Channel" && result.author.thumbnails[0]) { channelsHTML += `
` } else { console.log(result.type) } } catch (error) { console.error(error) console.log(result) } } if (channelsHTML.length > 30) { addedHTML += channelsHTML } if (videosHTML.length > 30) { addedHTML += videosHTML } addedHTML += "" return addedHTML } app.get("/", async (req, res) => { var innerTube = await ytjs.Innertube.create() res.setHeader("Content-Type", "text/html") res.setHeader("X-Accel-Buffering", "no") var html = fs.readFileSync(path.join(resources, 'mainPage.html')).toString() res.write(html.substring(0, html.indexOf("{RESULTS}"))) var results = (await innerTube.getHomeFeed()).contents.contents var addedHTML = searchResultToHTML(results) res.write(addedHTML + html.substring(html.indexOf("{RESULTS}") + 9), () => {res.end()}) }) app.get("/search", async (req, res) => { var search = req.query.q var innerTube = await ytjs.Innertube.create() res.setHeader("Content-Type", "text/html") res.setHeader("X-Accel-Buffering", "no") var html = fs.readFileSync(path.join(resources, 'searchPage.html')).toString() html = html.replaceAll("{SEARCH}", search) res.write(html.substring(0, html.indexOf("{RESULTS}"))) var results = (await innerTube.search(search, {type: "all"})) var addedHTML = searchResultToHTML(results.results) res.write(addedHTML + html.substring(html.indexOf("{RESULTS}") + 9), () => {res.end()}) }) // process.on('uncaughtException', (err, origin) => { // fs.writeSync( // process.stderr.fd, // `Caught exception: ${err}\n` + // `Exception origin: ${origin}`, // ); // });