Added auto captcha and link generating

This commit is contained in:
Filip Znachor 2022-03-14 20:18:08 +01:00
parent 1b12af714f
commit 0eda7a506d
11 changed files with 741 additions and 55 deletions

35
README.md Normal file
View file

@ -0,0 +1,35 @@
# Ulož.to streamer
Stream ulož.to video content without downloading
## Instalation
### Python libraries
Install all python libraries for `captcha.py`:
```
numpy, requests, tensorflow, PIL
```
### Install node modules
```
npm i --save
```
### Setup Tor proxy
Set `ControlPort`, `SocksPort` and `HashedControlPassword` in /etc/tor/torrc:
```
SocksPort 9050
ControlPort 9051
HashedControlPassword 16:872230D6EA809D4760AD5894ADB7A5A07191882EBCD188378544794F8F
```
Password can be generated with:
```
tor --hash-password giraffe
```

53
captcha.py Normal file
View file

@ -0,0 +1,53 @@
import numpy
import requests
import string
import sys
import tensorflow
from io import BytesIO
from PIL import Image
def decode(li) -> string:
available_chars = "abcdefghijklmnopqrstuvwxyz"
result = []
for char in li:
result.append(available_chars[char])
return "".join(result)
def solve(url: string) -> string:
interpreter = tensorflow.lite.Interpreter(
model_content=open("./model.tflite", "rb").read())
u = requests.get(url)
raw_data = u.content
img = Image.open(BytesIO(raw_data))
img = numpy.asarray(img)
# normalize to [0...1]
img = (img / 255).astype(numpy.float32)
# convert to grayscale
r, g, b = img[:, :, 0], img[:, :, 1], img[:, :, 2]
gray = 0.299 * r + 0.587 * g + 0.114 * b
# input has nowof shape (70, 175)
# we modify dimensions to match model's input
gray = numpy.expand_dims(gray, 0)
gray = numpy.expand_dims(gray, -1)
# input is now of shape (batch_size, 70, 175, 1)
# output will have shape (batch_size, 4, 26)
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
interpreter.set_tensor(input_details[0]['index'], gray)
interpreter.invoke()
# predict and get the output
output = interpreter.get_tensor(output_details[0]['index'])
# now get labels
labels_indices = numpy.argmax(output, axis=2)
decoded_label = [decode(x) for x in labels_indices][0]
return decoded_label
try:
result = solve(sys.argv[1])
print(result, end = "")
except:
pass

View file

@ -1 +1,30 @@
<video src="http://localhost:8000" controls>
<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>

View file

@ -4,33 +4,4 @@ let webserver = new Webserver;
process.on('uncaughtException', err => {
console.error('There was an uncaught error', err)
});
// (async () => {
// let downloader = new Downloader(pool);
// await downloader.init();
// console.log(downloader.total_size);
// let limit = Math.ceil(downloader.total_size/downloader.chunk_size);
// let chunk = -1;
// let interval = setInterval(() => {
// let available = pool.available(limit-chunk);
// if(available.length) {
// console.log("downloading new chunks", available.length);
// available.forEach(async (i: number) => {
// chunk++;
// if(!await downloader.download_chunk(chunk)) console.warn("Error!");
// });
// }
// console.log(downloader.downloaded_chunks + " / " + downloader.total_chunks);
// if(downloader.total_chunks == downloader.downloaded_chunks) {
// clearInterval(interval);
// console.log(downloader.chunks.length);
// fs.writeFileSync("vid.mkv", Buffer.concat(downloader.chunks));
// }
// }, 1000);
// });
});

84
links.ts Normal file
View file

