Compare commits

..

3 Commits
v2.0 ... v2.1

Author SHA1 Message Date
Isaac Grynsztein
505b145bb3 commented out debug console messages 2020-02-11 16:28:14 -05:00
Isaac Grynsztein
ba5592015d added download only mode that simply downloads files to the client when the server finishes the download
added dependency on savefile library for download-only mode
2020-02-11 13:10:02 -05:00
Isaac Grynsztein
10c90a01f2 linted files 2020-02-09 23:35:01 -05:00
6 changed files with 81 additions and 53 deletions

View File

@@ -255,9 +255,7 @@ app.post('/fileStatusMp4', function(req, res) {
var fullpath = videoPath + name + ".mp4"; var fullpath = videoPath + name + ".mp4";
if (fs.existsSync(fullpath)) { if (fs.existsSync(fullpath)) {
exists = [basePath + videoPath + name, getFileSizeMp4(name)]; exists = [basePath + videoPath + name, getFileSizeMp4(name)];
} } else {
else
{
var percent = 0; var percent = 0;
var size = getFileSizeMp4(name); var size = getFileSizeMp4(name);
var downloaded = getAmountDownloadedMp4(name); var downloaded = getAmountDownloadedMp4(name);
@@ -386,6 +384,19 @@ app.post('/deleteMp4', function(req, res) {
} }
}); });
app.post('/downloadFile', function(req, res) {
let fileName = req.body.fileName;
let type = req.body.type;
let file = null;
if (type === 'audio') {
file = __dirname + '/' + 'audio/' + fileName + '.mp3';
} else if (type === 'video') {
file = __dirname + '/' + 'video/' + fileName + '.mp4';
}
res.sendFile(file);
});
app.get('/video/:id', function(req , res){ app.get('/video/:id', function(req , res){
var head; var head;

View File

@@ -16,7 +16,8 @@
}, },
"Extra": { "Extra": {
"title_top": "Youtube Downloader", "title_top": "Youtube Downloader",
"file_manager_enabled": true "download_only_mode": false,
"file_manager_enabled": true
} }
} }
} }

View File

@@ -25,6 +25,7 @@
"@angular/platform-browser-dynamic": "^8.2.11", "@angular/platform-browser-dynamic": "^8.2.11",
"@angular/router": "^8.2.11", "@angular/router": "^8.2.11",
"core-js": "^2.4.1", "core-js": "^2.4.1",
"file-saver": "^2.0.2",
"ng4-configure": "^0.1.7", "ng4-configure": "^0.1.7",
"rxjs": "^6.5.3", "rxjs": "^6.5.3",
"rxjs-compat": "^6.0.0-rc.0", "rxjs-compat": "^6.0.0-rc.0",
@@ -32,10 +33,11 @@
"zone.js": "~0.9.1" "zone.js": "~0.9.1"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "~0.803.12", "@angular-devkit/build-angular": "^0.803.24",
"@angular/cli": "^8.3.12", "@angular/cli": "^8.3.12",
"@angular/compiler-cli": "^8.2.11", "@angular/compiler-cli": "^8.2.11",
"@angular/language-service": "^8.2.11", "@angular/language-service": "^8.2.11",
"@types/file-saver": "^2.0.1",
"@types/jasmine": "2.5.45", "@types/jasmine": "2.5.45",
"@types/node": "~6.0.60", "@types/node": "~6.0.60",
"codelyzer": "^5.0.1", "codelyzer": "^5.0.1",

View File

