mirror of
https://github.com/Tzahi12345/YoutubeDL-Material.git
synced 2026-04-17 21:41:29 +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.
|
description: User is not authorized to view the file.
|
||||||
security:
|
security:
|
||||||
- Auth query parameter: []
|
- 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:
|
/api/enableSharing:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
@@ -1509,6 +1530,8 @@ components:
|
|||||||
properties:
|
properties:
|
||||||
success:
|
success:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
error:
|
||||||
|
type: string
|
||||||
FileType:
|
FileType:
|
||||||
type: string
|
type: string
|
||||||
enum:
|
enum:
|
||||||
@@ -1738,6 +1761,18 @@ components:
|
|||||||
type: boolean
|
type: boolean
|
||||||
file:
|
file:
|
||||||
$ref: '#/components/schemas/DatabaseFile'
|
$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:
|
SharingToggle:
|
||||||
required:
|
required:
|
||||||
- uid
|
- uid
|
||||||
@@ -2321,6 +2356,9 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
thumbnailURL:
|
thumbnailURL:
|
||||||
type: string
|
type: string
|
||||||
|
description: Backup if thumbnailPath is not defined
|
||||||
|
thumbnailPath:
|
||||||
|
type: string
|
||||||
isAudio:
|
isAudio:
|
||||||
type: boolean
|
type: boolean
|
||||||
duration:
|
duration:
|
||||||
@@ -2332,6 +2370,7 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
size:
|
size:
|
||||||
type: number
|
type: number
|
||||||
|
description: In bytes
|
||||||
path:
|
path:
|
||||||
type: string
|
type: string
|
||||||
upload_date:
|
upload_date:
|
||||||
@@ -2340,6 +2379,12 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
sharingEnabled:
|
sharingEnabled:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
category:
|
||||||
|
$ref: '#/components/schemas/Category'
|
||||||
|
view_count:
|
||||||
|
type: number
|
||||||
|
local_view_count:
|
||||||
|
type: number
|
||||||
Playlist:
|
Playlist:
|
||||||
required:
|
required:
|
||||||
- uids
|
- uids
|
||||||
@@ -2369,6 +2414,8 @@ components:
|
|||||||
type: number
|
type: number
|
||||||
user_uid:
|
user_uid:
|
||||||
type: string
|
type: string
|
||||||
|
auto:
|
||||||
|
type: boolean
|
||||||
Download:
|
Download:
|
||||||
required:
|
required:
|
||||||
- url
|
- 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) => {
|
app.post('/api/checkConcurrentStream', async (req, res) => {
|
||||||
const uid = req.body.uid;
|
const uid = req.body.uid;
|
||||||
|
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ export type { UpdateCategoriesRequest } from './models/UpdateCategoriesRequest';
|
|||||||
export type { UpdateCategoryRequest } from './models/UpdateCategoryRequest';
|
export type { UpdateCategoryRequest } from './models/UpdateCategoryRequest';
|
||||||
export type { UpdateConcurrentStreamRequest } from './models/UpdateConcurrentStreamRequest';
|
export type { UpdateConcurrentStreamRequest } from './models/UpdateConcurrentStreamRequest';
|
||||||
export type { UpdateConcurrentStreamResponse } from './models/UpdateConcurrentStreamResponse';
|
export type { UpdateConcurrentStreamResponse } from './models/UpdateConcurrentStreamResponse';
|
||||||
|
export type { UpdateFileRequest } from './models/UpdateFileRequest';
|
||||||
export type { UpdatePlaylistRequest } from './models/UpdatePlaylistRequest';
|
export type { UpdatePlaylistRequest } from './models/UpdatePlaylistRequest';
|
||||||
export type { UpdaterStatus } from './models/UpdaterStatus';
|
export type { UpdaterStatus } from './models/UpdaterStatus';
|
||||||
export type { UpdateServerRequest } from './models/UpdateServerRequest';
|
export type { UpdateServerRequest } from './models/UpdateServerRequest';
|
||||||
|
|||||||
@@ -2,10 +2,16 @@
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
|
||||||
|
import type { Category } from './Category';
|
||||||
|
|
||||||
export type DatabaseFile = {
|
export type DatabaseFile = {
|
||||||
id: string;
|
id: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
/**
|
||||||
|
* Backup if thumbnailPath is not defined
|
||||||
|
*/
|
||||||
thumbnailURL: string;
|
thumbnailURL: string;
|
||||||
|
thumbnailPath?: string;
|
||||||
isAudio: boolean;
|
isAudio: boolean;
|
||||||
/**
|
/**
|
||||||
* In seconds
|
* In seconds
|
||||||
@@ -13,9 +19,15 @@ export type DatabaseFile = {
|
|||||||
duration: number;
|
duration: number;
|
||||||
url: string;
|
url: string;
|
||||||
uploader: string;
|
uploader: string;
|
||||||
|
/**
|
||||||
|
* In bytes
|
||||||
|
*/
|
||||||
size: number;
|
size: number;
|
||||||
path: string;
|
path: string;
|
||||||
upload_date: string;
|
upload_date: string;
|
||||||
uid: string;
|
uid: string;
|
||||||
sharingEnabled?: boolean;
|
sharingEnabled?: boolean;
|
||||||
|
category?: Category;
|
||||||
|
view_count?: number;
|
||||||
|
local_view_count?: number;
|
||||||
};
|
};
|
||||||
@@ -4,4 +4,5 @@
|
|||||||
|
|
||||||
export type SuccessObject = {
|
export type SuccessObject = {
|
||||||
success: boolean;
|
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 { BrowserModule } from '@angular/platform-browser';
|
||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { NgModule, LOCALE_ID } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { registerLocaleData, CommonModule } from '@angular/common';
|
import { registerLocaleData, CommonModule, DatePipe } from '@angular/common';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
||||||
import { MatCardModule } from '@angular/material/card';
|
import { MatCardModule } from '@angular/material/card';
|
||||||
@@ -189,7 +189,8 @@ registerLocaleData(es, 'es');
|
|||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
PostsService,
|
PostsService,
|
||||||
{ provide: HTTP_INTERCEPTORS, useClass: H401Interceptor, multi: true }
|
{ provide: HTTP_INTERCEPTORS, useClass: H401Interceptor, multi: true },
|
||||||
|
DatePipe
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
HighlightPipe,
|
HighlightPipe,
|
||||||
|
|||||||
@@ -1,36 +1,64 @@
|
|||||||
<h4 mat-dialog-title>{{file.title}}</h4>
|
<h4 mat-dialog-title>{{file.title}}</h4>
|
||||||
|
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<div class="info-item">
|
<div style="width: 100%; position: relative;">
|
||||||
<div class="info-item-label"><strong><ng-container i18n="Video name property">Name:</ng-container> </strong></div>
|
<button style="position: absolute; right: 16px; top: 8px;" mat-icon-button (click)="editing = !editing"><mat-icon>edit</mat-icon></button>
|
||||||
<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>
|
</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">
|
||||||
<div class="info-item-label"><strong><ng-container i18n="Video file size property">File size:</ng-container> </strong></div>
|
<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>
|
||||||
<div class="info-item">
|
<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-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 class="info-item-value">{{new_file.path ? new_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>
|
</div>
|
||||||
|
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
|
|
||||||
<mat-dialog-actions>
|
<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>
|
</mat-dialog-actions>
|
||||||
@@ -17,6 +17,10 @@
|
|||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.info-field {
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
.a-wrap {
|
.a-wrap {
|
||||||
word-wrap: break-word
|
word-wrap: break-word
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
import { Component, OnInit, Inject } from '@angular/core';
|
import { Component, OnInit, Inject } from '@angular/core';
|
||||||
import filesize from 'filesize';
|
import filesize from 'filesize';
|
||||||
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
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({
|
@Component({
|
||||||
selector: 'app-video-info-dialog',
|
selector: 'app-video-info-dialog',
|
||||||
@@ -8,15 +11,75 @@ import { MAT_DIALOG_DATA } from '@angular/material/dialog';
|
|||||||
styleUrls: ['./video-info-dialog.component.scss']
|
styleUrls: ['./video-info-dialog.component.scss']
|
||||||
})
|
})
|
||||||
export class VideoInfoDialogComponent implements OnInit {
|
export class VideoInfoDialogComponent implements OnInit {
|
||||||
file: any;
|
file: DatabaseFile;
|
||||||
|
new_file: DatabaseFile;
|
||||||
filesize;
|
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 {
|
ngOnInit(): void {
|
||||||
this.filesize = filesize;
|
this.filesize = filesize;
|
||||||
if (this.data) {
|
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;
|
@ViewChild('twitchchat') twitchChat: TwitchChatComponent;
|
||||||
|
|
||||||
@HostListener('window:resize', ['$event'])
|
@HostListener('window:resize', ['$event'])
|
||||||
onResize(event) {
|
onResize(): void {
|
||||||
this.innerWidth = window.innerWidth;
|
this.innerWidth = window.innerWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,12 +98,12 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit() {
|
ngAfterViewInit(): void {
|
||||||
this.cdr.detectChanges();
|
this.cdr.detectChanges();
|
||||||
this.postsService.sidenav.close();
|
this.postsService.sidenav.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy(): void {
|
||||||
// prevents volume save feature from running in the background
|
// prevents volume save feature from running in the background
|
||||||
clearInterval(this.save_volume_timer);
|
clearInterval(this.save_volume_timer);
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,7 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
public snackBar: MatSnackBar, private cdr: ChangeDetectorRef) {
|
public snackBar: MatSnackBar, private cdr: ChangeDetectorRef) {
|
||||||
|
|
||||||
}
|
}
|
||||||
processConfig() {
|
processConfig(): void {
|
||||||
this.baseStreamPath = this.postsService.path;
|
this.baseStreamPath = this.postsService.path;
|
||||||
this.audioFolderPath = this.postsService.config['Downloader']['path-audio'];
|
this.audioFolderPath = this.postsService.config['Downloader']['path-audio'];
|
||||||
this.videoFolderPath = this.postsService.config['Downloader']['path-video'];
|
this.videoFolderPath = this.postsService.config['Downloader']['path-video'];
|
||||||
@@ -143,14 +143,14 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getFile() {
|
getFile(): void {
|
||||||
this.postsService.getFile(this.uid, null, this.uuid).subscribe(res => {
|
this.postsService.getFile(this.uid, this.uuid).subscribe(res => {
|
||||||
this.db_file = res['file'];
|
this.db_file = res['file'];
|
||||||
if (!this.db_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;
|
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('Failed to increment view count');
|
||||||
console.error(err);
|
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 => {
|
this.postsService.getSubscription(this.sub_id).subscribe(res => {
|
||||||
const subscription = res['subscription'];
|
const subscription = res['subscription'];
|
||||||
this.subscription = subscription;
|
this.subscription = subscription;
|
||||||
this.type === this.subscription.type;
|
this.type === this.subscription.type;
|
||||||
this.uids = this.subscription.videos.map(video => video['uid']);
|
this.uids = this.subscription.videos.map(video => video['uid']);
|
||||||
this.parseFileNames();
|
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 => {
|
this.postsService.getPlaylist(this.playlist_id, this.uuid, true).subscribe(res => {
|
||||||
if (res['playlist']) {
|
if (res['playlist']) {
|
||||||
this.db_playlist = res['playlist'];
|
this.db_playlist = res['playlist'];
|
||||||
@@ -183,14 +183,14 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.show_player = true;
|
this.show_player = true;
|
||||||
this.parseFileNames();
|
this.parseFileNames();
|
||||||
} else {
|
} 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 = [];
|
this.playlist = [];
|
||||||
for (let i = 0; i < this.uids.length; i++) {
|
for (let i = 0; i < this.uids.length; i++) {
|
||||||
let file_obj = null;
|
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'
|
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']}`;
|
let fullLocation = this.baseStreamPath + baseLocation + `?test=test&uid=${file_obj['uid']}`;
|
||||||
|
|
||||||
if (this.postsService.isLoggedIn) {
|
if (this.postsService.isLoggedIn) {
|
||||||
@@ -238,7 +238,7 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.show_player = true;
|
this.show_player = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
onPlayerReady(api: VgApiService) {
|
onPlayerReady(api: VgApiService): void {
|
||||||
this.api = api;
|
this.api = api;
|
||||||
this.api_ready = true;
|
this.api_ready = true;
|
||||||
this.cdr.detectChanges();
|
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) {
|
if (this.original_volume !== api.volume) {
|
||||||
localStorage.setItem('player_volume', api.volume)
|
localStorage.setItem('player_volume', api.volume)
|
||||||
this.original_volume = api.volume;
|
this.original_volume = api.volume;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nextVideo() {
|
nextVideo(): void {
|
||||||
if (this.currentIndex === this.playlist.length - 1) {
|
if (this.currentIndex === this.playlist.length - 1) {
|
||||||
// dont continue playing
|
// dont continue playing
|
||||||
// this.currentIndex = 0;
|
// this.currentIndex = 0;
|
||||||
@@ -276,17 +276,16 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.currentItem = this.playlist[ this.currentIndex ];
|
this.currentItem = this.playlist[ this.currentIndex ];
|
||||||
}
|
}
|
||||||
|
|
||||||
playVideo() {
|
playVideo(): void {
|
||||||
this.api.play();
|
this.api.play();
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickPlaylistItem(item: IMedia, index: number) {
|
onClickPlaylistItem(item: IMedia, index: number): void {
|
||||||
// console.log('new current item is ' + item.title + ' at index ' + index);
|
|
||||||
this.currentIndex = index;
|
this.currentIndex = index;
|
||||||
this.currentItem = item;
|
this.currentItem = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
getFileNames() {
|
getFileNames(): string[] {
|
||||||
const fileNames = [];
|
const fileNames = [];
|
||||||
for (let i = 0; i < this.playlist.length; i++) {
|
for (let i = 0; i < this.playlist.length; i++) {
|
||||||
fileNames.push(this.playlist[i].title);
|
fileNames.push(this.playlist[i].title);
|
||||||
@@ -294,11 +293,11 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
return fileNames;
|
return fileNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
decodeURI(string) {
|
decodeURI(uri: string): string {
|
||||||
return decodeURI(string);
|
return decodeURI(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
downloadContent() {
|
downloadContent(): void {
|
||||||
const zipName = this.db_playlist.name;
|
const zipName = this.db_playlist.name;
|
||||||
this.downloading = true;
|
this.downloading = true;
|
||||||
this.postsService.downloadPlaylistFromServer(this.playlist_id, this.uuid).subscribe(res => {
|
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 filename = this.playlist[0].title;
|
||||||
const ext = (this.playlist[0].type === 'audio/mp3') ? '.mp3' : '.mp4';
|
const ext = (this.playlist[0].type === 'audio/mp3') ? '.mp3' : '.mp4';
|
||||||
this.downloading = true;
|
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
|
// changes the route without moving from the current view or
|
||||||
// triggering a navigation event
|
// triggering a navigation event
|
||||||
this.playlist_id = playlistID;
|
this.playlist_id = playlistID;
|
||||||
this.router.navigateByUrl(this.router.url + ';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);
|
moveItemInArray(this.playlist, event.previousIndex, event.currentIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
playlistChanged() {
|
playlistChanged(): boolean {
|
||||||
return JSON.stringify(this.playlist) !== this.original_playlist;
|
return JSON.stringify(this.playlist) !== this.original_playlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
openShareDialog() {
|
openShareDialog(): void {
|
||||||
const dialogRef = this.dialog.open(ShareMediaDialogComponent, {
|
const dialogRef = this.dialog.open(ShareMediaDialogComponent, {
|
||||||
data: {
|
data: {
|
||||||
uid: this.playlist_id ? this.playlist_id : this.uid,
|
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, {
|
this.dialog.open(VideoInfoDialogComponent, {
|
||||||
data: {
|
data: {
|
||||||
file: this.db_file,
|
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);
|
this.api.seekTime(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
togglePlayback(to_play) {
|
togglePlayback(to_play: boolean): void {
|
||||||
if (to_play) {
|
if (to_play) {
|
||||||
this.api.play();
|
this.api.play();
|
||||||
} else {
|
} else {
|
||||||
@@ -382,22 +381,14 @@ export class PlayerComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setPlaybackRate(speed) {
|
setPlaybackRate(speed: number): void {
|
||||||
this.api.playbackRate = speed;
|
this.api.playbackRate = speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
shuffleArray(array) {
|
shuffleArray(array: unknown[]): void {
|
||||||
for (let i = array.length - 1; i > 0; i--) {
|
for (let i = array.length - 1; i > 0; i--) {
|
||||||
const j = Math.floor(Math.random() * (i + 1));
|
const j = Math.floor(Math.random() * (i + 1));
|
||||||
[array[i], array[j]] = [array[j], array[i]];
|
[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,
|
UpdateTaskDataRequest,
|
||||||
RestoreDBBackupRequest,
|
RestoreDBBackupRequest,
|
||||||
Schedule,
|
Schedule,
|
||||||
ClearDownloadsRequest
|
ClearDownloadsRequest,
|
||||||
|
Category,
|
||||||
|
UpdateFileRequest
|
||||||
} from '../api-types';
|
} from '../api-types';
|
||||||
import { isoLangs } from './settings/locales_list';
|
import { isoLangs } from './settings/locales_list';
|
||||||
import { Title } from '@angular/platform-browser';
|
import { Title } from '@angular/platform-browser';
|
||||||
@@ -145,7 +147,7 @@ export class PostsService implements CanActivate {
|
|||||||
// global vars
|
// global vars
|
||||||
config = null;
|
config = null;
|
||||||
subscriptions = null;
|
subscriptions = null;
|
||||||
categories = null;
|
categories: Category[] = null;
|
||||||
sidenav = null;
|
sidenav = null;
|
||||||
locale = isoLangs['en'];
|
locale = isoLangs['en'];
|
||||||
version_info = null;
|
version_info = null;
|
||||||
@@ -348,8 +350,8 @@ export class PostsService implements CanActivate {
|
|||||||
return this.http.get<GetMp4sResponse>(this.path + 'getMp4s', this.httpOptions);
|
return this.http.get<GetMp4sResponse>(this.path + 'getMp4s', this.httpOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
getFile(uid: string, type: FileType, uuid: string = null) {
|
getFile(uid: string, uuid: string = null) {
|
||||||
const body: GetFileRequest = {uid: uid, type: type, uuid: uuid};
|
const body: GetFileRequest = {uid: uid, uuid: uuid};
|
||||||
return this.http.post<GetFileResponse>(this.path + 'getFile', body, this.httpOptions);
|
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);
|
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) {
|
downloadFileFromServer(uid: string, uuid: string = null) {
|
||||||
const body: DownloadFileRequest = {
|
const body: DownloadFileRequest = {
|
||||||
uid: uid,
|
uid: uid,
|
||||||
|
|||||||
Reference in New Issue
Block a user