@ -0,0 +1,84 @@
import { exec } from "child_process";
import axios from "axios";
let tor_axios = require('tor-axios');
export class Links {
tor = tor_axios.torSetup({
ip: 'localhost',
port: 9050,
controlPort: '9051',
controlPassword: 'giraffe'
})
inst = axios.create({
httpAgent: this.tor.httpAgent(),
httpsAgent: this.tor.httpsAgent(),
});
parse_cookie(cookies: string[] | undefined) {
if(!cookies) return "";
let cookie_list: string[] = [];
cookies.forEach(c => {
cookie_list.push(c.split(";")[0]);
});
return cookie_list.join("; ");
}
regex_escape(string: string) {
return string.replace(/[-[\]{}()*+!<=:?.\/\\^$|#\s,]/g, '\\$&');
}
regex_parse(regex: RegExp, text: string, group: number): string | undefined {
let match = regex.exec(text);
if(!match) return;
return match![group] ? match![group] : undefined;
}
async link(id: string) {
let download_link = "https://uloz.to/download-dialog/free/download?fileSlug="+id;
let captcha_page = await this.inst.get(download_link);
let cookies = this.parse_cookie(captcha_page.headers["set-cookie"]);
let url = this.regex_parse(/<img class="xapca-image" src="([^"]*)" alt="">/gm, captcha_page.data, 1);
if(!url) return undefined;
let captcha_image = new URL(url, "https://localhost").href;
let captcha = await this.captcha(captcha_image);
let form = new URLSearchParams();
["_token_", "timestamp", "salt", "hash", "captcha_type", "_do"].forEach(name => {
let regex = "name=\""+this.regex_escape(name)+"\" value=\"([^\"]*)\"";
let resp = this.regex_parse(new RegExp(regex), captcha_page.data, 1);
if(resp) form.append(name, resp);
});
form.append("captcha_value", captcha);
let result = await this.inst({
method: "POST",
url: download_link,
data: form,
headers: {
"Accept-Encoding": "gzip",
"X-Requested-With": "XMLHttpRequest",
"User-Agent": "Go-http-client/1.1",
"Cookie": cookies
}
});
this.tor.torNewSession();
return result.data.slowDownloadLink;
}
async captcha(url: string): Promise<string> {
return new Promise((resolve) => {
exec("python3 captcha.py "+url, (e, o) => {
resolve(o);
});
});
}
}

BIN
model.tflite Normal file

Binary file not shown.

View file

@ -4,7 +4,9 @@
"main": "index.ts",
"dependencies": {
"axios": "^0.26.0",
"express": "^4.17.3"
"express": "^4.17.3",
"tor-axios": "^1.0.9",
"tor-request": "^3.1.0"
},
"devDependencies": {
"@types/express": "^4.17.13",

View file

@ -5,10 +5,14 @@ specifiers:
'@types/node': ^17.0.20
axios: ^0.26.0
express: ^4.17.3
tor-axios: ^1.0.9
tor-request: ^3.1.0
dependencies:
axios: 0.26.0
express: 4.17.3
tor-axios: 1.0.9
tor-request: 3.1.0
devDependencies:
'@types/express': 4.17.13
@ -77,10 +81,57 @@ packages:
negotiator: 0.6.3
dev: false
/agent-base/4.2.1:
resolution: {integrity: sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==}
engines: {node: '>= 4.0.0'}
dependencies:
es6-promisify: 5.0.0
dev: false
/ajv/6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
dependencies:
fast-deep-equal: 3.1.3
fast-json-stable-stringify: 2.1.0
json-schema-traverse: 0.4.1
uri-js: 4.4.1
dev: false
/array-flatten/1.1.1:
resolution: {integrity: sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=}
dev: false
/asn1/0.2.6:
resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==}
dependencies:
safer-buffer: 2.1.2
dev: false
/assert-plus/1.0.0:
resolution: {integrity: sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=}
engines: {node: '>=0.8'}
dev: false
/asynckit/0.4.0:
resolution: {integrity: sha1-x57Zf380y48robyXkLzDZkdLS3k=}
dev: false
/aws-sign2/0.7.0:
resolution: {integrity: sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=}
dev: false
/aws4/1.11.0:
resolution: {integrity: sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==}
dev: false
/axios/0.18.1:
resolution: {integrity: sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==}
deprecated: Critical security vulnerability fixed in v0.21.1. For more information, see https://github.com/axios/axios/pull/3410
dependencies:
follow-redirects: 1.5.10
is-buffer: 2.0.5
dev: false
/axios/0.26.0:
resolution: {integrity: sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==}
dependencies:
@ -89,6 +140,12 @@ packages:
- debug
dev: false
/bcrypt-pbkdf/1.0.2:
resolution: {integrity: sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=}
dependencies:
tweetnacl: 0.14.5
dev: false
/body-parser/1.19.2:
resolution: {integrity: sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==}
engines: {node: '>= 0.8'}
@ -110,6 +167,17 @@ packages:
engines: {node: '>= 0.8'}
dev: false
/caseless/0.12.0:
resolution: {integrity: sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=}
dev: false
/combined-stream/1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
dependencies:
delayed-stream: 1.0.0
dev: false
/content-disposition/0.5.4:
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
engines: {node: '>= 0.6'}
@ -131,12 +199,34 @@ packages:
engines: {node: '>= 0.6'}
dev: false
/core-util-is/1.0.2:
resolution: {integrity: sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=}
dev: false
/dashdash/1.14.1:
resolution: {integrity: sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=}
engines: {node: '>=0.10'}
dependencies:
assert-plus: 1.0.0
dev: false
/debug/2.6.9:
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
dependencies:
ms: 2.0.0
dev: false
/debug/3.1.0:
resolution: {integrity: sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==}
dependencies:
ms: 2.0.0
dev: false
/delayed-stream/1.0.0:
resolution: {integrity: sha1-3zrhmayt+31ECqrgsp4icrJOxhk=}
engines: {node: '>=0.4.0'}
dev: false
/depd/1.1.2:
resolution: {integrity: sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=}
engines: {node: '>= 0.6'}
@ -146,6 +236,13 @@ packages:
resolution: {integrity: sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=}
dev: false
/ecc-jsbn/0.1.2:
resolution: {integrity: sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=}
dependencies:
jsbn: 0.1.1
safer-buffer: 2.1.2
dev: false
/ee-first/1.1.1:
resolution: {integrity: sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=}
dev: false
@ -155,6 +252,16 @@ packages:
engines: {node: '>= 0.8'}
dev: false
/es6-promise/4.2.8:
resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==}
dev: false
/es6-promisify/5.0.0:
resolution: {integrity: sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=}
dependencies:
es6-promise: 4.2.8
dev: false
/escape-html/1.0.3:
resolution: {integrity: sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=}
dev: false
@ -200,6 +307,23 @@ packages:
vary: 1.1.2
dev: false
/extend/3.0.2:
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
dev: false
/extsprintf/1.3.0:
resolution: {integrity: sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=}
engines: {'0': node >=0.6.0}
dev: false
/fast-deep-equal/3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: false
/fast-json-stable-stringify/2.1.0:
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
dev: false
/finalhandler/1.1.2:
resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==}
engines: {node: '>= 0.8'}
@ -223,6 +347,26 @@ packages:
optional: true
dev: false
/follow-redirects/1.5.10:
resolution: {integrity: sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==}
engines: {node: '>=4.0'}
dependencies:
debug: 3.1.0
dev: false
/forever-agent/0.6.1:
resolution: {integrity: sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=}
dev: false
/form-data/2.3.3:
resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==}
engines: {node: '>= 0.12'}
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
mime-types: 2.1.34
dev: false
/forwarded/0.2.0:
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
engines: {node: '>= 0.6'}
@ -233,6 +377,26 @@ packages:
engines: {node: '>= 0.6'}
dev: false
/getpass/0.1.7:
resolution: {integrity: sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=}
dependencies:
assert-plus: 1.0.0
dev: false
/har-schema/2.0.0:
resolution: {integrity: sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=}
engines: {node: '>=4'}
dev: false
/har-validator/5.1.5:
resolution: {integrity: sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==}
engines: {node: '>=6'}
deprecated: this library is no longer supported
dependencies:
ajv: 6.12.6
har-schema: 2.0.0
dev: false
/http-errors/1.8.1:
resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==}
engines: {node: '>= 0.6'}
@ -244,6 +408,15 @@ packages:
toidentifier: 1.0.1
dev: false
/http-signature/1.2.0:
resolution: {integrity: sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=}
engines: {node: '>=0.8', npm: '>=1.3.7'}
dependencies:
assert-plus: 1.0.0
jsprim: 1.4.2
sshpk: 1.17.0
dev: false
/iconv-lite/0.4.24:
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
engines: {node: '>=0.10.0'}
@ -255,11 +428,54 @@ packages:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
dev: false
/ip/1.1.5:
resolution: {integrity: sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=}
dev: false
/ipaddr.js/1.9.1:
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
engines: {node: '>= 0.10'}
dev: false
/is-buffer/2.0.5:
resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==}
engines: {node: '>=4'}
dev: false
/is-typedarray/1.0.0:
resolution: {integrity: sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=}
dev: false
/isstream/0.1.2:
resolution: {integrity: sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=}
dev: false
/jsbn/0.1.1:
resolution: {integrity: sha1-peZUwuWi3rXyAdls77yoDA7y9RM=}
dev: false
/json-schema-traverse/0.4.1:
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
dev: false
/json-schema/0.4.0:
resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==}
dev: false
/json-stringify-safe/5.0.1:
resolution: {integrity: sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=}
dev: false
/jsprim/1.4.2:
resolution: {integrity: sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==}
engines: {node: '>=0.6.0'}
dependencies:
assert-plus: 1.0.0
extsprintf: 1.3.0
json-schema: 0.4.0
verror: 1.10.0
dev: false
/media-typer/0.3.0:
resolution: {integrity: sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=}
engines: {node: '>= 0.6'}
@ -305,6 +521,10 @@ packages:
engines: {node: '>= 0.6'}
dev: false
/oauth-sign/0.9.0:
resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==}
dev: false
/on-finished/2.3.0:
resolution: {integrity: sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=}
engines: {node: '>= 0.8'}
@ -321,6 +541,10 @@ packages:
resolution: {integrity: sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=}
dev: false
/performance-now/2.1.0:
resolution: {integrity: sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=}
dev: false
/proxy-addr/2.0.7:
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
engines: {node: '>= 0.10'}
@ -329,6 +553,20 @@ packages:
ipaddr.js: 1.9.1
dev: false
/psl/1.8.0:
resolution: {integrity: sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==}
dev: false
/punycode/2.1.1:
resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==}
engines: {node: '>=6'}
dev: false
/qs/6.5.3:
resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==}
engines: {node: '>=0.6'}
dev: false
/qs/6.9.7:
resolution: {integrity: sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==}
engines: {node: '>=0.6'}
@ -349,6 +587,33 @@ packages:
unpipe: 1.0.0
dev: false
/request/2.88.2:
resolution: {integrity: sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==}
engines: {node: '>= 6'}
deprecated: request has been deprecated, see https://github.com/request/request/issues/3142
dependencies:
aws-sign2: 0.7.0
aws4: 1.11.0
caseless: 0.12.0
combined-stream: 1.0.8
extend: 3.0.2
forever-agent: 0.6.1
form-data: 2.3.3
har-validator: 5.1.5
http-signature: 1.2.0
is-typedarray: 1.0.0
isstream: 0.1.2
json-stringify-safe: 5.0.1
mime-types: 2.1.34
oauth-sign: 0.9.0
performance-now: 2.1.0
qs: 6.5.3
safe-buffer: 5.2.1
tough-cookie: 2.5.0
tunnel-agent: 0.6.0
uuid: 3.4.0
dev: false
/safe-buffer/5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
dev: false
@ -390,6 +655,43 @@ packages:
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
dev: false
/smart-buffer/4.2.0:
resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==}
engines: {node: '>= 6.0.0', npm: '>= 3.0.0'}
dev: false
/socks-proxy-agent/4.0.2:
resolution: {integrity: sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==}
engines: {node: '>= 6'}
dependencies:
agent-base: 4.2.1
socks: 2.3.3
dev: false
/socks/2.3.3:
resolution: {integrity: sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==}
engines: {node: '>= 6.0.0', npm: '>= 3.0.0'}
dependencies:
ip: 1.1.5
smart-buffer: 4.2.0
dev: false
/sshpk/1.17.0:
resolution: {integrity: sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==}
engines: {node: '>=0.10.0'}
hasBin: true
dependencies:
asn1: 0.2.6
assert-plus: 1.0.0
bcrypt-pbkdf: 1.0.2
dashdash: 1.14.1
ecc-jsbn: 0.1.2
getpass: 0.1.7
jsbn: 0.1.1
safer-buffer: 2.1.2
tweetnacl: 0.14.5
dev: false
/statuses/1.5.0:
resolution: {integrity: sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=}
engines: {node: '>= 0.6'}
@ -400,6 +702,38 @@ packages:
engines: {node: '>=0.6'}
dev: false
/tor-axios/1.0.9:
resolution: {integrity: sha512-JFBkpV7essVA7sB2Xwm5MhfJ5CwA4dLZSyOaQTl14hl9K+Q0wHWEOqtFoME2qPRmYIbIHJIIxZTPVQjB3aV8gw==}
dependencies:
axios: 0.18.1
socks-proxy-agent: 4.0.2
dev: false
/tor-request/3.1.0:
resolution: {integrity: sha512-153kvMc+f3U0TOncrxpQlbYRnRdfVHVOtlkVwSsgsUzU4RiuvIW8UyyIOMSMfVlu1u887d/FgHZF9K2YmOK3Mw==}
dependencies:
request: 2.88.2
socks-proxy-agent: 4.0.2
dev: false
/tough-cookie/2.5.0:
resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==}
engines: {node: '>=0.8'}
dependencies:
psl: 1.8.0
punycode: 2.1.1
dev: false
/tunnel-agent/0.6.0:
resolution: {integrity: sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=}
dependencies:
safe-buffer: 5.2.1
dev: false
/tweetnacl/0.14.5:
resolution: {integrity: sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=}
dev: false
/type-is/1.6.18:
resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
engines: {node: '>= 0.6'}
@ -413,12 +747,33 @@ packages:
engines: {node: '>= 0.8'}
dev: false
/uri-js/4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
dependencies:
punycode: 2.1.1
dev: false
/utils-merge/1.0.1:
resolution: {integrity: sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=}
engines: {node: '>= 0.4.0'}
dev: false
/uuid/3.4.0:
resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==}
deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.
hasBin: true
dev: false
/vary/1.1.2:
resolution: {integrity: sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=}
engines: {node: '>= 0.8'}
dev: false
/verror/1.10.0:
resolution: {integrity: sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=}
engines: {'0': node >=0.6.0}
dependencies:
assert-plus: 1.0.0
core-util-is: 1.0.2
extsprintf: 1.3.0
dev: false

