213 lines
6.5 KiB
TypeScript
213 lines
6.5 KiB
TypeScript
import {Component, ElementRef, ViewChild} from '@angular/core';
|
|
import axios from "axios";
|
|
import {DevelopmentStore} from "../../store/DevelopmentStore";
|
|
import {FormsModule} from "@angular/forms";
|
|
import {DecimalPipe, NgClass, NgIf} from "@angular/common";
|
|
import funfacts from "../../assets/funfacts";
|
|
import {ActivatedRoute, RouterLink} from "@angular/router";
|
|
|
|
@Component({
|
|
selector: 'app-download',
|
|
standalone: true,
|
|
imports: [
|
|
FormsModule,
|
|
NgIf,
|
|
DecimalPipe,
|
|
RouterLink,
|
|
NgClass
|
|
],
|
|
templateUrl: './download.component.html',
|
|
styleUrl: './download.component.scss'
|
|
})
|
|
export class DownloadComponent {
|
|
|
|
@ViewChild('download_not_possible') download_not_possible: ElementRef<HTMLDialogElement> | undefined;
|
|
@ViewChild('file_not_found_modal') file_not_found_modal: ElementRef<HTMLDialogElement> | undefined;
|
|
|
|
inputFileId: string = "";
|
|
fileId: string = "";
|
|
filePassword: string = "";
|
|
fileName: string = "";
|
|
downloadInfo: DownloadInfo | null = null;
|
|
|
|
fileDownloadStarted: boolean = false;
|
|
fileDownloadFinished: boolean = false;
|
|
waitingForPassword: boolean = false;
|
|
downloadProgress: number = 0;
|
|
targetUploadProgress: number = 0;
|
|
downloadDuration: string = "";
|
|
passwordWrong: boolean = false;
|
|
|
|
funfact: string = "";
|
|
|
|
|
|
constructor(private developmentStore: DevelopmentStore, private activatedRoute: ActivatedRoute) {
|
|
this.funfact = funfacts[Math.floor(Math.random() * funfacts.length)];
|
|
|
|
this.activatedRoute.queryParams.subscribe(params => {
|
|
const fileId = params['fileId'];
|
|
const password = params['password'];
|
|
if(password) {
|
|
this.filePassword = password;
|
|
}
|
|
if(fileId) {
|
|
this.inputFileId = fileId;
|
|
this.requestDownload();
|
|
}
|
|
});
|
|
|
|
this.speedTest();
|
|
}
|
|
|
|
requestDownload() {
|
|
|
|
if(this.waitingForPassword) {
|
|
console.log("Requesting download with password");
|
|
this.downloadFile();
|
|
return;
|
|
}
|
|
|
|
console.log(this.inputFileId);
|
|
this.fileId = this.inputFileId; // TODO: Implement link extraction logic
|
|
|
|
this.getDownloadInfo();
|
|
}
|
|
|
|
processDownloadInfo() {
|
|
if(!this.downloadInfo?.passwordProtected && this.downloadInfo?.downloadable) {
|
|
console.log("Proceeding with download");
|
|
this.downloadFile();
|
|
return;
|
|
}
|
|
else if(!this.downloadInfo?.downloadable) {
|
|
this.download_not_possible?.nativeElement.showModal();
|
|
return;
|
|
}
|
|
else if(this.downloadInfo?.passwordProtected) {
|
|
if(this.filePassword) {
|
|
console.log("Requesting download with password");
|
|
this.downloadFile();
|
|
return;
|
|
}
|
|
this.waitingForPassword = true;
|
|
console.log("Password protected");
|
|
}
|
|
}
|
|
|
|
private speedTest() {
|
|
const start = new Date().getTime(); // Start timer
|
|
|
|
axios({
|
|
method: 'get',
|
|
url: this.developmentStore.getBaseUrl() + 'api/v1/speed-test',
|
|
responseType: 'arraybuffer',
|
|
})
|
|
.then(response => {
|
|
const end = new Date().getTime(); // End timer
|
|
const duration = (end - start) / 1000; // Convert ms to seconds
|
|
const bitsLoaded = response.data.byteLength * 8;
|
|
const speedBps = bitsLoaded / duration;
|
|
const speedKbps = speedBps / 1024;
|
|
const speedMbps = speedKbps / 1024;
|
|
console.log(`Download speed: ${speedMbps.toFixed(2)} Mbps`);
|
|
})
|
|
.catch(error => {
|
|
console.error('Error during download test:', error);
|
|
});
|
|
}
|
|
|
|
private getDownloadInfo() {
|
|
axios({
|
|
method: 'get',
|
|
url: this.developmentStore.getBaseUrl() + 'api/v1/download-info?fileId=' + this.fileId,
|
|
responseType: 'json',
|
|
})
|
|
.then(response => {
|
|
this.downloadInfo = response.data;
|
|
console.log(response.data);
|
|
this.processDownloadInfo();
|
|
})
|
|
.catch(error => {
|
|
this.file_not_found_modal?.nativeElement.showModal();
|
|
console.error('Error during download info request:', error);
|
|
});
|
|
}
|
|
|
|
private downloadFile() {
|
|
const startTime = new Date().getTime();
|
|
this.fileDownloadStarted = true;
|
|
axios({
|
|
method: 'get',
|
|
url: this.developmentStore.getBaseUrl() + 'api/v1/download?fileId=' + this.fileId + '&password=' + this.filePassword,
|
|
responseType: 'arraybuffer',
|
|
onDownloadProgress: (progressEvent) => {
|
|
const endTime = new Date().getTime();
|
|
const duration = (endTime - startTime) / 1000;
|
|
this.downloadDuration = duration.toFixed(0);
|
|
// Calculate the percentage of download completed
|
|
if(progressEvent.total) {
|
|
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
|
|
this.targetUploadProgress = percentCompleted;
|
|
this.smoothProgressUpdate();
|
|
}
|
|
}
|
|
})
|
|
.then(response => {
|
|
const endTime = new Date().getTime();
|
|
const duration = (endTime - startTime) / 1000;
|
|
this.downloadDuration = duration.toFixed(2);
|
|
this.fileDownloadFinished = true;
|
|
|
|
const contentDisposition = response.headers['content-disposition'];
|
|
let filename = "default_filename"; // Default filename in case parsing fails
|
|
|
|
if (contentDisposition) {
|
|
const filenameRegex = /filename="?([^"]+)"?/;
|
|
const matches = contentDisposition.match(filenameRegex);
|
|
if (matches && matches[1]) {
|
|
filename = matches[1];
|
|
}
|
|
}
|
|
this.fileName = filename;
|
|
|
|
const blob = new Blob([response.data], {type: 'application/octet-stream'});
|
|
const url = window.URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.style.display = 'none';
|
|
a.href = url;
|
|
a.download = filename; // You can specify a filename here
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
|
|
// Clean up by revoking the Blob URL and removing the temporary anchor
|
|
window.URL.revokeObjectURL(url);
|
|
document.body.removeChild(a);
|
|
})
|
|
.catch(error => {
|
|
this.fileDownloadStarted = false;
|
|
this.wrongPassword();
|
|
console.error('Error during download request:', error);
|
|
});
|
|
}
|
|
|
|
private wrongPassword() {
|
|
this.passwordWrong = true;
|
|
}
|
|
|
|
smoothProgressUpdate() {
|
|
if (this.downloadProgress < this.targetUploadProgress) {
|
|
this.downloadProgress += 0.01 * (this.targetUploadProgress - this.downloadProgress);
|
|
requestAnimationFrame(this.smoothProgressUpdate.bind(this));
|
|
} else if (this.downloadProgress > this.targetUploadProgress) {
|
|
// Handle overshoot
|
|
this.downloadProgress = this.targetUploadProgress;
|
|
}
|
|
}
|
|
}
|
|
interface DownloadInfo {
|
|
downloadable: boolean;
|
|
passwordProtected: boolean;
|
|
singleDownload: boolean;
|
|
fileId: string;
|
|
}
|