From 08ce3d7ff8ee81e7b4e3ea04f30bbb7411b60f23 Mon Sep 17 00:00:00 2001 From: gsd Date: Sun, 11 Aug 2024 23:27:08 +0300 Subject: [PATCH] pre pre alpha --- backend/config_parser.py | 9 +++- backend/server.py | 4 +- frontend/ang_dvrip/src/app/app.module.ts | 39 ++++++++------- .../components/history/history.component.html | 5 +- .../components/history/history.component.ts | 22 +++++---- .../transcode-modal.component.css | 0 .../transcode-modal.component.html | 22 +++++++++ .../transcode-modal.component.spec.ts | 23 +++++++++ .../transcode-modal.component.ts | 49 +++++++++++++++++++ .../src/app/entities/IBackendResponse.ts | 5 ++ .../src/app/entities/TranscodeStatus.ts | 26 ++++++++++ frontend/ang_dvrip/src/app/utils/BaseUtils.ts | 8 +++ 12 files changed, 179 insertions(+), 33 deletions(-) create mode 100644 frontend/ang_dvrip/src/app/components/transcode-modal/transcode-modal.component.css create mode 100644 frontend/ang_dvrip/src/app/components/transcode-modal/transcode-modal.component.html create mode 100644 frontend/ang_dvrip/src/app/components/transcode-modal/transcode-modal.component.spec.ts create mode 100644 frontend/ang_dvrip/src/app/components/transcode-modal/transcode-modal.component.ts create mode 100644 frontend/ang_dvrip/src/app/entities/IBackendResponse.ts create mode 100644 frontend/ang_dvrip/src/app/entities/TranscodeStatus.ts create mode 100644 frontend/ang_dvrip/src/app/utils/BaseUtils.ts diff --git a/backend/config_parser.py b/backend/config_parser.py index 248ecd3..79cfad5 100644 --- a/backend/config_parser.py +++ b/backend/config_parser.py @@ -64,7 +64,13 @@ class TranscodeStatus: async def generate_bytes(self): async with aiofiles.open(self.outFile, "rb") as out: - yield await out.read(32 * 1024) + while True: + chunk = await out.read(32 * 1024) + if chunk: + yield chunk + else: + break + yield b"" class TranscodeTools: statuses:dict[str, TranscodeStatus] = {} @@ -180,6 +186,7 @@ class TranscodeTools: self.statuses[status.b64].total_h264_bytes = file.size async for chunk in nvr.stream_file(file): self.statuses[status.b64].downloaded_h264_bytes += len(chunk) + self.statuses[status.b64].h264 = round(100 * self.statuses[status.b64].downloaded_h264_bytes / self.statuses[status.b64].total_h264_bytes) await raw.write(chunk) print("raw file is downloaded") print("logout from nvr, he is not more needed") diff --git a/backend/server.py b/backend/server.py index 69a2b38..d5067fb 100644 --- a/backend/server.py +++ b/backend/server.py @@ -111,7 +111,7 @@ class Server: return "" if b64 in self.config.transcode_tools.statuses: - return self.config.transcode_tools.statuses[b64] + return {"ok":True, "data":self.config.transcode_tools.statuses[b64]} nvr:NVR = self.config.getRecorder(recorder_index).nvr await nvr.login() @@ -141,7 +141,7 @@ class Server: headers = {} headers.update({"Content-Length":str(self.config.transcode_tools.statuses[b64].outSize)}) headers.update({"Content-Disposition": f'attachment; filename="{self.config.transcode_tools.statuses[b64].outName}"'}) - return StreamingResponse(self.config.transcode_tools.statuses[b64].generate_bytes, media_type="application/octet-stream", headers=headers) + return StreamingResponse(self.config.transcode_tools.statuses[b64].generate_bytes(), media_type="application/octet-stream", headers=headers) else: response.status_code = 429 return "" diff --git a/frontend/ang_dvrip/src/app/app.module.ts b/frontend/ang_dvrip/src/app/app.module.ts index c739ada..f69bf1d 100644 --- a/frontend/ang_dvrip/src/app/app.module.ts +++ b/frontend/ang_dvrip/src/app/app.module.ts @@ -21,30 +21,35 @@ import {MatToolbarModule} from "@angular/material/toolbar"; import {MatListModule} from "@angular/material/list"; import { HistoryComponent } from './components/history/history.component'; import {MatTableModule} from "@angular/material/table"; -import {ReactiveFormsModule} from "@angular/forms"; +import {FormsModule, ReactiveFormsModule} from "@angular/forms"; import {MatNativeDateModule} from "@angular/material/core"; +import { TranscodeModalComponent } from './components/transcode-modal/transcode-modal.component'; +import {MatDialogModule} from "@angular/material/dialog"; +import {MatProgressBarModule} from "@angular/material/progress-bar"; +import {MatProgressSpinnerModule} from "@angular/material/progress-spinner"; @NgModule({ declarations: [ AppComponent, MainComponent, - HistoryComponent + HistoryComponent, + TranscodeModalComponent + ], + 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 ], - 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 - ], exports: [ BrowserModule, AppRoutingModule, 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 bf76863..1ac520f 100644 --- a/frontend/ang_dvrip/src/app/components/history/history.component.html +++ b/frontend/ang_dvrip/src/app/components/history/history.component.html @@ -33,15 +33,14 @@ Размер - {{getFancySize(element.size)}} + {{baseUtils.getFancySize(element.size)}} Действия Скачать h26Xx - Скачать MP4 - Скачать AVI + Перекодировать 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 b75c721..d036c42 100644 --- a/frontend/ang_dvrip/src/app/components/history/history.component.ts +++ b/frontend/ang_dvrip/src/app/components/history/history.component.ts @@ -4,6 +4,9 @@ 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 "../transcode-modal/transcode-modal.component"; +import {BaseUtils} from "../../utils/BaseUtils"; export interface DVRFILE { filename:string, @@ -14,19 +17,21 @@ export interface DVRFILE { @Component({ selector: 'app-history', templateUrl: './history.component.html', - styleUrls: ['./history.component.css'] + styleUrls: ['./history.component.css'], }) export class HistoryComponent implements OnInit { - selected_stream: number = 0; + selected_stream: number = 1; recorder_index: number = 0; dataSource:MatTableDataSource = new MatTableDataSource(); displayedColumns: string[] = ['filename', 'size', 'actions']; start_date:Date|null = null; end_date:Date|null = null; + baseUtils = BaseUtils; constructor(private route:ActivatedRoute, - private http: HttpClient) { } + private http: HttpClient, + private dialog:MatDialog) { } ngOnInit(): void { this.recorder_index = Number.parseInt(this.route.snapshot.paramMap.get('recorderId')); @@ -42,13 +47,6 @@ export class HistoryComponent implements OnInit { }) } - getFancySize(size:number):string { - if (size > 1024*1024*1024) return `${Math.round(size / 1024/1024/1024)} Гб`; - if (size > 1024*1024) return `${Math.round(size / 1024/1024)} Мб`; - if (size > 1024) return `${Math.round(size / 1024)} Кб`; - return `${size} Б` - } - setDate(event: MatDatepickerInputEvent, type:string) { switch (type) { case "start": { @@ -67,4 +65,8 @@ export class HistoryComponent implements OnInit { if (date == null) return ""; return date.toISOString().replace("T", " ").split(".")[0]; } + + openTransCodeDialog(b64:string) { + const dialog = this.dialog.open(TranscodeModalComponent, {data:{b64:b64, recorder_index:this.route.snapshot.paramMap.get('recorderId')}}); + } } diff --git a/frontend/ang_dvrip/src/app/components/transcode-modal/transcode-modal.component.css b/frontend/ang_dvrip/src/app/components/transcode-modal/transcode-modal.component.css new file mode 100644 index 0000000..e69de29 diff --git a/frontend/ang_dvrip/src/app/components/transcode-modal/transcode-modal.component.html b/frontend/ang_dvrip/src/app/components/transcode-modal/transcode-modal.component.html new file mode 100644 index 0000000..1620ac8 --- /dev/null +++ b/frontend/ang_dvrip/src/app/components/transcode-modal/transcode-modal.component.html @@ -0,0 +1,22 @@ +

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

+ + + +

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

+ +

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

+ +

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

+ +
+ + +
+ Скачать MP4 ({{baseUtils.getFancySize(status.outSize)}}) +
+
+ + + diff --git a/frontend/ang_dvrip/src/app/components/transcode-modal/transcode-modal.component.spec.ts b/frontend/ang_dvrip/src/app/components/transcode-modal/transcode-modal.component.spec.ts new file mode 100644 index 0000000..0977d6e --- /dev/null +++ b/frontend/ang_dvrip/src/app/components/transcode-modal/transcode-modal.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TranscodeModalComponent } from './transcode-modal.component'; + +describe('TranscodeModalComponent', () => { + let component: TranscodeModalComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ TranscodeModalComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(TranscodeModalComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/ang_dvrip/src/app/components/transcode-modal/transcode-modal.component.ts b/frontend/ang_dvrip/src/app/components/transcode-modal/transcode-modal.component.ts new file mode 100644 index 0000000..0711616 --- /dev/null +++ b/frontend/ang_dvrip/src/app/components/transcode-modal/transcode-modal.component.ts @@ -0,0 +1,49 @@ +import {Component, Inject, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog"; +import {HttpClient} from "@angular/common/http"; +import {IBackendResponse} from "../../entities/IBackendResponse"; +import {TranscodeStatus} from "../../entities/TranscodeStatus"; +import {BaseUtils} from "../../utils/BaseUtils"; + +@Component({ + selector: 'app-transcode-modal', + templateUrl: './transcode-modal.component.html', + styleUrls: ['./transcode-modal.component.css'], +}) +export class TranscodeModalComponent implements OnInit { + + status: TranscodeStatus = new TranscodeStatus(); + interval:any; + loading:boolean = true; + baseUtils = BaseUtils; + + constructor( + private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) private data:{b64:string, recorder_index:number}, + private client: HttpClient + ) { } + + ngOnInit(): void { + console.log(this.data); + this.interval = setInterval(() => { + this.getStatus() + }, 1000); + } + + close():void { + clearInterval(this.interval); + this.dialogRef.close(); + } + + getStatus() { + this.client.get(`api/transcode/status/${this.data.recorder_index}?b64=${this.data.b64}`) + .subscribe((data:any) => { + this.status = new TranscodeStatus().fromData(data["data"]); + this.loading = false; + if (this.status.done) + clearInterval(this.interval); + console.log(this.status); + }) + } + +} diff --git a/frontend/ang_dvrip/src/app/entities/IBackendResponse.ts b/frontend/ang_dvrip/src/app/entities/IBackendResponse.ts new file mode 100644 index 0000000..ff6d9bd --- /dev/null +++ b/frontend/ang_dvrip/src/app/entities/IBackendResponse.ts @@ -0,0 +1,5 @@ +export interface IBackendResponse { + ok:boolean, + data:any, + error:any|null +} diff --git a/frontend/ang_dvrip/src/app/entities/TranscodeStatus.ts b/frontend/ang_dvrip/src/app/entities/TranscodeStatus.ts new file mode 100644 index 0000000..7762e6b --- /dev/null +++ b/frontend/ang_dvrip/src/app/entities/TranscodeStatus.ts @@ -0,0 +1,26 @@ +export class TranscodeStatus { + b64:string = ""; + uuid:string = ""; + h264:number = 0; + downloaded_h264_bytes:number = 0; + total_h264_bytes:number = 0; + avi:number = 0; + mp4:number = 0; + outFile:string|null = null; + done:boolean = false; + outSize:number = 0; + + fromData(data:any):TranscodeStatus { + this.b64 = data["b64"]; + this.uuid = data["uuid"]; + this.h264 = data["h264"]; + this.downloaded_h264_bytes = data["downloaded_h264_bytes"]; + this.total_h264_bytes = data["total_h264_bytes"]; + this.avi = data["avi"]; + this.mp4 = data["mp4"]; + this.outFile = data["outFile"]; + this.done = data["done"]; + this.outSize = data["outSize"]; + return this; + } +} diff --git a/frontend/ang_dvrip/src/app/utils/BaseUtils.ts b/frontend/ang_dvrip/src/app/utils/BaseUtils.ts new file mode 100644 index 0000000..f58c309 --- /dev/null +++ b/frontend/ang_dvrip/src/app/utils/BaseUtils.ts @@ -0,0 +1,8 @@ +export class BaseUtils { + static getFancySize(size:number):string { + if (size > 1024*1024*1024) return `${Math.round(size / 1024/1024/1024)} Гб`; + if (size > 1024*1024) return `${Math.round(size / 1024/1024)} Мб`; + if (size > 1024) return `${Math.round(size / 1024)} Кб`; + return `${size} Б` + } +}