mirror of
https://github.com/Tzahi12345/YoutubeDL-Material.git
synced 2026-03-07 20:10:03 +03:00
Added ability to modify file metadata
This commit is contained in:
@@ -129,6 +129,27 @@ paths:
|
||||
description: User is not authorized to view the file.
|
||||
security:
|
||||
- Auth query parameter: []
|
||||
/api/updateFile:
|
||||
post:
|
||||
tags:
|
||||
- files
|
||||
summary: Updates file database object
|
||||
description: Updates a file db object using its uid and a change object.
|
||||
operationId: post-updateFile
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UpdateFileRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SuccessObject'
|
||||
security:
|
||||
- Auth query parameter: []
|
||||
/api/enableSharing:
|
||||
post:
|
||||
tags:
|
||||
@@ -1509,6 +1530,8 @@ components:
|
||||
properties:
|
||||
success:
|
||||
type: boolean
|
||||
error:
|
||||
type: string
|
||||
FileType:
|
||||
type: string
|
||||
enum:
|
||||
@@ -1738,6 +1761,18 @@ components:
|
||||
type: boolean
|
||||
file:
|
||||
$ref: '#/components/schemas/DatabaseFile'
|
||||
UpdateFileRequest:
|
||||
required:
|
||||
- uid
|
||||
- change_obj
|
||||
type: object
|
||||
properties:
|
||||
uid:
|
||||
type: string
|
||||
description: Video UID
|
||||
change_obj:
|
||||
type: object
|
||||
description: Object with fields to update as keys and their new values
|
||||
SharingToggle:
|
||||
required:
|
||||
- uid
|
||||
@@ -2321,6 +2356,9 @@ components:
|
||||
type: string
|
||||
thumbnailURL:
|
||||
type: string
|
||||
description: Backup if thumbnailPath is not defined
|
||||
thumbnailPath:
|
||||
type: string
|
||||
isAudio:
|
||||
type: boolean
|
||||
duration:
|
||||
@@ -2332,6 +2370,7 @@ components:
|
||||
type: string
|
||||
size:
|
||||
type: number
|
||||
description: In bytes
|
||||
path:
|
||||
type: string
|
||||
upload_date:
|
||||
@@ -2340,6 +2379,12 @@ components:
|
||||
type: string
|
||||
sharingEnabled:
|
||||
type: boolean
|
||||
category:
|
||||
$ref: '#/components/schemas/Category'
|
||||
view_count:
|
||||
type: number
|
||||
local_view_count:
|
||||
type: number
|
||||
Playlist:
|
||||
required:
|
||||
- uids
|
||||
@@ -2369,6 +2414,8 @@ components:
|
||||
type: number
|
||||
user_uid:
|
||||
type: string
|
||||
auto:
|
||||
type: boolean
|
||||
Download:
|
||||
required:
|
||||
- url
|
||||
|
||||
@@ -950,6 +950,24 @@ app.post('/api/getAllFiles', optionalJwt, async function (req, res) {
|
||||
});
|
||||
});
|
||||
|
||||
app.post('/api/updateFile', optionalJwt, async function (req, res) {
|
||||
const uid = req.body.uid;
|
||||
const change_obj = req.body.change_obj;
|
||||
|
||||
const file = await db_api.updateRecord('files', {uid: uid}, change_obj);
|
||||
|
||||
if (!file) {
|
||||
res.send({
|
||||
success: false,
|
||||
error: 'File could not be found'
|
||||
});
|
||||
} else {
|
||||
res.send({
|
||||
success: true
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/checkConcurrentStream', async (req, res) => {
|
||||
const uid = req.body.uid;
|
||||
|
||||
|
||||
@@ -100,6 +100,7 @@ export type { UpdateCategoriesRequest } from './models/UpdateCategoriesRequest';
|
||||
export type { UpdateCategoryRequest } from './models/UpdateCategoryRequest';
|
||||
export type { UpdateConcurrentStreamRequest } from './models/UpdateConcurrentStreamRequest';
|
||||
export type { UpdateConcurrentStreamResponse } from './models/UpdateConcurrentStreamResponse';
|
||||
export type { UpdateFileRequest } from './models/UpdateFileRequest';
|
||||
export type { UpdatePlaylistRequest } from './models/UpdatePlaylistRequest';
|
||||
export type { UpdaterStatus } from './models/UpdaterStatus';
|
||||
export type { UpdateServerRequest } from './models/UpdateServerRequest';
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import type { Category } from './Category';
|
||||
|
||||
export type DatabaseFile = {
|
||||
id: string;
|
||||
title: string;
|
||||
/**
|
||||
* Backup if thumbnailPath is not defined
|
||||
*/
|
||||
thumbnailURL: string;
|
||||
thumbnailPath?: string;
|
||||
isAudio: boolean;
|
||||
/**
|
||||
* In seconds
|
||||
@@ -13,9 +19,15 @@ export type DatabaseFile = {
|
||||
duration: number;
|
||||
url: string;
|
||||
uploader: string;
|
||||
/**
|
||||
* In bytes
|
||||
*/
|
||||
size: number;
|
||||
path: string;
|
||||
upload_date: string;
|
||||
uid: string;
|
||||
sharingEnabled?: boolean;
|
||||
category?: Category;
|
||||
view_count?: number;
|
||||
local_view_count?: number;
|
||||
};
|
||||
@@ -4,4 +4,5 @@
|
||||
|
||||
export type SuccessObject = {
|
||||
success: boolean;
|
||||
error?: string;
|
||||
};
|
||||
14
src/api-types/models/UpdateFileRequest.ts
Normal file
14
src/api-types/models/UpdateFileRequest.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
export type UpdateFileRequest = {
|
||||
/**
|
||||
* Video UID
|
||||
*/
|
||||
uid: string;
|
||||
/**
|
||||
* Object with fields to update as keys and their new values
|
||||
*/
|
||||
change_obj: any;
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { NgModule, LOCALE_ID } from '@angular/core';
|
||||
import { registerLocaleData, CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { registerLocaleData, CommonModule, DatePipe } from '@angular/common';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
@@ -189,7 +189,8 @@ registerLocaleData(es, 'es');
|
||||
],
|
||||
providers: [
|
||||
PostsService,
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: H401Interceptor, multi: true }
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: H401Interceptor, multi: true },
|
||||
DatePipe
|
||||
],
|
||||
exports: [
|
||||
HighlightPipe,
|
||||
|
||||
@@ -1,36 +1,64 @@
|
||||
<h4 mat-dialog-title>{{file.title}}</h4>
|
||||
|
||||
<mat-dialog-content>
|
||||
<div class="info-item">
|
||||
<div class="info-item-label"><strong><ng-container i18n="Video name property">Name:</ng-container> </strong></div>
|
||||
<div class="info-item-value">{{file.title}}</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-item-label"><strong><ng-container i18n="Video URL property">URL:</ng-container> </strong></div>
|
||||
<div class="info-item-value"><a target="_blank" [href]="file.url">{{file.url}}</a></div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-item-label"><strong><ng-container i18n="Video ID property">Uploader:</ng-container> </strong></div>
|
||||
<div class="info-item-value">{{file.uploader ? file.uploader : 'N/A'}}</div>
|
||||
<div style="width: 100%; position: relative;">
|
||||
<button style="position: absolute; right: 16px; top: 8px;" mat-icon-button (click)="editing = !editing"><mat-icon>edit</mat-icon></button>
|
||||
</div>
|
||||
<mat-form-field class="info-field">
|
||||
<input [(ngModel)]="new_file.title" matInput placeholder="Name" i18n-placeholder="Name" [disabled]="!editing">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="info-field">
|
||||
<input [(ngModel)]="new_file.url" matInput placeholder="URL" i18n-placeholder="URL" [disabled]="!editing">
|
||||
<button mat-icon-button matSuffix (click)="window.open(new_file.url, '_blank')">
|
||||
<mat-icon>link</mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="info-field">
|
||||
<input [(ngModel)]="new_file.uploader" matInput placeholder="Uploader" i18n-placeholder="Uploader" [disabled]="!editing">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="info-field">
|
||||
<mat-label i18n="Upload date">Upload date</mat-label>
|
||||
<input [value]="upload_date" matInput [matDatepicker]="picker" (dateChange)="uploadDateChanged($event)" [disabled]="!editing">
|
||||
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
|
||||
<mat-datepicker #picker></mat-datepicker>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="info-field">
|
||||
<input [(ngModel)]="new_file.thumbnailPath" matInput placeholder="Thumbnail path" i18n-placeholder="Thumbnail path" [disabled]="!editing">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="info-field">
|
||||
<input [(ngModel)]="new_file.thumbnailURL" matInput placeholder="Thumbnail URL" i18n-placeholder="Thumbnail URL" [disabled]="!editing || new_file.thumbnailPath">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="info-field">
|
||||
<mat-select placeholder="Category" i18n-placeholder="Category" [value]="category" (valueChange)="categoryChanged($event)" [compareWith]="categoryComparisonFunction" [disabled]="!editing">
|
||||
<mat-option [value]="{}">
|
||||
N/A
|
||||
</mat-option>
|
||||
<mat-option *ngFor="let available_category of postsService.categories | keyvalue" [value]="available_category">
|
||||
{{available_category.value.name}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="info-field">
|
||||
<input type="number" [(ngModel)]="new_file.view_count" matInput placeholder="View count" i18n-placeholder="View count" [disabled]="!editing">
|
||||
</mat-form-field>
|
||||
<mat-form-field class="info-field">
|
||||
<input type="number" [(ngModel)]="new_file.local_view_count" matInput placeholder="Local view count" i18n-placeholder="Local view count" [disabled]="!editing">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-divider style="margin-bottom: 16px;"></mat-divider>
|
||||
|
||||
<div class="info-item">
|
||||
<div class="info-item-label"><strong><ng-container i18n="Video file size property">File size:</ng-container> </strong></div>
|
||||
<div class="info-item-value">{{file.size ? filesize(file.size) : 'N/A'}}</div>
|
||||
<div class="info-item-value">{{new_file.size ? filesize(new_file.size) : 'N/A'}}</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<div class="info-item-label"><strong><ng-container i18n="Video path property">Path:</ng-container> </strong></div>
|
||||
<div class="info-item-value">{{file.path ? file.path : 'N/A'}}</div>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<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 class="info-item-value">{{new_file.path ? new_file.path : 'N/A'}}</div>
|
||||
</div>
|
||||
|
||||
</mat-dialog-content>
|
||||
|
||||
<mat-dialog-actions>
|
||||
<button mat-button mat-dialog-close><ng-container i18n="Close subscription info button">Close</ng-container></button>
|
||||
<button mat-button mat-dialog-close><ng-container i18n="Close video info button">Close</ng-container></button>
|
||||
<button mat-button [disabled]="!metadataChanged()" (click)="saveChanges()"><ng-container i18n="Save video info button">Save</ng-container></button>
|
||||
</mat-dialog-actions>
|
||||
@@ -17,6 +17,10 @@
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.info-field {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.a-wrap {
|
||||
word-wrap: break-word
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
import { Component, OnInit, Inject } from '@angular/core';
|
||||
import filesize from 'filesize';
|
||||
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { PostsService } from 'app/posts.services';
|
||||
import { Category, DatabaseFile } from 'api-types';
|
||||
import { DatePipe } from '@angular/common';
|
||||
|
||||
@Component({
|
||||
selector: 'app-video-info-dialog',
|
||||
@@ -8,15 +11,75 @@ import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
styleUrls: ['./video-info-dialog.component.scss']
|
||||
})
|
||||
export class VideoInfoDialogComponent implements OnInit {
|
||||
file: any;
|
||||
file: DatabaseFile;
|
||||
new_file: DatabaseFile;
|
||||
filesize;
|
||||
constructor(@Inject(MAT_DIALOG_DATA) public data: any) { }
|
||||
window = window;
|
||||
upload_date: Date;
|
||||
category: Category;
|
||||
editing = false;
|
||||
|
||||
constructor(@Inject(MAT_DIALOG_DATA) public data: any, public postsService: PostsService, private datePipe: DatePipe) { }
|
||||
|
||||
ngOnInit(): void {
|
||||
this.filesize = filesize;
|
||||
if (this.data) {
|
||||
this.file = this.data.file;
|
||||
this.initializeFile(this.data.file);
|
||||
}
|
||||
this.postsService.reloadCategories();
|
||||
}
|
||||
|
||||
initializeFile(file: DatabaseFile): void {
|
||||
this.file = file;
|
||||
this.new_file = JSON.parse(JSON.stringify(file));
|
||||
|
||||
// use UTC for the date picker. not the cleanest approach but it allows it to match the upload date
|
||||
this.upload_date = new Date(this.new_file.upload_date);
|
||||
this.upload_date.setMinutes( this.upload_date.getMinutes() + this.upload_date.getTimezoneOffset() );
|
||||
|
||||
this.category = this.file.category ? this.category : {};
|
||||
|
||||
// we need to align whether missing category is null or undefined. this line helps with that.
|
||||
if (!this.file.category) { this.new_file.category = null; this.file.category = null; }
|
||||
}
|
||||
|
||||
saveChanges(): void {
|
||||
const change_obj = {};
|
||||
const keys = Object.keys(this.file);
|
||||
keys.forEach(key => {
|
||||
if (this.file[key] !== this.new_file[key]) change_obj[key] = this.new_file[key];
|
||||
});
|
||||
|
||||
this.postsService.updateFile(this.file.uid, change_obj).subscribe(res => {
|
||||
this.getFile();
|
||||
});
|
||||
}
|
||||
|
||||
getFile(): void {
|
||||
this.postsService.getFile(this.file.uid).subscribe(res => {
|
||||
this.file = res['file'];
|
||||
this.initializeFile(this.file);
|
||||
});
|
||||
}
|
||||
|
||||
uploadDateChanged(event): void {
|
||||
this.new_file.upload_date = this.datePipe.transform(event.value, 'yyyy-MM-dd');
|
||||
}
|
||||
|
||||
categoryChanged(event): void {
|
||||
this.new_file.category = Object.keys(event).length ? {uid: event.uid, name: event.name} : null;
|
||||
}
|
||||
|
||||
categoryComparisonFunction(option: Category, value: Category): boolean {
|
||||
// can't access properties of null/undefined values, prehandle these
|
||||
if (!option && !value) return true;
|
||||
else if (!option || !value) return false;
|
||||
|
||||
return option.uid === value.uid;
|
||||
}
|
||||
|
||||
metadataChanged(): boolean {
|
||||
return JSON.stringify(this.file) !== JSON.stringify(this.new_file);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
@ViewChild('twitchchat') twitchChat: TwitchChatComponent;
|
||||
|
||||
@HostListener('window:resize', ['$event'])
|
||||
onResize(event) {
|
||||
onResize(): void {
|
||||
this.innerWidth = window.innerWidth;
|
||||
}
|
||||
|
||||
@@ -98,12 +98,12 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
ngAfterViewInit(): void {
|
||||
this.cdr.detectChanges();
|
||||
this.postsService.sidenav.close();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
ngOnDestroy(): void {
|
||||
// prevents volume save feature from running in the background
|
||||
clearInterval(this.save_volume_timer);
|
||||
}
|
||||
@@ -112,7 +112,7 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
public snackBar: MatSnackBar, private cdr: ChangeDetectorRef) {
|
||||
|
||||
}
|
||||
processConfig() {
|
||||
processConfig(): void {
|
||||
this.baseStreamPath = this.postsService.path;
|
||||
this.audioFolderPath = this.postsService.config['Downloader']['path-audio'];
|
||||
this.videoFolderPath = this.postsService.config['Downloader']['path-video'];
|
||||
@@ -143,14 +143,14 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
getFile() {
|
||||
this.postsService.getFile(this.uid, null, this.uuid).subscribe(res => {
|
||||
getFile(): void {
|
||||
this.postsService.getFile(this.uid, this.uuid).subscribe(res => {
|
||||
this.db_file = res['file'];
|
||||
if (!this.db_file) {
|
||||
this.openSnackBar('Failed to get file information from the server.', 'Dismiss');
|
||||
this.postsService.openSnackBar('Failed to get file information from the server.', 'Dismiss');
|
||||
return;
|
||||
}
|
||||
this.postsService.incrementViewCount(this.db_file['uid'], null, this.uuid).subscribe(res => {}, err => {
|
||||
this.postsService.incrementViewCount(this.db_file['uid'], null, this.uuid).subscribe(() => undefined, err => {
|
||||
console.error('Failed to increment view count');
|
||||
console.error(err);
|
||||
});
|
||||
@@ -161,19 +161,19 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
getSubscription() {
|
||||
getSubscription(): void {
|
||||
this.postsService.getSubscription(this.sub_id).subscribe(res => {
|
||||
const subscription = res['subscription'];
|
||||
this.subscription = subscription;
|
||||
this.type === this.subscription.type;
|
||||
this.uids = this.subscription.videos.map(video => video['uid']);
|
||||
this.parseFileNames();
|
||||
}, err => {
|
||||
this.openSnackBar(`Failed to find subscription ${this.sub_id}`, 'Dismiss');
|
||||
}, () => {
|
||||
this.postsService.openSnackBar(`Failed to find subscription ${this.sub_id}`, 'Dismiss');
|
||||
});
|
||||
}
|
||||
|
||||
getPlaylistFiles() {
|
||||
getPlaylistFiles(): void {
|
||||
this.postsService.getPlaylist(this.playlist_id, this.uuid, true).subscribe(res => {
|
||||
if (res['playlist']) {
|
||||
this.db_playlist = res['playlist'];
|
||||
@@ -183,14 +183,14 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.show_player = true;
|
||||
this.parseFileNames();
|
||||
} else {
|
||||
this.openSnackBar('Failed to load playlist!', '');
|
||||
this.postsService.openSnackBar('Failed to load playlist!', '');
|
||||
}
|
||||
}, err => {
|
||||
this.openSnackBar('Failed to load playlist!', '');
|
||||
}, () => {
|
||||
this.postsService.openSnackBar('Failed to load playlist!', '');
|
||||
});
|
||||
}
|
||||
|
||||
parseFileNames() {
|
||||
parseFileNames(): void {
|
||||
this.playlist = [];
|
||||
for (let i = 0; i < this.uids.length; i++) {
|
||||
let file_obj = null;
|
||||
@@ -204,7 +204,7 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
|
||||
const mime_type = file_obj.isAudio ? 'audio/mp3' : 'video/mp4'
|
||||
|
||||
let baseLocation = 'stream/';
|
||||
const baseLocation = 'stream/';
|
||||
let fullLocation = this.baseStreamPath + baseLocation + `?test=test&uid=${file_obj['uid']}`;
|
||||
|
||||
if (this.postsService.isLoggedIn) {
|
||||
@@ -238,7 +238,7 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.show_player = true;
|
||||
}
|
||||
|
||||
onPlayerReady(api: VgApiService) {
|
||||
onPlayerReady(api: VgApiService): void {
|
||||
this.api = api;
|
||||
this.api_ready = true;
|
||||
this.cdr.detectChanges();
|
||||
@@ -258,14 +258,14 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
saveVolume(api) {
|
||||
saveVolume(api: VgApiService): void {
|
||||
if (this.original_volume !== api.volume) {
|
||||
localStorage.setItem('player_volume', api.volume)
|
||||
this.original_volume = api.volume;
|
||||
}
|
||||
}
|
||||
|
||||
nextVideo() {
|
||||
nextVideo(): void {
|
||||
if (this.currentIndex === this.playlist.length - 1) {
|
||||
// dont continue playing
|
||||
// this.currentIndex = 0;
|
||||
@@ -276,17 +276,16 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
this.currentItem = this.playlist[ this.currentIndex ];
|
||||
}
|
||||
|
||||
playVideo() {
|
||||
playVideo(): void {
|
||||
this.api.play();
|
||||
}
|
||||
|
||||
onClickPlaylistItem(item: IMedia, index: number) {
|
||||
// console.log('new current item is ' + item.title + ' at index ' + index);
|
||||
onClickPlaylistItem(item: IMedia, index: number): void {
|
||||
this.currentIndex = index;
|
||||
this.currentItem = item;
|
||||
}
|
||||
|
||||
getFileNames() {
|
||||
getFileNames(): string[] {
|
||||
const fileNames = [];
|
||||
for (let i = 0; i < this.playlist.length; i++) {
|
||||
fileNames.push(this.playlist[i].title);
|
||||
@@ -294,11 +293,11 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
return fileNames;
|
||||
}
|
||||
|
||||
decodeURI(string) {
|
||||
return decodeURI(string);
|
||||
decodeURI(uri: string): string {
|
||||
return decodeURI(uri);
|
||||
}
|
||||
|
||||
downloadContent() {
|
||||
downloadContent(): void {
|
||||
const zipName = this.db_playlist.name;
|
||||
this.downloading = true;
|
||||
this.postsService.downloadPlaylistFromServer(this.playlist_id, this.uuid).subscribe(res => {
|
||||
@@ -311,7 +310,7 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
downloadFile() {
|
||||
downloadFile(): void {
|
||||
const filename = this.playlist[0].title;
|
||||
const ext = (this.playlist[0].type === 'audio/mp3') ? '.mp3' : '.mp4';
|
||||
this.downloading = true;
|
||||
@@ -325,22 +324,22 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
playlistPostCreationHandler(playlistID) {
|
||||
playlistPostCreationHandler(playlistID: string): void {
|
||||
// changes the route without moving from the current view or
|
||||
// triggering a navigation event
|
||||
this.playlist_id = playlistID;
|
||||
this.router.navigateByUrl(this.router.url + ';id=' + playlistID);
|
||||
}
|
||||
|
||||
drop(event: CdkDragDrop<string[]>) {
|
||||
drop(event: CdkDragDrop<string[]>): void {
|
||||
moveItemInArray(this.playlist, event.previousIndex, event.currentIndex);
|
||||
}
|
||||
|
||||
playlistChanged() {
|
||||
playlistChanged(): boolean {
|
||||
return JSON.stringify(this.playlist) !== this.original_playlist;
|
||||
}
|
||||
|
||||
openShareDialog() {
|
||||
openShareDialog(): void {
|
||||
const dialogRef = this.dialog.open(ShareMediaDialogComponent, {
|
||||
data: {
|
||||
uid: this.playlist_id ? this.playlist_id : this.uid,
|
||||
@@ -361,7 +360,7 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
openFileInfoDialog() {
|
||||
openFileInfoDialog(): void {
|
||||
this.dialog.open(VideoInfoDialogComponent, {
|
||||
data: {
|
||||
file: this.db_file,
|
||||
@@ -370,11 +369,11 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
})
|
||||
}
|
||||
|
||||
setPlaybackTimestamp(time) {
|
||||
setPlaybackTimestamp(time: number): void {
|
||||
this.api.seekTime(time);
|
||||
}
|
||||
|
||||
togglePlayback(to_play) {
|
||||
togglePlayback(to_play: boolean): void {
|
||||
if (to_play) {
|
||||
this.api.play();
|
||||
} else {
|
||||
@@ -382,22 +381,14 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
setPlaybackRate(speed) {
|
||||
setPlaybackRate(speed: number): void {
|
||||
this.api.playbackRate = speed;
|
||||
}
|
||||
|
||||
shuffleArray(array) {
|
||||
shuffleArray(array: unknown[]): void {
|
||||
for (let i = array.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[array[i], array[j]] = [array[j], array[i]];
|
||||
}
|
||||
}
|
||||
|
||||
// snackbar helper
|
||||
public openSnackBar(message: string, action: string) {
|
||||
this.snackBar.open(message, action, {
|
||||
duration: 2000,
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -95,7 +95,9 @@ import {
|
||||
UpdateTaskDataRequest,
|
||||
RestoreDBBackupRequest,
|
||||
Schedule,
|
||||
ClearDownloadsRequest
|
||||
ClearDownloadsRequest,
|
||||
Category,
|
||||
UpdateFileRequest
|
||||
} from '../api-types';
|
||||
import { isoLangs } from './settings/locales_list';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
@@ -145,7 +147,7 @@ export class PostsService implements CanActivate {
|
||||
// global vars
|
||||
config = null;
|
||||
subscriptions = null;
|
||||
categories = null;
|
||||
categories: Category[] = null;
|
||||
sidenav = null;
|
||||
locale = isoLangs['en'];
|
||||
version_info = null;
|
||||
@@ -348,8 +350,8 @@ export class PostsService implements CanActivate {
|
||||
return this.http.get<GetMp4sResponse>(this.path + 'getMp4s', this.httpOptions);
|
||||
}
|
||||
|
||||
getFile(uid: string, type: FileType, uuid: string = null) {
|
||||
const body: GetFileRequest = {uid: uid, type: type, uuid: uuid};
|
||||
getFile(uid: string, uuid: string = null) {
|
||||
const body: GetFileRequest = {uid: uid, uuid: uuid};
|
||||
return this.http.post<GetFileResponse>(this.path + 'getFile', body, this.httpOptions);
|
||||
}
|
||||
|
||||
@@ -357,6 +359,11 @@ export class PostsService implements CanActivate {
|
||||
return this.http.post<GetAllFilesResponse>(this.path + 'getAllFiles', {sort: sort, range: range, text_search: text_search, file_type_filter: file_type_filter}, this.httpOptions);
|
||||
}
|
||||
|
||||
updateFile(uid: string, change_obj: Object) {
|
||||
const body: UpdateFileRequest = {uid: uid, change_obj: change_obj};
|
||||
return this.http.post<SuccessObject>(this.path + 'updateFile', body, this.httpOptions);
|
||||
}
|
||||
|
||||
downloadFileFromServer(uid: string, uuid: string = null) {
|
||||
const body: DownloadFileRequest = {
|
||||
uid: uid,
|
||||
|
||||
Reference in New Issue
Block a user