Compare commits
No commits in common. "85122ba2e9ccc09f7cd1f5361cf9be41f544fbbc" and "c791be328eccebad1f5cf0bfc56a742ccc46660e" have entirely different histories.
85122ba2e9
...
c791be328e
@ -11,10 +11,6 @@ The server will search YouTube for `<query>`, pick the first result, pick the be
|
|||||||
|
|
||||||
Example: [`https://u2b.cx/nyan cat`](https://u2b.cx/nyan%20cat) will give you the raw mp4 file for [https://www.youtube.com/watch?v=QH2-TGUlwu4](https://www.youtube.com/watch?v=QH2-TGUlwu4), the first result on [https://www.youtube.com/results?search_query=nyan+cat](https://www.youtube.com/results?search_query=nyan+cat).
|
Example: [`https://u2b.cx/nyan cat`](https://u2b.cx/nyan%20cat) will give you the raw mp4 file for [https://www.youtube.com/watch?v=QH2-TGUlwu4](https://www.youtube.com/watch?v=QH2-TGUlwu4), the first result on [https://www.youtube.com/results?search_query=nyan+cat](https://www.youtube.com/results?search_query=nyan+cat).
|
||||||
|
|
||||||
### GET `https://u2b.cx/id/<video id>`
|
|
||||||
|
|
||||||
Bypasses search to serve the video directly.
|
|
||||||
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
12
server.py
12
server.py
@ -5,10 +5,11 @@ from threading import Event
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from os import environ
|
from os import environ
|
||||||
import logging
|
import logging
|
||||||
import re
|
|
||||||
|
|
||||||
def getBestMp4UrlFromInfo(info):
|
def getBestMp4UrlFromInfo(info):
|
||||||
formats = info['entries'][0].get('formats') if info.get("entries") else info.get("formats")
|
entries = info.get('entries')
|
||||||
|
if not entries: return None
|
||||||
|
formats = entries[0].get('formats')
|
||||||
if not formats: return None
|
if not formats: return None
|
||||||
valid = list(filter(lambda x: x['ext'] == "mp4" and x['vcodec'] != 'none' and x['acodec'] != 'none', formats))
|
valid = list(filter(lambda x: x['ext'] == "mp4" and x['vcodec'] != 'none' and x['acodec'] != 'none', formats))
|
||||||
if not valid: return None
|
if not valid: return None
|
||||||
@ -37,10 +38,7 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
self.send_error(404)
|
self.send_error(404)
|
||||||
return
|
return
|
||||||
|
|
||||||
path = unquote(self.path)
|
query = unquote(self.path[1:])
|
||||||
match = re.match("\/(?:id\/|(?:https?:\/\/)?(?:(?:www\.)?youtube\.com\/(?:watch\?v=|shorts\/)|youtu\.be\/))([A-Za-z0-9_-]{11})", path)
|
|
||||||
query = match[1] if match else "ytsearch:" + path[1:]
|
|
||||||
|
|
||||||
dict = query_dicts.get(query)
|
dict = query_dicts.get(query)
|
||||||
|
|
||||||
if not dict or 'expire' in dict and datetime.now() >= dict['expire']:
|
if not dict or 'expire' in dict and datetime.now() >= dict['expire']:
|
||||||
@ -52,7 +50,7 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
ips_running_ytdl.append(client_ip)
|
ips_running_ytdl.append(client_ip)
|
||||||
query_dicts[query] = dict = {'event': Event()}
|
query_dicts[query] = dict = {'event': Event()}
|
||||||
with YoutubeDL() as ydl:
|
with YoutubeDL() as ydl:
|
||||||
info = ydl.extract_info(query, download=False)
|
info = ydl.extract_info("ytsearch:" + query, download=False)
|
||||||
url = getBestMp4UrlFromInfo(info)
|
url = getBestMp4UrlFromInfo(info)
|
||||||
dict['url'] = url
|
dict['url'] = url
|
||||||
dict['expire'] = getExpireDatetime(url)
|
dict['expire'] = getExpireDatetime(url)
|
||||||
|
@ -10,74 +10,21 @@
|
|||||||
img {
|
img {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
code {
|
|
||||||
white-space: nowrap;
|
|
||||||
color: brown;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
</head><body>
|
</head><body>
|
||||||
<h2 id="Problem">Problem:</h2>
|
<i><h2>Problem:</h2></i>
|
||||||
<img src="VRChat_2023-03-21_22-37-32.758_1920x1080.png" alt="A video player in VRChat" style="max-height: 50vh" />
|
<img src="VRChat_2023-03-21_22-37-32.758_1920x1080.png" alt="A video player in VRChat" style="max-height: 50vh" />
|
||||||
<p>No video! No PC to put video! No URLs memorized! What do???</p>
|
<p>No video! No PC to put video! No URLs memorized! What do???</p>
|
||||||
<h2 id="Solution">SOLUTION!</h2>
|
<i><h2>SOLUTION!</h2></i>
|
||||||
<ol>
|
<ol>
|
||||||
<li>Type the following exactly into the URL bar: <code>https://u2b.cx/</code></li>
|
<li>Type the following exactly into the URL bar: <code>https://u2b.cx/</code></li>
|
||||||
<li>TIP: Press the copy <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADUAAAA0CAMAAAAdZIDnAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAADYUExURRwiKxwqMhsvNhwvNhwuNhwmLxwkLRo9QxhKUBdQVhZTWRZSWBdOVBhGTBsyORlCSRVVXBAdIw8XHQ8VGxNUWRdPVRs0Oxs3PhZUWhJFShlESxJJTxwkLBhJTxArMRVYXho6QBAqLxo6QRhLURApLxVZXxo7Qf///8rKy/39/VZYWfv7+2ZnaFBRU2RlZhRaYBo7QhhIThAxNhVXXRlARxRUWw8VHBZRWBswOBE2PRRYXxlCSBJKUBFITRNKURZTWxlFSxwpMRwtNRo8QxlGTBlFTBo4PxwjLAQa4UkAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADhSURBVEhL7dbXDoIwFIDhulFxD3Di3nvvPd7/jSxyIhjBHJF4I99VT5M/KU1ISr5gsdpw7A4oiNPFuD1eJNbnl6pAMBSOoEVjcTHieJiREox4ymQKRiyenjGdycKEJeToXTB5mLCEAq2KJZiwyhWzkv1ZVX2AjWdaVQ0W6oyu4IRUHTZlb6oGrJuv32ZWSoZWrbaeivppJYMdmXbVgUTtZ9Gu3jErJbNS0ld1e/S90R/AhDXk6NtmNIYJaTKd0crKzmHGWSzF1xfh2MVqjbXZ7vb3ihyOy9MZaXS5StHHCLkBefveLzCsA+EAAAAASUVORK5CYII=" width="24" height="24" /> button on the lower left 😉</li>
|
<li>TIP: Press the <img alt="copy" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADUAAAA0CAMAAAAdZIDnAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAADYUExURRwiKxwqMhsvNhwvNhwuNhwmLxwkLRo9QxhKUBdQVhZTWRZSWBdOVBhGTBsyORlCSRVVXBAdIw8XHQ8VGxNUWRdPVRs0Oxs3PhZUWhJFShlESxJJTxwkLBhJTxArMRVYXho6QBAqLxo6QRhLURApLxVZXxo7Qf///8rKy/39/VZYWfv7+2ZnaFBRU2RlZhRaYBo7QhhIThAxNhVXXRlARxRUWw8VHBZRWBswOBE2PRRYXxlCSBJKUBFITRNKURZTWxlFSxwpMRwtNRo8QxlGTBlFTBo4PxwjLAQa4UkAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADhSURBVEhL7dbXDoIwFIDhulFxD3Di3nvvPd7/jSxyIhjBHJF4I99VT5M/KU1ISr5gsdpw7A4oiNPFuD1eJNbnl6pAMBSOoEVjcTHieJiREox4ymQKRiyenjGdycKEJeToXTB5mLCEAq2KJZiwyhWzkv1ZVX2AjWdaVQ0W6oyu4IRUHTZlb6oGrJuv32ZWSoZWrbaeivppJYMdmXbVgUTtZ9Gu3jErJbNS0ld1e/S90R/AhDXk6NtmNIYJaTKd0crKzmHGWSzF1xfh2MVqjbXZ7vb3ihyOy9MZaXS5StHHCLkBefveLzCsA+EAAAAASUVORK5CYII=" width="24" height="24" /> button on the lower left 😉</li>
|
||||||
<li>Now after that just type what you want to watch. Here are just a few examples:</li>
|
<li>Now after that just type what you wanna watch. For example, if you wanna play nyan cat, type in like so: <code>https://u2b.cx/nyan cat</code></li>
|
||||||
<ul>
|
<li>The first result from YouTube will start playing. YAAY!</li>
|
||||||
<li><code>https://u2b.cx/nyan cat</code></li>
|
<li>TIP: When you wanna watch again, press the <img alt="paste" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADUAAAA0CAMAAAAdZIDnAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAADeUExURRwiKxwqMhsvNxwvNhwtNRsyORhGTBdOVBZRVhZSWBZRVxhLURo+RBwkLBs2PBdPVRNUWg8ZHw8VGw8WHBAdIxVXXBlFSxwlLhhKUBJHTA8WGxZUWho5QBszOhJKTxo6QRVYXhArMBhJTxwkLRo7QRVZXxAqLxo7QhApL6Skpf///1ZXWVxdXvf39/Hx8bKzs7KysrGxsrCxsUlKTBVZXhs4PhVYXREwNhwjLBsvNhRUWxlBRxlBSBE2PRsxOBwoMBZTWhNMUhFITRJHThRYXxdMUhs3PhlFTBo9RBwuNtYqywoAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADwSURBVEhL7dbZboJQEIDhcalacatWRLHWvfUUF1AsLlXrUvX9X6gcnFhCghliYlLDf3OYSb6Qk3ABXFEgGCIWRgHwEInGHonFhUTSQql05ilLLfecFzkqSEXc0CrJZVO9yDhSq/CXvVZxolarNwCaLZyotQVTvXlV776y9c9VhzF8cuSqPhRFYV3GzAM3ttwUs8r2Toczd4XQJDdQ53x1v6rfHwxUVdU0ja6G+D1Z4e4vN3U5X9nzlb1r1AgnapbSxzhR+5QMgEk8hyOx6Yz/SM29XewrveBqKa6+19Q2290PRwCGPovsiYmH4wl5DuAXf0nZllJEIHwAAAAASUVORK5CYII=" width="24" height="24" /> button on the lower right so you don't have to type it all again 👌</li>
|
||||||
<li><code>https://u2b.cx/never gonna give you up</code></li>
|
|
||||||
<li><code>https://u2b.cx/arabic cat</code></li>
|
|
||||||
<li><code>https://u2b.cx/gangnam style</code></li>
|
|
||||||
<li><code>https://u2b.cx/miku</code></li>
|
|
||||||
<li><code>https://u2b.cx/despacito</code></li>
|
|
||||||
<li><code>https://u2b.cx/baby shark dance</code></li>
|
|
||||||
<li><code>https://u2b.cx/technology connections</code></li>
|
|
||||||
</ul>
|
|
||||||
<li>Just like with the Discord music bots, the first search result from YouTube will start playing.</li>
|
|
||||||
<li>TIP: Next time, press the paste <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADUAAAA0CAMAAAAdZIDnAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAADeUExURRwiKxwqMhsvNxwvNhwtNRsyORhGTBdOVBZRVhZSWBZRVxhLURo+RBwkLBs2PBdPVRNUWg8ZHw8VGw8WHBAdIxVXXBlFSxwlLhhKUBJHTA8WGxZUWho5QBszOhJKTxo6QRVYXhArMBhJTxwkLRo7QRVZXxAqLxo7QhApL6Skpf///1ZXWVxdXvf39/Hx8bKzs7KysrGxsrCxsUlKTBVZXhs4PhVYXREwNhwjLBsvNhRUWxlBRxlBSBE2PRsxOBwoMBZTWhNMUhFITRJHThRYXxdMUhs3PhlFTBo9RBwuNtYqywoAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADwSURBVEhL7dbZboJQEIDhcalacatWRLHWvfUUF1AsLlXrUvX9X6gcnFhCghliYlLDf3OYSb6Qk3ABXFEgGCIWRgHwEInGHonFhUTSQql05ilLLfecFzkqSEXc0CrJZVO9yDhSq/CXvVZxolarNwCaLZyotQVTvXlV776y9c9VhzF8cuSqPhRFYV3GzAM3ttwUs8r2Toczd4XQJDdQ53x1v6rfHwxUVdU0ja6G+D1Z4e4vN3U5X9nzlb1r1AgnapbSxzhR+5QMgEk8hyOx6Yz/SM29XewrveBqKa6+19Q2290PRwCGPovsiYmH4wl5DuAXf0nZllJEIHwAAAAASUVORK5CYII=" width="24" height="24" /> button on the lower right so you don't have to type the whole thing all over again 👍</li>
|
|
||||||
</ol>
|
</ol>
|
||||||
<h3 id="Demo">Demo</h3>
|
<i><h3>Demo</h3></i>
|
||||||
<video controls style="max-height: 80vh"><source src="com.vrchat.oculus.quest-20230321-223838.mp4" type="video/mp4"/></video>
|
<video controls style="max-height: 80vh"><source src="com.vrchat.oculus.quest-20230321-223838.mp4" type="video/mp4"/></video>
|
||||||
<h3 id="Advanced_usage">Advanced Usage</h3>
|
<i><h3>Problems?</h3></i>
|
||||||
<p>For PC users or world creators who want to make a particular video work on Quest, u2b.cx can also be used as an alternative to sites like <a href="https://nextnex.com" target="_blank">nextnex.com</a> and <a href="https://ytdlh.cf/" target="_blank">ytdlh.cf</a> by using the following syntax: <code>https://u2b.cx/id/<youtube video id></code></p>
|
<p>If you encounter any issues, please submit on <a href="https://gitea.moe/lamp/u2b.cx/issues">issue tracker</a>. You can use Discord or GitHub account.</p>
|
||||||
<p>Paste a YouTube URL here to have it converted for you: <input id="input" type="text" placeholder="https://www.youtube.com/watch?v=dQw4w9WgXcQ" style="width: 309px" /> <span id="output_container" style="display: none"> ➡ <code><span id="output"></span></code> <button id="copy_btn">Copy</button></span></p>
|
|
||||||
<script>
|
|
||||||
var input = document.getElementById("input");
|
|
||||||
var output = document.getElementById("output");
|
|
||||||
var output_container = document.getElementById("output_container");
|
|
||||||
var copy_btn = document.getElementById("copy_btn");
|
|
||||||
input.oninput = function() {
|
|
||||||
var match = input.value.match(/[A-Za-z0-9_-]{11}/);
|
|
||||||
if (match) {
|
|
||||||
output.innerText = `https://u2b.cx/id/${match[0]}`;
|
|
||||||
output_container.style.display = '';
|
|
||||||
} else {
|
|
||||||
output.innerText = '';
|
|
||||||
output_container.style.display = "none";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
copy_btn.onclick = function() {
|
|
||||||
navigator.clipboard.writeText(output.innerText);
|
|
||||||
copy_btn.disabled = true;
|
|
||||||
copy_btn.innerText = "Copied";
|
|
||||||
setTimeout(function(){
|
|
||||||
copy_btn.disabled = false;
|
|
||||||
copy_btn.innerText = "Copy";
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<p>For potential support of prefixing implementations, known YouTube URL formats will also be parsed for the ID. This means any one of the following will bypass the YouTube search and look up the video directly:</p>
|
|
||||||
<ul>
|
|
||||||
<li><code>https://u2b.cx/id/dQw4w9WgXcQ</code> (recommended)</li>
|
|
||||||
<li><code>https://u2b.cx/https://www.youtube.com/watch?v=dQw4w9WgXcQ</code></li>
|
|
||||||
<li><code>https://u2b.cx/https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DdQw4w9WgXcQ</code></li>
|
|
||||||
<li><code>https://u2b.cx/http://youtube.com/watch?v=dQw4w9WgXcQ</code></li>
|
|
||||||
<li><code>https://u2b.cx/youtube.com/watch?v=dQw4w9WgXcQ</code></li>
|
|
||||||
<li><code>https://u2b.cx/https://youtu.be/dQw4w9WgXcQ</code></li>
|
|
||||||
<li><code>https://u2b.cx/https://youtube/shorts/dQw4w9WgXcQ</code></li>
|
|
||||||
</ul>
|
|
||||||
<p>Anything else will be sent to YouTube search, which will probably still get what you want.</p>
|
|
||||||
<h3 id="Problems">Problems?</h3>
|
|
||||||
<p>If you encounter any issues such as a service outage, please submit to the <a href="https://gitea.moe/lamp/u2b.cx/issues/new">issue tracker</a>. Thanks.</p>
|
|
||||||
</body></html>
|
</body></html>
|
||||||
|
Loading…
Reference in New Issue
Block a user