2022-04-23 01:37:41 +02:00
|
|
|
import axios from "axios";
|
2022-03-14 20:18:08 +01:00
|
|
|
import { Downloader } from "./downloader";
|
|
|
|
import { Links } from "./links";
|
2022-11-12 01:14:02 +01:00
|
|
|
import { random_int } from "./tools";
|
2023-02-06 22:18:56 +01:00
|
|
|
import { JSDOM } from "jsdom";
|
2022-03-14 20:18:08 +01:00
|
|
|
|
|
|
|
let links = new Links;
|
|
|
|
|
2023-02-06 21:43:07 +01:00
|
|
|
let unixtime = () => {
|
|
|
|
return new Date().getTime()/1000;
|
|
|
|
};
|
2022-03-14 20:18:08 +01:00
|
|
|
|
2022-02-23 19:50:47 +01:00
|
|
|
export class UrlPool {
|
|
|
|
|
2022-04-23 01:37:41 +02:00
|
|
|
id: string;
|
2022-11-13 11:37:30 +01:00
|
|
|
storage: UrlPoolStorage;
|
2022-04-23 14:49:12 +02:00
|
|
|
|
2022-04-23 01:37:41 +02:00
|
|
|
urls: string[] = [];
|
2022-02-23 19:50:47 +01:00
|
|
|
used: boolean[] = [];
|
2022-04-23 14:49:12 +02:00
|
|
|
|
2022-11-13 11:37:30 +01:00
|
|
|
valid_to: Date;
|
|
|
|
|
2022-03-14 20:18:08 +01:00
|
|
|
generating = false;
|
2023-02-06 21:43:07 +01:00
|
|
|
last_generated: number = unixtime();
|
2022-04-23 14:49:12 +02:00
|
|
|
downloaders: Downloader[] = [];
|
|
|
|
|
2023-02-06 22:18:56 +01:00
|
|
|
file_name?: string;
|
2022-04-23 14:49:12 +02:00
|
|
|
total_size: number = 0;
|
|
|
|
is_direct = false;
|
2022-02-23 19:50:47 +01:00
|
|
|
|
2022-11-13 11:37:30 +01:00
|
|
|
constructor(storage: UrlPoolStorage, id: string) {
|
|
|
|
this.valid_to = new Date();
|
|
|
|
this.valid_to.setDate(this.valid_to.getDate() + 1);
|
2022-04-23 01:37:41 +02:00
|
|
|
this.id = id;
|
2022-11-13 11:37:30 +01:00
|
|
|
this.storage = storage;
|
2022-04-23 01:37:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
async init() {
|
2022-04-23 14:49:12 +02:00
|
|
|
|
2022-04-23 01:37:41 +02:00
|
|
|
let page = await axios.get("https://uloz.to/file/"+this.id, {validateStatus: null});
|
|
|
|
if(page.status == 404) return false;
|
2023-02-06 22:18:56 +01:00
|
|
|
let dom = new JSDOM(page.data);
|
2022-04-23 01:37:41 +02:00
|
|
|
// TODO: Add quick download support
|
|
|
|
// let quick_dl_url = links.regex_parse(new RegExp('href="(/quickDownload/[^"]*)"'), page.data, 1);
|
|
|
|
this.is_direct = 'js-free-download-button-direct' == links.regex_parse(new RegExp('data-href="/download-dialog/free/[^"]+" +class=".+(js-free-download-button-direct).+"'), page.data, 1);
|
2023-02-06 22:18:56 +01:00
|
|
|
let filename = dom.window.document.querySelector(".jsFileTitle");
|
|
|
|
|
|
|
|
if(filename && filename.textContent) {
|
|
|
|
this.file_name = filename.textContent.trim();
|
|
|
|
}
|
2022-04-23 14:49:12 +02:00
|
|
|
|
|
|
|
await this.generate();
|
|
|
|
let url = await this.get();
|
|
|
|
if(!url) throw "No available URL in pool!";
|
|
|
|
let r = await axios.get(url[1], {
|
|
|
|
responseType: 'arraybuffer',
|
|
|
|
headers: {
|
|
|
|
Range: `bytes=0-0`
|
|
|
|
}
|
|
|
|
});
|
|
|
|
this.total_size = parseInt(r.headers["content-range"].split("/")[1]);
|
|
|
|
this.return(url[0]);
|
|
|
|
|
2023-02-06 21:43:07 +01:00
|
|
|
this.generating = true;
|
2022-04-23 01:37:41 +02:00
|
|
|
return true;
|
2022-11-13 11:37:30 +01:00
|
|
|
|
2022-02-23 19:50:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
get_raw(): [number, string] | undefined {
|
|
|
|
for(let i=0; i<this.urls.length; i++) {
|
|
|
|
if(this.used[i]) continue;
|
|
|
|
this.used[i] = true;
|
|
|
|
return [i, this.urls[i]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async get(): Promise<[number, string] | undefined> {
|
|
|
|
let url = this.get_raw();
|
|
|
|
if(url) return url;
|
|
|
|
return new Promise((complete) => {
|
|
|
|
let check = setInterval(() => {
|
|
|
|
let url = this.get_raw();
|
|
|
|
if(url) {
|
|
|
|
clearInterval(check);
|
|
|
|
complete(url);
|
2023-02-06 21:43:07 +01:00
|
|
|
} else {
|
|
|
|
this.request_generation();
|
2022-02-23 19:50:47 +01:00
|
|
|
}
|
2022-03-14 20:18:08 +01:00
|
|
|
}, 100);
|
2022-02-23 19:50:47 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-11-12 01:14:02 +01:00
|
|
|
return(i: number, sucess: boolean = true) {
|
|
|
|
setTimeout(() => this.used[i] = false, sucess ? random_int(1000, 5000) : random_int(5000, 60000));
|
2022-02-23 19:50:47 +01:00
|
|
|
}
|
|
|
|
|
2022-03-14 20:18:08 +01:00
|
|
|
add(url: string) {
|
|
|
|
this.urls.push(url);
|
|
|
|
this.used.push(false);
|
|
|
|
}
|
|
|
|
|
2022-02-23 19:50:47 +01:00
|
|
|
available(count?: number) {
|
|
|
|
let available: number[] = [];
|
|
|
|
for(let i=0; i<this.used.length; i++) {
|
|
|
|
if(!this.used[i]) {
|
|
|
|
available.push(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count ? available.slice(0, count) : available;
|
|
|
|
}
|
|
|
|
|
2023-02-06 21:43:07 +01:00
|
|
|
async request_generation() {
|
|
|
|
if(!this.generating || this.last_generated+10 > unixtime()) return;
|
|
|
|
console.log(this.id, "| new link:", (await this.generate()) ? true : false);
|
2022-03-14 20:18:08 +01:00
|
|
|
}
|
|
|
|
|
2022-04-23 01:37:41 +02:00
|
|
|
async generate(): Promise<string | undefined> {
|
2023-02-06 21:43:07 +01:00
|
|
|
this.last_generated = unixtime();
|
2022-04-23 01:37:41 +02:00
|
|
|
try {
|
|
|
|
let link = await (this.is_direct ? links.direct_link(this.id) : links.captcha_link(this.id));
|
|
|
|
if(link) this.add(link);
|
|
|
|
return link;
|
2022-04-23 14:49:12 +02:00
|
|
|
} catch(e) {
|
|
|
|
console.log(e);
|
|
|
|
this.generating = false;
|
2022-04-23 01:37:41 +02:00
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-23 14:49:12 +02:00
|
|
|
get_downloader(from: number) {
|
|
|
|
let d = new Downloader(this, from);
|
|
|
|
this.downloaders.push(d);
|
|
|
|
return d;
|
2022-03-14 20:18:08 +01:00
|
|
|
}
|
|
|
|
|
2022-11-13 11:37:30 +01:00
|
|
|
destroy() {
|
|
|
|
this.downloaders.forEach(d => d.destroy());
|
|
|
|
delete this.storage.pools[this.id];
|
|
|
|
}
|
|
|
|
|
2022-03-14 20:18:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
export class UrlPoolStorage {
|
|
|
|
|
2022-11-13 11:37:30 +01:00
|
|
|
validity_interval: NodeJS.Timer;
|
|
|
|
|
2022-03-14 20:18:08 +01:00
|
|
|
pools: {[U: string]: UrlPool} = {};
|
|
|
|
|
2022-11-13 11:37:30 +01:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-23 01:37:41 +02:00
|
|
|
async get(id: string): Promise<UrlPool | undefined> {
|
|
|
|
return this.pools[id] ? this.pools[id] : await this.new(id);
|
2022-03-14 20:18:08 +01:00
|
|
|
}
|
|
|
|
|
2022-04-23 01:37:41 +02:00
|
|
|
async new(id: string): Promise<UrlPool | undefined> {
|
2022-11-13 11:37:30 +01:00
|
|
|
let pool = new UrlPool(this, id);
|
2022-04-23 01:37:41 +02:00
|
|
|
let check = await pool.init();
|
|
|
|
if(!check) return undefined;
|
2023-02-06 21:43:07 +01:00
|
|
|
pool.request_generation();
|
2022-03-14 20:18:08 +01:00
|
|
|
this.pools[id] = pool;
|
|
|
|
return pool;
|
|
|
|
}
|
|
|
|
|
2022-02-23 19:50:47 +01:00
|
|
|
}
|