2023-10-26 12:35:34 -05:00
|
|
|
const express = require("express"),
|
|
|
|
path = require("path"),
|
|
|
|
fs = require("fs"),
|
2024-02-13 16:04:23 -06:00
|
|
|
ytjs = require('youtubei.js')
|
2023-10-26 12:35:34 -05:00
|
|
|
|
|
|
|
const PORT = process.env.PORT || 8080
|
|
|
|
|
|
|
|
var app = express()
|
|
|
|
|
2024-02-13 16:04:23 -06:00
|
|
|
var resources = path.join(__dirname, 'resources')
|
|
|
|
var staticpath = path.join(__dirname, 'static')
|
2023-10-26 12:35:34 -05:00
|
|
|
|
|
|
|
app.listen(PORT, () => {
|
2024-02-13 16:04:23 -06:00
|
|
|
console.log("SimpleTube is now listening on port " + PORT)
|
2023-10-26 12:35:34 -05:00
|
|
|
})
|
|
|
|
|
2024-02-13 16:04:23 -06:00
|
|
|
app.use(express.static(staticpath))
|
2023-11-27 12:32:33 -06:00
|
|
|
|
2024-02-13 16:04:23 -06:00
|
|
|
var thumbCount = 0
|
|
|
|
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/"
|
|
|
|
]
|
2023-11-27 12:32:33 -06:00
|
|
|
|
2024-02-13 16:04:23 -06:00
|
|
|
function getThumbor() {
|
|
|
|
thumbCount += 1
|
|
|
|
return thumborInstances[thumbCount % thumborInstances.length] + "unsafe"
|
|
|
|
}
|
2023-11-27 12:32:33 -06:00
|
|
|
|
2024-02-13 16:04:23 -06:00
|
|
|
function searchResultToHTML(results) {
|
2024-02-14 09:03:53 -06:00
|
|
|
var videosHTML = "<h2>Videos:<br></h2>"
|
|
|
|
var channelsHTML = "<h2>Channels:<br></h2>"
|
2024-02-13 16:04:23 -06:00
|
|
|
var addedHTML = ""
|
|
|
|
for (let index = 0; index < results.length; index++) {
|
2024-02-13 18:02:32 -06:00
|
|
|
const result = results[index].content || results[index];
|
2024-02-14 09:03:53 -06:00
|
|
|
if (result && result.type == "Video" && result.published && result.duration != "N/A") {
|
|
|
|
if (!result.description_snippet) {
|
|
|
|
if (result.snippets) {
|
|
|
|
result.description_snippet = result.snippets[0].text.runs[0]
|
|
|
|
} else {
|
|
|
|
result.description_snippet = {text: ''}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
videosHTML += `
|
2024-02-13 16:04:23 -06:00
|
|
|
<div class="col-xxl-4 col-sm-6 resultContainer">
|
|
|
|
<div class="videoResult container-fluid row">
|
|
|
|
<div class="col-lg-6 thumbparent">
|
|
|
|
<a class="videoLink" href="/watch?v=${result.id}">
|
|
|
|
<img class="thumbnail" src="${getThumbor()}/${result.thumbnails[0].url}">
|
|
|
|
<p style="display: block; text-align: left;">${result.duration.text}</p>
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
<div class="col-lg-6">
|
|
|
|
<a class="videoLink" href="/watch?v=${result.id}">
|
|
|
|
<p style="font-size: 1.25rem;">${result.title.text || "No Title Found"}</p>
|
2024-02-14 09:03:53 -06:00
|
|
|
<p class="resultDescription">${(result.description_snippet).text}</p>
|
2024-02-13 16:04:23 -06:00
|
|
|
<p style="display: block;">${result.published.text}</p>
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
<div style="display: inline-block; width: 100%;">
|
|
|
|
<a style="color: white; margin: 10px; display: inline-block;" href="/channel?q=${result.author.id}">
|
|
|
|
<img src="${getThumbor()}/${result.author.thumbnails[0].url}" class="minipfp">
|
|
|
|
${result.author.name}
|
|
|
|
</a>
|
|
|
|
</div>
|
2023-11-27 12:32:33 -06:00
|
|
|
</div>
|
|
|
|
</div>
|
2024-02-13 16:04:23 -06:00
|
|
|
`
|
2024-02-14 09:03:53 -06:00
|
|
|
} else if (result.type == "Channel" && result.author.thumbnails[0]) {
|
|
|
|
channelsHTML += `
|
|
|
|
<div class="col-xxl-4 col-sm-6 resultContainer">
|
|
|
|
<div class="videoResult container-fluid row">
|
|
|
|
<div class="col-lg-6 thumbparent">
|
|
|
|
<a class="videoLink" href="/channel?v=${result.id}">
|
|
|
|
<img class="pfp" src="${getThumbor()}/${result.author.thumbnails[0].url}">
|
|
|
|
<p style="display: block; text-align: left;">${result.video_count.text}</p>
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
<div class="col-lg-6">
|
|
|
|
<a class="videoLink" href="/channel?v=${result.id}">
|
|
|
|
<p style="font-size: 1.25rem;">${result.author.name}<br>
|
|
|
|
<span class="note">${result.subscriber_count.text}</span></p>
|
|
|
|
<p class="resultDescription">${(result.description_snippet).text}</p>
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
`
|
|
|
|
} else {
|
|
|
|
console.log(result.type)
|
2023-11-19 23:52:48 -06:00
|
|
|
}
|
2023-11-19 22:40:21 -06:00
|
|
|
}
|
|
|
|
|
2024-02-14 09:03:53 -06:00
|
|
|
if (channelsHTML.length > 30) {
|
|
|
|
addedHTML += channelsHTML
|
|
|
|
}
|
|
|
|
if (videosHTML.length > 30) {
|
|
|
|
addedHTML += videosHTML
|
|
|
|
}
|
|
|
|
|
2024-02-13 16:04:23 -06:00
|
|
|
return addedHTML
|
2023-10-29 23:28:17 -05:00
|
|
|
}
|
|
|
|
|
2023-11-27 22:39:06 -06:00
|
|
|
app.get("/", async (req, res) => {
|
2024-02-13 16:04:23 -06:00
|
|
|
var innerTube = await ytjs.Innertube.create()
|
2023-11-27 22:39:06 -06:00
|
|
|
|
2023-10-28 19:08:28 -05:00
|
|
|
res.setHeader("Content-Type", "text/html")
|
2023-10-26 12:35:34 -05:00
|
|
|
res.setHeader("X-Accel-Buffering", "no")
|
2024-02-13 18:02:32 -06:00
|
|
|
|
2024-02-13 16:04:23 -06:00
|
|
|
var html = fs.readFileSync(path.join(resources, 'mainPage.html')).toString()
|
2023-11-20 10:55:41 -06:00
|
|
|
|
2024-02-13 16:04:23 -06:00
|
|
|
res.write(html.substring(0, html.indexOf("{RESULTS}")))
|
2023-10-27 00:38:23 -05:00
|
|
|
|
2024-02-13 16:04:23 -06:00
|
|
|
var results = (await innerTube.getHomeFeed()).contents.contents
|
2023-10-27 00:38:23 -05:00
|
|
|
|
2024-02-13 16:04:23 -06:00
|
|
|
var addedHTML = searchResultToHTML(results)
|
2023-10-26 12:35:34 -05:00
|
|
|
|
2024-02-13 16:04:23 -06:00
|
|
|
res.write(addedHTML + html.substring(html.indexOf("{RESULTS}") + 9), () => {res.end()})
|
2023-10-26 12:35:34 -05:00
|
|
|
})
|
|
|
|
|
2024-02-13 18:02:32 -06:00
|
|
|
app.get("/search", async (req, res) => {
|
2024-02-14 09:03:53 -06:00
|
|
|
var search = req.query.q
|
2024-02-13 18:02:32 -06:00
|
|
|
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()
|
|
|
|
|
2024-02-14 09:03:53 -06:00
|
|
|
html = html.replaceAll("{SEARCH}", search)
|
|
|
|
|
2024-02-13 18:02:32 -06:00
|
|
|
res.write(html.substring(0, html.indexOf("{RESULTS}")))
|
|
|
|
|
2024-02-14 09:03:53 -06:00
|
|
|
var results = (await innerTube.search(search, {type: "all"}))
|
2024-02-13 18:02:32 -06:00
|
|
|
|
|
|
|
var addedHTML = searchResultToHTML(results.results)
|
|
|
|
|
|
|
|
res.write(addedHTML + html.substring(html.indexOf("{RESULTS}") + 9), () => {res.end()})
|
|
|
|
})
|
|
|
|
|
2024-02-14 10:53:50 -06:00
|
|
|
process.on('uncaughtException', (err, origin) => {
|
|
|
|
fs.writeSync(
|
|
|
|
process.stderr.fd,
|
|
|
|
`Caught exception: ${err}\n` +
|
|
|
|
`Exception origin: ${origin}`,
|
|
|
|
);
|
|
|
|
});
|