Compare commits

..

2 Commits

Author SHA1 Message Date
85122ba2e9 Merge branch 'master' of gitea.moe:lamp/u2b.cx 2023-03-27 12:56:41 -07:00
6e363f0787 Add direct id function 2023-03-27 12:53:52 -07:00
3 changed files with 73 additions and 14 deletions

View File

@ -11,6 +11,10 @@ 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).
### GET `https://u2b.cx/id/<video id>`
Bypasses search to serve the video directly.
## Installation

View File

@ -5,11 +5,10 @@ from threading import Event
from datetime import datetime, timedelta
from os import environ
import logging
import re
def getBestMp4UrlFromInfo(info):
entries = info.get('entries')
if not entries: return None
formats = entries[0].get('formats')
formats = info['entries'][0].get('formats') if info.get("entries") else info.get("formats")
if not formats: return None
valid = list(filter(lambda x: x['ext'] == "mp4" and x['vcodec'] != 'none' and x['acodec'] != 'none', formats))
if not valid: return None
@ -38,7 +37,10 @@ class Handler(BaseHTTPRequestHandler):
self.send_error(404)
return
query = unquote(self.path[1:])
path = unquote(self.path)
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)
if not dict or 'expire' in dict and datetime.now() >= dict['expire']:
@ -50,7 +52,7 @@ class Handler(BaseHTTPRequestHandler):
ips_running_ytdl.append(client_ip)
query_dicts[query] = dict = {'event': Event()}
with YoutubeDL() as ydl:
info = ydl.extract_info("ytsearch:" + query, download=False)
info = ydl.extract_info(query, download=False)
url = getBestMp4UrlFromInfo(info)
dict['url'] = url
dict['expire'] = getExpireDatetime(url)

View File

@ -10,21 +10,74 @@
img {
vertical-align: middle;
}
code {
white-space: nowrap;
color: brown;
}
</style>
</head><body>
<i><h2>Problem:</h2></i>
<h2 id="Problem">Problem:</h2>
<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>
<i><h2>SOLUTION!</h2></i>
<h2 id="Solution">SOLUTION!</h2>
<ol>
<li>Type the following exactly into the URL bar: <code>https://u2b.cx/</code></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 wanna watch. For example, if you wanna play nyan cat, type in like so: <code>https://u2b.cx/nyan cat</code></li>
<li>The first result from YouTube will start playing. YAAY!</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>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>Now after that just type what you want to watch. Here are just a few examples:</li>
<ul>
<li><code>https://u2b.cx/nyan cat</code></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>
<i><h3>Demo</h3></i>
<h3 id="Demo">Demo</h3>
<video controls style="max-height: 80vh"><source src="com.vrchat.oculus.quest-20230321-223838.mp4" type="video/mp4"/></video>
<i><h3>Problems?</h3></i>
<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>
<h3 id="Advanced_usage">Advanced Usage</h3>
<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/&lt;youtube video id&gt;</code></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>