mirror of
https://github.com/Tzahi12345/YoutubeDL-Material.git
synced 2026-04-14 21:51:29 +03:00
Fixed issue where selecting video quality would
Main component cleanup Removed deprecated file card component
This commit is contained in:
@@ -417,7 +417,7 @@ exports.generateArgs = async (url, type, options, user_uid = null, simulated = f
|
|||||||
downloadConfig = customArgs.split(',,');
|
downloadConfig = customArgs.split(',,');
|
||||||
} else {
|
} else {
|
||||||
if (customQualityConfiguration) {
|
if (customQualityConfiguration) {
|
||||||
qualityPath = ['-f', customQualityConfiguration];
|
qualityPath = ['-f', customQualityConfiguration, '--merge-output-format', 'mp4'];
|
||||||
} else if (selectedHeight && selectedHeight !== '' && !is_audio) {
|
} else if (selectedHeight && selectedHeight !== '' && !is_audio) {
|
||||||
qualityPath = ['-f', `'(mp4)[height=${selectedHeight}'`];
|
qualityPath = ['-f', `'(mp4)[height=${selectedHeight}'`];
|
||||||
} else if (is_audio) {
|
} else if (is_audio) {
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|||||||
import { AppComponent } from './app.component';
|
import { AppComponent } from './app.component';
|
||||||
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||||
import { PostsService } from 'app/posts.services';
|
import { PostsService } from 'app/posts.services';
|
||||||
import { FileCardComponent } from './file-card/file-card.component';
|
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
import { AppRoutingModule } from './app-routing.module';
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
import { MainComponent } from './main/main.component';
|
import { MainComponent } from './main/main.component';
|
||||||
@@ -98,7 +97,6 @@ export function isVisible({ event, element, scrollContainer, offset }: IsVisible
|
|||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent,
|
AppComponent,
|
||||||
FileCardComponent,
|
|
||||||
MainComponent,
|
MainComponent,
|
||||||
PlayerComponent,
|
PlayerComponent,
|
||||||
InputDialogComponent,
|
InputDialogComponent,
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
.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 {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.example-full-width-height {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%
|
|
||||||
}
|
|
||||||
|
|
||||||
.centered {
|
|
||||||
margin: 0 auto;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.img-div {
|
|
||||||
height: 60px;
|
|
||||||
padding: 0px;
|
|
||||||
margin: 8px 0px 0px -5px;
|
|
||||||
width: calc(100% + 5px + 5px);
|
|
||||||
overflow: hidden;
|
|
||||||
border-radius: 0px 0px 4px 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.max-two-lines {
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -moz-box;
|
|
||||||
max-height: 2.4em;
|
|
||||||
line-height: 1.2em;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-line-clamp: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.file-link {
|
|
||||||
width: 80%;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 576px){
|
|
||||||
|
|
||||||
.example-card {
|
|
||||||
width: 125px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
<mat-card class="example-card mat-elevation-z6">
|
|
||||||
<div style="padding:5px">
|
|
||||||
<div style="height: 52px;">
|
|
||||||
<div>
|
|
||||||
<b><a class="file-link" href="javascript:void(0)" (click)="!playlist ? mainComponent.goToFile(name, isAudio, uid) : mainComponent.goToPlaylist(name, type)">{{title}}</a></b>
|
|
||||||
</div>
|
|
||||||
<span class="max-two-lines"><ng-container i18n="File or playlist ID">ID:</ng-container> {{name}}</span>
|
|
||||||
<div *ngIf="playlist"><ng-container i18n="Playlist video count">Count:</ng-container> {{count}}</div>
|
|
||||||
</div>
|
|
||||||
<div *ngIf="!image_errored && thumbnailURL" class="img-div">
|
|
||||||
<img class="image" (error) ="onImgError($event)" [id]="type" [lazyLoad]="thumbnailURL" [customObservable]="scrollAndLoad" (onLoad)="imageLoaded($event)" alt="Thumbnail">
|
|
||||||
<span *ngIf="!image_loaded">
|
|
||||||
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button [matMenuTriggerFor]="playlist_menu" *ngIf="playlist" class="deleteButton" mat-icon-button><mat-icon>more_vert</mat-icon></button>
|
|
||||||
<mat-menu #playlist_menu="matMenu">
|
|
||||||
<button (click)="editPlaylistDialog()" mat-menu-item><mat-icon>edit</mat-icon><ng-container i18n="Playlist edit button">Edit</ng-container></button>
|
|
||||||
<button (click)="deleteFile()" mat-menu-item><mat-icon>delete_forever</mat-icon><ng-container i18n="Delete playlist">Delete</ng-container></button>
|
|
||||||
</mat-menu>
|
|
||||||
<button [matMenuTriggerFor]="action_menu" *ngIf="!playlist" 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 *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>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { FileCardComponent } from './file-card.component';
|
|
||||||
|
|
||||||
describe('FileCardComponent', () => {
|
|
||||||
let component: FileCardComponent;
|
|
||||||
let fixture: ComponentFixture<FileCardComponent>;
|
|
||||||
|
|
||||||
beforeEach(waitForAsync(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
declarations: [ FileCardComponent ]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fixture = TestBed.createComponent(FileCardComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
import { Component, OnInit, Input, Output } from '@angular/core';
|
|
||||||
import {PostsService} from '../posts.services';
|
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
|
||||||
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';
|
|
||||||
import { ModifyPlaylistComponent } from '../dialogs/modify-playlist/modify-playlist.component';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-file-card',
|
|
||||||
templateUrl: './file-card.component.html',
|
|
||||||
styleUrls: ['./file-card.component.css']
|
|
||||||
})
|
|
||||||
export class FileCardComponent implements OnInit {
|
|
||||||
@Input() file: any;
|
|
||||||
@Input() title: string;
|
|
||||||
@Input() length: string;
|
|
||||||
@Input() name: string;
|
|
||||||
@Input() uid: string;
|
|
||||||
@Input() thumbnailURL: string;
|
|
||||||
@Input() isAudio = true;
|
|
||||||
@Output() removeFile: EventEmitter<string> = new EventEmitter<string>();
|
|
||||||
@Input() playlist = null;
|
|
||||||
@Input() count = null;
|
|
||||||
@Input() use_youtubedl_archive = false;
|
|
||||||
type;
|
|
||||||
image_loaded = false;
|
|
||||||
image_errored = false;
|
|
||||||
|
|
||||||
scrollSubject;
|
|
||||||
scrollAndLoad;
|
|
||||||
|
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.type = this.isAudio ? 'audio' : 'video';
|
|
||||||
|
|
||||||
if (this.file && this.file.url && this.file.url.includes('youtu')) {
|
|
||||||
const string_id = (this.playlist ? '?list=' : '?v=')
|
|
||||||
const index_offset = (this.playlist ? 6 : 3);
|
|
||||||
const end_index = this.file.url.indexOf(string_id) + index_offset;
|
|
||||||
this.name = this.file.url.substring(end_index, this.file.url.length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteFile(blacklistMode = false) {
|
|
||||||
if (!this.playlist) {
|
|
||||||
this.postsService.deleteFile(this.uid, blacklistMode).subscribe(result => {
|
|
||||||
if (result) {
|
|
||||||
this.openSnackBar('Delete success!', 'OK.');
|
|
||||||
this.removeFile.emit(this.name);
|
|
||||||
} else {
|
|
||||||
this.openSnackBar('Delete failed!', 'OK.');
|
|
||||||
}
|
|
||||||
}, err => {
|
|
||||||
this.openSnackBar('Delete failed!', 'OK.');
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.removeFile.emit(this.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
openVideoInfoDialog() {
|
|
||||||
const dialogRef = this.dialog.open(VideoInfoDialogComponent, {
|
|
||||||
data: {
|
|
||||||
file: this.file,
|
|
||||||
},
|
|
||||||
minWidth: '50vw'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
editPlaylistDialog() {
|
|
||||||
const dialogRef = this.dialog.open(ModifyPlaylistComponent, {
|
|
||||||
data: {
|
|
||||||
playlist_id: this.playlist.id,
|
|
||||||
width: '65vw'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
dialogRef.afterClosed().subscribe(res => {
|
|
||||||
// updates playlist in file manager if it changed
|
|
||||||
if (dialogRef.componentInstance.playlist_updated) {
|
|
||||||
this.playlist = dialogRef.componentInstance.original_playlist;
|
|
||||||
this.title = this.playlist.name;
|
|
||||||
this.count = this.playlist.fileNames.length;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onImgError(event) {
|
|
||||||
this.image_errored = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
onHoverResponse() {
|
|
||||||
this.scrollSubject.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
imageLoaded(loaded) {
|
|
||||||
this.image_loaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public openSnackBar(message: string, action: string) {
|
|
||||||
this.snackBar.open(message, action, {
|
|
||||||
duration: 2000,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
Quality
|
Quality
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</mat-label>
|
</mat-label>
|
||||||
<mat-select [ngModelOptions]="{standalone: true}" [(ngModel)]="selectedQuality">
|
<mat-select [ngModelOptions]="{standalone: true}" [(ngModel)]="selectedQuality" (ngModelChange)="argsChanged($event)">
|
||||||
<mat-option [value]="''">
|
<mat-option [value]="''">
|
||||||
Max
|
Max
|
||||||
</mat-option>
|
</mat-option>
|
||||||
@@ -117,7 +117,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
<mat-form-field color="accent" style="margin-bottom: 42px;" class="advanced-input">
|
<mat-form-field color="accent" style="margin-bottom: 42px;" class="advanced-input">
|
||||||
<input [(ngModel)]="customArgs" [ngModelOptions]="{standalone: true}" [disabled]="!customArgsEnabled" matInput (ngModelChange)="argChanged()" placeholder="Custom args" i18n-placeholder="Custom args placeholder">
|
<input [(ngModel)]="customArgs" [ngModelOptions]="{standalone: true}" [disabled]="!customArgsEnabled" matInput (ngModelChange)="argsChanged()" placeholder="Custom args" i18n-placeholder="Custom args placeholder">
|
||||||
<mat-hint>
|
<mat-hint>
|
||||||
<ng-container i18n="Custom Args input hint">
|
<ng-container i18n="Custom Args input hint">
|
||||||
No need to include URL, just everything after. Args are delimited using two commas like so: ,,
|
No need to include URL, just everything after. Args are delimited using two commas like so: ,,
|
||||||
@@ -132,7 +132,7 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
<mat-form-field style="margin-bottom: 42px;" color="accent" class="advanced-input">
|
<mat-form-field style="margin-bottom: 42px;" color="accent" class="advanced-input">
|
||||||
<input [(ngModel)]="customOutput" [ngModelOptions]="{standalone: true}" [disabled]="!customOutputEnabled" matInput (ngModelChange)="argChanged()" placeholder="Custom output" i18n-placeholder="Custom output placeholder">
|
<input [(ngModel)]="customOutput" [ngModelOptions]="{standalone: true}" [disabled]="!customOutputEnabled" matInput (ngModelChange)="argsChanged()" placeholder="Custom output" i18n-placeholder="Custom output placeholder">
|
||||||
<mat-hint><a target="_blank" href="https://github.com/ytdl-org/youtube-dl/blob/master/README.md#output-template">
|
<mat-hint><a target="_blank" href="https://github.com/ytdl-org/youtube-dl/blob/master/README.md#output-template">
|
||||||
<ng-container i18n="Youtube-dl output template documentation link">Documentation</ng-container></a>.
|
<ng-container i18n="Youtube-dl output template documentation link">Documentation</ng-container></a>.
|
||||||
<ng-container i18n="Custom Output input hint">Path is relative to the config download path. Don't include extension.</ng-container>
|
<ng-container i18n="Custom Output input hint">Path is relative to the config download path. Don't include extension.</ng-container>
|
||||||
@@ -146,12 +146,12 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
<mat-form-field *ngIf="youtubeAuthEnabled" color="accent" class="advanced-input">
|
<mat-form-field *ngIf="youtubeAuthEnabled" color="accent" class="advanced-input">
|
||||||
<input [(ngModel)]="youtubeUsername" [ngModelOptions]="{standalone: true}" matInput (ngModelChange)="argChanged()" placeholder="Username" i18n-placeholder="YT Username placeholder">
|
<input [(ngModel)]="youtubeUsername" [ngModelOptions]="{standalone: true}" matInput (ngModelChange)="argsChanged()" placeholder="Username" i18n-placeholder="YT Username placeholder">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="!youtubeAuthDisabledOverride" class="col-12 col-sm-6 mt-3">
|
<div *ngIf="!youtubeAuthDisabledOverride" class="col-12 col-sm-6 mt-3">
|
||||||
<mat-form-field *ngIf="youtubeAuthEnabled" style="margin-top: 31px;" color="accent" class="advanced-input">
|
<mat-form-field *ngIf="youtubeAuthEnabled" style="margin-top: 31px;" color="accent" class="advanced-input">
|
||||||
<input [(ngModel)]="youtubePassword" type="password" [ngModelOptions]="{standalone: true}" matInput (ngModelChange)="argChanged()" placeholder="Password" i18n-placeholder="YT Password placeholder">
|
<input [(ngModel)]="youtubePassword" type="password" [ngModelOptions]="{standalone: true}" matInput (ngModelChange)="argsChanged()" placeholder="Password" i18n-placeholder="YT Password placeholder">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-sm-6 mt-3">
|
<div class="col-12 col-sm-6 mt-3">
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Component, OnInit, ElementRef, ViewChild, ViewChildren, QueryList } from '@angular/core';
|
import { Component, OnInit, ElementRef, ViewChild, ViewChildren, QueryList } from '@angular/core';
|
||||||
import {PostsService} from '../posts.services';
|
import {PostsService} from '../posts.services';
|
||||||
import {FileCardComponent} from '../file-card/file-card.component';
|
|
||||||
import { Observable, Subject } from 'rxjs';
|
import { Observable, Subject } from 'rxjs';
|
||||||
import {FormControl, Validators} from '@angular/forms';
|
import {FormControl, Validators} from '@angular/forms';
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
@@ -90,7 +89,6 @@ export class MainComponent implements OnInit {
|
|||||||
|
|
||||||
mp3s: any[] = [];
|
mp3s: any[] = [];
|
||||||
mp4s: any[] = [];
|
mp4s: any[] = [];
|
||||||
files_cols = null;
|
|
||||||
playlists = {'audio': [], 'video': []};
|
playlists = {'audio': [], 'video': []};
|
||||||
playlist_thumbnails = {};
|
playlist_thumbnails = {};
|
||||||
downloading_content = {'audio': {}, 'video': {}};
|
downloading_content = {'audio': {}, 'video': {}};
|
||||||
@@ -197,8 +195,6 @@ export class MainComponent implements OnInit {
|
|||||||
|
|
||||||
@ViewChild('urlinput', { read: ElementRef }) urlInput: ElementRef;
|
@ViewChild('urlinput', { read: ElementRef }) urlInput: ElementRef;
|
||||||
@ViewChild('recentVideos') recentVideos: RecentVideosComponent;
|
@ViewChild('recentVideos') recentVideos: RecentVideosComponent;
|
||||||
@ViewChildren('audiofilecard') audioFileCards: QueryList<FileCardComponent>;
|
|
||||||
@ViewChildren('videofilecard') videoFileCards: QueryList<FileCardComponent>;
|
|
||||||
last_valid_url = '';
|
last_valid_url = '';
|
||||||
last_url_check = 0;
|
last_url_check = 0;
|
||||||
|
|
||||||
@@ -220,14 +216,14 @@ export class MainComponent implements OnInit {
|
|||||||
this.audioOnly = false;
|
this.audioOnly = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async configLoad() {
|
async configLoad(): Promise<void> {
|
||||||
await this.loadConfig();
|
await this.loadConfig();
|
||||||
if (this.autoStartDownload) {
|
if (this.autoStartDownload) {
|
||||||
this.downloadClicked();
|
this.downloadClicked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadConfig() {
|
async loadConfig(): Promise<boolean> {
|
||||||
// loading config
|
// loading config
|
||||||
this.fileManagerEnabled = this.postsService.config['Extra']['file_manager_enabled']
|
this.fileManagerEnabled = this.postsService.config['Extra']['file_manager_enabled']
|
||||||
&& this.postsService.hasPermission('filemanager');
|
&& this.postsService.hasPermission('filemanager');
|
||||||
@@ -289,7 +285,7 @@ export class MainComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// app initialization.
|
// app initialization.
|
||||||
ngOnInit() {
|
ngOnInit(): void {
|
||||||
if (this.postsService.initialized) {
|
if (this.postsService.initialized) {
|
||||||
this.configLoad();
|
this.configLoad();
|
||||||
} else {
|
} else {
|
||||||
@@ -331,62 +327,17 @@ export class MainComponent implements OnInit {
|
|||||||
.subscribe((should_simulate) => {
|
.subscribe((should_simulate) => {
|
||||||
if (should_simulate) this.getSimulatedOutput();
|
if (should_simulate) this.getSimulatedOutput();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setCols();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit() {
|
ngAfterViewInit(): void {
|
||||||
if (this.youtubeSearchEnabled && this.youtubeAPIKey) {
|
if (this.youtubeSearchEnabled && this.youtubeAPIKey) {
|
||||||
this.youtubeSearch.initializeAPI(this.youtubeAPIKey);
|
this.youtubeSearch.initializeAPI(this.youtubeAPIKey);
|
||||||
this.attachToInput();
|
this.attachToInput();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public setCols() {
|
|
||||||
if (window.innerWidth <= 350) {
|
|
||||||
this.files_cols = 1;
|
|
||||||
} else if (window.innerWidth <= 500) {
|
|
||||||
this.files_cols = 2;
|
|
||||||
} else if (window.innerWidth <= 750) {
|
|
||||||
this.files_cols = 3
|
|
||||||
} else {
|
|
||||||
this.files_cols = 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public goToFile(container, isAudio, uid) {
|
|
||||||
this.downloadHelper(container, isAudio ? 'audio' : 'video', false, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public goToPlaylist(playlistID, type) {
|
|
||||||
const playlist = this.getPlaylistObjectByID(playlistID, type);
|
|
||||||
if (playlist) {
|
|
||||||
if (this.downloadOnlyMode) {
|
|
||||||
this.downloading_content[type][playlistID] = true;
|
|
||||||
this.downloadPlaylist(playlist);
|
|
||||||
} 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}]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// playlist not found
|
|
||||||
console.error(`Playlist with ID ${playlistID} not found!`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getPlaylistObjectByID(playlistID, type) {
|
|
||||||
for (let i = 0; i < this.playlists[type].length; i++) {
|
|
||||||
const playlist = this.playlists[type][i];
|
|
||||||
if (playlist.id === playlistID) {
|
|
||||||
return playlist;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// download helpers
|
// download helpers
|
||||||
downloadHelper(container, type, is_playlist = false, force_view = false, navigate_mode = false) {
|
downloadHelper(container, type: string, is_playlist = false, force_view = false, navigate_mode = false): void {
|
||||||
this.downloadingfile = false;
|
this.downloadingfile = false;
|
||||||
if (!this.autoplay && !this.downloadOnlyMode && !navigate_mode) {
|
if (!this.autoplay && !this.downloadOnlyMode && !navigate_mode) {
|
||||||
// do nothing
|
// do nothing
|
||||||
@@ -412,7 +363,7 @@ export class MainComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// download click handler
|
// download click handler
|
||||||
downloadClicked() {
|
downloadClicked(): void {
|
||||||
if (!this.ValidURL(this.url)) {
|
if (!this.ValidURL(this.url)) {
|
||||||
this.urlError = true;
|
this.urlError = true;
|
||||||
return;
|
return;
|
||||||
@@ -453,16 +404,19 @@ export class MainComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const selected_quality = this.selectedQuality;
|
||||||
|
this.selectedQuality = '';
|
||||||
|
|
||||||
this.downloadingfile = true;
|
this.downloadingfile = true;
|
||||||
this.postsService.downloadFile(this.url, type, (this.selectedQuality === '' ? null : this.selectedQuality),
|
this.postsService.downloadFile(this.url, type, (selected_quality === '' ? null : selected_quality),
|
||||||
customQualityConfiguration, customArgs, additionalArgs, customOutput, youtubeUsername, youtubePassword, cropFileSettings).subscribe(res => {
|
customQualityConfiguration, customArgs, additionalArgs, customOutput, youtubeUsername, youtubePassword, cropFileSettings).subscribe(res => {
|
||||||
this.current_download = res['download'];
|
this.current_download = res['download'];
|
||||||
this.downloads.push(res['download']);
|
this.downloads.push(res['download']);
|
||||||
this.download_uids.push(res['download']['uid']);
|
this.download_uids.push(res['download']['uid']);
|
||||||
}, error => { // can't access server
|
}, () => { // can't access server
|
||||||
this.downloadingfile = false;
|
this.downloadingfile = false;
|
||||||
this.current_download = null;
|
this.current_download = null;
|
||||||
this.openSnackBar('Download failed!', 'OK.');
|
this.postsService.openSnackBar('Download failed!', 'OK.');
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!this.autoplay) {
|
if (!this.autoplay) {
|
||||||
@@ -474,7 +428,7 @@ export class MainComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// download canceled handler
|
// download canceled handler
|
||||||
cancelDownload(download_to_cancel = null) {
|
cancelDownload(download_to_cancel = null): void {
|
||||||
// if one is provided, cancel that one. otherwise, remove the current one
|
// if one is provided, cancel that one. otherwise, remove the current one
|
||||||
if (download_to_cancel) {
|
if (download_to_cancel) {
|
||||||
this.removeDownloadFromCurrentDownloads(download_to_cancel)
|
this.removeDownloadFromCurrentDownloads(download_to_cancel)
|
||||||
@@ -485,33 +439,32 @@ export class MainComponent implements OnInit {
|
|||||||
this.current_download = null;
|
this.current_download = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
getSelectedAudioFormat() {
|
getSelectedAudioFormat(): string {
|
||||||
if (this.selectedQuality === '') { return null; }
|
if (this.selectedQuality === '') { return null; }
|
||||||
const cachedFormatsExists = this.cachedAvailableFormats[this.url] && this.cachedAvailableFormats[this.url]['formats'];
|
const cachedFormatsExists = this.cachedAvailableFormats[this.url] && this.cachedAvailableFormats[this.url]['formats'];
|
||||||
if (cachedFormatsExists) {
|
if (cachedFormatsExists) {
|
||||||
const audio_formats = this.cachedAvailableFormats[this.url]['formats']['audio'];
|
|
||||||
return this.selectedQuality['format_id'];
|
return this.selectedQuality['format_id'];
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getSelectedVideoFormat() {
|
getSelectedVideoFormat(): string {
|
||||||
if (this.selectedQuality === '') { return null; }
|
if (this.selectedQuality === '') { return null; }
|
||||||
const cachedFormats = this.cachedAvailableFormats[this.url] && this.cachedAvailableFormats[this.url]['formats'];
|
const cachedFormats = this.cachedAvailableFormats[this.url] && this.cachedAvailableFormats[this.url]['formats'];
|
||||||
if (cachedFormats) {
|
if (cachedFormats) {
|
||||||
const video_formats = cachedFormats['video'];
|
|
||||||
if (this.selectedQuality) {
|
if (this.selectedQuality) {
|
||||||
let selected_video_format = this.selectedQuality['format_id'];
|
let selected_video_format = this.selectedQuality['format_id'];
|
||||||
// add in audio format if necessary
|
// add in audio format if necessary
|
||||||
if (!this.selectedQuality['acodec'] && cachedFormats['best_audio_format']) selected_video_format += `+${cachedFormats['best_audio_format']}`;
|
const audio_missing = !this.selectedQuality['acodec'] || this.selectedQuality['acodec'] === 'none';
|
||||||
|
if (audio_missing && cachedFormats['best_audio_format']) selected_video_format += `+${cachedFormats['best_audio_format']}`;
|
||||||
return selected_video_format;
|
return selected_video_format;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
getDownloadByUID(uid) {
|
getDownloadByUID(uid: string) {
|
||||||
const index = this.downloads.findIndex(download => download.uid === uid);
|
const index = this.downloads.findIndex(download => download.uid === uid);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
return this.downloads[index];
|
return this.downloads[index];
|
||||||
@@ -520,7 +473,7 @@ export class MainComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeDownloadFromCurrentDownloads(download_to_remove) {
|
removeDownloadFromCurrentDownloads(download_to_remove): boolean {
|
||||||
if (this.current_download === download_to_remove) {
|
if (this.current_download === download_to_remove) {
|
||||||
this.current_download = null;
|
this.current_download = null;
|
||||||
}
|
}
|
||||||
@@ -533,7 +486,7 @@ export class MainComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadFileFromServer(file, type) {
|
downloadFileFromServer(file, type: string): void {
|
||||||
const ext = type === 'audio' ? 'mp3' : 'mp4'
|
const ext = type === 'audio' ? 'mp3' : 'mp4'
|
||||||
this.downloading_content[type][file.id] = true;
|
this.downloading_content[type][file.id] = true;
|
||||||
this.postsService.downloadFileFromServer(file.uid).subscribe(res => {
|
this.postsService.downloadFileFromServer(file.uid).subscribe(res => {
|
||||||
@@ -543,13 +496,12 @@ export class MainComponent implements OnInit {
|
|||||||
|
|
||||||
if (!this.fileManagerEnabled) {
|
if (!this.fileManagerEnabled) {
|
||||||
// tell server to delete the file once downloaded
|
// tell server to delete the file once downloaded
|
||||||
this.postsService.deleteFile(file.uid).subscribe(delRes => {
|
this.postsService.deleteFile(file.uid).subscribe(() => {});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadPlaylist(playlist) {
|
downloadPlaylist(playlist): void {
|
||||||
this.postsService.downloadPlaylistFromServer(playlist.id).subscribe(res => {
|
this.postsService.downloadPlaylistFromServer(playlist.id).subscribe(res => {
|
||||||
if (playlist.id) { this.downloading_content[playlist.type][playlist.id] = false };
|
if (playlist.id) { this.downloading_content[playlist.type][playlist.id] = false };
|
||||||
const blob: Blob = res;
|
const blob: Blob = res;
|
||||||
@@ -558,25 +510,25 @@ export class MainComponent implements OnInit {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clearInput() {
|
clearInput(): void {
|
||||||
this.url = '';
|
this.url = '';
|
||||||
this.results_showing = false;
|
this.results_showing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
onInputBlur() {
|
onInputBlur(): void {
|
||||||
this.results_showing = false;
|
this.results_showing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
visitURL(url) {
|
visitURL(url: string): void {
|
||||||
window.open(url);
|
window.open(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
useURL(url) {
|
useURL(url: string): void {
|
||||||
this.results_showing = false;
|
this.results_showing = false;
|
||||||
this.url = url;
|
this.url = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
inputChanged(new_val) {
|
inputChanged(new_val: string): void {
|
||||||
if (new_val === '' || !new_val) {
|
if (new_val === '' || !new_val) {
|
||||||
this.results_showing = false;
|
this.results_showing = false;
|
||||||
} else {
|
} else {
|
||||||
@@ -587,7 +539,7 @@ export class MainComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// checks if url is a valid URL
|
// checks if url is a valid URL
|
||||||
ValidURL(str) {
|
ValidURL(str: string): boolean {
|
||||||
// tslint:disable-next-line: max-line-length
|
// tslint:disable-next-line: max-line-length
|
||||||
const strRegex = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/;
|
const strRegex = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/;
|
||||||
const re = new RegExp(strRegex);
|
const re = new RegExp(strRegex);
|
||||||
@@ -603,21 +555,14 @@ export class MainComponent implements OnInit {
|
|||||||
if (str !== this.last_valid_url && this.allowQualitySelect) {
|
if (str !== this.last_valid_url && this.allowQualitySelect) {
|
||||||
// get info
|
// get info
|
||||||
this.getURLInfo(str);
|
this.getURLInfo(str);
|
||||||
this.argsChangedSubject.next(true);
|
this.argsChanged();
|
||||||
}
|
}
|
||||||
this.last_valid_url = str;
|
this.last_valid_url = str;
|
||||||
}
|
}
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
// snackbar helper
|
getURLInfo(url: string): void {
|
||||||
public openSnackBar(message: string, action: string) {
|
|
||||||
this.snackBar.open(message, action, {
|
|
||||||
duration: 2000,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getURLInfo(url) {
|
|
||||||
// if url is a youtube playlist, skip getting url info
|
// if url is a youtube playlist, skip getting url info
|
||||||
if (url.includes('playlist')) {
|
if (url.includes('playlist')) {
|
||||||
return;
|
return;
|
||||||
@@ -635,18 +580,14 @@ export class MainComponent implements OnInit {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.cachedAvailableFormats[url]['formats'] = this.getAudioAndVideoFormats(infos.formats);
|
this.cachedAvailableFormats[url]['formats'] = this.getAudioAndVideoFormats(infos.formats);
|
||||||
}, err => {
|
}, () => {
|
||||||
this.errorFormats(url);
|
this.errorFormats(url);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
argChanged(): void {
|
|
||||||
this.argsChangedSubject.next(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
getSimulatedOutput(): void {
|
getSimulatedOutput(): void {
|
||||||
// this function should be very similar to downloadFile()
|
// this function should be very similar to downloadClicked()
|
||||||
const customArgs = (this.customArgsEnabled && this.replaceArgs ? this.customArgs : null);
|
const customArgs = (this.customArgsEnabled && this.replaceArgs ? this.customArgs : null);
|
||||||
const additionalArgs = (this.customArgsEnabled && !this.replaceArgs ? this.customArgs : null);
|
const additionalArgs = (this.customArgsEnabled && !this.replaceArgs ? this.customArgs : null);
|
||||||
const customOutput = (this.customOutputEnabled ? this.customOutput : null);
|
const customOutput = (this.customOutputEnabled ? this.customOutput : null);
|
||||||
@@ -681,12 +622,12 @@ export class MainComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
errorFormats(url) {
|
errorFormats(url: string): void {
|
||||||
this.cachedAvailableFormats[url]['formats_loading'] = false;
|
this.cachedAvailableFormats[url]['formats_loading'] = false;
|
||||||
console.error('Could not load formats for url ' + url);
|
console.error('Could not load formats for url ' + url);
|
||||||
}
|
}
|
||||||
|
|
||||||
attachToInput() {
|
attachToInput(): void {
|
||||||
Observable.fromEvent(this.urlInput.nativeElement, 'keyup')
|
Observable.fromEvent(this.urlInput.nativeElement, 'keyup')
|
||||||
.map((e: any) => e.target.value) // extract the value of input
|
.map((e: any) => e.target.value) // extract the value of input
|
||||||
.filter((text: string) => text.length > 1) // filter out if empty
|
.filter((text: string) => text.length > 1) // filter out if empty
|
||||||
@@ -715,41 +656,41 @@ export class MainComponent implements OnInit {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
onResize(event) {
|
argsChanged(): void {
|
||||||
this.setCols();
|
|
||||||
}
|
|
||||||
|
|
||||||
videoModeChanged(new_val) {
|
|
||||||
this.selectedQuality = '';
|
|
||||||
localStorage.setItem('audioOnly', new_val.checked.toString());
|
|
||||||
this.argsChangedSubject.next(true);
|
this.argsChangedSubject.next(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
autoplayChanged(new_val) {
|
videoModeChanged(new_val): void {
|
||||||
|
this.selectedQuality = '';
|
||||||
|
localStorage.setItem('audioOnly', new_val.checked.toString());
|
||||||
|
this.argsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
autoplayChanged(new_val): void {
|
||||||
localStorage.setItem('autoplay', new_val.checked.toString());
|
localStorage.setItem('autoplay', new_val.checked.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
customArgsEnabledChanged(new_val) {
|
customArgsEnabledChanged(new_val): void {
|
||||||
localStorage.setItem('customArgsEnabled', new_val.checked.toString());
|
localStorage.setItem('customArgsEnabled', new_val.checked.toString());
|
||||||
this.argsChangedSubject.next(true);
|
this.argsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceArgsChanged(new_val) {
|
replaceArgsChanged(new_val): void {
|
||||||
localStorage.setItem('replaceArgs', new_val.checked.toString());
|
localStorage.setItem('replaceArgs', new_val.checked.toString());
|
||||||
this.argsChangedSubject.next(true);
|
this.argsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
customOutputEnabledChanged(new_val) {
|
customOutputEnabledChanged(new_val): void {
|
||||||
localStorage.setItem('customOutputEnabled', new_val.checked.toString());
|
localStorage.setItem('customOutputEnabled', new_val.checked.toString());
|
||||||
this.argsChangedSubject.next(true);
|
this.argsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
youtubeAuthEnabledChanged(new_val) {
|
youtubeAuthEnabledChanged(new_val): void {
|
||||||
localStorage.setItem('youtubeAuthEnabled', new_val.checked.toString());
|
localStorage.setItem('youtubeAuthEnabled', new_val.checked.toString());
|
||||||
this.argsChangedSubject.next(true);
|
this.argsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
getAudioAndVideoFormats(formats) {
|
getAudioAndVideoFormats(formats): void {
|
||||||
const audio_formats: any = {};
|
const audio_formats: any = {};
|
||||||
const video_formats: any = {};
|
const video_formats: any = {};
|
||||||
|
|
||||||
@@ -808,7 +749,7 @@ export class MainComponent implements OnInit {
|
|||||||
return parsed_formats;
|
return parsed_formats;
|
||||||
}
|
}
|
||||||
|
|
||||||
getBestAudioFormatForMp4(audio_formats) {
|
getBestAudioFormatForMp4(audio_formats): void {
|
||||||
let best_audio_format_for_mp4 = null;
|
let best_audio_format_for_mp4 = null;
|
||||||
let best_audio_format_bitrate = 0;
|
let best_audio_format_bitrate = 0;
|
||||||
const available_audio_format_keys = Object.keys(audio_formats);
|
const available_audio_format_keys = Object.keys(audio_formats);
|
||||||
@@ -824,46 +765,8 @@ export class MainComponent implements OnInit {
|
|||||||
return best_audio_format_for_mp4;
|
return best_audio_format_for_mp4;
|
||||||
}
|
}
|
||||||
|
|
||||||
accordionEntered(type) {
|
|
||||||
if (type === 'audio') {
|
|
||||||
audioFilesMouseHovering = true;
|
|
||||||
this.audioFileCards.forEach(filecard => {
|
|
||||||
filecard.onHoverResponse();
|
|
||||||
});
|
|
||||||
} else if (type === 'video') {
|
|
||||||
videoFilesMouseHovering = true;
|
|
||||||
this.videoFileCards.forEach(filecard => {
|
|
||||||
filecard.onHoverResponse();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
accordionLeft(type) {
|
|
||||||
if (type === 'audio') {
|
|
||||||
audioFilesMouseHovering = false;
|
|
||||||
} else if (type === 'video') {
|
|
||||||
videoFilesMouseHovering = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
accordionOpened(type) {
|
|
||||||
if (type === 'audio') {
|
|
||||||
audioFilesOpened = true;
|
|
||||||
} else if (type === 'video') {
|
|
||||||
videoFilesOpened = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
accordionClosed(type) {
|
|
||||||
if (type === 'audio') {
|
|
||||||
audioFilesOpened = false;
|
|
||||||
} else if (type === 'video') {
|
|
||||||
videoFilesOpened = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// modify custom args
|
// modify custom args
|
||||||
openArgsModifierDialog() {
|
openArgsModifierDialog(): void {
|
||||||
const dialogRef = this.dialog.open(ArgModifierDialogComponent, {
|
const dialogRef = this.dialog.open(ArgModifierDialogComponent, {
|
||||||
data: {
|
data: {
|
||||||
initial_args: this.customArgs
|
initial_args: this.customArgs
|
||||||
@@ -876,7 +779,7 @@ export class MainComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentDownload() {
|
getCurrentDownload(): void {
|
||||||
if (!this.current_download) {
|
if (!this.current_download) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -893,7 +796,7 @@ export class MainComponent implements OnInit {
|
|||||||
} else if (this.current_download['finished'] && this.current_download['error']) {
|
} else if (this.current_download['finished'] && this.current_download['error']) {
|
||||||
this.downloadingfile = false;
|
this.downloadingfile = false;
|
||||||
this.current_download = null;
|
this.current_download = null;
|
||||||
this.openSnackBar('Download failed!', 'OK.');
|
this.postsService.openSnackBar('Download failed!', 'OK.');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// console.log('failed to get new download');
|
// console.log('failed to get new download');
|
||||||
@@ -901,7 +804,7 @@ export class MainComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
reloadRecentVideos() {
|
reloadRecentVideos(): void {
|
||||||
this.postsService.files_changed.next(true);
|
this.postsService.files_changed.next(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user