added basic subscriptions support for playlists and channels

update youtube-dl binary on windows

updated favicon to the new icon
This commit is contained in:
Isaac Grynsztein
2020-03-05 20:14:36 -05:00
parent a755b0b281
commit a70abb3945
38 changed files with 1200 additions and 32 deletions

View File

@@ -0,0 +1,43 @@
<h4 mat-dialog-title>Subscribe to playlist or channel</h4>
<mat-dialog-content>
<div class="container-fluid">
<div class="row">
<div class="col-12">
<mat-form-field color="accent">
<input [(ngModel)]="url" matInput placeholder="URL" required aria-required="true">
<mat-hint>The playlist or channel URL</mat-hint>
</mat-form-field>
</div>
<div class="col-12">
<mat-form-field color="accent">
<input [(ngModel)]="name" matInput placeholder="Custom name">
<mat-hint>This is optional</mat-hint>
</mat-form-field>
</div>
<div class="col-12 mt-3">
<mat-checkbox [(ngModel)]="download_all">Download all uploads</mat-checkbox>
</div>
<div class="col-12" *ngIf="!download_all">
Download videos uploaded in the last
<mat-form-field color="accent" style="width: 50px; text-align: center">
<input type="number" matInput [(ngModel)]="timerange_amount">
</mat-form-field>
<mat-select color="accent" class="unit-select" [(ngModel)]="timerange_unit">
<mat-option *ngFor="let time_unit of time_units" [value]="time_unit + (timerange_amount === 1 ? '' : 's')">
{{time_unit + (timerange_amount === 1 ? '' : 's')}}
</mat-option>
</mat-select>
</div>
</div>
</div>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button mat-dialog-close>Cancel</button>
<!-- The mat-dialog-close directive optionally accepts a value as a result for the dialog. -->
<button mat-button [disabled]="!url" type="submit" (click)="subscribeClicked()">Subscribe</button>
<div class="mat-spinner" *ngIf="subscribing">
<mat-spinner [diameter]="25"></mat-spinner>
</div>
</mat-dialog-actions>

View File

@@ -0,0 +1,8 @@
.unit-select {
width: 75px;
margin-left: 20px;
}
.mat-spinner {
margin-left: 5%;
}

View File

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

View File

@@ -0,0 +1,69 @@
import { Component, OnInit } from '@angular/core';
import { MatSnackBar, MatDialogRef } from '@angular/material';
import { PostsService } from 'app/posts.services';
@Component({
selector: 'app-subscribe-dialog',
templateUrl: './subscribe-dialog.component.html',
styleUrls: ['./subscribe-dialog.component.scss']
})
export class SubscribeDialogComponent implements OnInit {
// inputs
timerange_amount;
timerange_unit = 'days';
download_all = true;
url = null;
name = null;
// state
subscribing = false;
time_units = [
'day',
'week',
'month',
'year'
]
constructor(private postsService: PostsService,
private snackBar: MatSnackBar,
public dialogRef: MatDialogRef<SubscribeDialogComponent>) { }
ngOnInit() {
}
subscribeClicked() {
if (this.url && this.url !== '') {
// timerange must be specified if download_all is false
if (!this.download_all && !this.timerange_amount) {
this.openSnackBar('You must specify an amount of time');
return;
}
this.subscribing = true;
let timerange = null;
if (!this.download_all) {
timerange = 'now-' + this.timerange_amount.toString() + this.timerange_unit;
}
this.postsService.createSubscription(this.url, this.name, timerange).subscribe(res => {
this.subscribing = false;
if (res['new_sub']) {
this.dialogRef.close(res['new_sub']);
} else {
if (res['error']) {
this.openSnackBar('ERROR: ' + res['error']);
}
this.dialogRef.close();
}
});
}
}
public openSnackBar(message: string, action = '') {
this.snackBar.open(message, action, {
duration: 2000,
});
}
}

View File

@@ -0,0 +1,10 @@
<h4 mat-dialog-title>{{sub.name}}</h4>
<mat-dialog-content>
<strong>Type:</strong> {{(sub.isPlaylist ? 'Playlist' : 'Channel')}}
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button mat-dialog-close>Close</button>
<button mat-button (click)="unsubscribe()" color="warn">Unsubscribe</button>
</mat-dialog-actions>

View File

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

View File

@@ -0,0 +1,32 @@
import { Component, OnInit, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
import { PostsService } from 'app/posts.services';
@Component({
selector: 'app-subscription-info-dialog',
templateUrl: './subscription-info-dialog.component.html',
styleUrls: ['./subscription-info-dialog.component.scss']
})
export class SubscriptionInfoDialogComponent implements OnInit {
sub = null;
unsubbedEmitter = null;
constructor(public dialogRef: MatDialogRef<SubscriptionInfoDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any, private postsService: PostsService) { }
ngOnInit() {
if (this.data) {
this.sub = this.data.sub;
this.unsubbedEmitter = this.data.unsubbedEmitter;
}
}
unsubscribe() {
this.postsService.unsubscribe(this.sub, true).subscribe(res => {
this.unsubbedEmitter.emit(true);
this.dialogRef.close();
});
}
}