Merge branch 'main' into main

This commit is contained in:
blade10101 2024-06-25 01:25:56 +00:00
commit 3ddbf9eed0
7 changed files with 196 additions and 19 deletions

View file

@ -1,8 +1,8 @@
# To run, please do either docker compose up -d (for docker's own version) or docker-compose up -d (for your OSes package managers verison)
services:
poketube:
image: codeberg.org/korbs/poke:amd64
# image: codeberg.org/korbs/poke:arm64 # Use this if you're using a Raspberry Pi or an arm architecture
poke:
image: codeberg.org/poketube/poke:amd64
# image: codeberg.org/poketube/poke:arm64 # Works with ARM64/v8, not ARM64/v7
restart: unless-stopped
volumes:
- ./config.json:/poketube/config.json

View file

@ -31,10 +31,7 @@
</a>
</div>
<div class="header-center">
<form action="/search">
<input/ class="search-bar" autocomplete="on" id="fname" name="query" data-ddg-inputtype="identities.firstName">
<button><?xml version="1.0" encoding="UTF-8"?><svg width="24px" height="24px" viewBox="0 0 24 24" stroke-width="1.5" fill="none" xmlns="http://www.w3.org/2000/svg" color="#ffffff"><path d="M17 17L21 21" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M3 11C3 15.4183 6.58172 19 11 19C13.213 19 15.2161 18.1015 16.6644 16.6493C18.1077 15.2022 19 13.2053 19 11C19 6.58172 15.4183 3 11 3C6.58172 3 3 6.58172 3 11Z" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg></button>
</form>
<%- include('./search.ejs') %>
</div>
<div class="header-end">
<a href="https://codeberg.org/Ashley/poketube/src/branch/main/instances.json"><?xml version="1.0" encoding="UTF-8"?><svg width="24px" height="24px" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#ffffff" style="--darkreader-inline-color: #e8e6e3;" data-darkreader-inline-color=""><path d="M6 18.01L6.01 17.9989" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="--darkreader-inline-stroke: #ffffff;" data-darkreader-inline-stroke=""></path><path d="M6 6.01L6.01 5.99889" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" style="--darkreader-inline-stroke: #ffffff;" data-darkreader-inline-stroke=""></path><path d="M2 9.4V2.6C2 2.26863 2.26863 2 2.6 2H21.4C21.7314 2 22 2.26863 22 2.6V9.4C22 9.73137 21.7314 10 21.4 10H2.6C2.26863 10 2 9.73137 2 9.4Z" stroke="#ffffff" stroke-width="1.5" style="--darkreader-inline-stroke: #ffffff;" data-darkreader-inline-stroke=""></path><path d="M2 21.4V14.6C2 14.2686 2.26863 14 2.6 14H21.4C21.7314 14 22 14.2686 22 14.6V21.4C22 21.7314 21.7314 22 21.4 22H2.6C2.26863 22 2 21.7314 2 21.4Z" stroke="#ffffff" stroke-width="1.5" style="--darkreader-inline-stroke: #ffffff;" data-darkreader-inline-stroke=""></path></svg></a>
@ -122,4 +119,5 @@
color: white;
gap: 6px;
}
</style> <link href="<%- proxyurl %>/https://site-assets.fontawesome.com/releases/v6.1.1/css/all.css" rel=stylesheet>
</style>
<link href="<%- proxyurl %>/https://site-assets.fontawesome.com/releases/v6.1.1/css/all.css" rel=stylesheet>

88
html/partials/search.ejs Normal file
View file

@ -0,0 +1,88 @@
<form action="/search">
<input autocomplete="off" type="search" class="search-bar" id="fname" name="query">
<button><?xml version="1.0" encoding="UTF-8"?><svg width="24px" height="24px" viewBox="0 0 24 24" stroke-width="1.5" fill="none" xmlns="http://www.w3.org/2000/svg" color="#ffffff"><path d="M17 17L21 21" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M3 11C3 15.4183 6.58172 19 11 19C13.213 19 15.2161 18.1015 16.6644 16.6493C18.1077 15.2022 19 13.2053 19 11C19 6.58172 15.4183 3 11 3C6.58172 3 3 6.58172 3 11Z" stroke="#ffffff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg></button>
</form>
<div style="opacity: 0;" class="suggestions"></div>
<script>
/*
@licstart The following is the entire license notice for the
JavaScript code in this page.
Copyright (C) 2024 SudoVanilla
The JavaScript code in this page is free software: you can
redistribute it and/or modify it under the terms of the GNU
General Public License (GNU GPL) as published by the Free Software
Foundation, either version 3 of the License, or (at your option)
any later version. The code is distributed WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
As additional permission under GNU GPL version 3 section 7, you
may distribute non-source (e.g., minimized or compacted) forms of
that code without the copy of the GNU GPL normally required by
section 4, provided you include this license notice and a URL
through which recipients can access the Corresponding Source.
@licend The above is the entire license notice
for the JavaScript code in this page.
*/
// Dismiss when the end-user clicks else where
document.body.addEventListener("click", function (evt) {
document.querySelector('.suggestions').style.opacity = '0'
});
// When the end-user starts typing, trigget the fetch function
document.querySelector('input[type="search"]').addEventListener('input', function(e) {
if (e.target.value !== '') {
document.querySelector('.suggestions').style.opacity = '1'
GetResults()
}
else {null}
});
// Fetch
function GetResults() {
var SearchValue = document.querySelector('input[type="search"]').value
var YouTubeSuggestions = document.querySelector('.suggestions')
fetch(`https://yt.sudovanilla.org/api/v1/search/suggestions?q=${SearchValue}`)
.then(response => response.json())
.then(data => {YouTubeSuggestions.innerHTML = ListOfSuggestionsYT(data)})
}
// Create List
function ListOfSuggestionsYT(data) {
const text = data.suggestions.map(data => `<a href="/search?query=${data}">${data}</a>`).join("\n")
return `${text}`
}
</script>
<style>
.suggestions {
position: absolute;
display: grid;
background: #473e46d6;
border-radius: 6px;
margin-top: 10px;
width: 329px;
z-index: 5;
backdrop-filter: blur(10px);
gap: 4px;
padding: 4px 0px;
}
.suggestions a {
color: white;
background: transparent;
padding: 6px 12px;
border-radius: 4px;
margin: 0px 4px;
}
.suggestions a:hover {
background: #f9f9f917;
text-decoration: none;
}
</style>

