feat: custom the file size and duration limit
This commit is contained in:
parent
1b6ac56099
commit
7282a1b429
1
src/blrec/data/webapp/146.5a8902910bda9e87.js
Normal file
1
src/blrec/data/webapp/146.5a8902910bda9e87.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
src/blrec/data/webapp/183.2c7c85597ba82f9e.js
Normal file
1
src/blrec/data/webapp/183.2c7c85597ba82f9e.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
src/blrec/data/webapp/500.5d39ab52fb714a12.js
Normal file
1
src/blrec/data/webapp/500.5d39ab52fb714a12.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
src/blrec/data/webapp/91.be3cbd4101dc7500.js
Normal file
1
src/blrec/data/webapp/91.be3cbd4101dc7500.js
Normal file
File diff suppressed because one or more lines are too long
@ -10,6 +10,6 @@
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
<noscript>Please enable JavaScript to continue using this application.</noscript>
|
||||
<script src="runtime.d0b2d3624e101c6d.js" type="module"></script><script src="polyfills.4b08448aee19bb22.js" type="module"></script><script src="main.888c50197ddf8040.js" type="module"></script>
|
||||
<script src="runtime.68e08c4d681726f6.js" type="module"></script><script src="polyfills.4b08448aee19bb22.js" type="module"></script><script src="main.16a8fc7b1f8a870d.js" type="module"></script>
|
||||
|
||||
</body></html>
|
File diff suppressed because one or more lines are too long
@ -1,6 +1,6 @@
|
||||
{
|
||||
"configVersion": 1,
|
||||
"timestamp": 1659242444285,
|
||||
"timestamp": 1659243718041,
|
||||
"index": "/index.html",
|
||||
"assetGroups": [
|
||||
{
|
||||
@ -12,17 +12,17 @@
|
||||
},
|
||||
"urls": [
|
||||
"/103.5b5d2a6e5a8a7479.js",
|
||||
"/146.92e3b29c4c754544.js",
|
||||
"/183.90c399afcab1b014.js",
|
||||
"/202.f24f6ef0c4c16342.js",
|
||||
"/146.5a8902910bda9e87.js",
|
||||
"/183.2c7c85597ba82f9e.js",
|
||||
"/45.c90c3cea2bf1a66e.js",
|
||||
"/66.d61b8b935d3ed1ff.js",
|
||||
"/500.5d39ab52fb714a12.js",
|
||||
"/91.be3cbd4101dc7500.js",
|
||||
"/common.858f777e9296e6f2.js",
|
||||
"/index.html",
|
||||
"/main.888c50197ddf8040.js",
|
||||
"/main.16a8fc7b1f8a870d.js",
|
||||
"/manifest.webmanifest",
|
||||
"/polyfills.4b08448aee19bb22.js",
|
||||
"/runtime.d0b2d3624e101c6d.js",
|
||||
"/runtime.68e08c4d681726f6.js",
|
||||
"/styles.2e152d608221c2ee.css"
|
||||
],
|
||||
"patterns": []
|
||||
@ -1635,11 +1635,11 @@
|
||||
"dataGroups": [],
|
||||
"hashTable": {
|
||||
"/103.5b5d2a6e5a8a7479.js": "cc0240f217015b6d4ddcc14f31fcc42e1c1c282a",
|
||||
"/146.92e3b29c4c754544.js": "3824de681dd1f982ea69a065cdf54d7a1e781f4d",
|
||||
"/183.90c399afcab1b014.js": "467a8b4c21dace3ae358507932287ca3596051e6",
|
||||
"/202.f24f6ef0c4c16342.js": "0e583339251cf7346f46b19f13342dd30ab9d6ad",
|
||||
"/146.5a8902910bda9e87.js": "d9c33c7073662699f00f46f3a384ae5b749fdef9",
|
||||
"/183.2c7c85597ba82f9e.js": "22a1524d6399d9bde85334a2eba15670f68ccd96",
|
||||
"/45.c90c3cea2bf1a66e.js": "e5bfb8cf3803593e6b8ea14c90b3d3cb6a066764",
|
||||
"/66.d61b8b935d3ed1ff.js": "6b81e8268d5a2d2596b0a7926985dd80fb06532a",
|
||||
"/500.5d39ab52fb714a12.js": "646fbfd3af1124519171f1cd9fac4c214b5af60f",
|
||||
"/91.be3cbd4101dc7500.js": "f0fec71455c96f9a60c4fa671d2ccdba07e9a00a",
|
||||
"/assets/animal/panda.js": "fec2868bb3053dd2da45f96bbcb86d5116ed72b1",
|
||||
"/assets/animal/panda.svg": "bebd302cdc601e0ead3a6d2710acf8753f3d83b1",
|
||||
"/assets/fill/.gitkeep": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
|
||||
@ -3234,11 +3234,11 @@
|
||||
"/assets/twotone/warning.js": "fb2d7ea232f3a99bf8f080dbc94c65699232ac01",
|
||||
"/assets/twotone/warning.svg": "8c7a2d3e765a2e7dd58ac674870c6655cecb0068",
|
||||
"/common.858f777e9296e6f2.js": "b68ca68e1e214a2537d96935c23410126cc564dd",
|
||||
"/index.html": "eb71622159c7cfc8674746c857e97f0825058b53",
|
||||
"/main.888c50197ddf8040.js": "f506b85641a4598b002c21bc49c9a36e0c058326",
|
||||
"/index.html": "3f28dbdfc92c1a0930448a8ff6d5d2ac49648987",
|
||||
"/main.16a8fc7b1f8a870d.js": "9c680888ae14907d6c20e60c026b49a2331768e9",
|
||||
"/manifest.webmanifest": "62c1cb8c5ad2af551a956b97013ab55ce77dd586",
|
||||
"/polyfills.4b08448aee19bb22.js": "8e73f2d42cc13ca353cea5c886d930bd6da08d0d",
|
||||
"/runtime.d0b2d3624e101c6d.js": "3d52e48c0441e75e5d16b979724068f2cd8e2914",
|
||||
"/runtime.68e08c4d681726f6.js": "04815a3dd35466f647f3707a295bc2c76c9f0375",
|
||||
"/styles.2e152d608221c2ee.css": "9830389a46daa5b4511e0dd343aad23ca9f9690f"
|
||||
},
|
||||
"navigationUrls": [
|
||||
|
1
src/blrec/data/webapp/runtime.68e08c4d681726f6.js
Normal file
1
src/blrec/data/webapp/runtime.68e08c4d681726f6.js
Normal file
@ -0,0 +1 @@
|
||||
(()=>{"use strict";var e,v={},m={};function r(e){var i=m[e];if(void 0!==i)return i.exports;var t=m[e]={exports:{}};return v[e].call(t.exports,t,t.exports,r),t.exports}r.m=v,e=[],r.O=(i,t,o,f)=>{if(!t){var a=1/0;for(n=0;n<e.length;n++){for(var[t,o,f]=e[n],c=!0,l=0;l<t.length;l++)(!1&f||a>=f)&&Object.keys(r.O).every(b=>r.O[b](t[l]))?t.splice(l--,1):(c=!1,f<a&&(a=f));if(c){e.splice(n--,1);var d=o();void 0!==d&&(i=d)}}return i}f=f||0;for(var n=e.length;n>0&&e[n-1][2]>f;n--)e[n]=e[n-1];e[n]=[t,o,f]},r.n=e=>{var i=e&&e.__esModule?()=>e.default:()=>e;return r.d(i,{a:i}),i},r.d=(e,i)=>{for(var t in i)r.o(i,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:i[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((i,t)=>(r.f[t](e,i),i),[])),r.u=e=>(592===e?"common":e)+"."+{45:"c90c3cea2bf1a66e",91:"be3cbd4101dc7500",103:"5b5d2a6e5a8a7479",146:"5a8902910bda9e87",183:"2c7c85597ba82f9e",500:"5d39ab52fb714a12",592:"858f777e9296e6f2"}[e]+".js",r.miniCssF=e=>{},r.o=(e,i)=>Object.prototype.hasOwnProperty.call(e,i),(()=>{var e={},i="blrec:";r.l=(t,o,f,n)=>{if(e[t])e[t].push(o);else{var a,c;if(void 0!==f)for(var l=document.getElementsByTagName("script"),d=0;d<l.length;d++){var u=l[d];if(u.getAttribute("src")==t||u.getAttribute("data-webpack")==i+f){a=u;break}}a||(c=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",i+f),a.src=r.tu(t)),e[t]=[o];var s=(g,b)=>{a.onerror=a.onload=null,clearTimeout(p);var _=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),_&&_.forEach(h=>h(b)),g)return g(b)},p=setTimeout(s.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=s.bind(null,a.onerror),a.onload=s.bind(null,a.onload),c&&document.head.appendChild(a)}}})(),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e;r.tu=i=>(void 0===e&&(e={createScriptURL:t=>t},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e.createScriptURL(i))})(),r.p="",(()=>{var e={666:0};r.f.j=(o,f)=>{var n=r.o(e,o)?e[o]:void 0;if(0!==n)if(n)f.push(n[2]);else if(666!=o){var a=new Promise((u,s)=>n=e[o]=[u,s]);f.push(n[2]=a);var c=r.p+r.u(o),l=new Error;r.l(c,u=>{if(r.o(e,o)&&(0!==(n=e[o])&&(e[o]=void 0),n)){var s=u&&("load"===u.type?"missing":u.type),p=u&&u.target&&u.target.src;l.message="Loading chunk "+o+" failed.\n("+s+": "+p+")",l.name="ChunkLoadError",l.type=s,l.request=p,n[1](l)}},"chunk-"+o,o)}else e[o]=0},r.O.j=o=>0===e[o];var i=(o,f)=>{var l,d,[n,a,c]=f,u=0;if(n.some(p=>0!==e[p])){for(l in a)r.o(a,l)&&(r.m[l]=a[l]);if(c)var s=c(r)}for(o&&o(f);u<n.length;u++)r.o(e,d=n[u])&&e[d]&&e[d][0](),e[n[u]]=0;return r.O(s)},t=self.webpackChunkblrec=self.webpackChunkblrec||[];t.forEach(i.bind(null,0)),t.push=i.bind(null,t.push.bind(t))})()})();
|
@ -1 +0,0 @@
|
||||
(()=>{"use strict";var e,v={},m={};function r(e){var f=m[e];if(void 0!==f)return f.exports;var t=m[e]={exports:{}};return v[e].call(t.exports,t,t.exports,r),t.exports}r.m=v,e=[],r.O=(f,t,i,o)=>{if(!t){var a=1/0;for(n=0;n<e.length;n++){for(var[t,i,o]=e[n],c=!0,l=0;l<t.length;l++)(!1&o||a>=o)&&Object.keys(r.O).every(b=>r.O[b](t[l]))?t.splice(l--,1):(c=!1,o<a&&(a=o));if(c){e.splice(n--,1);var d=i();void 0!==d&&(f=d)}}return f}o=o||0;for(var n=e.length;n>0&&e[n-1][2]>o;n--)e[n]=e[n-1];e[n]=[t,i,o]},r.n=e=>{var f=e&&e.__esModule?()=>e.default:()=>e;return r.d(f,{a:f}),f},r.d=(e,f)=>{for(var t in f)r.o(f,t)&&!r.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:f[t]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((f,t)=>(r.f[t](e,f),f),[])),r.u=e=>(592===e?"common":e)+"."+{45:"c90c3cea2bf1a66e",66:"d61b8b935d3ed1ff",103:"5b5d2a6e5a8a7479",146:"92e3b29c4c754544",183:"90c399afcab1b014",202:"f24f6ef0c4c16342",592:"858f777e9296e6f2"}[e]+".js",r.miniCssF=e=>{},r.o=(e,f)=>Object.prototype.hasOwnProperty.call(e,f),(()=>{var e={},f="blrec:";r.l=(t,i,o,n)=>{if(e[t])e[t].push(i);else{var a,c;if(void 0!==o)for(var l=document.getElementsByTagName("script"),d=0;d<l.length;d++){var u=l[d];if(u.getAttribute("src")==t||u.getAttribute("data-webpack")==f+o){a=u;break}}a||(c=!0,(a=document.createElement("script")).type="module",a.charset="utf-8",a.timeout=120,r.nc&&a.setAttribute("nonce",r.nc),a.setAttribute("data-webpack",f+o),a.src=r.tu(t)),e[t]=[i];var s=(g,b)=>{a.onerror=a.onload=null,clearTimeout(p);var _=e[t];if(delete e[t],a.parentNode&&a.parentNode.removeChild(a),_&&_.forEach(h=>h(b)),g)return g(b)},p=setTimeout(s.bind(null,void 0,{type:"timeout",target:a}),12e4);a.onerror=s.bind(null,a.onerror),a.onload=s.bind(null,a.onload),c&&document.head.appendChild(a)}}})(),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e;r.tu=f=>(void 0===e&&(e={createScriptURL:t=>t},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("angular#bundler",e))),e.createScriptURL(f))})(),r.p="",(()=>{var e={666:0};r.f.j=(i,o)=>{var n=r.o(e,i)?e[i]:void 0;if(0!==n)if(n)o.push(n[2]);else if(666!=i){var a=new Promise((u,s)=>n=e[i]=[u,s]);o.push(n[2]=a);var c=r.p+r.u(i),l=new Error;r.l(c,u=>{if(r.o(e,i)&&(0!==(n=e[i])&&(e[i]=void 0),n)){var s=u&&("load"===u.type?"missing":u.type),p=u&&u.target&&u.target.src;l.message="Loading chunk "+i+" failed.\n("+s+": "+p+")",l.name="ChunkLoadError",l.type=s,l.request=p,n[1](l)}},"chunk-"+i,i)}else e[i]=0},r.O.j=i=>0===e[i];var f=(i,o)=>{var l,d,[n,a,c]=o,u=0;if(n.some(p=>0!==e[p])){for(l in a)r.o(a,l)&&(r.m[l]=a[l]);if(c)var s=c(r)}for(i&&i(o);u<n.length;u++)r.o(e,d=n[u])&&e[d]&&e[d][0](),e[n[u]]=0;return r.O(s)},t=self.webpackChunkblrec=self.webpackChunkblrec||[];t.forEach(f.bind(null,0)),t.push=f.bind(null,t.push.bind(t))})()})();
|
@ -242,18 +242,22 @@ class OutputOptions(BaseModel):
|
||||
|
||||
@validator('filesize_limit')
|
||||
def _validate_filesize_limit(cls, value: Optional[int]) -> Optional[int]:
|
||||
# allowed 1 ~ 20 GB, 0 indicates not limit.
|
||||
# file size in bytes, 0 indicates not limit。
|
||||
if value is not None:
|
||||
allowed_values = frozenset(1024**3 * i for i in range(0, 21))
|
||||
cls._validate_with_collection(value, allowed_values)
|
||||
if not (0 <= value <= 1073731086581): # 1073731086581(999.99 GB)
|
||||
raise ValueError(
|
||||
'The filesize limit must be in the range of 0 to 1073731086581'
|
||||
)
|
||||
return value
|
||||
|
||||
@validator('duration_limit')
|
||||
def _validate_duration_limit(cls, value: Optional[int]) -> Optional[int]:
|
||||
# allowed 1 ~ 24 hours, 0 indicates not limit.
|
||||
# duration in seconds, 0 indicates not limit。
|
||||
if value is not None:
|
||||
allowed_values = frozenset(3600 * i for i in range(0, 25))
|
||||
cls._validate_with_collection(value, allowed_values)
|
||||
if not (0 <= value <= 359999): # 359999(99:59:59)
|
||||
raise ValueError(
|
||||
'The duration limit must be in the range of 0 to 359999'
|
||||
)
|
||||
return value
|
||||
|
||||
|
||||
|
@ -44,9 +44,19 @@
|
||||
<nz-form-label
|
||||
class="setting-label"
|
||||
nzNoColon
|
||||
[nzTooltipTitle]="splitFileTip"
|
||||
[nzTooltipTitle]="filesizeLimitTip"
|
||||
>大小限制</nz-form-label
|
||||
>
|
||||
<ng-template #filesizeLimitTip>
|
||||
<p>
|
||||
自动分割文件以限制录播文件大小
|
||||
<br />
|
||||
格式:数字 + 单位(GB, MB, KB, B)
|
||||
<br />
|
||||
不自动分割文件设置为 <strong>0 B</strong>
|
||||
<br />
|
||||
</p>
|
||||
</ng-template>
|
||||
<nz-form-control
|
||||
class="setting-control select"
|
||||
[nzWarningTip]="syncFailedWarningTip"
|
||||
@ -54,20 +64,26 @@
|
||||
syncStatus.filesizeLimit ? filesizeLimitControl : 'warning'
|
||||
"
|
||||
>
|
||||
<nz-select
|
||||
formControlName="filesizeLimit"
|
||||
[nzOptions]="filesizeLimitOptions"
|
||||
>
|
||||
</nz-select>
|
||||
<app-input-filesize formControlName="filesizeLimit"></app-input-filesize>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
<nz-form-item class="setting-item">
|
||||
<nz-form-label
|
||||
class="setting-label"
|
||||
nzNoColon
|
||||
[nzTooltipTitle]="splitFileTip"
|
||||
[nzTooltipTitle]="durationLimitTip"
|
||||
>时长限制</nz-form-label
|
||||
>
|
||||
<ng-template #durationLimitTip>
|
||||
<p>
|
||||
自动分割文件以限制录播文件时长
|
||||
<br />
|
||||
格式:HH:MM:SS
|
||||
<br />
|
||||
不自动分割文件设置为 <strong>00:00:00</strong>
|
||||
<br />
|
||||
</p>
|
||||
</ng-template>
|
||||
<nz-form-control
|
||||
class="setting-control select"
|
||||
[nzWarningTip]="syncFailedWarningTip"
|
||||
@ -75,11 +91,7 @@
|
||||
syncStatus.durationLimit ? durationLimitControl : 'warning'
|
||||
"
|
||||
>
|
||||
<nz-select
|
||||
formControlName="durationLimit"
|
||||
[nzOptions]="durationLimitOptions"
|
||||
>
|
||||
</nz-select>
|
||||
<app-input-duration formControlName="durationLimit"></app-input-duration>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
</form>
|
||||
|
@ -6,25 +6,23 @@ import {
|
||||
OnChanges,
|
||||
ChangeDetectorRef,
|
||||
} from '@angular/core';
|
||||
import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
|
||||
import {
|
||||
FormBuilder,
|
||||
FormControl,
|
||||
FormGroup,
|
||||
Validators,
|
||||
} from '@angular/forms';
|
||||
|
||||
import { Observable } from 'rxjs';
|
||||
import cloneDeep from 'lodash-es/cloneDeep';
|
||||
import mapValues from 'lodash-es/mapValues';
|
||||
|
||||
import type { Mutable } from '../../shared/utility-types';
|
||||
import { OutputSettings } from '../shared/setting.model';
|
||||
import { filterValueChanges } from '../shared/rx-operators';
|
||||
import {
|
||||
SettingsSyncService,
|
||||
SyncStatus,
|
||||
calcSyncStatus,
|
||||
} from '../shared/services/settings-sync.service';
|
||||
import {
|
||||
DURATION_LIMIT_OPTIONS,
|
||||
FILESIZE_LIMIT_OPTIONS,
|
||||
SPLIT_FILE_TIP,
|
||||
SYNC_FAILED_WARNING_TIP,
|
||||
} from '../shared/constants/form';
|
||||
import { SYNC_FAILED_WARNING_TIP } from '../shared/constants/form';
|
||||
|
||||
@Component({
|
||||
selector: 'app-output-settings',
|
||||
@ -37,14 +35,7 @@ export class OutputSettingsComponent implements OnInit, OnChanges {
|
||||
syncStatus!: SyncStatus<OutputSettings>;
|
||||
|
||||
readonly settingsForm: FormGroup;
|
||||
readonly splitFileTip = SPLIT_FILE_TIP;
|
||||
readonly syncFailedWarningTip = SYNC_FAILED_WARNING_TIP;
|
||||
readonly filesizeLimitOptions = cloneDeep(FILESIZE_LIMIT_OPTIONS) as Mutable<
|
||||
typeof FILESIZE_LIMIT_OPTIONS
|
||||
>;
|
||||
readonly durationLimitOptions = cloneDeep(DURATION_LIMIT_OPTIONS) as Mutable<
|
||||
typeof DURATION_LIMIT_OPTIONS
|
||||
>;
|
||||
|
||||
constructor(
|
||||
formBuilder: FormBuilder,
|
||||
@ -54,8 +45,22 @@ export class OutputSettingsComponent implements OnInit, OnChanges {
|
||||
this.settingsForm = formBuilder.group({
|
||||
outDir: [''],
|
||||
pathTemplate: [''],
|
||||
filesizeLimit: [''],
|
||||
durationLimit: [''],
|
||||
filesizeLimit: [
|
||||
'',
|
||||
[
|
||||
Validators.required,
|
||||
Validators.min(0),
|
||||
Validators.max(1073731086581), // 1073731086581(999.99 GB)
|
||||
],
|
||||
],
|
||||
durationLimit: [
|
||||
'',
|
||||
[
|
||||
Validators.required,
|
||||
Validators.min(0),
|
||||
Validators.max(359999), // 359999(99:59:59)
|
||||
],
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
@ -70,6 +75,7 @@ export class OutputSettingsComponent implements OnInit, OnChanges {
|
||||
get filesizeLimitControl() {
|
||||
return this.settingsForm.get('filesizeLimit') as FormControl;
|
||||
}
|
||||
|
||||
get durationLimitControl() {
|
||||
return this.settingsForm.get('durationLimit') as FormControl;
|
||||
}
|
||||
@ -84,7 +90,9 @@ export class OutputSettingsComponent implements OnInit, OnChanges {
|
||||
.syncSettings(
|
||||
'output',
|
||||
this.settings,
|
||||
this.settingsForm.valueChanges as Observable<OutputSettings>
|
||||
this.settingsForm.valueChanges.pipe(
|
||||
filterValueChanges<OutputSettings>(this.settingsForm)
|
||||
)
|
||||
)
|
||||
.subscribe((detail) => {
|
||||
this.syncStatus = { ...this.syncStatus, ...calcSyncStatus(detail) };
|
||||
|
@ -1,8 +1,5 @@
|
||||
import { CoverSaveStrategy, DeleteStrategy } from '../setting.model';
|
||||
|
||||
import range from 'lodash-es/range';
|
||||
|
||||
export const SPLIT_FILE_TIP = '会按照此限制自动分割文件';
|
||||
export const SYNC_FAILED_WARNING_TIP = '设置同步失败!';
|
||||
|
||||
export const PATH_TEMPLATE_PATTERN =
|
||||
@ -30,22 +27,6 @@ export const PATH_TEMPLATE_VARIABLES: Readonly<PathTemplateVariable[]> = [
|
||||
{ name: 'second', desc: '文件创建日期时间之秒数' },
|
||||
] as const;
|
||||
|
||||
export const FILESIZE_LIMIT_OPTIONS = [
|
||||
{ label: '不限', value: 0 },
|
||||
...range(1, 21).map((i) => ({
|
||||
label: `${i} GB`,
|
||||
value: 1024 ** 3 * i,
|
||||
})),
|
||||
] as const;
|
||||
|
||||
export const DURATION_LIMIT_OPTIONS = [
|
||||
{ label: '不限', value: 0 },
|
||||
...range(1, 25).map((i) => ({
|
||||
label: `${i} 小时`,
|
||||
value: 3600 * i,
|
||||
})),
|
||||
] as const;
|
||||
|
||||
export const DELETE_STRATEGIES = [
|
||||
{ label: '自动', value: DeleteStrategy.AUTO },
|
||||
{ label: '谨慎', value: DeleteStrategy.SAFE },
|
||||
|
@ -23,16 +23,18 @@ export function filterValueChanges<T extends object>(control: AbstractControl) {
|
||||
|
||||
export function trimString<T extends object>() {
|
||||
return pipe(
|
||||
map(
|
||||
(object: T) =>
|
||||
transform(
|
||||
object,
|
||||
(result, value: any, prop) => {
|
||||
result[prop] = isString(value) ? value.trim() : value;
|
||||
},
|
||||
{} as T
|
||||
) as T
|
||||
)
|
||||
map((object: T) => {
|
||||
if (isString(object)) {
|
||||
return object.trim() as unknown as T;
|
||||
}
|
||||
return transform(
|
||||
object,
|
||||
(result, value: any, prop) => {
|
||||
result[prop] = isString(value) ? value.trim() : value;
|
||||
},
|
||||
{} as T
|
||||
) as T;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,15 @@
|
||||
<form nz-form [formGroup]="formGroup">
|
||||
<nz-form-item>
|
||||
<nz-form-control [nzErrorTip]="errorTip">
|
||||
<input nz-input type="text" formControlName="duration" />
|
||||
<ng-template #errorTip let-control>
|
||||
<ng-container *ngIf="control.hasError('required')">
|
||||
请输入文件大小
|
||||
</ng-container>
|
||||
<ng-container *ngIf="control.hasError('pattern')">
|
||||
输入有错误
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
</form>
|
@ -0,0 +1,3 @@
|
||||
nz-form-item {
|
||||
margin: 0;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { InputDurationComponent } from './input-duration.component';
|
||||
|
||||
describe('InputDurationComponent', () => {
|
||||
let component: InputDurationComponent;
|
||||
let fixture: ComponentFixture<InputDurationComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ InputDurationComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(InputDurationComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,95 @@
|
||||
import {
|
||||
Component,
|
||||
ChangeDetectionStrategy,
|
||||
forwardRef,
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
import {
|
||||
ControlValueAccessor,
|
||||
FormBuilder,
|
||||
FormControl,
|
||||
FormGroup,
|
||||
NG_VALUE_ACCESSOR,
|
||||
Validators,
|
||||
} from '@angular/forms';
|
||||
|
||||
import { OnChangeType, OnTouchedType } from 'ng-zorro-antd/core/types';
|
||||
|
||||
import { formatDuration, parseDuration } from '../../../shared/utils';
|
||||
import { filterValueChanges } from 'src/app/settings/shared/rx-operators';
|
||||
|
||||
@Component({
|
||||
selector: 'app-input-duration',
|
||||
templateUrl: './input-duration.component.html',
|
||||
styleUrls: ['./input-duration.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: forwardRef(() => InputDurationComponent),
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class InputDurationComponent implements OnInit, ControlValueAccessor {
|
||||
readonly formGroup: FormGroup;
|
||||
private value: number = 0;
|
||||
|
||||
onChange: OnChangeType = () => {};
|
||||
onTouched: OnTouchedType = () => {};
|
||||
|
||||
constructor(formBuilder: FormBuilder) {
|
||||
this.formGroup = formBuilder.group({
|
||||
duration: [
|
||||
'',
|
||||
[Validators.required, Validators.pattern(/^\d{2}:[0~5]\d:[0~5]\d$/)],
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
get durationControl() {
|
||||
return this.formGroup.get('duration') as FormControl;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.durationControl.valueChanges
|
||||
.pipe(filterValueChanges(this.durationControl))
|
||||
.subscribe((displayValue) => {
|
||||
this.onDisplayValueChange(displayValue);
|
||||
});
|
||||
}
|
||||
|
||||
writeValue(value: number): void {
|
||||
this.value = value;
|
||||
this.updateDisplayValue(value);
|
||||
}
|
||||
|
||||
registerOnChange(fn: OnChangeType): void {
|
||||
this.onChange = fn;
|
||||
}
|
||||
|
||||
registerOnTouched(fn: OnTouchedType): void {
|
||||
this.onTouched = fn;
|
||||
}
|
||||
|
||||
setDisabledState(disabled: boolean): void {
|
||||
if (disabled) {
|
||||
this.durationControl.disable();
|
||||
} else {
|
||||
this.durationControl.enable();
|
||||
}
|
||||
}
|
||||
|
||||
private onDisplayValueChange(displayValue: string): void {
|
||||
const value = parseDuration(displayValue);
|
||||
if (typeof value === 'number' && this.value !== value) {
|
||||
this.value = value;
|
||||
this.onChange(value);
|
||||
}
|
||||
}
|
||||
|
||||
private updateDisplayValue(value: number): void {
|
||||
const displayValue = formatDuration(value);
|
||||
this.durationControl.setValue(displayValue);
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
<form nz-form [formGroup]="formGroup">
|
||||
<nz-form-item>
|
||||
<nz-form-control [nzErrorTip]="errorTip">
|
||||
<input nz-input type="text" formControlName="filesize" />
|
||||
<ng-template #errorTip let-control>
|
||||
<ng-container *ngIf="control.hasError('required')">
|
||||
请输入文件大小
|
||||
</ng-container>
|
||||
<ng-container *ngIf="control.hasError('pattern')">
|
||||
输入有错误
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</nz-form-control>
|
||||
</nz-form-item>
|
||||
</form>
|
@ -0,0 +1,3 @@
|
||||
nz-form-item {
|
||||
margin: 0;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { InputFilesizeComponent } from './input-filesize.component';
|
||||
|
||||
describe('InputFilesizeComponent', () => {
|
||||
let component: InputFilesizeComponent;
|
||||
let fixture: ComponentFixture<InputFilesizeComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ InputFilesizeComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(InputFilesizeComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,98 @@
|
||||
import {
|
||||
Component,
|
||||
ChangeDetectionStrategy,
|
||||
forwardRef,
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
import {
|
||||
ControlValueAccessor,
|
||||
FormBuilder,
|
||||
FormControl,
|
||||
FormGroup,
|
||||
NG_VALUE_ACCESSOR,
|
||||
Validators,
|
||||
} from '@angular/forms';
|
||||
|
||||
import { OnChangeType, OnTouchedType } from 'ng-zorro-antd/core/types';
|
||||
|
||||
import { formatFilesize, parseFilesize } from '../../../shared/utils';
|
||||
import { filterValueChanges } from 'src/app/settings/shared/rx-operators';
|
||||
|
||||
@Component({
|
||||
selector: 'app-input-filesize',
|
||||
templateUrl: './input-filesize.component.html',
|
||||
styleUrls: ['./input-filesize.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [
|
||||
{
|
||||
provide: NG_VALUE_ACCESSOR,
|
||||
useExisting: forwardRef(() => InputFilesizeComponent),
|
||||
multi: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
export class InputFilesizeComponent implements OnInit, ControlValueAccessor {
|
||||
readonly formGroup: FormGroup;
|
||||
private value: number = 0;
|
||||
|
||||
onChange: OnChangeType = () => {};
|
||||
onTouched: OnTouchedType = () => {};
|
||||
|
||||
constructor(formBuilder: FormBuilder) {
|
||||
this.formGroup = formBuilder.group({
|
||||
filesize: [
|
||||
'',
|
||||
[
|
||||
Validators.required,
|
||||
Validators.pattern(/^\d{1,3}(?:\.\d{1,2})?\s?[GMK]?B$/),
|
||||
],
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
get filesizeControl() {
|
||||
return this.formGroup.get('filesize') as FormControl;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.filesizeControl.valueChanges
|
||||
.pipe(filterValueChanges(this.filesizeControl))
|
||||
.subscribe((displayValue) => {
|
||||
this.onDisplayValueChange(displayValue);
|
||||
});
|
||||
}
|
||||
|
||||
writeValue(value: number): void {
|
||||
this.value = value;
|
||||
this.updateDisplayValue(value);
|
||||
}
|
||||
|
||||
registerOnChange(fn: OnChangeType): void {
|
||||
this.onChange = fn;
|
||||
}
|
||||
|
||||
registerOnTouched(fn: OnTouchedType): void {
|
||||
this.onTouched = fn;
|
||||
}
|
||||
|
||||
setDisabledState(disabled: boolean): void {
|
||||
if (disabled) {
|
||||
this.filesizeControl.disable();
|
||||
} else {
|
||||
this.filesizeControl.enable();
|
||||
}
|
||||
}
|
||||
|
||||
private onDisplayValueChange(displayValue: string): void {
|
||||
const value = parseFilesize(displayValue);
|
||||
if (typeof value === 'number' && this.value !== value) {
|
||||
this.value = value;
|
||||
this.onChange(value);
|
||||
}
|
||||
}
|
||||
|
||||
private updateDisplayValue(value: number): void {
|
||||
const displayValue = formatFilesize(value);
|
||||
this.filesizeControl.setValue(displayValue);
|
||||
}
|
||||
}
|
@ -1,29 +1,11 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { formatDuration } from '../utils';
|
||||
|
||||
@Pipe({
|
||||
name: 'duration',
|
||||
})
|
||||
export class DurationPipe implements PipeTransform {
|
||||
transform(totalSeconds: number): string {
|
||||
if (totalSeconds < 0) {
|
||||
throw RangeError(
|
||||
'the argument totalSeconds must be greater than or equal to 0'
|
||||
);
|
||||
}
|
||||
|
||||
const hours = Math.floor(totalSeconds / 3600);
|
||||
const minutes = Math.floor((totalSeconds / 60) % 60);
|
||||
const seconds = Math.floor(totalSeconds % 60);
|
||||
|
||||
let result = '';
|
||||
|
||||
if (hours > 0) {
|
||||
result += hours + ':';
|
||||
}
|
||||
result += minutes < 10 ? '0' + minutes : minutes;
|
||||
result += ':';
|
||||
result += seconds < 10 ? '0' + seconds : seconds;
|
||||
|
||||
return result;
|
||||
return formatDuration(totalSeconds, true);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,12 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
import { NzSpinModule } from 'ng-zorro-antd/spin';
|
||||
import { NzPageHeaderModule } from 'ng-zorro-antd/page-header';
|
||||
import { NzFormModule } from 'ng-zorro-antd/form';
|
||||
import { NzInputModule } from 'ng-zorro-antd/input';
|
||||
|
||||
import { DataurlPipe } from './pipes/dataurl.pipe';
|
||||
import { DurationPipe } from './pipes/duration.pipe';
|
||||
@ -11,10 +15,12 @@ import { FilesizePipe } from './pipes/filesize.pipe';
|
||||
import { QualityPipe } from './pipes/quality.pipe';
|
||||
import { ProgressPipe } from './pipes/progress.pipe';
|
||||
import { FilenamePipe } from './pipes/filename.pipe';
|
||||
import { FilestatusPipe } from './pipes/filestatus.pipe';
|
||||
import { SubPageContentDirective } from './directives/sub-page-content.directive';
|
||||
import { PageSectionComponent } from './components/page-section/page-section.component';
|
||||
import { SubPageComponent } from './components/sub-page/sub-page.component';
|
||||
import { SubPageContentDirective } from './directives/sub-page-content.directive';
|
||||
import { FilestatusPipe } from './pipes/filestatus.pipe';
|
||||
import { InputFilesizeComponent } from './components/input-filesize/input-filesize.component';
|
||||
import { InputDurationComponent } from './components/input-duration/input-duration.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@ -23,14 +29,24 @@ import { FilestatusPipe } from './pipes/filestatus.pipe';
|
||||
DataratePipe,
|
||||
FilesizePipe,
|
||||
QualityPipe,
|
||||
SubPageComponent,
|
||||
SubPageContentDirective,
|
||||
PageSectionComponent,
|
||||
ProgressPipe,
|
||||
FilenamePipe,
|
||||
FilestatusPipe,
|
||||
SubPageContentDirective,
|
||||
SubPageComponent,
|
||||
PageSectionComponent,
|
||||
InputFilesizeComponent,
|
||||
InputDurationComponent,
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
NzSpinModule,
|
||||
NzFormModule,
|
||||
NzPageHeaderModule,
|
||||
NzInputModule,
|
||||
],
|
||||
imports: [CommonModule, NzSpinModule, NzPageHeaderModule],
|
||||
exports: [
|
||||
DataurlPipe,
|
||||
DurationPipe,
|
||||
@ -39,11 +55,12 @@ import { FilestatusPipe } from './pipes/filestatus.pipe';
|
||||
QualityPipe,
|
||||
ProgressPipe,
|
||||
FilenamePipe,
|
||||
|
||||
SubPageComponent,
|
||||
SubPageContentDirective,
|
||||
PageSectionComponent,
|
||||
FilestatusPipe,
|
||||
SubPageContentDirective,
|
||||
SubPageComponent,
|
||||
PageSectionComponent,
|
||||
InputFilesizeComponent,
|
||||
InputDurationComponent,
|
||||
],
|
||||
})
|
||||
export class SharedModule {}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { transform, isEqual, isObject } from 'lodash-es';
|
||||
import * as filesize from 'filesize';
|
||||
|
||||
// ref: https://gist.github.com/Yimiprod/7ee176597fef230d1451
|
||||
export function difference(object: object, base: object): object {
|
||||
@ -85,3 +86,70 @@ export function toByteRateString(
|
||||
const digits = precision - Math.floor(Math.abs(Math.log10(num))) - 1;
|
||||
return num.toFixed(digits < 0 ? 0 : digits) + spacer + unit;
|
||||
}
|
||||
|
||||
export function formatDuration(
|
||||
totalSeconds: number,
|
||||
concise: boolean = false
|
||||
): string {
|
||||
if (!(totalSeconds > 0)) {
|
||||
totalSeconds = 0;
|
||||
}
|
||||
|
||||
const hours = Math.floor(totalSeconds / 3600);
|
||||
const minutes = Math.floor((totalSeconds / 60) % 60);
|
||||
const seconds = Math.floor(totalSeconds % 60);
|
||||
|
||||
let result = '';
|
||||
|
||||
if (concise) {
|
||||
if (hours > 0) {
|
||||
result += hours + ':';
|
||||
}
|
||||
} else {
|
||||
result += hours < 10 ? '0' + hours : hours;
|
||||
result += ':';
|
||||
}
|
||||
result += minutes < 10 ? '0' + minutes : minutes;
|
||||
result += ':';
|
||||
result += seconds < 10 ? '0' + seconds : seconds;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function parseDuration(str: string): number | null {
|
||||
try {
|
||||
const [_, hours, minutes, seconds] = /(\d{1,2}):(\d{2}):(\d{2})/.exec(str)!;
|
||||
return parseInt(hours) * 3600 + parseInt(minutes) * 60 + parseInt(seconds);
|
||||
} catch (error) {
|
||||
console.error(`Failed to parse duration: ${str}`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function formatFilesize(size: number): string {
|
||||
return filesize(size);
|
||||
}
|
||||
|
||||
export function parseFilesize(str: string): number | null {
|
||||
try {
|
||||
const [_, num, unit] = /^(\d+(?:\.\d+)?)\s*([TGMK]?B)$/.exec(str)!;
|
||||
switch (unit) {
|
||||
case 'B':
|
||||
return parseFloat(num);
|
||||
case 'KB':
|
||||
return 1024 ** 1 * parseFloat(num);
|
||||
case 'MB':
|
||||
return 1024 ** 2 * parseFloat(num);
|
||||
case 'GB':
|
||||
return 1024 ** 3 * parseFloat(num);
|
||||
case 'TB':
|
||||
return 1024 ** 4 * parseFloat(num);
|
||||
default:
|
||||
console.warn(`Unexpected unit: ${unit}`, str);
|
||||
return null;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Failed to parse filesize: ${str}`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@
|
||||
>
|
||||
</nz-form-item>
|
||||
<nz-form-item
|
||||
class="setting-item"
|
||||
class="setting-item filesize-limit"
|
||||
*ngIf="
|
||||
(options.recorder.streamFormat || model.recorder.streamFormat) ===
|
||||
'flv' ||
|
||||
@ -66,17 +66,25 @@
|
||||
<nz-form-label
|
||||
class="setting-label"
|
||||
nzNoColon
|
||||
[nzTooltipTitle]="splitFileTip"
|
||||
[nzTooltipTitle]="filesizeLimitTip"
|
||||
>大小限制</nz-form-label
|
||||
>
|
||||
<nz-form-control class="setting-control select">
|
||||
<nz-select
|
||||
<ng-template #filesizeLimitTip>
|
||||
<p>
|
||||
自动分割文件以限制录播文件大小
|
||||
<br />
|
||||
格式:数字 + 单位(GB, MB, KB, B)
|
||||
<br />
|
||||
不自动分割文件设置为 <strong>0 B</strong>
|
||||
<br />
|
||||
</p>
|
||||
</ng-template>
|
||||
<nz-form-control class="setting-control input">
|
||||
<app-input-filesize
|
||||
name="filesizeLimit"
|
||||
[(ngModel)]="model.output.filesizeLimit"
|
||||
[disabled]="options.output.filesizeLimit === null"
|
||||
[nzOptions]="filesizeLimitOptions"
|
||||
>
|
||||
</nz-select>
|
||||
></app-input-filesize>
|
||||
</nz-form-control>
|
||||
<label
|
||||
nz-checkbox
|
||||
@ -90,7 +98,7 @@
|
||||
>
|
||||
</nz-form-item>
|
||||
<nz-form-item
|
||||
class="setting-item"
|
||||
class="setting-item duration-limit"
|
||||
*ngIf="
|
||||
(options.recorder.streamFormat || model.recorder.streamFormat) ===
|
||||
'flv' ||
|
||||
@ -103,17 +111,25 @@
|
||||
<nz-form-label
|
||||
class="setting-label"
|
||||
nzNoColon
|
||||
[nzTooltipTitle]="splitFileTip"
|
||||
[nzTooltipTitle]="durationLimitTip"
|
||||
>时长限制</nz-form-label
|
||||
>
|
||||
<nz-form-control class="setting-control select">
|
||||
<nz-select
|
||||
<ng-template #durationLimitTip>
|
||||
<p>
|
||||
自动分割文件以限制录播文件时长
|
||||
<br />
|
||||
格式:HH:MM:SS
|
||||
<br />
|
||||
不自动分割文件设置为 <strong>00:00:00</strong>
|
||||
<br />
|
||||
</p>
|
||||
</ng-template>
|
||||
<nz-form-control class="setting-control input">
|
||||
<app-input-duration
|
||||
name="durationLimit"
|
||||
[(ngModel)]="model.output.durationLimit"
|
||||
[disabled]="options.output.durationLimit === null"
|
||||
[nzOptions]="durationLimitOptions"
|
||||
>
|
||||
</nz-select>
|
||||
></app-input-duration>
|
||||
</nz-form-control>
|
||||
<label
|
||||
nz-checkbox
|
||||
|
@ -1,4 +1,4 @@
|
||||
@use '../../settings/shared/styles/setting';
|
||||
@use "../../settings/shared/styles/setting";
|
||||
|
||||
nz-divider {
|
||||
margin: 0 !important;
|
||||
@ -44,7 +44,8 @@ nz-divider {
|
||||
}
|
||||
}
|
||||
|
||||
&.input, &.textarea {
|
||||
&.input,
|
||||
&.textarea {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
|
||||
.setting-label {
|
||||
@ -80,3 +81,19 @@ nz-divider {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.filesize-limit,
|
||||
.duration-limit {
|
||||
.setting-control {
|
||||
&.input {
|
||||
max-width: 8em !important;
|
||||
width: 8em !important;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 319px) {
|
||||
&.input {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,15 +21,12 @@ import {
|
||||
} from '../../settings/shared/setting.model';
|
||||
import {
|
||||
PATH_TEMPLATE_PATTERN,
|
||||
FILESIZE_LIMIT_OPTIONS,
|
||||
DURATION_LIMIT_OPTIONS,
|
||||
STREAM_FORMAT_OPTIONS,
|
||||
QUALITY_OPTIONS,
|
||||
TIMEOUT_OPTIONS,
|
||||
DISCONNECTION_TIMEOUT_OPTIONS,
|
||||
BUFFER_OPTIONS,
|
||||
DELETE_STRATEGIES,
|
||||
SPLIT_FILE_TIP,
|
||||
COVER_SAVE_STRATEGIES,
|
||||
RECORDING_MODE_OPTIONS,
|
||||
} from '../../settings/shared/constants/form';
|
||||
@ -58,14 +55,7 @@ export class TaskSettingsDialogComponent implements OnChanges {
|
||||
|
||||
readonly warningTip =
|
||||
'需要重启弹幕客户端才能生效,如果任务正在录制可能会丢失弹幕!';
|
||||
readonly splitFileTip = SPLIT_FILE_TIP;
|
||||
readonly pathTemplatePattern = PATH_TEMPLATE_PATTERN;
|
||||
readonly filesizeLimitOptions = cloneDeep(FILESIZE_LIMIT_OPTIONS) as Mutable<
|
||||
typeof FILESIZE_LIMIT_OPTIONS
|
||||
>;
|
||||
readonly durationLimitOptions = cloneDeep(DURATION_LIMIT_OPTIONS) as Mutable<
|
||||
typeof DURATION_LIMIT_OPTIONS
|
||||
>;
|
||||
readonly streamFormatOptions = cloneDeep(STREAM_FORMAT_OPTIONS) as Mutable<
|
||||
typeof STREAM_FORMAT_OPTIONS
|
||||
>;
|
||||
@ -121,6 +111,7 @@ export class TaskSettingsDialogComponent implements OnChanges {
|
||||
}
|
||||
|
||||
handleConfirm(): void {
|
||||
debugger;
|
||||
this.confirm.emit(difference(this.options, this.taskOptions!));
|
||||
this.close();
|
||||
}
|
||||
@ -132,7 +123,6 @@ export class TaskSettingsDialogComponent implements OnChanges {
|
||||
const prop = key as keyof TaskOptions;
|
||||
const options = this.options[prop];
|
||||
const globalSettings = this.globalSettings[prop];
|
||||
|
||||
Reflect.set(
|
||||
model,
|
||||
prop,
|
||||
|
Loading…
Reference in New Issue
Block a user