mirror of
https://codeberg.org/ashley/poke.git
synced 2024-11-26 23:38:17 +01:00
Merge branch 'main' into main
This commit is contained in:
commit
3ddbf9eed0
7 changed files with 196 additions and 19 deletions
|
@ -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
|
||||
|
|
|
@ -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
88
html/partials/search.ejs
Normal 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>
|
|
@ -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);
|
||||
|
|
5
videobundler/.env.example
Normal file
5
videobundler/.env.example
Normal 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
26
videobundler/README.md
Normal 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
71
videobundler/main.py
Normal 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)
|
Loading…
Reference in a new issue