View file

@ -181,17 +181,6 @@ app.use("/sb/i/:v/:imagePath/:img", async function (req, res) {
} catch {}
});
app.get("/feeds/videos.xml", async (req, res) => {
const id = req.query.channel_id;
let url = `https://youtube.com/feeds/videos.xml?channel_id=${id}`;
let f = await modules.fetch(url, {
method: req.method,
});
f.body.pipe(res);
});
app.get("/api/redirect", async (req, res) => {
const red_url = atob(req.query.u);

View file

@ -0,0 +1,5 @@
TIME_BEFORE_DELETE=30
INACTIVE_TIME_BEFORE_DELETE=3600
PORT=45872
# DO NOT PUT A / AT THE END OF THE URL
PROXY_URL=https://eu-proxy.poketube.fun

26
videobundler/README.md Normal file
View file

@ -0,0 +1,26 @@
# poke-videobundler
Takes 2 input streams, downloads them, and spits out a combined file.
## Installation
1. Make sure `ffmpeg`, `wget`, and Python 3 are all installed.
2. Download the program files to your computer - `main.py` and `.env.example`.
3. Run `python3 -m pip install flask python-dotenv waitress`.
## Configuration
1. Run `mv .env.example .env`, **even if you don't want to configure anything**.
2. Edit and fill in the values if needed.
## Usage
1. `python3 main.py`.
2. If everything went well, you shouldn't see any output at launch.
3. You will now be able to call the server at the configured port.
## Endpoints
- `/`: Will return `{success:true}` if alive.
- `/[ANYTHING]?id=VIDEO_ID&audio_itag=AUDIO_ITAG&video_itag=VIDEO_ITAG`: Starts the merging process. ID is the youtube video ID, and itags are self explanatory. As a response, you will get a job ID that you will be able to use in future requests to query the video or its status. When this process is finished, the inactive autodelete counter will start, which will allow you to fetch the video until the countdown is over.
> Replace `[ANYTHING]` with absolutely anything, however it has to be unique to the request. Preferably use an UUID

71
videobundler/main.py Normal file
View file

@ -0,0 +1,71 @@
import asyncio
import aiohttp
from aiohttp import web
import string
import os
import random
import subprocess
app = web.Application()
app.router._frozen = False
def get_random_string(length):
# choose from all lowercase letter
letters = string.ascii_lowercase
result_str = "".join(random.choice(letters) for i in range(length))
return result_str
async def merge(request):
# register params
try:
job_id = request.rel_url.query["id"]
video_id: str = request.rel_url.query["id"]
audio_itag: str = request.rel_url.query["audio_itag"]
video_itag: str = request.rel_url.query["video_itag"]
except:
# no one gives a fuck
_ = 0
# validate
if " " in video_id or len(video_id) > 11:
print(f"Video {video_id} flagged as invalid, dropping request")
return
if not audio_itag.isdigit():
print(f"Audio itag {audio_itag} flagged as invalid, dropping request")
return
if not video_itag.isdigit():
print(f"Video itag {video_itag} flagged as invalid, dropping request")
return
if os.path.isfile(f"done.{job_id}"):
return web.FileResponse(
path=f"output.{job_id}.mp4"
)
proc_audio = await asyncio.create_subprocess_shell(
f"wget -O{job_id}.m4a \"https://eu-proxy.poketube.fun/latest_version?id={video_id}&itag={audio_itag}&local=true\"",
)
proc_video = await asyncio.create_subprocess_shell(
f"wget -O{job_id}.mp4 \"https://eu-proxy.poketube.fun/latest_version?id={video_id}&itag={video_itag}&local=true\""
)
await asyncio.gather(proc_audio.wait(), proc_video.wait())
proc_ffmpeg = await asyncio.create_subprocess_shell(
f"ffmpeg -i {job_id}.m4a -i {job_id}.mp4 -c copy output.{job_id}.mp4"
)
await proc_ffmpeg.wait()
f = open(f"done.{job_id}", "a")
f.write(":3")
f.close()
return web.FileResponse(
path=f"output.{job_id}.mp4"
)
async def ping(request):
return web.Response(body='{"success": true}', content_type="application/json")
async def init_app():
app.router.add_get("/{id:.+}", merge)
app.router.add_get("/", ping)
return app
if __name__ == '__main__':
loop = asyncio.get_event_loop()
app = loop.run_until_complete(init_app())
web.run_app(app, port=3030)