mirror of
https://github.com/Tzahi12345/YoutubeDL-Material.git
synced 2026-04-02 09:41:29 +03:00
Added ability to backup remote DB
Added ability to restore DB
This commit is contained in:
@@ -21,6 +21,7 @@ export type { CreatePlaylistRequest } from './models/CreatePlaylistRequest';
|
||||
export type { CreatePlaylistResponse } from './models/CreatePlaylistResponse';
|
||||
export type { CropFileSettings } from './models/CropFileSettings';
|
||||
export type { DatabaseFile } from './models/DatabaseFile';
|
||||
export { DBBackup } from './models/DBBackup';
|
||||
export type { DBInfoResponse } from './models/DBInfoResponse';
|
||||
export type { DeleteCategoryRequest } from './models/DeleteCategoryRequest';
|
||||
export type { DeleteMp3Mp4Request } from './models/DeleteMp3Mp4Request';
|
||||
@@ -45,6 +46,7 @@ export type { GetAllDownloadsResponse } from './models/GetAllDownloadsResponse';
|
||||
export type { GetAllFilesResponse } from './models/GetAllFilesResponse';
|
||||
export type { GetAllSubscriptionsResponse } from './models/GetAllSubscriptionsResponse';
|
||||
export type { GetAllTasksResponse } from './models/GetAllTasksResponse';
|
||||
export type { GetDBBackupsResponse } from './models/GetDBBackupsResponse';
|
||||
export type { GetDownloadRequest } from './models/GetDownloadRequest';
|
||||
export type { GetDownloadResponse } from './models/GetDownloadResponse';
|
||||
export type { GetFileFormatsRequest } from './models/GetFileFormatsRequest';
|
||||
@@ -74,6 +76,7 @@ export type { LoginResponse } from './models/LoginResponse';
|
||||
export type { Playlist } from './models/Playlist';
|
||||
export type { RegisterRequest } from './models/RegisterRequest';
|
||||
export type { RegisterResponse } from './models/RegisterResponse';
|
||||
export type { RestoreDBBackupRequest } from './models/RestoreDBBackupRequest';
|
||||
export { Schedule } from './models/Schedule';
|
||||
export type { SetConfigRequest } from './models/SetConfigRequest';
|
||||
export type { SharingToggle } from './models/SharingToggle';
|
||||
@@ -98,6 +101,7 @@ export type { UpdateConcurrentStreamResponse } from './models/UpdateConcurrentSt
|
||||
export type { UpdatePlaylistRequest } from './models/UpdatePlaylistRequest';
|
||||
export type { UpdaterStatus } from './models/UpdaterStatus';
|
||||
export type { UpdateServerRequest } from './models/UpdateServerRequest';
|
||||
export type { UpdateTaskDataRequest } from './models/UpdateTaskDataRequest';
|
||||
export type { UpdateTaskScheduleRequest } from './models/UpdateTaskScheduleRequest';
|
||||
export type { UpdateUserRequest } from './models/UpdateUserRequest';
|
||||
export type { User } from './models/User';
|
||||
|
||||
21
src/api-types/models/DBBackup.ts
Normal file
21
src/api-types/models/DBBackup.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
|
||||
export interface DBBackup {
|
||||
name: string;
|
||||
timestamp: number;
|
||||
size: number;
|
||||
source: DBBackup.source;
|
||||
}
|
||||
|
||||
export namespace DBBackup {
|
||||
|
||||
export enum source {
|
||||
LOCAL = 'local',
|
||||
REMOTE = 'remote',
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
9
src/api-types/models/GetDBBackupsResponse.ts
Normal file
9
src/api-types/models/GetDBBackupsResponse.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
import { DBBackup } from './DBBackup';
|
||||
|
||||
export interface GetDBBackupsResponse {
|
||||
tasks?: Array<DBBackup>;
|
||||
}
|
||||
8
src/api-types/models/RestoreDBBackupRequest.ts
Normal file
8
src/api-types/models/RestoreDBBackupRequest.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
|
||||
export interface RestoreDBBackupRequest {
|
||||
file_name: string;
|
||||
}
|
||||
9
src/api-types/models/UpdateTaskDataRequest.ts
Normal file
9
src/api-types/models/UpdateTaskDataRequest.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
/* istanbul ignore file */
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
|
||||
export interface UpdateTaskDataRequest {
|
||||
task_key: string;
|
||||
new_data: any;
|
||||
}
|
||||
@@ -90,6 +90,7 @@ import { ConcurrentStreamComponent } from './components/concurrent-stream/concur
|
||||
import { SkipAdButtonComponent } from './components/skip-ad-button/skip-ad-button.component';
|
||||
import { TasksComponent } from './components/tasks/tasks.component';
|
||||
import { UpdateTaskScheduleDialogComponent } from './dialogs/update-task-schedule-dialog/update-task-schedule-dialog.component';
|
||||
import { RestoreDbDialogComponent } from './dialogs/restore-db-dialog/restore-db-dialog.component';
|
||||
|
||||
registerLocaleData(es, 'es');
|
||||
|
||||
@@ -140,7 +141,8 @@ export function isVisible({ event, element, scrollContainer, offset }: IsVisible
|
||||
ConcurrentStreamComponent,
|
||||
SkipAdButtonComponent,
|
||||
TasksComponent,
|
||||
UpdateTaskScheduleDialogComponent
|
||||
UpdateTaskScheduleDialogComponent,
|
||||
RestoreDbDialogComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
|
||||
@@ -48,15 +48,23 @@
|
||||
<ng-container matColumnDef="actions">
|
||||
<mat-header-cell *matHeaderCellDef> <ng-container i18n="Actions">Actions</ng-container> </mat-header-cell>
|
||||
<mat-cell *matCellDef="let element">
|
||||
<div>
|
||||
<ng-container *ngIf="element.data?.uids?.length > 0">
|
||||
<button (click)="confirmTask(element.key)" [disabled]="element.running || element.confirming" mat-stroked-button>
|
||||
<ng-container *ngIf="element.key == 'missing_files_check'" i18n="Clear missing files from DB">Clear missing files from DB:</ng-container>
|
||||
<ng-container *ngIf="element.key == 'duplicate_files_check'" i18n="Clear duplicate files from DB">Clear duplicate files from DB:</ng-container> {{element.data.uids.length}}
|
||||
</button>
|
||||
</ng-container>
|
||||
<button (click)="runTask(element.key)" [disabled]="element.running || element.confirming" mat-icon-button matTooltip="Run" i18n-matTooltip="Run"><mat-icon>play_arrow</mat-icon></button>
|
||||
<button (click)="scheduleTask(element)" mat-icon-button matTooltip="Schedule" i18n-matTooltip="Schedule"><mat-icon>schedule</mat-icon></button>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div *ngIf="element.data?.uids?.length > 0" class="col-12 mt-2">
|
||||
<ng-container>
|
||||
<button (click)="confirmTask(element.key)" [disabled]="element.running || element.confirming" mat-stroked-button>
|
||||
<ng-container *ngIf="element.key == 'missing_files_check'" i18n="Clear missing files from DB">Clear missing files from DB:</ng-container>
|
||||
<ng-container *ngIf="element.key == 'duplicate_files_check'" i18n="Clear duplicate files from DB">Clear duplicate files from DB:</ng-container> {{element.data.uids.length}}
|
||||
</button>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="col-3" style="padding-right: 0px">
|
||||
<button (click)="runTask(element.key)" [disabled]="element.running || element.confirming" mat-icon-button matTooltip="Run" i18n-matTooltip="Run"><mat-icon>play_arrow</mat-icon></button>
|
||||
</div>
|
||||
<div class="col-3" style="padding-left: 0px">
|
||||
<button (click)="scheduleTask(element)" mat-icon-button matTooltip="Schedule" i18n-matTooltip="Schedule"><mat-icon>schedule</mat-icon></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
@@ -70,6 +78,8 @@
|
||||
aria-label="Select page of tasks">
|
||||
</mat-paginator>
|
||||
</div>
|
||||
|
||||
<button style="margin-top: 10px; margin-left: 5px;" mat-stroked-button (click)="openRestoreDBBackupDialog()" i18n="Restore DB from backup button">Restore DB from backup</button>
|
||||
</div>
|
||||
|
||||
<div *ngIf="(!tasks || tasks.length === 0) && tasks_retrieved">
|
||||
|
||||
@@ -3,6 +3,7 @@ import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatPaginator } from '@angular/material/paginator';
|
||||
import { MatSort } from '@angular/material/sort';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { RestoreDbDialogComponent } from 'app/dialogs/restore-db-dialog/restore-db-dialog.component';
|
||||
import { UpdateTaskScheduleDialogComponent } from 'app/dialogs/update-task-schedule-dialog/update-task-schedule-dialog.component';
|
||||
import { PostsService } from 'app/posts.services';
|
||||
|
||||
@@ -21,6 +22,8 @@ export class TasksComponent implements OnInit {
|
||||
displayedColumns: string[] = ['title', 'last_ran', 'last_confirmed', 'status', 'actions'];
|
||||
dataSource = null;
|
||||
|
||||
db_backups = [];
|
||||
|
||||
@ViewChild(MatPaginator) paginator: MatPaginator;
|
||||
@ViewChild(MatSort) sort: MatSort;
|
||||
|
||||
@@ -70,12 +73,23 @@ export class TasksComponent implements OnInit {
|
||||
runTask(task_key: string): void {
|
||||
this.postsService.runTask(task_key).subscribe(res => {
|
||||
this.getTasks();
|
||||
this.getDBBackups();
|
||||
if (res['success']) this.postsService.openSnackBar($localize`Successfully ran task!`);
|
||||
else this.postsService.openSnackBar($localize`Failed to run task!`);
|
||||
}, err => {
|
||||
this.postsService.openSnackBar($localize`Failed to run task!`);
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
|
||||
confirmTask(task_key: string): void {
|
||||
this.postsService.confirmTask(task_key).subscribe(res => {
|
||||
this.getTasks();
|
||||
if (res['success']) this.postsService.openSnackBar($localize`Successfully confirmed task!`);
|
||||
else this.postsService.openSnackBar($localize`Failed to confirm task!`);
|
||||
}, err => {
|
||||
this.postsService.openSnackBar($localize`Failed to confirm task!`);
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -96,6 +110,21 @@ export class TasksComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
getDBBackups(): void {
|
||||
this.postsService.getDBBackups().subscribe(res => {
|
||||
this.db_backups = res['db_backups'];
|
||||
});
|
||||
}
|
||||
|
||||
openRestoreDBBackupDialog(): void {
|
||||
this.dialog.open(RestoreDbDialogComponent, {
|
||||
data: {
|
||||
db_backups: this.db_backups
|
||||
},
|
||||
width: '80vw'
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export interface Task {
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<h4 mat-dialog-title><ng-container i18n="Restore DB from backup">Restore DB from backup</ng-container></h4>
|
||||
|
||||
<mat-dialog-content>
|
||||
<mat-selection-list [multiple]="false" [(ngModel)]="selected_backup">
|
||||
<mat-list-option *ngFor="let db_backup of db_backups" [value]="db_backup.name" [matTooltip]="db_backup.name">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
{{db_backup.timestamp*1000 | date: 'short'}}
|
||||
</div>
|
||||
<div class="col-4">
|
||||
{{(db_backup.size/1000).toFixed(2)}} kB
|
||||
</div>
|
||||
<div class="col-4" style="text-transform: capitalize;">
|
||||
{{db_backup.source}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-list-option>
|
||||
</mat-selection-list>
|
||||
</mat-dialog-content>
|
||||
|
||||
<mat-dialog-actions>
|
||||
<button mat-button mat-dialog-close><ng-container i18n="Restore DB cancel button">Cancel</ng-container></button>
|
||||
<button mat-button [disabled]="restoring" (click)="restoreClicked()" [disabled]="!selected_backup || selected_backup.length !== 1"><ng-container i18n="Restore button">Restore</ng-container></button>
|
||||
<div class="mat-spinner" *ngIf="restoring">
|
||||
<mat-spinner [diameter]="25"></mat-spinner>
|
||||
</div>
|
||||
</mat-dialog-actions>
|
||||
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RestoreDbDialogComponent } from './restore-db-dialog.component';
|
||||
|
||||
describe('RestoreDbDialogComponent', () => {
|
||||
let component: RestoreDbDialogComponent;
|
||||
let fixture: ComponentFixture<RestoreDbDialogComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ RestoreDbDialogComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(RestoreDbDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { PostsService } from 'app/posts.services';
|
||||
|
||||
@Component({
|
||||
selector: 'app-restore-db-dialog',
|
||||
templateUrl: './restore-db-dialog.component.html',
|
||||
styleUrls: ['./restore-db-dialog.component.scss']
|
||||
})
|
||||
export class RestoreDbDialogComponent implements OnInit {
|
||||
|
||||
db_backups = [];
|
||||
selected_backup = null;
|
||||
restoring = false;
|
||||
|
||||
constructor(@Inject(MAT_DIALOG_DATA) public data: any, private dialogRef: MatDialogRef<RestoreDbDialogComponent>, private postsService: PostsService) {
|
||||
if (this.data?.db_backups) {
|
||||
this.db_backups = this.data.db_backups;
|
||||
}
|
||||
|
||||
this.getDBBackups();
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
}
|
||||
|
||||
getDBBackups(): void {
|
||||
this.postsService.getDBBackups().subscribe(res => {
|
||||
this.db_backups = res['db_backups'];
|
||||
});
|
||||
}
|
||||
|
||||
restoreClicked(): void {
|
||||
if (this.selected_backup.length !== 1) return;
|
||||
this.postsService.restoreDBBackup(this.selected_backup[0]).subscribe(res => {
|
||||
if (res['success']) {
|
||||
this.postsService.openSnackBar('Database successfully restored!');
|
||||
} else {
|
||||
this.postsService.openSnackBar('Failed to restore database! See logs for more info.');
|
||||
}
|
||||
}, err => {
|
||||
this.postsService.openSnackBar('Failed to restore database! See browser console for more info.');
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -93,6 +93,9 @@ import {
|
||||
GetTaskRequest,
|
||||
GetTaskResponse,
|
||||
UpdateTaskScheduleRequest,
|
||||
UpdateTaskDataRequest,
|
||||
RestoreDBBackupRequest,
|
||||
Schedule,
|
||||
} from '../api-types';
|
||||
import { isoLangs } from './settings/locales_list';
|
||||
import { Title } from '@angular/platform-browser';
|
||||
@@ -588,26 +591,40 @@ export class PostsService implements CanActivate {
|
||||
return this.http.post<SuccessObject>(this.path + 'getTasks', {}, this.httpOptions);
|
||||
}
|
||||
|
||||
getTask(task_key) {
|
||||
getTask(task_key: string) {
|
||||
const body: GetTaskRequest = {task_key: task_key};
|
||||
return this.http.post<GetTaskResponse>(this.path + 'getTask', body, this.httpOptions);
|
||||
}
|
||||
|
||||
runTask(task_key) {
|
||||
runTask(task_key: string) {
|
||||
const body: GetTaskRequest = {task_key: task_key};
|
||||
return this.http.post<SuccessObject>(this.path + 'runTask', body, this.httpOptions);
|
||||
}
|
||||
|
||||
confirmTask(task_key) {
|
||||
confirmTask(task_key: string) {
|
||||
const body: GetTaskRequest = {task_key: task_key};
|
||||
return this.http.post<SuccessObject>(this.path + 'confirmTask', body, this.httpOptions);
|
||||
}
|
||||
|
||||
updateTaskSchedule(task_key, schedule) {
|
||||
updateTaskSchedule(task_key: string, schedule: Schedule) {
|
||||
const body: UpdateTaskScheduleRequest = {task_key: task_key, new_schedule: schedule};
|
||||
return this.http.post<SuccessObject>(this.path + 'updateTaskSchedule', body, this.httpOptions);
|
||||
}
|
||||
|
||||
updateTaskData(task_key: string, data: any) {
|
||||
const body: UpdateTaskDataRequest = {task_key: task_key, new_data: data};
|
||||
return this.http.post<SuccessObject>(this.path + 'updateTaskData', body, this.httpOptions);
|
||||
}
|
||||
|
||||
getDBBackups() {
|
||||
return this.http.post<SuccessObject>(this.path + 'getDBBackups', {}, this.httpOptions);
|
||||
}
|
||||
|
||||
restoreDBBackup(file_name: string) {
|
||||
const body: RestoreDBBackupRequest = {file_name: file_name};
|
||||
return this.http.post<SuccessObject>(this.path + 'restoreDBBackup', body, this.httpOptions);
|
||||
}
|
||||
|
||||
getVersionInfo() {
|
||||
return this.http.get<VersionInfoResponse>(this.path + 'versionInfo', this.httpOptions);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user