Added GUI & fixed bugs
This commit is contained in:
parent
51d31d16fa
commit
a04efa5042
|
@ -6,7 +6,8 @@ export class Downloader {
|
||||||
pool: UrlPool;
|
pool: UrlPool;
|
||||||
chunks: {[U: string]: (Buffer | null)} = {};
|
chunks: {[U: string]: (Buffer | null)} = {};
|
||||||
|
|
||||||
chunk_size = Math.round(0.3*1024*1024);
|
chunk_size = Math.round(1*1024*1024);
|
||||||
|
cache_size = 15;
|
||||||
|
|
||||||
loading: boolean = false;
|
loading: boolean = false;
|
||||||
destroyed: boolean = false;
|
destroyed: boolean = false;
|
||||||
|
@ -44,7 +45,7 @@ export class Downloader {
|
||||||
cache() {
|
cache() {
|
||||||
let chunks: string[] = [];
|
let chunks: string[] = [];
|
||||||
let existing_chunks = Object.keys(this.chunks);
|
let existing_chunks = Object.keys(this.chunks);
|
||||||
for(let i=0; i<15; i++) {
|
for(let i=0; i<this.cache_size; i++) {
|
||||||
chunks.push((this.from+(this.chunk_size*i)).toString());
|
chunks.push((this.from+(this.chunk_size*i)).toString());
|
||||||
}
|
}
|
||||||
chunks.forEach(from => {
|
chunks.forEach(from => {
|
||||||
|
|
30
index.html
30
index.html
|
@ -1,30 +0,0 @@
|
||||||
<head>
|
|
||||||
<link href="https://vjs.zencdn.net/7.17.0/video-js.css" rel="stylesheet" />
|
|
||||||
|
|
||||||
<!-- If you'd like to support IE8 (for Video.js versions prior to v7) -->
|
|
||||||
<!-- <script src="https://vjs.zencdn.net/ie8/1.1.2/videojs-ie8.min.js"></script> -->
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<video
|
|
||||||
id="my-video"
|
|
||||||
class="video-js"
|
|
||||||
controls
|
|
||||||
preload="auto"
|
|
||||||
width="640"
|
|
||||||
height="264"
|
|
||||||
poster="MY_VIDEO_POSTER.jpg"
|
|
||||||
data-setup="{}"
|
|
||||||
>
|
|
||||||
<source src="/api/stream/ulozto_id" type="video/mp4" />
|
|
||||||
<p class="vjs-no-js">
|
|
||||||
To view this video please enable JavaScript, and consider upgrading to a
|
|
||||||
web browser that
|
|
||||||
<a href="https://videojs.com/html5-video-support/" target="_blank"
|
|
||||||
>supports HTML5 video</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</video>
|
|
||||||
|
|
||||||
<script src="https://vjs.zencdn.net/7.17.0/video.min.js"></script>
|
|
||||||
</body>
|
|
|
@ -1,4 +1,4 @@
|
||||||
lockfileVersion: 5.3
|
lockfileVersion: 5.4
|
||||||
|
|
||||||
specifiers:
|
specifiers:
|
||||||
'@types/express': ^4.17.13
|
'@types/express': ^4.17.13
|
||||||
|
@ -130,6 +130,8 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
follow-redirects: 1.5.10
|
follow-redirects: 1.5.10
|
||||||
is-buffer: 2.0.5
|
is-buffer: 2.0.5
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/axios/0.26.0:
|
/axios/0.26.0:
|
||||||
|
@ -160,6 +162,8 @@ packages:
|
||||||
qs: 6.9.7
|
qs: 6.9.7
|
||||||
raw-body: 2.4.3
|
raw-body: 2.4.3
|
||||||
type-is: 1.6.18
|
type-is: 1.6.18
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/bytes/3.1.2:
|
/bytes/3.1.2:
|
||||||
|
@ -212,12 +216,22 @@ packages:
|
||||||
|
|
||||||
/debug/2.6.9:
|
/debug/2.6.9:
|
||||||
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
|
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
|
||||||
|
peerDependencies:
|
||||||
|
supports-color: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
supports-color:
|
||||||
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.0.0
|
ms: 2.0.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/debug/3.1.0:
|
/debug/3.1.0:
|
||||||
resolution: {integrity: sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==}
|
resolution: {integrity: sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==}
|
||||||
|
peerDependencies:
|
||||||
|
supports-color: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
supports-color:
|
||||||
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.0.0
|
ms: 2.0.0
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -305,6 +319,8 @@ packages:
|
||||||
type-is: 1.6.18
|
type-is: 1.6.18
|
||||||
utils-merge: 1.0.1
|
utils-merge: 1.0.1
|
||||||
vary: 1.1.2
|
vary: 1.1.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/extend/3.0.2:
|
/extend/3.0.2:
|
||||||
|
@ -335,6 +351,8 @@ packages:
|
||||||
parseurl: 1.3.3
|
parseurl: 1.3.3
|
||||||
statuses: 1.5.0
|
statuses: 1.5.0
|
||||||
unpipe: 1.0.0
|
unpipe: 1.0.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/follow-redirects/1.14.9:
|
/follow-redirects/1.14.9:
|
||||||
|
@ -352,6 +370,8 @@ packages:
|
||||||
engines: {node: '>=4.0'}
|
engines: {node: '>=4.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 3.1.0
|
debug: 3.1.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/forever-agent/0.6.1:
|
/forever-agent/0.6.1:
|
||||||
|
@ -639,6 +659,8 @@ packages:
|
||||||
on-finished: 2.3.0
|
on-finished: 2.3.0
|
||||||
range-parser: 1.2.1
|
range-parser: 1.2.1
|
||||||
statuses: 1.5.0
|
statuses: 1.5.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/serve-static/1.14.2:
|
/serve-static/1.14.2:
|
||||||
|
@ -649,6 +671,8 @@ packages:
|
||||||
escape-html: 1.0.3
|
escape-html: 1.0.3
|
||||||
parseurl: 1.3.3
|
parseurl: 1.3.3
|
||||||
send: 0.17.2
|
send: 0.17.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/setprototypeof/1.2.0:
|
/setprototypeof/1.2.0:
|
||||||
|
@ -707,6 +731,8 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
axios: 0.18.1
|
axios: 0.18.1
|
||||||
socks-proxy-agent: 4.0.2
|
socks-proxy-agent: 4.0.2
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/tor-request/3.1.0:
|
/tor-request/3.1.0:
|
||||||
|
|
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
38
public/index.html
Normal file
38
public/index.html
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Ulož.to Rychle</title>
|
||||||
|
<style>
|
||||||
|
body {display: flex; justify-content: center; align-items: center; height: 100vh; font-family: sans-serif; text-align: center; font-size: 20px; background: #4a0f4d; color: #fff;}
|
||||||
|
.page {max-width: 550px; width: 100%;}
|
||||||
|
.input {display: flex; gap: 5px; flex-flow: row; justify-content: space-between; width: 100%; margin-top: 30px;}
|
||||||
|
.input * {background-color: #702673; border: 2px solid #330a35; border-radius: 5px; padding: 10px 15px; font-size: 17px; outline: 0; color: #fff;}
|
||||||
|
.input input {width: 100%;}
|
||||||
|
.input button {background: #702673;}
|
||||||
|
.input button:hover {background-color: #4a0f4d; cursor: pointer;}
|
||||||
|
.result {justify-content: center; margin-top: 20px; font-size: 17px; display: block; display: flex; gap: 10px;}
|
||||||
|
.result a {color: #fff5;}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="page">
|
||||||
|
<h1>Ulož.to Rychle</h1>
|
||||||
|
<p>Stahujte z Ulož.to vysokou rychlostí</p>
|
||||||
|
<div class="input">
|
||||||
|
<input placeholder="Vložte odkaz z Ulož.to" /> <button onclick="download();">Získat</button>
|
||||||
|
</div>
|
||||||
|
<div class="result"></div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
function download() {
|
||||||
|
let url = document.querySelector("input").value;
|
||||||
|
let regex = new RegExp(/https:\/\/.*(ulozto\.cz|uloz\.to)\/file\/(.*?)\/.*/gm);
|
||||||
|
let res = regex.exec(url);
|
||||||
|
if(!res) return alert("Neplatná URL!");
|
||||||
|
let id = res[2];
|
||||||
|
let new_url = new URL(`/u/${id}`, location.origin);
|
||||||
|
document.querySelector(".result").innerHTML = `<code>${new_url}</code> <a href="${new_url}" download>Stáhnout</a>`;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
30
urlpool.ts
30
urlpool.ts
|
@ -12,10 +12,13 @@ function sleep(ms: number) {
|
||||||
export class UrlPool {
|
export class UrlPool {
|
||||||
|
|
||||||
id: string;
|
id: string;
|
||||||
|
storage: UrlPoolStorage;
|
||||||
|
|
||||||
urls: string[] = [];
|
urls: string[] = [];
|
||||||
used: boolean[] = [];
|
used: boolean[] = [];
|
||||||
|
|
||||||
|
valid_to: Date;
|
||||||
|
|
||||||
generating = false;
|
generating = false;
|
||||||
downloaders: Downloader[] = [];
|
downloaders: Downloader[] = [];
|
||||||
|
|
||||||
|
@ -23,8 +26,11 @@ export class UrlPool {
|
||||||
is_direct = false;
|
is_direct = false;
|
||||||
ready = false;
|
ready = false;
|
||||||
|
|
||||||
constructor(id: string) {
|
constructor(storage: UrlPoolStorage, id: string) {
|
||||||
|
this.valid_to = new Date();
|
||||||
|
this.valid_to.setDate(this.valid_to.getDate() + 1);
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
this.storage = storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
|
@ -49,6 +55,7 @@ export class UrlPool {
|
||||||
|
|
||||||
this.ready = true;
|
this.ready = true;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get_raw(): [number, string] | undefined {
|
get_raw(): [number, string] | undefined {
|
||||||
|
@ -119,18 +126,37 @@ export class UrlPool {
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.downloaders.forEach(d => d.destroy());
|
||||||
|
delete this.storage.pools[this.id];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UrlPoolStorage {
|
export class UrlPoolStorage {
|
||||||
|
|
||||||
|
validity_interval: NodeJS.Timer;
|
||||||
|
|
||||||
pools: {[U: string]: UrlPool} = {};
|
pools: {[U: string]: UrlPool} = {};
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.validity_interval = setInterval(this.validity_check, 1000*60*60);
|
||||||
|
}
|
||||||
|
|
||||||
|
validity_check() {
|
||||||
|
for(let i in this.pools) {
|
||||||
|
if(this.pools[i].valid_to.getTime() < new Date().getTime()) {
|
||||||
|
this.pools[i].destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async get(id: string): Promise<UrlPool | undefined> {
|
async get(id: string): Promise<UrlPool | undefined> {
|
||||||
return this.pools[id] ? this.pools[id] : await this.new(id);
|
return this.pools[id] ? this.pools[id] : await this.new(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
async new(id: string): Promise<UrlPool | undefined> {
|
async new(id: string): Promise<UrlPool | undefined> {
|
||||||
let pool = new UrlPool(id);
|
let pool = new UrlPool(this, id);
|
||||||
let check = await pool.init();
|
let check = await pool.init();
|
||||||
if(!check) return undefined;
|
if(!check) return undefined;
|
||||||
pool.start_generation();
|
pool.start_generation();
|
||||||
|
|
|
@ -11,6 +11,8 @@ export class Webserver {
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
|
app.use(express.static('public'));
|
||||||
|
|
||||||
app.get("/status/:id", async (req, res) => {
|
app.get("/status/:id", async (req, res) => {
|
||||||
|
|
||||||
let p = await storage.get(req.params.id);
|
let p = await storage.get(req.params.id);
|
||||||
|
@ -37,7 +39,7 @@ export class Webserver {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/stream/:id", async (req, res) => {
|
app.get("/u/:id", async (req, res) => {
|
||||||
|
|
||||||
let p = await storage.get(req.params.id);
|
let p = await storage.get(req.params.id);
|
||||||
if(!p) {
|
if(!p) {
|
||||||
|
|
Reference in a new issue