100
tsconfig.json Normal file
View file

@ -0,0 +1,100 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Projects */
// "incremental": true, /* Enable incremental compilation */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "es5", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
// "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
/* Modules */
"module": "commonjs", /* Specify what module code is generated. */
// "rootDir": "./", /* Specify the root folder within your source files. */
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "resolveJsonModule": true, /* Enable importing .json files */
// "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
// "outDir": "./", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
// "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
// "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
}

View file

@ -1,11 +1,22 @@
import { Downloader } from "./downloader";
import { Links } from "./links";
let links = new Links;
function sleep(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}
export class UrlPool {
urls: string[];
used: boolean[] = [];
generating = false;
downloader?: Downloader;
constructor(urls: string[]) {
this.urls = urls;
for(let i=0; i<urls.length; i++) {
constructor(urls?: string[]) {
this.urls = urls ? urls : [];
for(let i=0; i<this.urls.length; i++) {
this.used[i] = false;
}
}
@ -28,7 +39,7 @@ export class UrlPool {
clearInterval(check);
complete(url);
}
}, 500);
}, 100);
});
}
@ -36,6 +47,11 @@ export class UrlPool {
this.used[i] = false;
}
add(url: string) {
this.urls.push(url);
this.used.push(false);
}
available(count?: number) {
let available: number[] = [];
for(let i=0; i<this.used.length; i++) {
@ -46,4 +62,40 @@ export class UrlPool {
return count ? available.slice(0, count) : available;
}
async generate(id: string) {
this.generating = true;
while(this.urls.length < 10) {
let link = await links.link(id);
if(link) this.add(link);
console.log(link);
await sleep(2000);
}
this.generating = false;
}
get_downloader() {
if(this.downloader) return this.downloader;
this.downloader = new Downloader(this)
return this.downloader;
}
}
export class UrlPoolStorage {
pools: {[U: string]: UrlPool} = {};
get(id: string) {
return this.pools[id] ? this.pools[id] : this.new(id);
}
new(id: string) {
let pool = new UrlPool;
pool.generate(id);
this.pools[id] = pool;
return pool;
}
}

View file

@ -1,22 +1,10 @@
import express from "express";
import { Downloader } from "./downloader";
import { UrlPool } from "./urlpool";
import { UrlPoolStorage } from "./urlpool";
import { Readable } from 'stream';
let pool = new UrlPool(`https://download.uloz.to/Ps;Hs;up=0;cid=1412447369;uip=89.163.243.88;aff=uloz.to;did=uloz-to;fide=az2Gxzu;fs=pLlZx78VhpLo;hid=JPWTfrY;rid=53936164;tm=1645827197;ut=f;rs=0;He;ch=3676c0f11954b17f3b47a432f1ae1ee8;Pe/file/pLlZx78VhpLo/matrix-1999-cz-mp4?bD&c=1412447369&De
https://download.uloz.to/Ps;Hs;up=0;cid=1129985479;uip=185.220.102.249;aff=uloz.to;did=uloz-to;fide=az2Gxzu;fs=pLlZx78VhpLo;hid=JPWTfrY;rid=561098867;tm=1645827209;ut=f;rs=0;He;ch=519cfbfcb4efe4af4a94b34ec9644609;Pe/file/pLlZx78VhpLo/matrix-1999-cz-mp4?bD&c=1129985479&De
https://download.uloz.to/Ps;Hs;up=0;cid=114914590;uip=185.220.101.86;aff=uloz.to;did=uloz-to;fide=az2Gxzu;fs=pLlZx78VhpLo;hid=JPWTfrY;rid=1829476423;tm=1645827209;ut=f;rs=0;He;ch=4cf0db28c8c81955bdc81ccd3b7f92f6;Pe/file/pLlZx78VhpLo/matrix-1999-cz-mp4?bD&c=114914590&De
https://download.uloz.to/Ps;Hs;up=0;cid=1617820972;uip=107.189.4.253;aff=uloz.to;did=uloz-to;fide=az2Gxzu;fs=pLlZx78VhpLo;hid=JPWTfrY;rid=141776455;tm=1645827211;ut=f;rs=0;He;ch=7c1fb7f1a836590c274039c66dfcda99;Pe/file/pLlZx78VhpLo/matrix-1999-cz-mp4?bD&c=1617820972&De
https://download.uloz.to/Ps;Hs;up=0;cid=1469359686;uip=5.2.72.226;aff=uloz.to;did=uloz-to;fide=az2Gxzu;fs=pLlZx78VhpLo;hid=JPWTfrY;rid=1774386903;tm=1645827212;ut=f;rs=0;He;ch=6b1485bc3e20cc06d0a712ebe4036905;Pe/file/pLlZx78VhpLo/matrix-1999-cz-mp4?bD&c=1469359686&De
https://download.uloz.to/Ps;Hs;up=0;cid=1910168684;uip=107.189.10.63;aff=uloz.to;did=uloz-to;fide=az2Gxzu;fs=pLlZx78VhpLo;hid=JPWTfrY;rid=1577890352;tm=1645827223;ut=f;rs=0;He;ch=3be975ccb9361af36b61255001a5427b;Pe/file/pLlZx78VhpLo/matrix-1999-cz-mp4?bD&c=1910168684&De
https://download.uloz.to/Ps;Hs;up=0;cid=381158312;uip=89.248.168.41;aff=uloz.to;did=uloz-to;fide=az2Gxzu;fs=pLlZx78VhpLo;hid=JPWTfrY;rid=666945992;tm=1645827223;ut=f;rs=0;He;ch=ef7f799ef9521ff132ef82f8c21cd831;Pe/file/pLlZx78VhpLo/matrix-1999-cz-mp4?bD&c=381158312&De
https://download.uloz.to/Ps;Hs;up=0;cid=335896018;uip=185.195.71.2;aff=uloz.to;did=uloz-to;fide=az2Gxzu;fs=pLlZx78VhpLo;hid=JPWTfrY;rid=1195420583;tm=1645827224;ut=f;rs=0;He;ch=b77f94898e04485661c3120f1f23e95d;Pe/file/pLlZx78VhpLo/matrix-1999-cz-mp4?bD&c=335896018&De
https://download.uloz.to/Ps;Hs;up=0;cid=1364037004;uip=185.195.71.244;aff=uloz.to;did=uloz-to;fide=az2Gxzu;fs=pLlZx78VhpLo;hid=JPWTfrY;rid=1209800903;tm=1645827245;ut=f;rs=0;He;ch=d3a38438c7c8786cb869458f391d6ca3;Pe/file/pLlZx78VhpLo/matrix-1999-cz-mp4?bD&c=1364037004&De
https://download.uloz.to/Ps;Hs;up=0;cid=947300788;uip=185.220.100.243;aff=uloz.to;did=uloz-to;fide=az2Gxzu;fs=pLlZx78VhpLo;hid=JPWTfrY;rid=1975067348;tm=1645827245;ut=f;rs=0;He;ch=39019f9e27d7a216eb2d2cecffda619c;Pe/file/pLlZx78VhpLo/matrix-1999-cz-mp4?bD&c=947300788&De
https://download.uloz.to/Ps;Hs;up=0;cid=1608448688;uip=185.220.101.42;aff=uloz.to;did=uloz-to;fide=az2Gxzu;fs=pLlZx78VhpLo;hid=JPWTfrY;rid=1643356760;tm=1645827246;ut=f;rs=0;He;ch=1347a9cf2cabad923867347b897924a3;Pe/file/pLlZx78VhpLo/matrix-1999-cz-mp4?bD&c=1608448688&De
https://download.uloz.to/Ps;Hs;up=0;cid=709281061;uip=185.220.101.20;aff=uloz.to;did=uloz-to;fide=az2Gxzu;fs=pLlZx78VhpLo;hid=JPWTfrY;rid=2092835317;tm=1645827247;ut=f;rs=0;He;ch=254d43fbd221b68723edcb0c6f0d9181;Pe/file/pLlZx78VhpLo/matrix-1999-cz-mp4?bD&c=709281061&De`.split("\n"));
let d = new Downloader(pool);
let storage = new UrlPoolStorage;
export class Webserver {
@ -27,7 +15,25 @@ export class Webserver {
const app = express();
app.get("/", async (req, res) => {
app.get("/status/:id", async (req, res) => {
let p = storage.get(req.params.id);
res.write(JSON.stringify({
streams: {
total: p.urls.length,
available: p.available().length,
generating: p.generating
}
}));
res.end();
});
app.get("/stream/:id", async (req, res) => {
let p = storage.get(req.params.id);
let d = p.get_downloader();
let range: Range = {from: 0, to: null};
if(req.headers.range) range = this.parse_range(req.headers.range);
@ -48,7 +54,6 @@ export class Webserver {
res.writeHead(206, headers);
const readable = new Readable()
readable._read = async () => {
[from, to] = this.from_to([to+1, to+1+this.chunk_size], d.total_size);
@ -57,11 +62,11 @@ export class Webserver {
//res.end();
}
else {
let stream = await this.download_chunk(from, to);
let stream = await this.download_chunk(d, from, to);
readable.push(stream);
}
}
let stream = await this.download_chunk(from, to);
let stream = await this.download_chunk(d, from, to);
readable.push(stream);
readable.pipe(res);
@ -73,7 +78,7 @@ export class Webserver {
}
async download_chunk(from: number, to: number) {
async download_chunk(d: Downloader, from: number, to: number) {
console.log("downloading...", from, to);
let stream = await d.download_range(from, to);
console.log("downloaded ", from, to);