mirror of
https://github.com/Tzahi12345/YoutubeDL-Material.git
synced 2026-03-22 20:51:00 +03:00
Merge pull request #290 from Tzahi12345/updated-player
Updated player & much more (v4.2)
This commit is contained in:
@@ -32,7 +32,7 @@ import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||
import { ClipboardModule } from '@angular/cdk/clipboard';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { AppComponent } from './app.component';
|
||||
import { HttpClientModule, HttpClient } from '@angular/common/http';
|
||||
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
import { PostsService } from 'app/posts.services';
|
||||
import { FileCardComponent } from './file-card/file-card.component';
|
||||
import { RouterModule } from '@angular/router';
|
||||
@@ -84,6 +84,8 @@ import { EditSubscriptionDialogComponent } from './dialogs/edit-subscription-dia
|
||||
import { CustomPlaylistsComponent } from './components/custom-playlists/custom-playlists.component';
|
||||
import { EditCategoryDialogComponent } from './dialogs/edit-category-dialog/edit-category-dialog.component';
|
||||
import { TwitchChatComponent } from './components/twitch-chat/twitch-chat.component';
|
||||
import { LinkifyPipe, SeeMoreComponent } from './components/see-more/see-more.component';
|
||||
import { H401Interceptor } from './http.interceptor';
|
||||
|
||||
registerLocaleData(es, 'es');
|
||||
|
||||
@@ -110,6 +112,7 @@ export function isVisible({ event, element, scrollContainer, offset }: IsVisible
|
||||
VideoInfoDialogComponent,
|
||||
ArgModifierDialogComponent,
|
||||
HighlightPipe,
|
||||
LinkifyPipe,
|
||||
UpdaterComponent,
|
||||
UpdateProgressDialogComponent,
|
||||
ShareMediaDialogComponent,
|
||||
@@ -130,7 +133,8 @@ export function isVisible({ event, element, scrollContainer, offset }: IsVisible
|
||||
EditSubscriptionDialogComponent,
|
||||
CustomPlaylistsComponent,
|
||||
EditCategoryDialogComponent,
|
||||
TwitchChatComponent
|
||||
TwitchChatComponent,
|
||||
SeeMoreComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
@@ -188,10 +192,12 @@ export function isVisible({ event, element, scrollContainer, offset }: IsVisible
|
||||
SettingsComponent
|
||||
],
|
||||
providers: [
|
||||
PostsService
|
||||
PostsService,
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: H401Interceptor, multi: true }
|
||||
],
|
||||
exports: [
|
||||
HighlightPipe
|
||||
HighlightPipe,
|
||||
LinkifyPipe
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
|
||||
@@ -62,7 +62,7 @@ export class CustomPlaylistsComponent implements OnInit {
|
||||
} else {
|
||||
localStorage.setItem('player_navigator', this.router.url);
|
||||
const fileNames = playlist.fileNames;
|
||||
this.router.navigate(['/player', {fileNames: fileNames.join('|nvr|'), type: type, id: playlistID, uid: playlistID}]);
|
||||
this.router.navigate(['/player', {fileNames: fileNames.join('|nvr|'), type: type, id: playlistID, uid: playlistID, auto: playlist.auto}]);
|
||||
}
|
||||
} else {
|
||||
// playlist not found
|
||||
|
||||
@@ -27,7 +27,7 @@ export class LoginComponent implements OnInit {
|
||||
constructor(private postsService: PostsService, private snackBar: MatSnackBar, private router: Router) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
if (this.postsService.isLoggedIn) {
|
||||
if (this.postsService.isLoggedIn && localStorage.getItem('jwt_token') !== 'null') {
|
||||
this.router.navigate(['/home']);
|
||||
}
|
||||
this.postsService.service_initialized.subscribe(init => {
|
||||
|
||||
@@ -98,7 +98,7 @@ export class RecentVideosComponent implements OnInit {
|
||||
|
||||
private filterFiles(value: string) {
|
||||
const filterValue = value.toLowerCase();
|
||||
this.filtered_files = this.files.filter(option => option.id.toLowerCase().includes(filterValue));
|
||||
this.filtered_files = this.files.filter(option => option.id.toLowerCase().includes(filterValue) || option.category?.name?.toLowerCase().includes(filterValue));
|
||||
this.pageChangeEvent({pageSize: this.pageSize, pageIndex: this.paginator.pageIndex});
|
||||
}
|
||||
|
||||
@@ -127,9 +127,11 @@ export class RecentVideosComponent implements OnInit {
|
||||
this.normal_files_received = false;
|
||||
this.postsService.getAllFiles().subscribe(res => {
|
||||
this.files = res['files'];
|
||||
this.files.forEach(file => {
|
||||
for (let i = 0; i < this.files.length; i++) {
|
||||
const file = this.files[i];
|
||||
file.duration = typeof file.duration !== 'string' ? file.duration : this.durationStringToNumber(file.duration);
|
||||
});
|
||||
file.index = i;
|
||||
}
|
||||
this.files.sort(this.sortFiles);
|
||||
if (this.search_mode) {
|
||||
this.filterFiles(this.search_text);
|
||||
@@ -247,7 +249,9 @@ export class RecentVideosComponent implements OnInit {
|
||||
this.postsService.deleteFile(file.uid, file.isAudio ? 'audio' : 'video', blacklistMode).subscribe(result => {
|
||||
if (result) {
|
||||
this.postsService.openSnackBar('Delete success!', 'OK.');
|
||||
this.files.splice(index, 1);
|
||||
this.files.splice(file.index, 1);
|
||||
for (let i = 0; i < this.files.length; i++) { this.files[i].index = i }
|
||||
this.filterByProperty(this.filterProperty['property']);
|
||||
} else {
|
||||
this.postsService.openSnackBar('Delete failed!', 'OK.');
|
||||
}
|
||||
|
||||
11
src/app/components/see-more/see-more.component.html
Normal file
11
src/app/components/see-more/see-more.component.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<span class="text" [ngStyle]="{'-webkit-line-clamp': !see_more_active ? line_limit : null}" [innerHTML]="text | linkify"></span>
|
||||
<span>
|
||||
<a [routerLink]="" (click)="toggleSeeMore()">
|
||||
<ng-container *ngIf="!see_more_active" i18n="See more">
|
||||
See more.
|
||||
</ng-container>
|
||||
<ng-container *ngIf="see_more_active" i18n="See less">
|
||||
See less.
|
||||
</ng-container>
|
||||
</a>
|
||||
</span>
|
||||
7
src/app/components/see-more/see-more.component.scss
Normal file
7
src/app/components/see-more/see-more.component.scss
Normal file
@@ -0,0 +1,7 @@
|
||||
.text {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
25
src/app/components/see-more/see-more.component.spec.ts
Normal file
25
src/app/components/see-more/see-more.component.spec.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SeeMoreComponent } from './see-more.component';
|
||||
|
||||
describe('SeeMoreComponent', () => {
|
||||
let component: SeeMoreComponent;
|
||||
let fixture: ComponentFixture<SeeMoreComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ SeeMoreComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SeeMoreComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
60
src/app/components/see-more/see-more.component.ts
Normal file
60
src/app/components/see-more/see-more.component.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { Component, Input, OnInit, Pipe, PipeTransform } from '@angular/core';
|
||||
import { DomSanitizer } from '@angular/platform-browser';
|
||||
|
||||
@Pipe({ name: 'linkify' })
|
||||
export class LinkifyPipe implements PipeTransform {
|
||||
|
||||
constructor(private _domSanitizer: DomSanitizer) {}
|
||||
|
||||
transform(value: any, args?: any): any {
|
||||
return this._domSanitizer.bypassSecurityTrustHtml(this.stylize(value));
|
||||
}
|
||||
|
||||
// Modify this method according to your custom logic
|
||||
private stylize(text: string): string {
|
||||
let stylizedText: string = '';
|
||||
if (text && text.length > 0) {
|
||||
for (let line of text.split("\n")) {
|
||||
for (let t of line.split(" ")) {
|
||||
if (t.startsWith("http") && t.length>7) {
|
||||
stylizedText += `<a target="_blank" href="${t}">${t}</a> `;
|
||||
}
|
||||
else
|
||||
stylizedText += t + " ";
|
||||
}
|
||||
stylizedText += '<br>';
|
||||
}
|
||||
return stylizedText;
|
||||
}
|
||||
else return text;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-see-more',
|
||||
templateUrl: './see-more.component.html',
|
||||
providers: [LinkifyPipe],
|
||||
styleUrls: ['./see-more.component.scss']
|
||||
})
|
||||
export class SeeMoreComponent implements OnInit {
|
||||
|
||||
see_more_active = false;
|
||||
|
||||
@Input() text = '';
|
||||
@Input() line_limit = 2;
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
toggleSeeMore() {
|
||||
this.see_more_active = !this.see_more_active;
|
||||
}
|
||||
|
||||
parseText() {
|
||||
return this.text.replace(/(http.*?\s)/, "<a href=\"$1\">$1</a>")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,10 @@
|
||||
<div (mouseover)="elevated=true" (mouseout)="elevated=false" (contextmenu)="onRightClick($event)" style="position: relative; width: fit-content;">
|
||||
<div *ngIf="!loading" class="download-time"><mat-icon class="audio-video-icon">{{(file_obj.type === 'audio' || file_obj.isAudio) ? 'audiotrack' : 'movie'}}</mat-icon> {{file_obj.registered | date:'shortDate' : undefined : locale.ngID}}</div>
|
||||
<div *ngIf="!loading" class="download-time">
|
||||
<mat-icon class="audio-video-icon">{{(file_obj.type === 'audio' || file_obj.isAudio) ? 'audiotrack' : 'movie'}}</mat-icon>
|
||||
|
||||
<ng-container i18n="Auto-generated label" *ngIf="file_obj.auto">Auto-generated</ng-container>
|
||||
<ng-container *ngIf="!file_obj.auto">{{file_obj.registered | date:'shortDate' : undefined : locale.ngID}}</ng-container>
|
||||
</div>
|
||||
<div *ngIf="loading" class="download-time" style="width: 75%; margin-top: 5px;"><content-loader [primaryColor]="theme.ghost_primary" [secondaryColor]="theme.ghost_secondary" width="250" height="30"><svg:rect x="0" y="0" rx="3" ry="3" width="250" height="30" /></content-loader></div>
|
||||
<!-- The context menu trigger must be kept above the "more info" menu -->
|
||||
<div style="visibility: hidden; position: fixed"
|
||||
@@ -7,7 +12,7 @@
|
||||
[style.top]="contextMenuPosition.y"
|
||||
[matMenuTriggerFor]="context_menu">
|
||||
</div>
|
||||
<button [disabled]="loading" [matMenuTriggerFor]="action_menu" class="menuButton" mat-icon-button><mat-icon>more_vert</mat-icon></button>
|
||||
<button *ngIf="!file_obj || !file_obj.auto" [disabled]="loading" [matMenuTriggerFor]="action_menu" class="menuButton" mat-icon-button><mat-icon>more_vert</mat-icon></button>
|
||||
<mat-menu #context_menu>
|
||||
<ng-container *ngIf="!loading">
|
||||
<button (click)="navigateToFile($event)" mat-menu-item><mat-icon>open_in_browser</mat-icon><ng-container i18n="Open file button">Open file</ng-container></button>
|
||||
|
||||
@@ -111,6 +111,11 @@
|
||||
top: 1px;
|
||||
left: 5px;
|
||||
z-index: 99999;
|
||||
width: calc(100% - 8px);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.audio-video-icon {
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const CURRENT_VERSION = 'v4.1';
|
||||
export const CURRENT_VERSION = 'v4.2';
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
<h4 mat-dialog-title i18n="Edit subscription dialog title prefix">Editing</h4> {{sub.name}}
|
||||
<h4 mat-dialog-title><ng-container i18n="Edit subscription dialog title prefix">Editing</ng-container> {{sub.name}} <ng-container *ngIf="sub.paused" i18n="Paused suffix">(Paused)</ng-container></h4>
|
||||
|
||||
<mat-dialog-content>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12 mt-3">
|
||||
<mat-checkbox [(ngModel)]="new_sub.paused"><ng-container i18n="Paused subscription setting">Paused</ng-container></mat-checkbox>
|
||||
</div>
|
||||
<div class="col-12 mt-3">
|
||||
<mat-checkbox (change)="downloadAllToggled()" [(ngModel)]="download_all"><ng-container i18n="Download all uploads subscription setting">Download all uploads</ng-container></mat-checkbox>
|
||||
</div>
|
||||
@@ -31,7 +34,7 @@
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="col-12 mt-1">
|
||||
<div>
|
||||
<mat-checkbox [disabled]="new_sub.type === 'audio'" [(ngModel)]="new_sub.streamingOnly"><ng-container i18n="Streaming-only mode">Streaming-only mode</ng-container></mat-checkbox>
|
||||
</div>
|
||||
|
||||
@@ -61,9 +61,13 @@ export class EditSubscriptionDialogComponent implements OnInit {
|
||||
];
|
||||
|
||||
constructor(@Inject(MAT_DIALOG_DATA) public data: any, private dialog: MatDialog, private postsService: PostsService) {
|
||||
this.sub = this.data.sub;
|
||||
this.sub = JSON.parse(JSON.stringify(this.data.sub));
|
||||
this.new_sub = JSON.parse(JSON.stringify(this.sub));
|
||||
|
||||
// ignore videos to keep requests small
|
||||
delete this.sub['videos'];
|
||||
delete this.new_sub['videos'];
|
||||
|
||||
this.audioOnlyMode = this.sub.type === 'audio';
|
||||
this.download_all = !this.sub.timerange;
|
||||
|
||||
|
||||
@@ -8,14 +8,24 @@
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 10px; height: 40px;">
|
||||
<div style="float: left">
|
||||
<span *ngIf="reverse_order === false" i18n="Normal order">Normal order </span>
|
||||
<span *ngIf="reverse_order === true" i18n="Reverse order">Reverse order </span>
|
||||
<button (click)="togglePlaylistOrder()" mat-icon-button><mat-icon>{{!reverse_order ? 'arrow_downward' : 'arrow_upward'}}</mat-icon></button>
|
||||
</div>
|
||||
|
||||
<div style="float: right">
|
||||
<button [disabled]="available_files.length === 0" mat-stroked-button [matMenuTriggerFor]="menu"><ng-container i18n="Add content">Add content</ng-container></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Playlist order -->
|
||||
<mat-button-toggle-group class="media-list" cdkDropList (cdkDropListDropped)="drop($event)" style="width: 80%; left: 9%" vertical name="videoSelect" aria-label="Video Select" #group="matButtonToggleGroup">
|
||||
<mat-button-toggle class="media-box" cdkDrag *ngFor="let playlist_item of playlist.fileNames; let i = index" [checked]="false"><div><div class="playlist-item-text">{{playlist_item}}</div> <button (click)="removeContent(i)" class="remove-item-button" mat-icon-button><mat-icon>cancel</mat-icon></button></div></mat-button-toggle>
|
||||
<!-- The following for loop can be optimized but it requires a pipe https://stackoverflow.com/a/35703364/8088021 -->
|
||||
<mat-button-toggle class="media-box" cdkDrag *ngFor="let playlist_item of (reverse_order ? playlist.fileNames.slice().reverse() : playlist.fileNames); let i = index" [checked]="false"><div><div class="playlist-item-text">{{playlist_item}}</div> <button (click)="removeContent(i)" class="remove-item-button" mat-icon-button><mat-icon>cancel</mat-icon></button></div></mat-button-toggle>
|
||||
</mat-button-toggle-group>
|
||||
|
||||
<div class="add-content-button">
|
||||
<button [disabled]="available_files.length === 0" mat-stroked-button [matMenuTriggerFor]="menu"><ng-container i18n="Add more content">Add more content</ng-container></button>
|
||||
</div>
|
||||
|
||||
<mat-menu #menu="matMenu">
|
||||
<button *ngFor="let file of available_files" (click)="addContent(file)" mat-menu-item>{{file}}</button>
|
||||
</mat-menu>
|
||||
|
||||
@@ -30,11 +30,6 @@ border: none;
|
||||
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.add-content-button {
|
||||
margin-top: 15px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.remove-item-button {
|
||||
right: 10px;
|
||||
position: absolute;
|
||||
|
||||
@@ -15,6 +15,7 @@ export class ModifyPlaylistComponent implements OnInit {
|
||||
available_files = [];
|
||||
all_files = [];
|
||||
playlist_updated = false;
|
||||
reverse_order = false;
|
||||
|
||||
constructor(@Inject(MAT_DIALOG_DATA) public data: any,
|
||||
private postsService: PostsService,
|
||||
@@ -26,6 +27,8 @@ export class ModifyPlaylistComponent implements OnInit {
|
||||
this.original_playlist = JSON.parse(JSON.stringify(this.data.playlist));
|
||||
this.getFiles();
|
||||
}
|
||||
|
||||
this.reverse_order = localStorage.getItem('default_playlist_order_reversed') === 'true';
|
||||
}
|
||||
|
||||
getFiles() {
|
||||
@@ -72,11 +75,23 @@ export class ModifyPlaylistComponent implements OnInit {
|
||||
}
|
||||
|
||||
removeContent(index) {
|
||||
if (this.reverse_order) {
|
||||
index = this.playlist.fileNames.length - 1 - index;
|
||||
}
|
||||
this.playlist.fileNames.splice(index, 1);
|
||||
this.processFiles();
|
||||
}
|
||||
|
||||
togglePlaylistOrder() {
|
||||
this.reverse_order = !this.reverse_order;
|
||||
localStorage.setItem('default_playlist_order_reversed', '' + this.reverse_order);
|
||||
}
|
||||
|
||||
drop(event: CdkDragDrop<string[]>) {
|
||||
if (this.reverse_order) {
|
||||
event.previousIndex = this.playlist.fileNames.length - 1 - event.previousIndex;
|
||||
event.currentIndex = this.playlist.fileNames.length - 1 - event.currentIndex;
|
||||
}
|
||||
moveItemInArray(this.playlist.fileNames, event.previousIndex, event.currentIndex);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<h4 mat-dialog-title>{{sub.name}}</h4>
|
||||
<h4 mat-dialog-title>{{sub.name}} <ng-container *ngIf="sub.paused" i18n="Paused suffix">(Paused)</ng-container></h4>
|
||||
|
||||
<mat-dialog-content>
|
||||
<div class="info-item">
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
<div class="info-item-label"><strong><ng-container i18n="Video upload date property">Upload Date:</ng-container> </strong></div>
|
||||
<div class="info-item-value">{{file.upload_date ? file.upload_date : 'N/A'}}</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-item-label"><strong><ng-container i18n="Category property">Category:</ng-container> </strong></div>
|
||||
<div class="info-item-value"><ng-container *ngIf="file.category"><mat-chip-list><mat-chip>{{file.category.name}}</mat-chip></mat-chip-list></ng-container><ng-container *ngIf="!file.category">N/A</ng-container></div>
|
||||
</div>
|
||||
</mat-dialog-content>
|
||||
|
||||
<mat-dialog-actions>
|
||||
|
||||
34
src/app/http.interceptor.ts
Normal file
34
src/app/http.interceptor.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { Router } from '@angular/router';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
|
||||
@Injectable()
|
||||
export class H401Interceptor implements HttpInterceptor {
|
||||
|
||||
constructor(private router: Router, private snackBar: MatSnackBar) { }
|
||||
|
||||
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
|
||||
return next.handle(request).pipe(catchError(err => {
|
||||
if (err.status === 401) {
|
||||
localStorage.setItem('jwt_token', null);
|
||||
if (this.router.url !== '/login') {
|
||||
this.router.navigate(['/login']).then(() => {
|
||||
this.openSnackBar('Login expired, please login again.');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const error = err.error.message || err.statusText;
|
||||
return throwError(error);
|
||||
}));
|
||||
}
|
||||
|
||||
public openSnackBar(message: string, action: string = '') {
|
||||
this.snackBar.open(message, action, {
|
||||
duration: 2000,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -187,92 +187,3 @@
|
||||
<h4 style="text-align: center">Custom playlists</h4>
|
||||
<app-custom-playlists></app-custom-playlists>
|
||||
</ng-container>
|
||||
|
||||
<!--<div style="margin: 20px" *ngIf="fileManagerEnabled && (!postsService.isLoggedIn || postsService.permissions.includes('filemanager'))">
|
||||
<mat-accordion>
|
||||
<mat-expansion-panel (opened)="accordionOpened('audio')" (closed)="accordionClosed('audio')" (mouseleave)="accordionLeft('audio')" (mouseenter)="accordionEntered('audio')" class="big">
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
<ng-container i18n="Audio files title">
|
||||
Audio
|
||||
</ng-container>
|
||||
</mat-panel-title>
|
||||
<mat-panel-description>
|
||||
<ng-container i18n="Audio files description">
|
||||
Your audio files are here
|
||||
</ng-container>
|
||||
</mat-panel-description>
|
||||
</mat-expansion-panel-header>
|
||||
<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)" [file]="file" [title]="file.title" [name]="file.id" [uid]="file.uid" [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>
|
||||
</mat-grid-list>
|
||||
<mat-divider></mat-divider>
|
||||
<div style="width: 100%; text-align: center; margin-top: 10px;">
|
||||
<h6 i18n="Playlists title">Playlists</h6>
|
||||
</div>
|
||||
<mat-grid-list *ngIf="playlists.audio.length > 0" (window:resize)="onResize($event)" [cols]="files_cols" rowHeight="150px">
|
||||
<mat-grid-tile *ngFor="let playlist of playlists.audio; let i = index;">
|
||||
<app-file-card #audiofilecard (removeFile)="removePlaylistMp3(playlist.id, i)" [title]="playlist.name" [name]="playlist.id" [thumbnailURL]="playlist_thumbnails[playlist.id]"
|
||||
[length]="null" [isAudio]="true" [playlist]="playlist" [count]="playlist.fileNames.length" [use_youtubedl_archive]="use_youtubedl_archive"></app-file-card>
|
||||
<mat-progress-bar *ngIf="downloading_content['audio'][playlist.id]" class="download-progress-bar" mode="indeterminate"></mat-progress-bar>
|
||||
</mat-grid-tile>
|
||||
</mat-grid-list>
|
||||
<div class="add-playlist-button"><button (click)="openCreatePlaylistDialog('audio')" mat-fab><mat-icon>add</mat-icon></button></div>
|
||||
<div *ngIf="playlists.audio.length === 0">
|
||||
<ng-container i18n="No video playlists available text">
|
||||
No playlists available. Create one from your downloading audio files by clicking the blue plus button.
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</mat-expansion-panel>
|
||||
<mat-expansion-panel (opened)="accordionOpened('video')" (closed)="accordionClosed('video')" (mouseleave)="accordionLeft('video')" (mouseenter)="accordionEntered('video')" class="big">
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>
|
||||
<ng-container i18n="Video files title">
|
||||
Video
|
||||
</ng-container>
|
||||
</mat-panel-title>
|
||||
<mat-panel-description>
|
||||
<ng-container i18n="Video files description">
|
||||
Your video files are here
|
||||
</ng-container>
|
||||
</mat-panel-description>
|
||||
</mat-expansion-panel-header>
|
||||
<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)" [file]="file" [title]="file.title" [name]="file.id" [uid]="file.uid" [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>
|
||||
</mat-grid-list>
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
<div style="width: 100%; text-align: center; margin-top: 10px;">
|
||||
<h6 i18n="Playlists title">Playlists</h6>
|
||||
</div>
|
||||
<mat-grid-list *ngIf="playlists.video.length > 0" (window:resize)="onResize($event)" [cols]="files_cols" rowHeight="150px">
|
||||
<mat-grid-tile *ngFor="let playlist of playlists.video; let i = index;">
|
||||
<app-file-card #videofilecard (removeFile)="removePlaylistMp4(playlist.id, i)" [title]="playlist.name" [name]="playlist.id" [thumbnailURL]="playlist_thumbnails[playlist.id]"
|
||||
[length]="null" [isAudio]="false" [playlist]="playlist" [count]="playlist.fileNames.length" [use_youtubedl_archive]="use_youtubedl_archive"></app-file-card>
|
||||
<mat-progress-bar *ngIf="downloading_content['video'][playlist.id]" class="download-progress-bar" mode="indeterminate"></mat-progress-bar>
|
||||
</mat-grid-tile>
|
||||
</mat-grid-list>
|
||||
|
||||
<!-- Add video playlist button --<
|
||||
<div class="add-playlist-button"><button (click)="openCreatePlaylistDialog('video')" mat-fab><mat-icon>add</mat-icon></button></div>
|
||||
<div *ngIf="playlists.video.length === 0">
|
||||
<ng-container i18n="No video playlists available text">
|
||||
No playlists available. Create one from your downloading video files by clicking the blue plus button.
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</mat-expansion-panel>
|
||||
</mat-accordion>
|
||||
</div>-->
|
||||
@@ -8,7 +8,6 @@ import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { saveAs } from 'file-saver';
|
||||
import { YoutubeSearchService, Result } from '../youtube-search.service';
|
||||
import { Router, ActivatedRoute } from '@angular/router';
|
||||
import { CreatePlaylistComponent } from 'app/create-playlist/create-playlist.component';
|
||||
import { Platform } from '@angular/cdk/platform';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { ArgModifierDialogComponent } from 'app/dialogs/arg-modifier-dialog/arg-modifier-dialog.component';
|
||||
@@ -244,13 +243,6 @@ export class MainComponent implements OnInit {
|
||||
this.useDefaultDownloadingAgent = this.postsService.config['Advanced']['use_default_downloading_agent'];
|
||||
this.customDownloadingAgent = this.postsService.config['Advanced']['custom_downloading_agent'];
|
||||
|
||||
|
||||
|
||||
if (this.fileManagerEnabled) {
|
||||
this.getMp3s();
|
||||
this.getMp4s();
|
||||
}
|
||||
|
||||
if (this.youtubeSearchEnabled && this.youtubeAPIKey) {
|
||||
this.youtubeSearch.initializeAPI(this.youtubeAPIKey);
|
||||
this.attachToInput();
|
||||
@@ -335,61 +327,6 @@ export class MainComponent implements OnInit {
|
||||
this.setCols();
|
||||
}
|
||||
|
||||
// file manager stuff
|
||||
|
||||
getMp3s() {
|
||||
this.postsService.getMp3s().subscribe(result => {
|
||||
const mp3s = result['mp3s'];
|
||||
const playlists = result['playlists'];
|
||||
// if they are different
|
||||
if (JSON.stringify(this.mp3s) !== JSON.stringify(mp3s)) { this.mp3s = mp3s };
|
||||
this.playlists.audio = playlists;
|
||||
|
||||
// get thumbnail url by using first video. this is a temporary hack
|
||||
for (let i = 0; i < this.playlists.audio.length; i++) {
|
||||
const playlist = this.playlists.audio[i];
|
||||
let videoToExtractThumbnail = null;
|
||||
for (let j = 0; j < this.mp3s.length; j++) {
|
||||
if (this.mp3s[j].id === playlist.fileNames[0]) {
|
||||
// found the corresponding file
|
||||
videoToExtractThumbnail = this.mp3s[j];
|
||||
}
|
||||
}
|
||||
|
||||
if (videoToExtractThumbnail) { this.playlist_thumbnails[playlist.id] = videoToExtractThumbnail.thumbnailURL; }
|
||||
}
|
||||
}, error => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
getMp4s() {
|
||||
this.postsService.getMp4s().subscribe(result => {
|
||||
const mp4s = result['mp4s'];
|
||||
const playlists = result['playlists'];
|
||||
// if they are different
|
||||
if (JSON.stringify(this.mp4s) !== JSON.stringify(mp4s)) { this.mp4s = mp4s };
|
||||
this.playlists.video = playlists;
|
||||
|
||||
// get thumbnail url by using first video. this is a temporary hack
|
||||
for (let i = 0; i < this.playlists.video.length; i++) {
|
||||
const playlist = this.playlists.video[i];
|
||||
let videoToExtractThumbnail = null;
|
||||
for (let j = 0; j < this.mp4s.length; j++) {
|
||||
if (this.mp4s[j].id === playlist.fileNames[0]) {
|
||||
// found the corresponding file
|
||||
videoToExtractThumbnail = this.mp4s[j];
|
||||
}
|
||||
}
|
||||
|
||||
if (videoToExtractThumbnail) { this.playlist_thumbnails[playlist.id] = videoToExtractThumbnail.thumbnailURL; }
|
||||
}
|
||||
},
|
||||
error => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
public setCols() {
|
||||
if (window.innerWidth <= 350) {
|
||||
this.files_cols = 1;
|
||||
@@ -437,44 +374,6 @@ export class MainComponent implements OnInit {
|
||||
return null;
|
||||
}
|
||||
|
||||
public removeFromMp3(name: string) {
|
||||
for (let i = 0; i < this.mp3s.length; i++) {
|
||||
if (this.mp3s[i].id === name || this.mp3s[i].id + '.mp3' === name) {
|
||||
this.mp3s.splice(i, 1);
|
||||
}
|
||||
}
|
||||
this.getMp3s();
|
||||
}
|
||||
|
||||
public removePlaylistMp3(playlistID, index) {
|
||||
this.postsService.removePlaylist(playlistID, 'audio').subscribe(res => {
|
||||
if (res['success']) {
|
||||
this.playlists.audio.splice(index, 1);
|
||||
this.openSnackBar('Playlist successfully removed.', '');
|
||||
}
|
||||
this.getMp3s();
|
||||
});
|
||||
}
|
||||
|
||||
public removeFromMp4(name: string) {
|
||||
for (let i = 0; i < this.mp4s.length; i++) {
|
||||
if (this.mp4s[i].id === name || this.mp4s[i].id + '.mp4' === name) {
|
||||
this.mp4s.splice(i, 1);
|
||||
}
|
||||
}
|
||||
this.getMp4s();
|
||||
}
|
||||
|
||||
public removePlaylistMp4(playlistID, index) {
|
||||
this.postsService.removePlaylist(playlistID, 'video').subscribe(res => {
|
||||
if (res['success']) {
|
||||
this.playlists.video.splice(index, 1);
|
||||
this.openSnackBar('Playlist successfully removed.', '');
|
||||
}
|
||||
this.getMp4s();
|
||||
});
|
||||
}
|
||||
|
||||
// download helpers
|
||||
|
||||
downloadHelperMp3(name, uid, is_playlist = false, forceView = false, new_download = null, navigate_mode = false) {
|
||||
@@ -504,16 +403,6 @@ export class MainComponent implements OnInit {
|
||||
|
||||
// remove download from current downloads
|
||||
this.removeDownloadFromCurrentDownloads(new_download);
|
||||
|
||||
// reloads mp3s
|
||||
if (this.fileManagerEnabled) {
|
||||
this.getMp3s();
|
||||
setTimeout(() => {
|
||||
this.audioFileCards.forEach(filecard => {
|
||||
filecard.onHoverResponse();
|
||||
});
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
|
||||
downloadHelperMp4(name, uid, is_playlist = false, forceView = false, new_download = null, navigate_mode = false) {
|
||||
@@ -543,16 +432,6 @@ export class MainComponent implements OnInit {
|
||||
|
||||
// remove download from current downloads
|
||||
this.removeDownloadFromCurrentDownloads(new_download);
|
||||
|
||||
// reloads mp4s
|
||||
if (this.fileManagerEnabled) {
|
||||
this.getMp4s();
|
||||
setTimeout(() => {
|
||||
this.videoFileCards.forEach(filecard => {
|
||||
filecard.onHoverResponse();
|
||||
});
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
|
||||
// download click handler
|
||||
@@ -745,8 +624,6 @@ export class MainComponent implements OnInit {
|
||||
if (!this.fileManagerEnabled) {
|
||||
// tell server to delete the file once downloaded
|
||||
this.postsService.deleteFile(name, 'video').subscribe(delRes => {
|
||||
// reload mp3s
|
||||
this.getMp3s();
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -762,8 +639,6 @@ export class MainComponent implements OnInit {
|
||||
if (!this.fileManagerEnabled) {
|
||||
// tell server to delete the file once downloaded
|
||||
this.postsService.deleteFile(name, 'audio').subscribe(delRes => {
|
||||
// reload mp4s
|
||||
this.getMp4s();
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1110,25 +985,6 @@ export class MainComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
// creating a playlist
|
||||
openCreatePlaylistDialog(type) {
|
||||
const dialogRef = this.dialog.open(CreatePlaylistComponent, {
|
||||
data: {
|
||||
filesToSelectFrom: (type === 'audio') ? this.mp3s : this.mp4s,
|
||||
type: type
|
||||
}
|
||||
});
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
if (type === 'audio') { this.getMp3s() };
|
||||
if (type === 'video') { this.getMp4s() };
|
||||
this.openSnackBar('Successfully created playlist!', '');
|
||||
} else if (result === false) {
|
||||
this.openSnackBar('ERROR: failed to create playlist!', '');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// modify custom args
|
||||
openArgsModifierDialog() {
|
||||
const dialogRef = this.dialog.open(ArgModifierDialogComponent, {
|
||||
|
||||
@@ -37,10 +37,8 @@
|
||||
}
|
||||
|
||||
.spinner {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
bottom: 3px;
|
||||
left: 3px;
|
||||
bottom: 1px;
|
||||
left: 2px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,20 +8,49 @@
|
||||
</video>
|
||||
</vg-player>
|
||||
</div>
|
||||
<div *ngIf="db_file" style="height: fit-content; width: 100%; margin-top: 10px;">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-2 col-lg-1">
|
||||
<ng-container *ngIf="db_file">{{db_file['local_view_count'] ? db_file['local_view_count']+1 : 1}} <ng-container i18n="View count label">views</ng-container></ng-container>
|
||||
</div>
|
||||
<div style="white-space: pre-line;" class="col-8 col-lg-9">
|
||||
<ng-container *ngIf="db_file && db_file['description']">
|
||||
<p>
|
||||
<app-see-more [text]="db_file['description']"></app-see-more>
|
||||
</p>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="!db_file || !db_file['description']">
|
||||
<p style="text-align: center;">
|
||||
No description available.
|
||||
</p>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<ng-container *ngIf="playlist.length > 1">
|
||||
<button (click)="downloadContent()" [disabled]="downloading" mat-icon-button><mat-icon>save</mat-icon><mat-spinner *ngIf="downloading" class="spinner" [diameter]="35"></mat-spinner></button>
|
||||
<button *ngIf="!id" color="accent" (click)="namePlaylistDialog()" mat-icon-button><mat-icon>favorite</mat-icon></button>
|
||||
<button *ngIf="!is_shared && id && (!postsService.isLoggedIn || postsService.permissions.includes('sharing'))" (click)="openShareDialog()" mat-icon-button><mat-icon>share</mat-icon></button>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="playlist.length === 1">
|
||||
<button (click)="downloadFile()" [disabled]="downloading" mat-icon-button><mat-icon>save</mat-icon><mat-spinner *ngIf="downloading" class="spinner" [diameter]="35"></mat-spinner></button>
|
||||
<button *ngIf="!is_shared && uid && uid !== 'false' && type !== 'subscription' && (!postsService.isLoggedIn || postsService.permissions.includes('sharing'))" (click)="openShareDialog()" mat-icon-button><mat-icon>share</mat-icon></button>
|
||||
</ng-container>
|
||||
<button *ngIf="db_file && db_file.url.includes('twitch.tv/videos/') && postsService['config']['API']['use_twitch_API']" (click)="drawer.toggle()" mat-icon-button><mat-icon>chat</mat-icon></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: fit-content; width: 100%; margin-top: 10px;">
|
||||
<mat-button-toggle-group cdkDropList [cdkDropListSortingDisabled]="!id" (cdkDropListDropped)="drop($event)" style="width: 80%; left: 9%" vertical name="videoSelect" aria-label="Video Select" #group="matButtonToggleGroup">
|
||||
<mat-button-toggle cdkDrag *ngFor="let playlist_item of playlist; let i = index" [checked]="currentItem.title === playlist_item.title" (click)="onClickPlaylistItem(playlist_item, i)" class="toggle-button" [value]="playlist_item.title">{{playlist_item.label}}</mat-button-toggle>
|
||||
</mat-button-toggle-group>
|
||||
</div>
|
||||
<mat-drawer #drawer class="example-sidenav" mode="side" position="end" [opened]="db_file && db_file['chat_exists']">
|
||||
<mat-drawer #drawer class="example-sidenav" mode="side" position="end" [opened]="db_file && db_file['chat_exists'] && postsService['config']['API']['use_twitch_API']">
|
||||
<ng-container *ngIf="api_ready && db_file && db_file.url.includes('twitch.tv/videos/')">
|
||||
<app-twitch-chat #twitchchat [db_file]="db_file" [current_timestamp]="api.currentTime" [sub]="subscription"></app-twitch-chat>
|
||||
</ng-container>
|
||||
</mat-drawer>
|
||||
|
||||
<div *ngIf="db_file && db_file.url.includes('twitch.tv/videos/') && postsService['config']['API']['use_twitch_API']" style="position: absolute; right: 0px">
|
||||
<button style="right: 0px; top: -46px;" (click)="drawer.toggle()" mat-icon-button><mat-icon>chat</mat-icon></button>
|
||||
</div>
|
||||
|
||||
<div class="update-playlist-button-div" *ngIf="id && playlistChanged()">
|
||||
<div class="spinner-div">
|
||||
@@ -30,16 +59,6 @@
|
||||
<button color="primary" [disabled]="playlist_updating" (click)="updatePlaylist()" mat-raised-button><ng-container i18n="Playlist save changes button">Save changes</ng-container> <mat-icon>update</mat-icon></button>
|
||||
|
||||
</div>
|
||||
|
||||
<div *ngIf="playlist.length > 1">
|
||||
<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>
|
||||
<button *ngIf="!id" color="accent" class="favorite-button" color="primary" (click)="namePlaylistDialog()" mat-fab><mat-icon class="save-icon">favorite</mat-icon></button>
|
||||
<button *ngIf="!is_shared && id && (!postsService.isLoggedIn || postsService.permissions.includes('sharing'))" class="share-button" color="primary" (click)="openShareDialog()" mat-fab><mat-icon class="save-icon">share</mat-icon></button>
|
||||
</div>
|
||||
<div *ngIf="playlist.length === 1">
|
||||
<button class="save-button" color="primary" (click)="downloadFile()" [disabled]="downloading" mat-fab><mat-icon class="save-icon">save</mat-icon><mat-spinner *ngIf="downloading" class="spinner" [diameter]="50"></mat-spinner></button>
|
||||
<button *ngIf="!is_shared && uid && uid !== 'false' && type !== 'subscription' && (!postsService.isLoggedIn || postsService.permissions.includes('sharing'))" class="share-button" color="primary" (click)="openShareDialog()" mat-fab><mat-icon class="save-icon">share</mat-icon></button>
|
||||
</div>
|
||||
</mat-drawer-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -160,6 +160,10 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.openSnackBar('Failed to get file information from the server.', 'Dismiss');
|
||||
return;
|
||||
}
|
||||
this.postsService.incrementViewCount(this.db_file['uid'], null, this.uuid).subscribe(res => {}, err => {
|
||||
console.error('Failed to increment view count');
|
||||
console.error(err);
|
||||
});
|
||||
this.sharingEnabled = this.db_file.sharingEnabled;
|
||||
if (!this.fileNames) {
|
||||
// means it's a shared video
|
||||
@@ -186,6 +190,10 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
subscription.videos.forEach(video => {
|
||||
if (video['id'] === this.fileNames[0]) {
|
||||
this.db_file = video;
|
||||
this.postsService.incrementViewCount(this.db_file['uid'], this.subscription['id'], this.uuid).subscribe(res => {}, err => {
|
||||
console.error('Failed to increment view count');
|
||||
console.error(err);
|
||||
});
|
||||
this.show_player = true;
|
||||
this.parseFileNames();
|
||||
}
|
||||
@@ -199,6 +207,10 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
|
||||
getPlaylistFiles() {
|
||||
if (this.route.snapshot.paramMap.get('auto') === 'true') {
|
||||
this.show_player = true;
|
||||
return;
|
||||
}
|
||||
this.postsService.getPlaylist(this.id, null, this.uuid).subscribe(res => {
|
||||
if (res['playlist']) {
|
||||
this.db_playlist = res['playlist'];
|
||||
|
||||
@@ -286,6 +286,10 @@ export class PostsService implements CanActivate {
|
||||
return this.http.post(this.path + 'enableSharing', {uid: uid, type: type, is_playlist: is_playlist}, this.httpOptions);
|
||||
}
|
||||
|
||||
incrementViewCount(file_uid, sub_id, uuid) {
|
||||
return this.http.post(this.path + 'incrementViewCount', {file_uid: file_uid, sub_id: sub_id, uuid: uuid}, this.httpOptions);
|
||||
}
|
||||
|
||||
disableSharing(uid, type, is_playlist) {
|
||||
return this.http.post(this.path + 'disableSharing', {uid: uid, type: type, is_playlist: is_playlist}, this.httpOptions);
|
||||
}
|
||||
@@ -370,7 +374,7 @@ export class PostsService implements CanActivate {
|
||||
}
|
||||
|
||||
getAllSubscriptions() {
|
||||
return this.http.post(this.path + 'getAllSubscriptions', {}, this.httpOptions);
|
||||
return this.http.post(this.path + 'getSubscriptions', {}, this.httpOptions);
|
||||
}
|
||||
|
||||
// current downloads
|
||||
|
||||
@@ -53,12 +53,15 @@
|
||||
<mat-hint><ng-container i18n="Subscriptions base path setting input hint">Base path for videos from your subscribed channels and playlists. It is relative to YTDL-Material's root folder.</ng-container></mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-12 mt-5 mb-3">
|
||||
<div class="col-12 mt-4">
|
||||
<mat-form-field class="text-field" color="accent">
|
||||
<input [disabled]="!new_config['Subscriptions']['allow_subscriptions']" [(ngModel)]="new_config['Subscriptions']['subscriptions_check_interval']" matInput placeholder="Check interval" i18n-placeholder="Check interval input setting placeholder">
|
||||
<mat-hint><ng-container i18n="Check interval setting input hint">Unit is seconds, only include numbers.</ng-container></mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="col-12 mt-2 mb-3">
|
||||
<mat-checkbox color="accent" [(ngModel)]="new_config['Subscriptions']['redownload_fresh_uploads']" matTooltip="Sometimes new videos are downloaded before being fully processed. This setting will mean new videos will be checked for a higher quality version the following day." i18n-matTooltip="Redownload fresh uploads tooltip"><ng-container i18n="Redownload fresh uploads">Redownload fresh uploads</ng-container></mat-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
<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}}
|
||||
{{subscription.name}} <ng-container *ngIf="subscription.paused" i18n="Paused suffix">(Paused)</ng-container>
|
||||
</h2>
|
||||
<mat-progress-bar style="width: 80%; margin: 0 auto; margin-top: 15px;" *ngIf="subscription && subscription.downloading" mode="indeterminate"></mat-progress-bar>
|
||||
</div>
|
||||
<mat-divider style="width: 80%; margin: 0 auto"></mat-divider>
|
||||
<br/>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||
import { PostsService } from 'app/posts.services';
|
||||
import { ActivatedRoute, Router, ParamMap } from '@angular/router';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
@@ -9,7 +9,7 @@ import { EditSubscriptionDialogComponent } from 'app/dialogs/edit-subscription-d
|
||||
templateUrl: './subscription.component.html',
|
||||
styleUrls: ['./subscription.component.scss']
|
||||
})
|
||||
export class SubscriptionComponent implements OnInit {
|
||||
export class SubscriptionComponent implements OnInit, OnDestroy {
|
||||
|
||||
id = null;
|
||||
subscription = null;
|
||||
@@ -44,22 +44,11 @@ export class SubscriptionComponent implements OnInit {
|
||||
};
|
||||
filterProperty = this.filterProperties['upload_date'];
|
||||
downloading = false;
|
||||
|
||||
initialized = false;
|
||||
sub_interval = null;
|
||||
|
||||
constructor(private postsService: PostsService, private route: ActivatedRoute, private router: Router, private dialog: MatDialog) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.route.paramMap.subscribe((params: ParamMap) => {
|
||||
this.id = params.get('id');
|
||||
this.postsService.service_initialized.subscribe(init => {
|
||||
if (init) {
|
||||
this.initialized = true;
|
||||
this.getConfig();
|
||||
this.getSubscription();
|
||||
}
|
||||
});
|
||||
});
|
||||
if (this.route.snapshot.paramMap.get('id')) {
|
||||
this.id = this.route.snapshot.paramMap.get('id');
|
||||
|
||||
@@ -67,6 +56,7 @@ export class SubscriptionComponent implements OnInit {
|
||||
if (init) {
|
||||
this.getConfig();
|
||||
this.getSubscription();
|
||||
this.sub_interval = setInterval(() => this.getSubscription(true), 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -78,12 +68,25 @@ export class SubscriptionComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
// prevents subscription getter from running in the background
|
||||
if (this.sub_interval) {
|
||||
clearInterval(this.sub_interval);
|
||||
}
|
||||
}
|
||||
|
||||
goBack() {
|
||||
this.router.navigate(['/subscriptions']);
|
||||
}
|
||||
|
||||
getSubscription() {
|
||||
getSubscription(low_cost = false) {
|
||||
this.postsService.getSubscription(this.id).subscribe(res => {
|
||||
if (low_cost && res['subscription'].videos.length === this.subscription?.videos.length) {
|
||||
if (res['subscription']['downloading'] !== this.subscription['downloading']) {
|
||||
this.subscription['downloading'] = res['subscription']['downloading'];
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.subscription = res['subscription'];
|
||||
this.files = res['files'];
|
||||
if (this.search_mode) {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<mat-nav-list class="sub-nav-list">
|
||||
<mat-list-item *ngFor="let sub of channel_subscriptions">
|
||||
<a class="a-list-item" matLine (click)="goToSubscription(sub)" href="javascript:void(0)">
|
||||
<strong *ngIf="sub.name">{{ sub.name }}</strong>
|
||||
<strong *ngIf="sub.name">{{ sub.name }} <ng-container *ngIf="sub.paused" i18n="Paused suffix">(Paused)</ng-container></strong>
|
||||
<div *ngIf="!sub.name">
|
||||
<ng-container i18n="Subscription playlist not available text">Name not available. Channel retrieval in progress.</ng-container>
|
||||
</div>
|
||||
@@ -28,7 +28,7 @@
|
||||
<mat-nav-list class="sub-nav-list">
|
||||
<mat-list-item *ngFor="let sub of playlist_subscriptions">
|
||||
<a class="a-list-item" matLine (click)="goToSubscription(sub)" href="javascript:void(0)">
|
||||
<strong>{{ sub.name }}</strong>
|
||||
<strong>{{ sub.name }} <ng-container *ngIf="sub.paused" i18n="Paused suffix">(Paused)</ng-container></strong>
|
||||
<div class="content-loading-div" *ngIf="!sub.name">
|
||||
<ng-container i18n="Subscription playlist not available text">Name not available. Playlist retrieval in progress.</ng-container>
|
||||
</div>
|
||||
|
||||
@@ -26,7 +26,9 @@
|
||||
"use_API_key": false,
|
||||
"API_key": "",
|
||||
"use_youtube_API": false,
|
||||
"youtube_API_key": ""
|
||||
"youtube_API_key": "",
|
||||
"use_twitch_API": false,
|
||||
"twitch_API_key": ""
|
||||
},
|
||||
"Themes": {
|
||||
"default_theme": "default",
|
||||
@@ -57,7 +59,8 @@
|
||||
"allow_advanced_download": true,
|
||||
"jwt_expiration": 86400,
|
||||
"logger_level": "debug",
|
||||
"use_cookies": false
|
||||
"use_cookies": false,
|
||||
"default_downloader": "youtube-dlc"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user