Merge pull request #32 from Tzahi12345/subscriptions-v2

Subscriptions v2
pull/33/head
Tzahi12345 5 years ago committed by GitHub
commit c4fe1a2fb0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -84,12 +84,17 @@ app.use(bodyParser.json());
// objects
function File(id, title, thumbnailURL, isAudio, duration) {
function File(id, title, thumbnailURL, isAudio, duration, url, uploader, size, path, upload_date) {
this.id = id;
this.title = title;
this.thumbnailURL = thumbnailURL;
this.isAudio = isAudio;
this.duration = duration;
this.url = url;
this.uploader = uploader;
this.size = size;
this.path = path;
this.upload_date = upload_date;
}
// actual functions
@ -353,10 +358,16 @@ function getVideoFormatID(name)
}
}
async function createPlaylistZipFile(fileNames, type, outputName) {
async function createPlaylistZipFile(fileNames, type, outputName, fullPathProvided = null) {
return new Promise(async resolve => {
let zipFolderPath = path.join(__dirname, (type === 'audio') ? audioFolderPath : videoFolderPath);
// let name = fileNames[0].split(' ')[0] + fileNames[1].split(' ')[0];
let zipFolderPath = null;
if (!fullPathProvided) {
zipFolderPath = path.join(__dirname, (type === 'audio') ? audioFolderPath : videoFolderPath);
} else {
zipFolderPath = path.join(__dirname, config_api.getConfigItem('ytdl_subscriptions_base_path'));
}
let ext = (type === 'audio') ? '.mp3' : '.mp4';
let output = fs.createWriteStream(path.join(zipFolderPath, outputName + '.zip'));
@ -376,7 +387,8 @@ async function createPlaylistZipFile(fileNames, type, outputName) {
for (let i = 0; i < fileNames.length; i++) {
let fileName = fileNames[i];
archive.file(zipFolderPath + fileName + ext, {name: fileName + ext})
let file_path = !fullPathProvided ? zipFolderPath + fileName + ext : fileName;
archive.file(file_path, {name: fileName + ext})
}
await archive.finalize();
@ -951,20 +963,24 @@ app.post('/api/getMp3s', function(req, res) {
for (let i = 0; i < files.length; i++) {
let file = files[i];
var file_path = file.substring(audioFolderPath.length, file.length);
var stats = fs.statSync(file);
var id = file_path.substring(0, file_path.length-4);
var jsonobj = getJSONMp3(id);
if (!jsonobj) continue;
var title = jsonobj.title;
var url = jsonobj.webpage_url;
var uploader = jsonobj.uploader;
var upload_date = jsonobj.upload_date;
upload_date = `${upload_date.substring(0, 4)}-${upload_date.substring(4, 6)}-${upload_date.substring(6, 8)}`;
if (title.length > 14) // edits title if it's too long
{
title = title.substring(0,12) + "...";
}
var size = stats.size;
var thumbnail = jsonobj.thumbnail;
var duration = jsonobj.duration;
var isaudio = true;
var file_obj = new File(id, title, thumbnail, isaudio, duration);
var file_obj = new File(id, title, thumbnail, isaudio, duration, url, uploader, size, file, upload_date);
mp3s.push(file_obj);
}
@ -984,20 +1000,24 @@ app.post('/api/getMp4s', function(req, res) {
for (let i = 0; i < files.length; i++) {
let file = files[i];
var file_path = file.substring(videoFolderPath.length, file.length);
var stats = fs.statSync(file);
var id = file_path.substring(0, file_path.length-4);
var jsonobj = getJSONMp4(id);
if (!jsonobj) continue;
var title = jsonobj.title;
if (title.length > 14) // edits title if it's too long
{
title = title.substring(0,12) + "...";
}
var url = jsonobj.webpage_url;
var uploader = jsonobj.uploader;
var upload_date = jsonobj.upload_date;
upload_date = `${upload_date.substring(0, 4)}-${upload_date.substring(4, 6)}-${upload_date.substring(6, 8)}`;
var thumbnail = jsonobj.thumbnail;
var duration = jsonobj.duration;
var size = stats.size;
var isaudio = false;
var file_obj = new File(id, title, thumbnail, isaudio, duration);
var file_obj = new File(id, title, thumbnail, isaudio, duration, url, uploader, size, file, upload_date);
mp4s.push(file_obj);
}
@ -1101,6 +1121,8 @@ app.post('/api/getSubscription', async (req, res) => {
for (let i = 0; i < files.length; i++) {
let file = files[i];
var file_path = file.substring(appended_base_path.length, file.length);
var stats = fs.statSync(file);
var id = file_path.substring(0, file_path.length-4);
var jsonobj = getJSONMp4(id, appended_base_path);
if (!jsonobj) continue;
@ -1108,8 +1130,14 @@ app.post('/api/getSubscription', async (req, res) => {
var thumbnail = jsonobj.thumbnail;
var duration = jsonobj.duration;
var url = jsonobj.webpage_url;
var uploader = jsonobj.uploader;
var upload_date = jsonobj.upload_date;
upload_date = `${upload_date.substring(0, 4)}-${upload_date.substring(4, 6)}-${upload_date.substring(6, 8)}`;
var size = stats.size;
var isaudio = false;
var file_obj = new File(id, title, thumbnail, isaudio, duration);
var file_obj = new File(id, title, thumbnail, isaudio, duration, url, uploader, size, file, upload_date);
parsed_files.push(file_obj);
}
@ -1120,9 +1148,6 @@ app.post('/api/getSubscription', async (req, res) => {
} else {
res.sendStatus(500);
}
});
app.post('/api/downloadVideosForSubscription', async (req, res) => {
@ -1257,11 +1282,12 @@ app.post('/api/deleteMp4', async (req, res) => {
app.post('/api/downloadFile', async (req, res) => {
let fileNames = req.body.fileNames;
let is_playlist = req.body.is_playlist;
let zip_mode = req.body.zip_mode;
let type = req.body.type;
let outputName = req.body.outputName;
let fullPathProvided = req.body.fullPathProvided;
let file = null;
if (!is_playlist) {
if (!zip_mode) {
fileNames = decodeURIComponent(fileNames);
if (type === 'audio') {
file = __dirname + '/' + audioFolderPath + fileNames + '.mp3';
@ -1272,10 +1298,20 @@ app.post('/api/downloadFile', async (req, res) => {
for (let i = 0; i < fileNames.length; i++) {
fileNames[i] = decodeURIComponent(fileNames[i]);
}
file = await createPlaylistZipFile(fileNames, type, outputName);
file = await createPlaylistZipFile(fileNames, type, outputName, fullPathProvided);
}
res.sendFile(file);
res.sendFile(file, function (err) {
if (err) {
next(err);
} else if (fullPathProvided) {
try {
fs.unlinkSync(file);
} catch(e) {
console.log("ERROR: Failed to remove file", file);
}
}
});
});
app.post('/api/deleteFile', async (req, res) => {

@ -33,6 +33,7 @@
"@locl/core": "0.0.1-beta.2",
"core-js": "^2.4.1",
"file-saver": "^2.0.2",
"filesize": "^6.1.0",
"ng-lazyload-image": "^7.0.1",
"ng4-configure": "^0.1.7",
"ngx-content-loading": "^0.1.3",

@ -49,6 +49,7 @@ import { SettingsComponent } from './settings/settings.component';
import es from '@angular/common/locales/es';
import { AboutDialogComponent } from './dialogs/about-dialog/about-dialog.component';
import { VideoInfoDialogComponent } from './dialogs/video-info-dialog/video-info-dialog.component';
registerLocaleData(es, 'es');
export function isVisible({ event, element, scrollContainer, offset }: IsVisibleProps<any>) {
@ -70,7 +71,8 @@ export function isVisible({ event, element, scrollContainer, offset }: IsVisible
SubscriptionFileCardComponent,
SubscriptionInfoDialogComponent,
SettingsComponent,
AboutDialogComponent
AboutDialogComponent,
VideoInfoDialogComponent
],
imports: [
BrowserModule,

@ -0,0 +1,32 @@
<h4 mat-dialog-title>{{file.title}}</h4>
<mat-dialog-content>
<div class="info-item">
<div class="info-item-label"><strong><ng-container i18n="Video name property">Name:</ng-container>&nbsp;</strong></div>
<div class="info-item-value">{{file.title}}</div>
</div>
<div class="info-item">
<div class="info-item-label"><strong><ng-container i18n="Video URL property">URL:</ng-container>&nbsp;</strong></div>
<div class="info-item-value"><a target="_blank" [href]="file.url">{{file.url}}</a></div>
</div>
<div class="info-item">
<div class="info-item-label"><strong><ng-container i18n="Video ID property">Uploader:</ng-container>&nbsp;</strong></div>
<div class="info-item-value">{{file.uploader ? file.uploader : 'N/A'}}</div>
</div>
<div class="info-item">
<div class="info-item-label"><strong><ng-container i18n="Video file size property">File size:</ng-container>&nbsp;</strong></div>
<div class="info-item-value">{{filesize(file.size)}}</div>
</div>
<div class="info-item">
<div class="info-item-label"><strong><ng-container i18n="Video path property">Path:</ng-container>&nbsp;</strong></div>
<div class="info-item-value">{{file.path}}</div>
</div>
<div class="info-item">
<div class="info-item-label"><strong><ng-container i18n="Video upload date property">Upload Date:</ng-container>&nbsp;</strong></div>
<div class="info-item-value">{{file.upload_date}}</div>
</div>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button mat-dialog-close><ng-container i18n="Close subscription info button">Close</ng-container></button>
</mat-dialog-actions>

@ -0,0 +1,18 @@
.info-item {
margin-bottom: 12px;
width: 100%;
}
.info-item-value {
font-size: 13px;
display: inline-block;
width: 70%;
}
.spacer {flex: 1 1 auto;}
.info-item-label {
display: inline-block;
width: 30%;
vertical-align: top;
}

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

@ -0,0 +1,22 @@
import { Component, OnInit, Inject } from '@angular/core';
import filesize from 'filesize';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
@Component({
selector: 'app-video-info-dialog',
templateUrl: './video-info-dialog.component.html',
styleUrls: ['./video-info-dialog.component.scss']
})
export class VideoInfoDialogComponent implements OnInit {
file: any;
filesize;
constructor(@Inject(MAT_DIALOG_DATA) public data: any) { }
ngOnInit(): void {
this.filesize = filesize;
if (this.data) {
this.file = this.data.file;
}
}
}

@ -51,6 +51,14 @@
-webkit-line-clamp: 2;
}
.file-link {
width: 80%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: block;
}
@media (max-width: 576px){
.example-card {

@ -1,8 +1,9 @@
<mat-card class="example-card mat-elevation-z6">
<div style="padding:5px">
<div style="height: 52px;">
<b><a href="javascript:void(0)" (click)="!isPlaylist ? mainComponent.goToFile(name, isAudio) : mainComponent.goToPlaylist(name, type)">{{title}}</a></b>
<br/>
<div>
<b><a class="file-link" href="javascript:void(0)" (click)="!isPlaylist ? mainComponent.goToFile(name, isAudio) : mainComponent.goToPlaylist(name, type)">{{title}}</a></b>
</div>
<span class="max-two-lines"><ng-container i18n="File or playlist ID">ID:</ng-container>&nbsp;{{name}}</span>
<div *ngIf="isPlaylist"><ng-container i18n="Playlist video count">Count:</ng-container>&nbsp;{{count}}</div>
</div>
@ -15,10 +16,11 @@
</span>
</div>
</div>
<button *ngIf="!use_youtubedl_archive" (click)="deleteFile()" class="deleteButton" mat-icon-button><mat-icon>delete_forever</mat-icon></button>
<button [matMenuTriggerFor]="action_menu" *ngIf="use_youtubedl_archive" class="deleteButton" mat-icon-button><mat-icon>more_vert</mat-icon></button>
<button *ngIf="isPlaylist" (click)="deleteFile()" class="deleteButton" mat-icon-button><mat-icon>delete_forever</mat-icon></button>
<button [matMenuTriggerFor]="action_menu" *ngIf="!isPlaylist" class="deleteButton" mat-icon-button><mat-icon>more_vert</mat-icon></button>
<mat-menu #action_menu="matMenu">
<button (click)="openVideoInfoDialog()" mat-menu-item><mat-icon>info</mat-icon><ng-container i18n="Video info button">Info</ng-container></button>
<button (click)="deleteFile()" mat-menu-item><mat-icon>delete</mat-icon><ng-container i18n="Delete video button">Delete</ng-container></button>
<button (click)="deleteFile(true)" mat-menu-item><mat-icon>delete_forever</mat-icon><ng-container i18n="Delete and blacklist video button">Delete and blacklist</ng-container></button>
<button *ngIf="use_youtubedl_archive" (click)="deleteFile(true)" mat-menu-item><mat-icon>delete_forever</mat-icon><ng-container i18n="Delete and blacklist video button">Delete and blacklist</ng-container></button>
</mat-menu>
</mat-card>

@ -5,6 +5,8 @@ import {EventEmitter} from '@angular/core';
import { MainComponent } from 'app/main/main.component';
import { Subject, Observable } from 'rxjs';
import 'rxjs/add/observable/merge';
import { MatDialog } from '@angular/material/dialog';
import { VideoInfoDialogComponent } from 'app/dialogs/video-info-dialog/video-info-dialog.component';
@Component({
selector: 'app-file-card',
@ -12,7 +14,7 @@ import 'rxjs/add/observable/merge';
styleUrls: ['./file-card.component.css']
})
export class FileCardComponent implements OnInit {
@Input() file: any;
@Input() title: string;
@Input() length: string;
@Input() name: string;
@ -29,8 +31,10 @@ export class FileCardComponent implements OnInit {
scrollSubject;
scrollAndLoad;
constructor(private postsService: PostsService, public snackBar: MatSnackBar, public mainComponent: MainComponent) {
this.scrollSubject = new Subject();
constructor(private postsService: PostsService, public snackBar: MatSnackBar, public mainComponent: MainComponent,
private dialog: MatDialog) {
this.scrollSubject = new Subject();
this.scrollAndLoad = Observable.merge(
Observable.fromEvent(window, 'scroll'),
this.scrollSubject
@ -57,6 +61,15 @@ export class FileCardComponent implements OnInit {
}
openVideoInfoDialog() {
const dialogRef = this.dialog.open(VideoInfoDialogComponent, {
data: {
file: this.file,
},
minWidth: '50vw'
});
}
onImgError(event) {
this.image_errored = true;
}

@ -203,7 +203,7 @@
<div *ngIf="mp3s.length > 0;else nomp3s">
<mat-grid-list style="margin-bottom: 15px;" (window:resize)="onResize($event)" [cols]="files_cols" rowHeight="150px">
<mat-grid-tile *ngFor="let file of mp3s; index as i;">
<app-file-card #audiofilecard (removeFile)="removeFromMp3($event)" [title]="file.title" [name]="file.id" [thumbnailURL]="file.thumbnailURL"
<app-file-card #audiofilecard (removeFile)="removeFromMp3($event)" [file]="file" [title]="file.title" [name]="file.id" [thumbnailURL]="file.thumbnailURL"
[length]="file.duration" [isAudio]="true" [use_youtubedl_archive]="use_youtubedl_archive"></app-file-card>
<mat-progress-bar *ngIf="downloading_content['audio'][file.id]" class="download-progress-bar" mode="indeterminate"></mat-progress-bar>
</mat-grid-tile>
@ -244,7 +244,7 @@
<div *ngIf="mp4s.length > 0;else nomp4s">
<mat-grid-list style="margin-bottom: 15px;" (window:resize)="onResize($event)" [cols]="files_cols" rowHeight="150px">
<mat-grid-tile *ngFor="let file of mp4s; index as i;">
<app-file-card #videofilecard (removeFile)="removeFromMp4($event)" [title]="file.title" [name]="file.id" [thumbnailURL]="file.thumbnailURL"
<app-file-card #videofilecard (removeFile)="removeFromMp4($event)" [file]="file" [title]="file.title" [name]="file.id" [thumbnailURL]="file.thumbnailURL"
[length]="file.duration" [isAudio]="false" [use_youtubedl_archive]="use_youtubedl_archive"></app-file-card>
<mat-progress-bar *ngIf="downloading_content['video'][file.id]" class="download-progress-bar" mode="indeterminate"></mat-progress-bar>
</mat-grid-tile>

@ -114,11 +114,12 @@ export class PostsService {
return this.http.post(this.path + 'getMp4s', {});
}
downloadFileFromServer(fileName, type, outputName = null) {
downloadFileFromServer(fileName, type, outputName = null, fullPathProvided = null) {
return this.http.post(this.path + 'downloadFile', {fileNames: fileName,
type: type,
is_playlist: Array.isArray(fileName),
outputName: outputName},
zip_mode: Array.isArray(fileName),
outputName: outputName,
fullPathProvided: fullPathProvided},
{responseType: 'blob'});
}

@ -4,6 +4,7 @@
</div>
<button [matMenuTriggerFor]="action_menu" class="menuButton" mat-icon-button><mat-icon>more_vert</mat-icon></button>
<mat-menu #action_menu="matMenu">
<button (click)="openSubscriptionInfoDialog()" mat-menu-item><mat-icon>info</mat-icon><ng-container i18n="Subscription video info button">Info</ng-container></button>
<button (click)="deleteAndRedownload()" mat-menu-item><mat-icon>restore</mat-icon><ng-container i18n="Delete and redownload subscription video button">Delete and redownload</ng-container></button>
<button (click)="deleteForever()" mat-menu-item *ngIf="sub.archive && use_youtubedl_archive"><mat-icon>delete_forever</mat-icon><ng-container i18n="Delete forever subscription video button">Delete forever</ng-container></button>
</mat-menu>

@ -3,6 +3,8 @@ import { Observable, Subject } from 'rxjs';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Router } from '@angular/router';
import { PostsService } from 'app/posts.services';
import { MatDialog } from '@angular/material/dialog';
import { VideoInfoDialogComponent } from 'app/dialogs/video-info-dialog/video-info-dialog.component';
@Component({
selector: 'app-subscription-file-card',
@ -25,7 +27,7 @@ export class SubscriptionFileCardComponent implements OnInit {
@Output() goToFileEmit = new EventEmitter<any>();
@Output() reloadSubscription = new EventEmitter<boolean>();
constructor(private snackBar: MatSnackBar, private postsService: PostsService) {
constructor(private snackBar: MatSnackBar, private postsService: PostsService, private dialog: MatDialog) {
this.scrollSubject = new Subject();
this.scrollAndLoad = Observable.merge(
Observable.fromEvent(window, 'scroll'),
@ -55,6 +57,15 @@ export class SubscriptionFileCardComponent implements OnInit {
this.goToFileEmit.emit(this.file.id);
}
openSubscriptionInfoDialog() {
const dialogRef = this.dialog.open(VideoInfoDialogComponent, {
data: {
file: this.file,
},
minWidth: '50vw'
});
}
deleteAndRedownload() {
this.postsService.deleteSubscriptionFile(this.sub, this.file.id, false).subscribe(res => {
this.reloadSubscription.emit(true);
@ -77,8 +88,7 @@ export class SubscriptionFileCardComponent implements OnInit {
}
function fancyTimeFormat(time)
{
function fancyTimeFormat(time) {
// Hours, minutes and seconds
const hrs = ~~(time / 3600);
const mins = ~~((time % 3600) / 60);

@ -1,31 +1,46 @@
<br/>
<button class="back-button" (click)="goBack()" mat-icon-button><mat-icon>arrow_back</mat-icon></button>
<div style="margin-bottom: 15px;">
<h2 style="text-align: center;" *ngIf="subscription">
{{subscription.name}}
</h2>
</div>
<mat-divider style="width: 80%; margin: 0 auto"></mat-divider>
<br/>
<div style="margin-top: 14px;">
<button class="back-button" (click)="goBack()" mat-icon-button><mat-icon>arrow_back</mat-icon></button>
<div style="margin-bottom: 15px;">
<h2 style="text-align: center;" *ngIf="subscription">
{{subscription.name}}
</h2>
</div>
<mat-divider style="width: 80%; margin: 0 auto"></mat-divider>
<br/>
<div *ngIf="subscription">
<div class="flex-grid">
<div class="col"></div>
<div class="col">
<h4 i18n="Subscription videos title" style="text-align: center; margin-bottom: 20px;">Videos</h4>
</div>
<div class="col">
<mat-form-field [ngClass]="searchIsFocused ? 'search-bar-focused' : 'search-bar-unfocused'" class="search-bar" color="accent">
<input (focus)="searchIsFocused = true" (blur)="searchIsFocused = false" class="search-input" type="text" placeholder="Search" i18n-placeholder="Subscription videos search placeholder" [(ngModel)]="search_text" (ngModelChange)="onSearchInputChanged($event)" matInput>
<mat-icon matSuffix>search</mat-icon>
</mat-form-field>
<div *ngIf="subscription">
<div class="flex-grid">
<div class="filter-select-parent">
<div style="display: inline-block;">
<mat-select style="width: 110px;" [(ngModel)]="this.filterProperty" (selectionChange)="filterOptionChanged($event.value)">
<mat-option *ngFor="let filterOption of filterProperties | keyvalue" [value]="filterOption.value">
{{filterOption['value']['label']}}
</mat-option>
</mat-select>
</div>
<div style="display: inline-block;">
<button (click)="toggleModeChange()" mat-icon-button><mat-icon>{{descendingMode ? 'arrow_downward' : 'arrow_upward'}}</mat-icon></button>
</div>
</div>
<div class="col">
</div>
<div class="col">
<h4 i18n="Subscription videos title" style="text-align: center; margin-bottom: 20px;">Videos</h4>
</div>
<div style="top: -12px;" class="col">
<mat-form-field [ngClass]="searchIsFocused ? 'search-bar-focused' : 'search-bar-unfocused'" class="search-bar" color="accent">
<input (focus)="searchIsFocused = true" (blur)="searchIsFocused = false" class="search-input" type="text" placeholder="Search" i18n-placeholder="Subscription videos search placeholder" [(ngModel)]="search_text" (ngModelChange)="onSearchInputChanged($event)" matInput>
<mat-icon matSuffix>search</mat-icon>
</mat-form-field>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div *ngFor="let file of filtered_files" class="col-6 col-lg-4 mb-2 mt-2 sub-file-col">
<app-subscription-file-card (reloadSubscription)="getSubscription()" (goToFileEmit)="goToFile($event)" [file]="file" [sub]="subscription" [use_youtubedl_archive]="use_youtubedl_archive"></app-subscription-file-card>
<div class="container">
<div class="row justify-content-center">
<div *ngFor="let file of filtered_files" class="col-6 col-lg-4 mb-2 mt-2 sub-file-col">
<app-subscription-file-card (reloadSubscription)="getSubscription()" (goToFileEmit)="goToFile($event)" [file]="file" [sub]="subscription" [use_youtubedl_archive]="use_youtubedl_archive"></app-subscription-file-card>
</div>
</div>
</div>
</div>
<button class="save-button" color="primary" (click)="downloadContent()" [disabled]="downloading" mat-fab><mat-icon class="save-icon">save</mat-icon><mat-spinner *ngIf="downloading" class="spinner" [diameter]="50"></mat-spinner></button>
</div>

@ -8,6 +8,13 @@
left: 15px;
}
.filter-select-parent {
position: absolute;
top: 0px;
left: 20px;
display: block;
}
.search-bar {
transition: all .5s ease;
position: relative;
@ -29,8 +36,29 @@
.flex-grid {
width: 100%;
display: block;
position: relative;
}
.col {
width: 33%;
display: inline-block;
}
.spinner {
width: 50px;
height: 50px;
bottom: 3px;
left: 3px;
position: absolute;
}
.save-button {
right: 25px;
position: absolute;
bottom: 25px;
}
.save-icon {
bottom: 1px;
position: relative;
}

@ -17,6 +17,31 @@ export class SubscriptionComponent implements OnInit {
search_mode = false;
search_text = '';
searchIsFocused = false;
descendingMode = true;
filterProperties = {
'upload_date': {
'key': 'upload_date',
'label': 'Upload Date',
'property': 'upload_date'
},
'name': {
'key': 'name',
'label': 'Name',
'property': 'title'
},
'file_size': {
'key': 'file_size',
'label': 'File Size',
'property': 'size'
},
'duration': {
'key': 'duration',
'label': 'Duration',
'property': 'duration'
}
};
filterProperty = this.filterProperties['upload_date'];
downloading = false;
constructor(private postsService: PostsService, private route: ActivatedRoute, private router: Router) { }
@ -27,6 +52,12 @@ export class SubscriptionComponent implements OnInit {
this.getSubscription();
this.getConfig();
}
// set filter property to cached
const cached_filter_property = localStorage.getItem('filter_property');
if (cached_filter_property && this.filterProperties[cached_filter_property]) {
this.filterProperty = this.filterProperties[cached_filter_property];
}
}
goBack() {
@ -42,6 +73,7 @@ export class SubscriptionComponent implements OnInit {
} else {
this.filtered_files = this.files;
}
this.filterByProperty(this.filterProperty['property']);
});
}
@ -72,4 +104,40 @@ export class SubscriptionComponent implements OnInit {
this.filtered_files = this.files.filter(option => option.id.toLowerCase().includes(filterValue));
}
filterByProperty(prop) {
if (this.descendingMode) {
this.filtered_files = this.filtered_files.sort((a, b) => (a[prop] > b[prop] ? -1 : 1));
} else {
this.filtered_files = this.filtered_files.sort((a, b) => (a[prop] > b[prop] ? 1 : -1));
}
}
filterOptionChanged(value) {
// this.filterProperty = value;
this.filterByProperty(value['property']);
localStorage.setItem('filter_property', value['key']);
}
toggleModeChange() {
this.descendingMode = !this.descendingMode;
this.filterByProperty(this.filterProperty['property']);
}
downloadContent() {
const fileNames = [];
for (let i = 0; i < this.files.length; i++) {
fileNames.push(this.files[i].path);
}
this.downloading = true;
this.postsService.downloadFileFromServer(fileNames, 'video', this.subscription.name, true).subscribe(res => {
this.downloading = false;
const blob: Blob = res;
saveAs(blob, this.subscription.name + '.zip');
}, err => {
console.log(err);
this.downloading = false;
});
}
}

@ -33,6 +33,9 @@ export class SubscriptionsComponent implements OnInit {
this.postsService.getAllSubscriptions().subscribe(res => {
this.subscriptions_loading = false;
this.subscriptions = res['subscriptions'];
if (!this.subscriptions) {
return;
}
for (let i = 0; i < this.subscriptions.length; i++) {
const sub = this.subscriptions[i];

Loading…
Cancel
Save