import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core'; import { PostsService } from 'app/posts.services'; import { trigger, transition, animateChild, stagger, query, style, animate } from '@angular/animations'; import { Router } from '@angular/router'; import { MatPaginator } from '@angular/material/paginator'; import { MatTableDataSource } from '@angular/material/table'; import { MatDialog } from '@angular/material/dialog'; import { ConfirmDialogComponent } from 'app/dialogs/confirm-dialog/confirm-dialog.component'; import { MatSort } from '@angular/material/sort'; @Component({ selector: 'app-downloads', templateUrl: './downloads.component.html', styleUrls: ['./downloads.component.scss'], animations: [ // nice stagger effect when showing existing elements trigger('list', [ transition(':enter', [ // child animation selector + stagger query('@items', stagger(100, animateChild()), { optional: true } ) ]), ]), trigger('items', [ // cubic-bezier for a tiny bouncing feel transition(':enter', [ style({ transform: 'scale(0.5)', opacity: 0 }), animate('500ms cubic-bezier(.8,-0.6,0.2,1.5)', style({ transform: 'scale(1)', opacity: 1 })) ]), transition(':leave', [ style({ transform: 'scale(1)', opacity: 1, height: '*' }), animate('1s cubic-bezier(.8,-0.6,0.2,1.5)', style({ transform: 'scale(0.5)', opacity: 0, height: '0px', margin: '0px' })) ]), ]) ], }) export class DownloadsComponent implements OnInit, OnDestroy { downloads_check_interval = 1000; downloads = []; finished_downloads = []; interval_id = null; keys = Object.keys; valid_sessions_length = 0; STEP_INDEX_TO_LABEL = { 0: 'Creating download', 1: 'Getting info', 2: 'Downloading file', 3: 'Complete' } displayedColumns: string[] = ['date', 'title', 'stage', 'subscription', 'progress', 'actions']; dataSource = null; // new MatTableDataSource(); downloads_retrieved = false; @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; sort_downloads = (a, b) => { const result = b.timestamp_start - a.timestamp_start; return result; } constructor(public postsService: PostsService, private router: Router, private dialog: MatDialog) { } ngOnInit(): void { if (this.postsService.initialized) { this.getCurrentDownloadsRecurring(); } else { this.postsService.service_initialized.subscribe(init => { if (init) { this.getCurrentDownloadsRecurring(); } }); } } getCurrentDownloadsRecurring() { if (!this.postsService.config['Extra']['enable_downloads_manager']) { this.router.navigate(['/home']); return; } this.getCurrentDownloads(); this.interval_id = setInterval(() => { this.getCurrentDownloads(); }, this.downloads_check_interval); } ngOnDestroy(): void { if (this.interval_id) { clearInterval(this.interval_id) } } getCurrentDownloads(): void { this.postsService.getCurrentDownloads().subscribe(res => { this.downloads_retrieved = true; if (res['downloads'] !== null && res['downloads'] !== undefined && JSON.stringify(this.downloads) !== JSON.stringify(res['downloads'])) { this.downloads = this.combineDownloads(this.downloads, res['downloads']); // this.downloads = res['downloads']; this.downloads.sort(this.sort_downloads); this.dataSource = new MatTableDataSource(this.downloads); this.dataSource.paginator = this.paginator; this.dataSource.sort = this.sort; } else { // failed to get downloads } }); } clearFinishedDownloads(): void { const dialogRef = this.dialog.open(ConfirmDialogComponent, { data: { dialogTitle: $localize`Clear finished downloads`, dialogText: $localize`Would you like to clear your finished downloads?`, submitText: $localize`Clear`, warnSubmitColor: true } }); dialogRef.afterClosed().subscribe(confirmed => { if (confirmed) { this.postsService.clearFinishedDownloads().subscribe(res => { if (!res['success']) { this.postsService.openSnackBar('Failed to clear finished downloads!'); } }); } }); } pauseDownload(download_uid: string): void { this.postsService.pauseDownload(download_uid).subscribe(res => { if (!res['success']) { this.postsService.openSnackBar('Failed to pause download! See server logs for more info.'); } }); } resumeDownload(download_uid: string): void { this.postsService.resumeDownload(download_uid).subscribe(res => { if (!res['success']) { this.postsService.openSnackBar('Failed to resume download! See server logs for more info.'); } }); } restartDownload(download_uid: string): void { this.postsService.restartDownload(download_uid).subscribe(res => { if (!res['success']) { this.postsService.openSnackBar('Failed to restart download! See server logs for more info.'); } }); } cancelDownload(download_uid: string): void { this.postsService.cancelDownload(download_uid).subscribe(res => { if (!res['success']) { this.postsService.openSnackBar('Failed to cancel download! See server logs for more info.'); } }); } clearDownload(download_uid: string): void { this.postsService.clearDownload(download_uid).subscribe(res => { if (!res['success']) { this.postsService.openSnackBar('Failed to pause download! See server logs for more info.'); } }); } watchContent(download): void { const container = download['container']; localStorage.setItem('player_navigator', this.router.url.split(';')[0]); const is_playlist = container['uids']; // hacky, TODO: fix if (is_playlist) { this.router.navigate(['/player', {playlist_id: container['id'], type: download['type']}]); } else { this.router.navigate(['/player', {type: download['type'], uid: container['uid']}]); } } combineDownloads(downloads_old, downloads_new) { // only keeps downloads that exist in the new set downloads_old = downloads_old.filter(download_old => downloads_new.some(download_new => download_new.uid === download_old.uid)); // add downloads from the new set that the old one doesn't have const downloads_to_add = downloads_new.filter(download_new => !downloads_old.some(download_old => download_new.uid === download_old.uid)); downloads_old.push(...downloads_to_add); downloads_old.forEach(download_old => { const download_new = downloads_new.find(download_to_check => download_old.uid === download_to_check.uid); Object.keys(download_new).forEach(key => { download_old[key] = download_new[key]; }); Object.keys(download_old).forEach(key => { if (!download_new[key]) delete download_old[key]; }); }); return downloads_old; } } export interface Download { timestamp_start: number; title: string; step_index: number; progress: string; }