import axios from "axios"; import { Downloader } from "./downloader"; import { Links } from "./links"; import { random_int } from "./tools"; import { JSDOM } from "jsdom"; let links = new Links; let unixtime = () => { return new Date().getTime()/1000; }; export class UrlPool { id: string; storage: UrlPoolStorage; urls: string[] = []; used: boolean[] = []; valid_to: Date; generating = false; last_generated: number = unixtime(); downloaders: Downloader[] = []; file_name?: string; total_size: number = 0; constructor(storage: UrlPoolStorage, id: string) { this.valid_to = new Date(); this.valid_to.setDate(this.valid_to.getDate() + 1); this.id = id; this.storage = storage; } async init() { let page = await axios.get("https://uloz.to/file/"+this.id, {validateStatus: null}); if(page.status == 404) return false; let dom = new JSDOM(page.data); // TODO: Add quick download support // let quick_dl_url = links.regex_parse(new RegExp('href="(/quickDownload/[^"]*)"'), page.data, 1); let filename = dom.window.document.querySelector(".jsFileTitle"); if(filename && filename.textContent) { this.file_name = filename.textContent.trim(); } 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]); this.generating = true; return true; } get_raw(): [number, string] | undefined { for(let i=0; i { 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); } else { this.request_generation(); } }, 100); }); } return(i: number, sucess: boolean = true) { setTimeout(() => this.used[i] = false, sucess ? random_int(2000, 5000) : random_int(10000, 60000)); } add(url: string) { this.urls.push(url); this.used.push(false); } available(count?: number) { let available: number[] = []; for(let i=0; i unixtime()) return; console.log(this.id, "| new link:", (await this.generate()) ? true : false); } async generate(): Promise { this.last_generated = unixtime(); try { let link = await links.captcha_link(this.id); if(link) this.add(link); return link; } catch(e) { console.log(e); this.generating = false; return undefined; } } get_downloader(from: number) { let d = new Downloader(this, from); this.downloaders.push(d); return d; } destroy() { this.downloaders.forEach(d => d.destroy()); delete this.storage.pools[this.id]; } } export class UrlPoolStorage { validity_interval: NodeJS.Timer; 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 { return this.pools[id] ? this.pools[id] : await this.new(id); } async new(id: string): Promise { let pool = new UrlPool(this, id); let check = await pool.init(); if(!check) return undefined; pool.request_generation(); this.pools[id] = pool; return pool; } }