Browse Source

pre pre alpha

master
gsd 8 months ago
parent
commit
08ce3d7ff8
  1. 9
      backend/config_parser.py
  2. 4
      backend/server.py
  3. 39
      frontend/ang_dvrip/src/app/app.module.ts
  4. 5
      frontend/ang_dvrip/src/app/components/history/history.component.html
  5. 22
      frontend/ang_dvrip/src/app/components/history/history.component.ts
  6. 0
      frontend/ang_dvrip/src/app/components/transcode-modal/transcode-modal.component.css
  7. 22
      frontend/ang_dvrip/src/app/components/transcode-modal/transcode-modal.component.html
  8. 23
      frontend/ang_dvrip/src/app/components/transcode-modal/transcode-modal.component.spec.ts
  9. 49
      frontend/ang_dvrip/src/app/components/transcode-modal/transcode-modal.component.ts
  10. 5
      frontend/ang_dvrip/src/app/entities/IBackendResponse.ts
  11. 26
      frontend/ang_dvrip/src/app/entities/TranscodeStatus.ts
  12. 8
      frontend/ang_dvrip/src/app/utils/BaseUtils.ts

9
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")

4
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 ""

39
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,

5
frontend/ang_dvrip/src/app/components/history/history.component.html

@ -33,15 +33,14 @@
<ng-container matColumnDef="size">
<th mat-header-cell *matHeaderCellDef> Размер </th>
<td mat-cell *matCellDef="let element"> {{getFancySize(element.size)}} </td>
<td mat-cell *matCellDef="let element"> {{baseUtils.getFancySize(element.size)}} </td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> Действия </th>
<td mat-cell *matCellDef="let element">
<a [href]="'api/file/'+recorder_index+'?b64='+element.b64">Скачать h26Xx</a>
<a style="padding-left: 4px" [href]="'api/file/'+recorder_index+'?b64='+element.b64">Скачать MP4</a>
<a style="padding-left: 4px" [href]="'api/file/'+recorder_index+'?b64='+element.b64">Скачать AVI</a>
<a style="padding-left: 4px" (click)="openTransCodeDialog(element.b64)">Перекодировать</a>
</td>
</ng-container>

22
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<DVRFILE> = new MatTableDataSource<DVRFILE>();
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(<string>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<Date>, 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')}});
}
}

0
frontend/ang_dvrip/src/app/components/transcode-modal/transcode-modal.component.css

22
frontend/ang_dvrip/src/app/components/transcode-modal/transcode-modal.component.html

@ -0,0 +1,22 @@
<h2 mat-dialog-title>{{status.done?"Файл успешно преобразован":"Подождите, перекодировка файла"}}</h2>
<mat-dialog-content>
<mat-spinner *ngIf="loading"></mat-spinner>
<ng-container *ngIf="!loading && !status.done">
<p>Прогресс загрузки h264x {{status.h264}} %</p>
<mat-progress-bar [mode]="'determinate'" [value]="status.h264"></mat-progress-bar>
<p>Прогресс загрузки avi {{status.avi}} %</p>
<mat-progress-bar [mode]="'determinate'" [value]="status.avi"></mat-progress-bar>
<p>Прогресс загрузки avi {{status.mp4}} %</p>
<mat-progress-bar [mode]="'determinate'" [value]="status.mp4"></mat-progress-bar>
</ng-container>
<ng-container *ngIf="!loading && status.done">
<video controls>
<source [src]="'api/transcode/download?b64=' + status.b64" type="video/mp4"/>
</video>
<br>
<a [href]="'api/transcode/download?b64=' + status.b64">Скачать MP4 ({{baseUtils.getFancySize(status.outSize)}})</a>
</ng-container>
</mat-dialog-content>
<mat-dialog-actions>
<button mat-button (click)="close()">Закрыть</button>
</mat-dialog-actions>

23
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<TranscodeModalComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ TranscodeModalComponent ]
})
.compileComponents();
fixture = TestBed.createComponent(TranscodeModalComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

49
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<TranscodeModalComponent>,
@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);
})
}
}

5
frontend/ang_dvrip/src/app/entities/IBackendResponse.ts

@ -0,0 +1,5 @@
export interface IBackendResponse {
ok:boolean,
data:any,
error:any|null
}

26
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;
}
}

8
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} Б`
}
}
Loading…
Cancel
Save