Added support for modifying downloaded files

This commit is contained in:
Isaac Grynsztein
2018-01-22 03:43:47 -05:00
parent e4e1e67855
commit 1cdd4d0e15
9 changed files with 501 additions and 95 deletions

View File

@@ -48,6 +48,125 @@ app.get('/using-encryption', function(req, res) {
res.end("yes");
});
// objects
function File(id, title, thumbnailURL, isAudio, duration) {
this.id = id;
this.title = title;
this.thumbnailURL = thumbnailURL;
this.isAudio = isAudio;
this.duration = duration;
}
// actual functions
function getThumbnailMp3(name)
{
var obj = getJSONMp3(name);
var thumbnailLink = obj.thumbnail;
return thumbnailLink;
}
function getThumbnailMp4(name)
{
var obj = getJSONMp4(name);
var thumbnailLink = obj.thumbnail;
return thumbnailLink;
}
function getFileSizeMp3(name)
{
var jsonPath = audioPath+name+".mp3.info.json";
if (fs.existsSync(jsonPath))
var obj = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
else
var obj = 0;
return obj.filesize;
}
function getFileSizeMp4(name)
{
var jsonPath = videoPath+name+".info.json";
var filesize = 0;
if (fs.existsSync(jsonPath))
{
var obj = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
var format = obj.format.substring(0,3);
for (i = 0; i < obj.formats.length; i++)
{
if (obj.formats[i].format_id == format)
{
filesize = obj.formats[i].filesize;
}
}
}
return filesize;
}
function getJSONMp3(name)
{
var jsonPath = audioPath+name+".mp3.info.json";
if (fs.existsSync(jsonPath))
var obj = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
else
var obj = 0;
return obj;
}
function getJSONMp4(name)
{
var jsonPath = videoPath+name+".info.json";
if (fs.existsSync(jsonPath))
{
var obj = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
return obj;
}
else return 0;
}
function getAmountDownloadedMp3(name)
{
var partPath = audioPath+name+".mp3.part";
if (fs.existsSync(partPath))
{
const stats = fs.statSync(partPath);
const fileSizeInBytes = stats.size;
return fileSizeInBytes;
}
else
return 0;
}
function getAmountDownloadedMp4(name)
{
var format = getVideoFormatID(name);
var partPath = videoPath+name+".f"+format+".mp4.part";
if (fs.existsSync(partPath))
{
const stats = fs.statSync(partPath);
const fileSizeInBytes = stats.size;
return fileSizeInBytes;
}
else
return 0;
}
function getVideoFormatID(name)
{
var jsonPath = videoPath+name+".info.json";
if (fs.existsSync(jsonPath))
{
var obj = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
var format = obj.format.substring(0,3);
return format;
}
}
app.post('/tomp3', function(req, res) {
var url = req.body.url;
@@ -81,76 +200,6 @@ app.post('/tomp3', function(req, res) {
res.end("yes");
});
function getFileSizeMp3(name)
{
var jsonPath = audioPath+name+".mp3.info.json";
if (fs.existsSync(jsonPath))
var obj = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
else
var obj = 0;
return obj.filesize;
}
function getAmountDownloadedMp3(name)
{
var partPath = audioPath+name+".mp3.part";
if (fs.existsSync(partPath))
{
const stats = fs.statSync(partPath);
const fileSizeInBytes = stats.size;
return fileSizeInBytes;
}
else
return 0;
}
function getFileSizeMp4(name)
{
var jsonPath = videoPath+name+".info.json";
var filesize = 0;
if (fs.existsSync(jsonPath))
{
var obj = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
var format = obj.format.substring(0,3);
for (i = 0; i < obj.formats.length; i++)
{
if (obj.formats[i].format_id == format)
{
filesize = obj.formats[i].filesize;
}
}
}
return filesize;
}
function getAmountDownloadedMp4(name)
{
var format = getVideoFormatID(name);
var partPath = videoPath+name+".f"+format+".mp4.part";
if (fs.existsSync(partPath))
{
const stats = fs.statSync(partPath);
const fileSizeInBytes = stats.size;
return fileSizeInBytes;
}
else
return 0;
}
function getVideoFormatID(name)
{
var jsonPath = videoPath+name+".info.json";
if (fs.existsSync(jsonPath))
{
var obj = JSON.parse(fs.readFileSync(jsonPath, 'utf8'));
var format = obj.format.substring(0,3);
return format;
}
}
app.post('/tomp4', function(req, res) {
var url = req.body.url;
var date = Date.now();
@@ -168,7 +217,8 @@ app.post('/tomp4', function(req, res) {
res.end("yes");
});
app.post('/mp3fileexists', function(req, res) {
// gets the status of the mp3 file that's being downloaded
app.post('/fileStatusMp3', function(req, res) {
var name = req.body.name + "";
var exists = "";
var fullpath = audioPath + name + ".mp3";
@@ -189,7 +239,8 @@ app.post('/mp3fileexists', function(req, res) {
res.end("yes");
});
app.post('/mp4fileexists', function(req, res) {
// gets the status of the mp4 file that's being downloaded
app.post('/fileStatusMp4', function(req, res) {
var name = req.body.name;
var exists = "";
var fullpath = videoPath + name + ".mp4";
@@ -210,6 +261,113 @@ app.post('/mp4fileexists', function(req, res) {
res.end("yes");
});
// gets all download mp3s
app.post('/getMp3s', function(req, res) {
var mp3s = [];
var fullpath = audioPath;
var files = fs.readdirSync(audioPath);
for (var i in files)
{
var nameLength = path.basename(files[i]).length;
var ext = path.basename(files[i]).substring(nameLength-4, nameLength);
if (ext == ".mp3")
{
var jsonobj = getJSONMp3(path.basename(files[i]).substring(0, path.basename(files[i]).length-4));
var id = path.basename(files[i]).substring(0, path.basename(files[i]).length-4);
var title = jsonobj.title;
if (title.length > 14) // edits title if it's too long
{
title = title.substring(0,12) + "...";
}
var thumbnail = jsonobj.thumbnail;
var duration = jsonobj.duration;
var isaudio = true;
var file = new File(id, title, thumbnail, isaudio, duration);
mp3s.push(file);
}
}
res.send(mp3s);
res.end("yes");
});
// gets all download mp4s
app.post('/getMp4s', function(req, res) {
var mp4s = [];
var fullpath = videoPath;
var files = fs.readdirSync(videoPath);
for (var i in files)
{
var nameLength = path.basename(files[i]).length;
var ext = path.basename(files[i]).substring(nameLength-4, nameLength);
if (ext == ".mp4")
{
var jsonobj = getJSONMp4(path.basename(files[i]).substring(0, path.basename(files[i]).length-4));
var id = path.basename(files[i]).substring(0, path.basename(files[i]).length-4);
var title = jsonobj.title;
if (title.length > 14) // edits title if it's too long
{
title = title.substring(0,12) + "...";
}
var thumbnail = jsonobj.thumbnail;
var duration = jsonobj.duration;
var isaudio = false;
var file = new File(id, title, thumbnail, isaudio, duration);
mp4s.push(file);
}
}
res.send(mp4s);
res.end("yes");
});
// deletes mp3 file
app.post('/deleteMp3', function(req, res) {
var name = req.body.name;
var fullpath = audioPath + name + ".mp3";
var wasDeleted = false;
if (fs.existsSync(fullpath))
{
fs.unlink(fullpath);
wasDeleted = true;
res.send(wasDeleted);
res.end("yes");
}
else
{
wasDeleted = false;
res.send(wasDeleted);
res.end("yes");
}
});
// deletes mp4 file
app.post('/deleteMp4', function(req, res) {
var name = req.body.name;
var fullpath = videoPath + name + ".mp4";
var wasDeleted = false;
if (fs.existsSync(fullpath))
{
fs.unlink(fullpath);
wasDeleted = true;
res.send(wasDeleted);
res.end("yes");
}
else
{
wasDeleted = false;
res.send(wasDeleted);
res.end("yes");
}
});
app.get('/video/:id', function(req , res){
var head;
const path = "video/" + req.params.id + ".mp4";

View File

@@ -1,14 +1,14 @@
<mat-toolbar color="primary" class="top">
<table width="100%" height="100%">
<td class="topbar" style="text-align: left; left:0px; font-size: 15px">
</td>
<td class="topbar" style="text-align: center">
<div style="margin-top: 14px">{{topBarTitle}}</div>
</td>
<td class="topbar" style="text-align: right">
</td>
</table>
<table width="100%" height="100%">
<td class="topbar" style="text-align: left; left:0px; font-size: 15px">
</td>
<td class="topbar" style="text-align: center">
<div style="margin-top: 14px">{{topBarTitle}}</div>
</td>
<td class="topbar" style="text-align: right">
</td>
</table>
</mat-toolbar>
<br/>
@@ -27,19 +27,66 @@
</form>
<br/>
<mat-checkbox [(ngModel)]="audioOnly" style="float: left; margin-top: -12px">Only Audio</mat-checkbox>
<button style="float: right; margin-top: -16px" (click)="downloadClicked()" [disabled]="downloadingfile" type="submit" mat-raised-button color="primary">Download</button>
<button style="float: right; margin-top: -16px" (click)="downloadClicked()" [disabled]="downloadingfile" type="submit" mat-raised-button
color="primary">Download</button>
</mat-card-content>
</div>
</mat-card>
<br/>
<div class="centered big" id="bar_div" *ngIf="downloadingfile;else nofile">
<div *ngIf="determinateProgress;else indeterminateprogress">
<mat-progress-bar mode="determinate" value="{{percentDownloaded}}"></mat-progress-bar>
</div>
<ng-template #indeterminateprogress>
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
</ng-template>
<div *ngIf="determinateProgress;else indeterminateprogress">
<mat-progress-bar mode="determinate" value="{{percentDownloaded}}"></mat-progress-bar>
</div>
<ng-template #indeterminateprogress>
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
</ng-template>
<br/>
</div>
<ng-template #nofile>
</ng-template>
<mat-accordion>
<mat-expansion-panel class="big">
<mat-expansion-panel-header>
<mat-panel-title>
Audio
</mat-panel-title>
<mat-panel-description>
Your audio files are here
</mat-panel-description>
</mat-expansion-panel-header>
<div *ngIf="mp3s.length > 0;else nomp3s">
<mat-grid-list cols="4" rowHeight="150px">
<mat-grid-tile *ngFor="let file of mp3s; index as i;">
<app-file-card [title]="file.title" [name]="file.id" [thumbnailURL]="file.thumbnailURL" [length]="file.duration" [isAudio]="true"></app-file-card>
</mat-grid-tile>
</mat-grid-list>
</div>
</mat-expansion-panel>
<mat-expansion-panel class="big">
<mat-expansion-panel-header>
<mat-panel-title>
Video
</mat-panel-title>
<mat-panel-description>
Your video files are here
</mat-panel-description>
</mat-expansion-panel-header>
<div *ngIf="mp4s.length > 0;else nomp4s">
<mat-grid-list cols="4" rowHeight="150px">
<mat-grid-tile *ngFor="let file of mp4s; index as i;">
<app-file-card [title]="file.title" [name]="file.id" [thumbnailURL]="file.thumbnailURL" [length]="file.duration" [isAudio]="false"></app-file-card>
</mat-grid-tile>
</mat-grid-list>
</div>
</mat-expansion-panel>
</mat-accordion>
<ng-template #nomp3s>
</ng-template>
<ng-template #nomp4s>
</ng-template>

View File

@@ -1,5 +1,6 @@
import { Component, OnInit } from '@angular/core';
import {PostsService} from './posts.services';
import {FileCardComponent} from './file-card/file-card.component';
import { Observable } from 'rxjs/Observable';
import {FormControl, Validators} from '@angular/forms';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
@@ -23,6 +24,10 @@ export class AppComponent {
exists: string = "";
topBarTitle: string = "Youtube Downloader";
percentDownloaded: number;
mp3s: any[] = [];
mp4s: any[] = [];
constructor(private postsService: PostsService, public snackBar: MatSnackBar) {
this.audioOnly = true;
@@ -35,10 +40,14 @@ export class AppComponent {
this.postsService.path = backendUrl;
this.postsService.startPath = backendUrl;
this.postsService.startPathSSL = backendUrl;
this.getMp3s();
this.getMp4s();
},
error => {
console.log(error);
});
}
urlForm = new FormControl('', [Validators.required]);
@@ -67,6 +76,48 @@ export class AppComponent {
});
}
getMp3s() {
this.postsService.getMp3s().subscribe(result => {
var mp3s = result;
this.mp3s = mp3s;
},
error => {
console.log(error);
});
}
getMp4s() {
this.postsService.getMp4s().subscribe(result => {
var mp4s = result;
this.mp4s = mp4s;
},
error => {
console.log(error);
});
}
public removeFromMp3(name: string)
{
for (var i = 0; i < this.mp3s.length; i++)
{
if (this.mp3s[i].id == name)
{
this.mp3s.splice(i,1);
}
}
}
public removeFromMp4(name: string)
{
for (var i = 0; i < this.mp4s.length; i++)
{
if (this.mp4s[i].id == name)
{
this.mp4s.splice(i,1);
}
}
}
ngOnInit() {
}
@@ -167,7 +218,7 @@ export class AppComponent {
return re.test(str);
}
openSnackBar(message: string, action: string) {
public openSnackBar(message: string, action: string) {
this.snackBar.open(message, action, {
duration: 2000,
});

View File

@@ -1,8 +1,9 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import {MatNativeDateModule, MatRadioModule, MatInputModule, MatButtonModule, MatSidenavModule, MatIconModule, MatListModule,
MatSnackBarModule, MatCardModule, MatSelectModule, MatToolbarModule, MatCheckboxModule,
MatProgressBarModule } from '@angular/material';
MatSnackBarModule, MatCardModule, MatSelectModule, MatToolbarModule, MatCheckboxModule, MatGridListModule,
MatProgressBarModule, MatExpansionModule,
MatGridList} from '@angular/material';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import { AppComponent } from './app.component';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
@@ -10,10 +11,12 @@ import { HttpModule } from '@angular/http';
import { HttpClientModule } from '@angular/common/http';
import { PostsService } from 'app/posts.services';
import {APP_BASE_HREF} from '@angular/common';
import { FileCardComponent } from './file-card/file-card.component';
@NgModule({
declarations: [
AppComponent
AppComponent,
FileCardComponent
],
imports: [
BrowserModule,
@@ -34,6 +37,8 @@ import {APP_BASE_HREF} from '@angular/common';
MatSidenavModule,
MatIconModule,
MatListModule,
MatGridListModule,
MatExpansionModule,
MatProgressBarModule
],
providers: [PostsService],

View File

@@ -0,0 +1,33 @@
.example-card {
width: 150px;
height: 125px;
padding: 0px;
}
.deleteButton {
top:-5px;
right:-5px;
position:absolute;
}
/* Coerce the <span> icon container away from display:inline */
.mat-icon-button .mat-button-wrapper {
display: flex;
justify-content: center;
}
.image {
max-width:100%;
max-height:100%;
}
.example-full-width-height {
width: 100%;
height: 100%
}
.centered {
margin: 0 auto;
top: 50%;
left: 50%;
}

View File

@@ -0,0 +1,13 @@
<mat-card class="example-card">
<button (click)="deleteFile()" class="deleteButton" mat-icon-button><mat-icon>delete_forever</mat-icon></button>
<div style="padding:5px">
<b>{{title}}</b>
<br/>
ID: {{name}}
</div>
<div class="centered example-full-width-height"><img class="image" src="{{thumbnailURL}}" alt="Thumbnail"></div>
</mat-card>

View File

@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { FileCardComponent } from './file-card.component';
describe('FileCardComponent', () => {
let component: FileCardComponent;
let fixture: ComponentFixture<FileCardComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ FileCardComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(FileCardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,48 @@
import { Component, OnInit, Input } from '@angular/core';
import {PostsService} from '../posts.services';
import {MatSnackBar} from '@angular/material';
import {AppComponent} from '../app.component';
@Component({
selector: 'app-file-card',
templateUrl: './file-card.component.html',
styleUrls: ['./file-card.component.css']
})
export class FileCardComponent implements OnInit {
@Input() title:string;
@Input() length:string;
@Input() name:string;
@Input() thumbnailURL: string;
@Input() isAudio: boolean = true;
constructor(private postsService: PostsService, public snackBar: MatSnackBar, private appComponent: AppComponent) { }
ngOnInit() {
}
deleteFile()
{
this.postsService.deleteFile(this.name, this.isAudio).subscribe(result => {
if (result == true)
{
this.openSnackBar("Delete success!", "OK.");
if (this.isAudio)
this.appComponent.removeFromMp3(name);
else
this.appComponent.removeFromMp4(name);
}
else
{
this.openSnackBar("Delete failed!", "OK.");
}
});
}
public openSnackBar(message: string, action: string) {
this.snackBar.open(message, action, {
duration: 2000,
});
}
}

View File

@@ -56,12 +56,12 @@ export class PostsService {
}
getFileStatusMp3(name: string): Observable<any> {
return this.http.post(this.path + "mp3fileexists",{name: name})
return this.http.post(this.path + "fileStatusMp3",{name: name})
.map(res => res.json());
}
getFileStatusMp4(name: string): Observable<any> {
return this.http.post(this.path + "mp4fileexists",{name: name})
return this.http.post(this.path + "fileStatusMp4",{name: name})
.map(res => res.json());
}
@@ -70,6 +70,32 @@ export class PostsService {
return this.http.get(window.location.href + "backend/config/default.json")
.map(res => res.json());
}
deleteFile(name: string, isAudio: boolean)
{
if (isAudio)
{
return this.http.post(this.path + "deleteMp3",{name: name})
.map(res => res.json());
}
else
{
return this.http.post(this.path + "deleteMp4",{name: name})
.map(res => res.json());
}
}
getMp3s()
{
return this.http.post(this.path + "getMp3s", {})
.map(res => res.json());
}
getMp4s()
{
return this.http.post(this.path + "getMp4s", {})
.map(res => res.json());
}
}