@@ -5,6 +5,7 @@ import { Observable } from 'rxjs/Observable';
import {FormControl, Validators} from '@angular/forms'; import {FormControl, Validators} from '@angular/forms';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {MatSnackBar} from '@angular/material'; import {MatSnackBar} from '@angular/material';
import { saveAs } from 'file-saver';
import 'rxjs/add/observable/of'; import 'rxjs/add/observable/of';
import 'rxjs/add/operator/mapTo'; import 'rxjs/add/operator/mapTo';
import 'rxjs/add/operator/toPromise'; import 'rxjs/add/operator/toPromise';
@@ -14,7 +15,9 @@ import 'rxjs/add/operator/toPromise';
templateUrl: './app.component.html', templateUrl: './app.component.html',
styleUrls: ['./app.component.css'] styleUrls: ['./app.component.css']
}) })
export class AppComponent { export class AppComponent implements OnInit {
iOS = false;
determinateProgress = false; determinateProgress = false;
downloadingfile = false; downloadingfile = false;
audioOnly: boolean; audioOnly: boolean;
@@ -25,6 +28,7 @@ export class AppComponent {
topBarTitle = 'Youtube Downloader'; topBarTitle = 'Youtube Downloader';
percentDownloaded: number; percentDownloaded: number;
fileManagerEnabled = false; fileManagerEnabled = false;
downloadOnlyMode = false;
mp3s: any[] = []; mp3s: any[] = [];
mp4s: any[] = []; mp4s: any[] = [];
@@ -35,11 +39,12 @@ export class AppComponent {
this.audioOnly = false; this.audioOnly = false;
// loading config
this.postsService.loadNavItems().subscribe(result => { // loads settings this.postsService.loadNavItems().subscribe(result => { // loads settings
const backendUrl = result['YoutubeDLMaterial']['Host']['backendurl']; const backendUrl = result['YoutubeDLMaterial']['Host']['backendurl'];
this.topBarTitle = result['YoutubeDLMaterial']['Extra']['title_top']; this.topBarTitle = result['YoutubeDLMaterial']['Extra']['title_top'];
this.fileManagerEnabled = result['YoutubeDLMaterial']['Extra']['file_manager_enabled']; this.fileManagerEnabled = result['YoutubeDLMaterial']['Extra']['file_manager_enabled'];
this.downloadOnlyMode = result['YoutubeDLMaterial']['Extra']['download_only_mode'];
this.postsService.path = backendUrl; this.postsService.path = backendUrl;
this.postsService.startPath = backendUrl; this.postsService.startPath = backendUrl;
@@ -54,30 +59,8 @@ export class AppComponent {
}); });
} }
/*
doHandshake(url: string) { // file manager stuff
this.postsService.startHandshake(url).subscribe(theurl => {
this.postsService.path = theurl;
this.postsService.handShakeComplete = true;
console.log('Handshake complete!');
}, error => {
console.log('Initial handshake failed on http.');
this.doHandshakeSSL(url);
});
}
doHandshakeSSL(url: string) {
this.postsService.startHandshakeSSL(url).subscribe(theurl => {
this.postsService.path = theurl;
this.postsService.handShakeComplete = true;
console.log('Handshake complete!');
},
error => {
console.log('Initial handshake failed on https too! Make sure port 17442 is open.');
this.postsService.handShakeComplete = false;
});
}*/
getMp3s() { getMp3s() {
this.postsService.getMp3s().subscribe(result => { this.postsService.getMp3s().subscribe(result => {
@@ -100,9 +83,9 @@ export class AppComponent {
public goToFile(name, isAudio) { public goToFile(name, isAudio) {
if (isAudio) { if (isAudio) {
this.downloadHelperMp3(name); this.downloadHelperMp3(name, true);
} else { } else {
this.downloadHelperMp4(name); this.downloadHelperMp4(name, true);
} }
} }
@@ -115,8 +98,8 @@ export class AppComponent {
} }
public removeFromMp4(name: string) { public removeFromMp4(name: string) {
console.log(name); // console.log(name);
console.log(this.mp4s); // console.log(this.mp4s);
for (let i = 0; i < this.mp4s.length; i++) { for (let i = 0; i < this.mp4s.length; i++) {
if (this.mp4s[i].id === name) { if (this.mp4s[i].id === name) {
this.mp4s.splice(i, 1); this.mp4s.splice(i, 1);
@@ -124,29 +107,45 @@ export class AppComponent {
} }
} }
// app initialization.
ngOnInit() { ngOnInit() {
this.iOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window['MSStream'];
} }
downloadHelperMp3(name: string) { // download helpers
downloadHelperMp3(name: string, forceView = false) {
this.postsService.getFileStatusMp3(name).subscribe(fileExists => { this.postsService.getFileStatusMp3(name).subscribe(fileExists => {
const exists = fileExists; const exists = fileExists;
this.exists = exists[0]; this.exists = exists[0];
if (exists[0] === 'failed') { if (exists[0] === 'failed') {
const percent = exists[2]; const percent = exists[2];
console.log(percent); // console.log(percent);
if (percent > 0.30) { if (percent > 0.30) {
this.determinateProgress = true; this.determinateProgress = true;
this.percentDownloaded = percent * 100; this.percentDownloaded = percent * 100;
} }
setTimeout(() => this.downloadHelperMp3(name), 500); setTimeout(() => this.downloadHelperMp3(name), 500);
} else { } else {
window.location.href = this.exists; // if download only mode, just download the file. no redirect
if (forceView === false && this.downloadOnlyMode && !this.iOS) {
this.postsService.downloadFileFromServer(name, 'audio').subscribe(res => {
const blob: Blob = res;
saveAs(blob, name + '.mp3');
this.downloadingfile = false;
});
} else {
window.location.href = this.exists;
}
// reloads mp3s
this.getMp3s();
} }
}); });
} }
downloadHelperMp4(name: string) { downloadHelperMp4(name: string, forceView = false) {
this.postsService.getFileStatusMp4(name).subscribe(fileExists => { this.postsService.getFileStatusMp4(name).subscribe(fileExists => {
const exists = fileExists; const exists = fileExists;
this.exists = exists[0]; this.exists = exists[0];
@@ -158,12 +157,25 @@ export class AppComponent {
} }
setTimeout(() => this.downloadHelperMp4(name), 500); setTimeout(() => this.downloadHelperMp4(name), 500);
} else { } else {
window.location.href = this.exists; // if download only mode, just download the file. no redirect
if (forceView === false && this.downloadOnlyMode) {
this.postsService.downloadFileFromServer(name, 'video').subscribe(res => {
const blob: Blob = res;
saveAs(blob, name + '.mp4');
this.downloadingfile = false;
});
} else {
window.location.href = this.exists;
}
// reloads mp4s
this.getMp4s();
} }
}); });
} }
// download click handler
downloadClicked() { downloadClicked() {
if (this.ValidURL(this.url)) { if (this.ValidURL(this.url)) {
this.urlError = false; this.urlError = false;
@@ -197,6 +209,7 @@ export class AppComponent {
} }
} }
// checks if url is a valid URL
ValidURL(str) { ValidURL(str) {
// tslint:disable-next-line: max-line-length // tslint:disable-next-line: max-line-length
const strRegex = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/; const strRegex = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/;
@@ -204,6 +217,7 @@ export class AppComponent {
return re.test(str); return re.test(str);
} }
// snackbar helper
public openSnackBar(message: string, action: string) { public openSnackBar(message: string, action: string) {
this.snackBar.open(message, action, { this.snackBar.open(message, action, {
duration: 2000, duration: 2000,

View File

@@ -11,11 +11,11 @@ import {EventEmitter} from '@angular/core';
}) })
export class FileCardComponent implements OnInit { export class FileCardComponent implements OnInit {
@Input() title:string; @Input() title: string;
@Input() length:string; @Input() length: string;
@Input() name:string; @Input() name: string;
@Input() thumbnailURL: string; @Input() thumbnailURL: string;
@Input() isAudio: boolean = true; @Input() isAudio = true;
@Output() removeFile: EventEmitter<string> = new EventEmitter<string>(); @Output() removeFile: EventEmitter<string> = new EventEmitter<string>();
constructor(private postsService: PostsService, public snackBar: MatSnackBar, public appComponent: AppComponent) { } constructor(private postsService: PostsService, public snackBar: MatSnackBar, public appComponent: AppComponent) { }
@@ -23,17 +23,13 @@ export class FileCardComponent implements OnInit {
ngOnInit() { ngOnInit() {
} }
deleteFile() deleteFile() {
{
this.postsService.deleteFile(this.name, this.isAudio).subscribe(result => { this.postsService.deleteFile(this.name, this.isAudio).subscribe(result => {
if (result == true) if (result === true) {
{ this.openSnackBar('Delete success!', 'OK.');
this.openSnackBar("Delete success!", "OK.");
this.removeFile.emit(this.name); this.removeFile.emit(this.name);
} } else {
else this.openSnackBar('Delete failed!', 'OK.');
{
this.openSnackBar("Delete failed!", "OK.");
} }
}); });
} }

View File

@@ -1,5 +1,5 @@
import {Injectable, isDevMode} from '@angular/core'; import {Injectable, isDevMode} from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient, HttpHeaders, HttpRequest, HttpResponseBase } from '@angular/common/http';
import config from '../assets/default.json'; import config from '../assets/default.json';
import 'rxjs/add/operator/map'; import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
@@ -75,6 +75,10 @@ export class PostsService {
getMp4s() { getMp4s() {
return this.http.post(this.path + 'getMp4s', {}); return this.http.post(this.path + 'getMp4s', {});
} }
downloadFileFromServer(fileName, type) {
return this.http.post(this.path + 'downloadFile', {fileName: fileName, type: type}, {responseType: 'blob'});
}
} }