From efef84e3ae59a87275150e7c6a6bc3bad300263a Mon Sep 17 00:00:00 2001 From: gsd Date: Wed, 28 Aug 2024 02:10:21 +0300 Subject: [PATCH] preview grid --- backend/config_parser.py | 15 ++++-- backend/nvr_types.py | 9 +++- frontend/ang_dvrip/src/app/app.module.ts | 31 ++++++------ .../components/history/history.component.css | 6 +++ .../components/history/history.component.html | 48 +++++++++---------- .../components/history/history.component.ts | 19 ++++---- .../ang_dvrip/src/app/entities/DVRFILE.ts | 3 +- .../transcode-modal.component.html | 23 +++++---- frontend/ang_dvrip/src/app/utils/BaseUtils.ts | 10 ++++ 9 files changed, 100 insertions(+), 64 deletions(-) diff --git a/backend/config_parser.py b/backend/config_parser.py index 87abb9f..64f9330 100644 --- a/backend/config_parser.py +++ b/backend/config_parser.py @@ -8,6 +8,8 @@ from nvr_types import File import platform import aiofiles +from subprocess import DEVNULL + from global_funcs import * class NeedNVR(Exception): @@ -234,7 +236,7 @@ class TranscodeTools: await proc.communicate() if delete_source_file: - os.remove(source_file) + self.deleteFile(source_file) if os.path.exists(source_file + ".avi"): return source_file + ".avi" else: @@ -247,7 +249,7 @@ class TranscodeTools: await proc.communicate() if delete_source_file: - os.remove(source_file) + self.deleteFile(source_file) if os.path.exists(source_file + ".mp4"): return source_file + ".mp4" else: @@ -256,18 +258,21 @@ class TranscodeTools: async def anytoimage(self, source_file, out_file, delete_source_file = False): exec_string = ["-y", "-i", source_file, "-ss", "1", "-vframes", "1", out_file] self.logger.debug(f"execute {exec_string}") - proc = await asyncio.create_subprocess_exec("ffmpeg", *exec_string) + proc = await asyncio.create_subprocess_exec("ffmpeg", *exec_string, stderr=DEVNULL) await proc.communicate() if delete_source_file: - os.remove(source_file) + self.deleteFile(source_file) if os.path.exists(out_file): return out_file else: raise Exception(f"{out_file} not be created") def deleteFile(self, source_file): - os.remove(source_file) + try: + os.remove(source_file) + except: + pass async def processing_preview(self, file:File, nvr: NVR, ext = "webp"): raw_file = file.previewPath(self.transcode_directory) diff --git a/backend/nvr_types.py b/backend/nvr_types.py index ec7297e..57a1618 100644 --- a/backend/nvr_types.py +++ b/backend/nvr_types.py @@ -47,7 +47,14 @@ class File: @property def json(self): b64 = self.to_b64.replace("==", "") - return {"filename": self.filename_cleared, "type": self.type, "size": self.size, "b64": b64, "converted":self.converted} + return { + "filename": self.filename_cleared, + "type": self.type, + "size": self.size, + "b64": b64, + "converted":self.converted, + "date":self.begin.strftime(NVR_DATE_FORMAT) + } @staticmethod def from_b64(b64): diff --git a/frontend/ang_dvrip/src/app/app.module.ts b/frontend/ang_dvrip/src/app/app.module.ts index 1e0ff40..17db593 100644 --- a/frontend/ang_dvrip/src/app/app.module.ts +++ b/frontend/ang_dvrip/src/app/app.module.ts @@ -30,6 +30,7 @@ import {MatProgressSpinnerModule} from "@angular/material/progress-spinner"; import {MatIconModule} from "@angular/material/icon"; import { AboutComponent } from './components/about/about.component'; import { StreamComponent } from './components/stream/stream.component'; +import {MatCardModule} from "@angular/material/card"; @NgModule({ declarations: [ @@ -40,21 +41,21 @@ import { StreamComponent } from './components/stream/stream.component'; AboutComponent, StreamComponent ], - imports: [ - BrowserModule, - AppRoutingModule, - MatSidenavModule, - MatFormFieldModule, - MatInputModule, - MatSelectModule, - HttpClientModule, - BrowserAnimationsModule, - MatDatepickerModule, - MatButtonModule, - MatFormFieldModule, - MatNativeDateModule, - MatAutocompleteModule, MatCheckboxModule, MatButtonModule, MatFormFieldModule, MatDatepickerModule, MatRadioModule, MatInputModule, MatSelectModule, MatSlideToggleModule, MatSlideToggleModule, MatToolbarModule, MatListModule, MatTableModule, ReactiveFormsModule, MatDialogModule, FormsModule, MatProgressBarModule, MatProgressSpinnerModule, MatIconModule - ], + imports: [ + BrowserModule, + AppRoutingModule, + MatSidenavModule, + MatFormFieldModule, + MatInputModule, + MatSelectModule, + HttpClientModule, + BrowserAnimationsModule, + MatDatepickerModule, + MatButtonModule, + MatFormFieldModule, + MatNativeDateModule, + MatAutocompleteModule, MatCheckboxModule, MatButtonModule, MatFormFieldModule, MatDatepickerModule, MatRadioModule, MatInputModule, MatSelectModule, MatSlideToggleModule, MatSlideToggleModule, MatToolbarModule, MatListModule, MatTableModule, ReactiveFormsModule, MatDialogModule, FormsModule, MatProgressBarModule, MatProgressSpinnerModule, MatIconModule, MatCardModule + ], exports: [ BrowserModule, AppRoutingModule, diff --git a/frontend/ang_dvrip/src/app/components/history/history.component.css b/frontend/ang_dvrip/src/app/components/history/history.component.css index e4ba4dd..90437a7 100644 --- a/frontend/ang_dvrip/src/app/components/history/history.component.css +++ b/frontend/ang_dvrip/src/app/components/history/history.component.css @@ -13,3 +13,9 @@ .processing { color: coral; } + +.responsive-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); + gap: 24px; +} diff --git a/frontend/ang_dvrip/src/app/components/history/history.component.html b/frontend/ang_dvrip/src/app/components/history/history.component.html index 72fa77a..78c7a7a 100644 --- a/frontend/ang_dvrip/src/app/components/history/history.component.html +++ b/frontend/ang_dvrip/src/app/components/history/history.component.html @@ -9,41 +9,41 @@ Choose a date - + MM/DD/YYYY Choose a date - + MM/DD/YYYY - - - - - - - - - - - - - - - - - -
Имя файла / Время обнаружения {{element.filename}} Размер {{baseUtils.getFancySize(element.size)}} Действия - {{element.converted?'cloud_done':'cloud_download'}} - attachment -
-
+
+ + + {{element.filename}} + {{baseUtils.getFancySize(element.size)}} + + Превью + + + + + + + +
diff --git a/frontend/ang_dvrip/src/app/components/history/history.component.ts b/frontend/ang_dvrip/src/app/components/history/history.component.ts index 21bf1e5..85744e2 100644 --- a/frontend/ang_dvrip/src/app/components/history/history.component.ts +++ b/frontend/ang_dvrip/src/app/components/history/history.component.ts @@ -1,8 +1,6 @@ import { Component, OnInit } from '@angular/core'; -import {ActivatedRoute} from "@angular/router"; +import {ActivatedRoute, Router} from "@angular/router"; import {HttpClient} from "@angular/common/http"; -import {MatTableDataSource} from "@angular/material/table"; -import {FormControl, FormGroup} from "@angular/forms"; import {MatDatepickerInputEvent} from "@angular/material/datepicker"; import {MatDialog} from "@angular/material/dialog"; import {TranscodeModalComponent} from "../../modals/transcode-modal/transcode-modal.component"; @@ -18,27 +16,29 @@ export class HistoryComponent implements OnInit { selected_stream: number = 1; recorder_index: number = 0; - dataSource:MatTableDataSource = new MatTableDataSource(); - displayedColumns: string[] = ['filename', 'size', 'actions']; + dataSource: DVRFILE[] = []; start_date:Date|null = null; end_date:Date|null = null; baseUtils = BaseUtils; constructor(private route:ActivatedRoute, private http: HttpClient, - private dialog:MatDialog) { } + private dialog:MatDialog, + private router:Router) { } ngOnInit(): void { this.recorder_index = Number.parseInt(this.route.snapshot.paramMap.get('recorderId')); + this.start_date = this.baseUtils.parseDate(this.route.snapshot.queryParamMap.get("start")); + this.end_date = this.baseUtils.parseDate(this.route.snapshot.queryParamMap.get("end")); this.getHistory(); } getHistory() { const params = this.route.snapshot.paramMap; - this.dataSource = new MatTableDataSource(); + this.dataSource = []; this.http.get(`api/dvrip/history/${params.get('recorderId')}/${params.get('channelId')}/${this.selected_stream}?start_date=${this.baseUtils.prepareDate(this.start_date, true)}&end_date=${this.baseUtils.prepareDate(this.end_date, false)}`) .subscribe((a:any) => { - this.dataSource = new MatTableDataSource(a['data']); + this.dataSource = a['data']; }) } @@ -54,12 +54,13 @@ export class HistoryComponent implements OnInit { } } console.log(this.start_date, this.end_date); + this.router.navigate([], {queryParams: {start:this.start_date?.toLocaleDateString(), end:this.end_date?.toLocaleDateString()}, queryParamsHandling:"merge"}) this.getHistory(); } openTransCodeDialog(dvrfile:DVRFILE) { const dialog = this.dialog.open(TranscodeModalComponent, {data:{b64:dvrfile.b64, recorder_index:this.route.snapshot.paramMap.get('recorderId')}}); - dialog.afterOpened().subscribe(() => dvrfile.processing = true); + dialog.afterOpened().subscribe(() => dvrfile.converted?'':dvrfile.processing = true); dialog.afterClosed().subscribe((res:boolean) => { dvrfile.converted = res; if (res) { diff --git a/frontend/ang_dvrip/src/app/entities/DVRFILE.ts b/frontend/ang_dvrip/src/app/entities/DVRFILE.ts index 21ea5d8..096a2d9 100644 --- a/frontend/ang_dvrip/src/app/entities/DVRFILE.ts +++ b/frontend/ang_dvrip/src/app/entities/DVRFILE.ts @@ -3,5 +3,6 @@ export default interface DVRFILE { size:number, b64:string, converted:boolean, - processing:boolean|null + processing:boolean|null, + date:string } diff --git a/frontend/ang_dvrip/src/app/modals/transcode-modal/transcode-modal.component.html b/frontend/ang_dvrip/src/app/modals/transcode-modal/transcode-modal.component.html index cbe743b..d8134c2 100644 --- a/frontend/ang_dvrip/src/app/modals/transcode-modal/transcode-modal.component.html +++ b/frontend/ang_dvrip/src/app/modals/transcode-modal/transcode-modal.component.html @@ -1,16 +1,22 @@

{{status.done?"Файл успешно преобразован":"Подождите, перекодировка файла"}}

- + -

Прогресс загрузки h264x {{status.h264}} %

- -

Прогресс перекодировки avi {{status.avi}} %

- -

Прогресс перекодировки mp4 {{status.mp4}} %

- +
+

1) Прогресс загрузки h264x {{status.h264}} %

+ +
+
+

2) Прогресс перекодировки avi {{status.avi}} %

+ +
+
+

3) Прогресс перекодировки mp4 {{status.mp4}} %

+ +
- @@ -18,5 +24,4 @@ - Превью diff --git a/frontend/ang_dvrip/src/app/utils/BaseUtils.ts b/frontend/ang_dvrip/src/app/utils/BaseUtils.ts index f1affb3..fe86b25 100644 --- a/frontend/ang_dvrip/src/app/utils/BaseUtils.ts +++ b/frontend/ang_dvrip/src/app/utils/BaseUtils.ts @@ -15,4 +15,14 @@ export class BaseUtils { else return d.toISOString().split("T")[0] + " 23:59:59"; } + + static parseDate(date: any): any { + try { + const p: number[] = date.split(".").map((v: any) => Number(v)) + return new Date(Date.UTC(p[2], p[1] - 1, p[0])); + } catch (e) { + console.log("cannot parse date", date) + return new Date(); + } + } }