feat: add codegen and refactor mkv models
This commit is contained in:
		
							parent
							
								
									f921819d2a
								
							
						
					
					
						commit
						0b681d4fd1
					
				| @ -1,135 +1,229 @@ | ||||
| import { | ||||
|   type EbmlTagType, | ||||
|   EbmlTagIdEnum, | ||||
|   EbmlTagPosition, | ||||
|   type EbmlTracksTagType, | ||||
|   type EbmlInfoTagType, | ||||
|   type EbmlClusterTagType, | ||||
|   type EbmlCuePointTagType, | ||||
|   type EbmlCuesTagType, | ||||
|   type EbmlInfoTagType, | ||||
|   type EbmlMasterTagType, | ||||
|   type EbmlSeekHeadTagType, | ||||
|   type EbmlSegmentTagType, | ||||
|   type EbmlCuePointTagType, | ||||
|   type EbmlMasterTagType, | ||||
|   EbmlTagIdEnum, | ||||
|   EbmlTagPosition, | ||||
|   type EbmlTagType, | ||||
|   type EbmlTrackEntryTagType, | ||||
|   type EbmlTracksTagType, | ||||
| } from 'konoebml'; | ||||
| import {convertEbmlTagToComponent, type InferType,} from './util'; | ||||
| import {isEqual, maxBy} from 'lodash-es'; | ||||
| import {ArkErrors, type Type} from 'arktype'; | ||||
| import { | ||||
|   convertEbmlTagToModelShape, | ||||
|   type InferType, | ||||
|   isTagIdPos, | ||||
|   SEEK_ID_KAX_CUES, | ||||
|   SEEK_ID_KAX_INFO, | ||||
|   SEEK_ID_KAX_TRACKS, | ||||
| } from './util'; | ||||
| import { isEqual } from 'lodash-es'; | ||||
| import type { Type } from 'arktype'; | ||||
| import { CuePointSchema, type CuePointType } from './schema'; | ||||
|   ClusterSchema, | ||||
|   type ClusterType, | ||||
|   CuePointSchema, | ||||
|   type CuePointType, | ||||
|   type CueTrackPositionsType, | ||||
|   InfoSchema, | ||||
|   type InfoType, | ||||
|   SeekHeadSchema, | ||||
|   type SeekHeadType, | ||||
|   TrackEntrySchema, | ||||
|   type TrackEntryType | ||||
| } from './schema'; | ||||
| 
 | ||||
| export abstract class StandardComponentSystem< | ||||
|   E extends EbmlMasterTagType, | ||||
|   S extends Type<any>, | ||||
| > { | ||||
|   abstract get schema(): S; | ||||
| export const SEEK_ID_KAX_INFO = new Uint8Array([0x15, 0x49, 0xa9, 0x66]); | ||||
| export const SEEK_ID_KAX_TRACKS = new Uint8Array([0x16, 0x54, 0xae, 0x6b]); | ||||
| export const SEEK_ID_KAX_CUES = new Uint8Array([0x1c, 0x53, 0xbb, 0x6b]); | ||||
| 
 | ||||
|   componentFromTag(tag: E): InferType<S> { | ||||
|     const extracted = convertEbmlTagToModelShape(tag); | ||||
|     return this.schema.assert(extracted) as InferType<S>; | ||||
|   } | ||||
| } | ||||
| export class SegmentSystem { | ||||
|   startTag: EbmlSegmentTagType; | ||||
|   headTags: EbmlTagType[] = []; | ||||
| 
 | ||||
|   cue: CueSystem; | ||||
|   cluster: ClusterSystem; | ||||
|   seek: SeekSystem; | ||||
|   info: InfoSystem; | ||||
|   track: TrackSystem; | ||||
| 
 | ||||
| export class EbmlSegment { | ||||
|   startNode: EbmlSegmentTagType; | ||||
|   seekHeadNode?: EbmlSeekHeadTagType; | ||||
|   seekEntries: EbmlSeekEntry[]; | ||||
|   tracksNode?: EbmlTracksTagType; | ||||
|   infoNode?: EbmlInfoTagType; | ||||
|   cuesNode?: EbmlCuesTagType; | ||||
|   metaBuffer: EbmlTagType[] = []; | ||||
|   metaOffsets: Map<number, EbmlTagType> = new Map(); | ||||
| 
 | ||||
|   constructor(startNode: EbmlSegmentTagType) { | ||||
|     this.startNode = startNode; | ||||
|     this.seekEntries = []; | ||||
|     this.metaBuffer = []; | ||||
|     this.startTag = startNode; | ||||
|     this.cue = new CueSystem(this); | ||||
|     this.cluster = new ClusterSystem(this); | ||||
|     this.seek = new SeekSystem(this); | ||||
|     this.info = new InfoSystem(this); | ||||
|     this.track = new TrackSystem(this); | ||||
|   } | ||||
| 
 | ||||
|   get dataOffset() { | ||||
|     return this.startNode.startOffset + this.startNode.headerLength; | ||||
|   get dataStartOffset() { | ||||
|     return this.startTag.startOffset + this.startTag.headerLength; | ||||
|   } | ||||
| 
 | ||||
|   private addSeekHead(node: EbmlSeekHeadTagType) { | ||||
|     this.seekHeadNode = node; | ||||
|     this.seekEntries = this.seekHeadNode.children | ||||
|       .filter(isTagIdPos(EbmlTagIdEnum.Seek, EbmlTagPosition.End)) | ||||
|       .map((c) => { | ||||
|         const seekId = c.children.find( | ||||
|           (item) => item.id === EbmlTagIdEnum.SeekID | ||||
|         )?.data; | ||||
|         const seekPosition = c.children.find( | ||||
|           (item) => item.id === EbmlTagIdEnum.SeekPosition | ||||
|         )?.data as number; | ||||
|         if (seekId && seekPosition) { | ||||
|           return { | ||||
|             seekId, | ||||
|             seekPosition, | ||||
|           }; | ||||
|         } | ||||
|         return null; | ||||
|       }) | ||||
|       .filter((c): c is EbmlSeekEntry => !!c); | ||||
|   get startOffset () { | ||||
|     return this.startTag.startOffset; | ||||
|   } | ||||
| 
 | ||||
|   findSeekPositionBySeekId(seekId: Uint8Array): number | undefined { | ||||
|     return this.seekEntries.find((c) => isEqual(c.seekId, seekId)) | ||||
|       ?.seekPosition; | ||||
|   completeHeads () { | ||||
|     const infoTag = this.seek.seekTagBySeekId(SEEK_ID_KAX_INFO); | ||||
|     const tracksTag = this.seek.seekTagBySeekId(SEEK_ID_KAX_TRACKS); | ||||
|     const cuesTag = this.seek.seekTagBySeekId(SEEK_ID_KAX_CUES); | ||||
| 
 | ||||
|     if (cuesTag?.id === EbmlTagIdEnum.Cues) { | ||||
|       this.cue.prepareCuesWithTag(cuesTag) | ||||
|     } | ||||
|     if (infoTag?.id === EbmlTagIdEnum.Info) { | ||||
|       this.info.prepareWithInfoTag(infoTag); | ||||
|     } | ||||
|     if (tracksTag?.id === EbmlTagIdEnum.Tracks) { | ||||
|       this.track.prepareTracksWithTag(tracksTag); | ||||
|     } | ||||
| 
 | ||||
|   findLocalNodeBySeekId(seekId: Uint8Array): EbmlTagType | undefined { | ||||
|     return this.findLocalNodeBySeekPosition( | ||||
|       this.findSeekPositionBySeekId(seekId) | ||||
|     ); | ||||
|     return this; | ||||
|   } | ||||
| 
 | ||||
|   findLocalNodeBySeekPosition( | ||||
|     seekPosition: number | undefined | ||||
|   scanHead (tag: EbmlTagType) { | ||||
|     if ( | ||||
|       tag.id === EbmlTagIdEnum.SeekHead && | ||||
|       tag.position === EbmlTagPosition.End | ||||
|     ) { | ||||
|       this.seek.addSeekHeadTag(tag); | ||||
|     } | ||||
|     this.headTags.push(tag); | ||||
|     this.seek.memoTag(tag); | ||||
|     return this; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export class SegmentComponentSystemTrait<E extends EbmlMasterTagType, S extends Type<any>> { | ||||
|   segment: SegmentSystem; | ||||
| 
 | ||||
|   get schema(): S { | ||||
|     throw new Error("unimplemented!") | ||||
|   } | ||||
| 
 | ||||
|   constructor(segment: SegmentSystem) { | ||||
|     this.segment = segment; | ||||
|   } | ||||
| 
 | ||||
|   componentFromTag(tag: E): InferType<S> { | ||||
|     const extracted = convertEbmlTagToComponent(tag); | ||||
|     const result = this.schema(extracted); | ||||
|     if (result instanceof ArkErrors) { | ||||
|       const errors = result; | ||||
|       console.error('Parse component from tag error:', tag.toDebugRecord(), errors.flatProblemsByPath) | ||||
|       throw errors; | ||||
|     } | ||||
|     return result as InferType<S> | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export class SeekSystem extends SegmentComponentSystemTrait<EbmlSeekHeadTagType, typeof SeekHeadSchema> { | ||||
|   override get schema() { | ||||
|     return SeekHeadSchema; | ||||
|   } | ||||
| 
 | ||||
|   seekHeads: SeekHeadType[] = []; | ||||
|   offsetToTagMemo: Map<number, EbmlTagType> = new Map(); | ||||
| 
 | ||||
|   memoTag (tag: EbmlTagType) { | ||||
|     this.offsetToTagMemo.set(tag.startOffset, tag); | ||||
|   } | ||||
| 
 | ||||
|   addSeekHeadTag (tag: EbmlSeekHeadTagType) { | ||||
|     const seekHead = this.componentFromTag(tag); | ||||
|     this.seekHeads.push(seekHead); | ||||
|     return seekHead; | ||||
|   } | ||||
| 
 | ||||
|   offsetFromSeekPosition (position: number): number { | ||||
|     return position + this.segment.startOffset; | ||||
|   } | ||||
| 
 | ||||
|   offsetFromSeekDataPosition (position: number) : number { | ||||
|     return position + this.segment.dataStartOffset; | ||||
|   } | ||||
| 
 | ||||
|   seekTagByStartOffset ( | ||||
|     startOffset: number | undefined | ||||
|   ): EbmlTagType | undefined { | ||||
|     return seekPosition! >= 0 | ||||
|       ? this.metaOffsets.get(seekPosition as number) | ||||
|     return startOffset! >= 0 | ||||
|       ? this.offsetToTagMemo.get(startOffset!) | ||||
|       : undefined; | ||||
|   } | ||||
| 
 | ||||
|   markMetaEnd() { | ||||
|     this.infoNode = this.findLocalNodeBySeekId( | ||||
|       SEEK_ID_KAX_INFO | ||||
|     ) as EbmlInfoTagType; | ||||
|     this.tracksNode = this.findLocalNodeBySeekId( | ||||
|       SEEK_ID_KAX_TRACKS | ||||
|     ) as EbmlTracksTagType; | ||||
|     this.cuesNode = this.findLocalNodeBySeekId( | ||||
|       SEEK_ID_KAX_CUES | ||||
|     ) as EbmlCuesTagType; | ||||
|   seekOffsetBySeekId(seekId: Uint8Array): number | undefined { | ||||
|     const seekPosition = this.seekHeads[0]?.Seek?.find((c) => isEqual(c.SeekID, seekId)) | ||||
|       ?.SeekPosition; | ||||
|     return seekPosition! >= 0 ? this.offsetFromSeekPosition(seekPosition!) : undefined; | ||||
|   } | ||||
| 
 | ||||
|   scanMeta(node: EbmlTagType): boolean { | ||||
|     if ( | ||||
|       node.id === EbmlTagIdEnum.SeekHead && | ||||
|       node.position === EbmlTagPosition.End | ||||
|     ) { | ||||
|       this.addSeekHead(node); | ||||
|     } | ||||
|     this.metaBuffer.push(node); | ||||
|     this.metaOffsets.set(node.startOffset - this.dataOffset, node); | ||||
|     return true; | ||||
|   seekTagBySeekId(seekId: Uint8Array): EbmlTagType | undefined { | ||||
|     return this.seekTagByStartOffset( | ||||
|       this.seekOffsetBySeekId(seekId) | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export class CuesSystem extends StandardComponentSystem< | ||||
| export class InfoSystem extends SegmentComponentSystemTrait<EbmlInfoTagType, typeof InfoSchema> { | ||||
|   override get schema() { | ||||
|     return InfoSchema; | ||||
|   } | ||||
| 
 | ||||
|   info!: InfoType; | ||||
| 
 | ||||
|   prepareWithInfoTag (tag: EbmlInfoTagType) { | ||||
|     this.info = this.componentFromTag(tag); | ||||
|     return this; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export class ClusterSystem extends SegmentComponentSystemTrait<EbmlClusterTagType, typeof ClusterSchema> { | ||||
|   override get schema() { | ||||
|     return ClusterSchema | ||||
|   } | ||||
| 
 | ||||
|   clustersBuffer: ClusterType[] = []; | ||||
| 
 | ||||
|   addClusterWithTag (tag: EbmlClusterTagType): ClusterType { | ||||
|     const cluster = this.componentFromTag(tag); | ||||
|     this.clustersBuffer.push(cluster); | ||||
|     return cluster; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export class TrackSystem extends SegmentComponentSystemTrait<EbmlTrackEntryTagType, typeof TrackEntrySchema> { | ||||
|   override get schema() { | ||||
|     return TrackEntrySchema; | ||||
|   } | ||||
| 
 | ||||
|   tracks = new Map<number, TrackEntryType>(); | ||||
| 
 | ||||
|   prepareTracksWithTag (tag: EbmlTracksTagType) { | ||||
|     this.tracks.clear(); | ||||
|     for (const c of tag.children) { | ||||
|       if (c.id === EbmlTagIdEnum.TrackEntry) { | ||||
|         const trackEntry = this.componentFromTag(c); | ||||
|         this.tracks.set(trackEntry.TrackNumber, trackEntry); | ||||
|       } | ||||
|     } | ||||
|     return this; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export class CueSystem extends SegmentComponentSystemTrait< | ||||
|   EbmlCuePointTagType, | ||||
|   typeof CuePointSchema | ||||
| > { | ||||
|   schema = CuePointSchema; | ||||
|   cues: CuePointType[]; | ||||
|   override get schema () { | ||||
|     return CuePointSchema | ||||
|   }; | ||||
| 
 | ||||
|   constructor(cues: CuePointType[]) { | ||||
|     super(); | ||||
|     this.cues = cues; | ||||
|   cues: CuePointType[] = []; | ||||
| 
 | ||||
| 
 | ||||
|   prepareCuesWithTag (tag: EbmlCuesTagType) { | ||||
|     this.cues = tag.children | ||||
|       .filter(c => c.id === EbmlTagIdEnum.CuePoint) | ||||
|       .map(this.componentFromTag.bind(this)); | ||||
|     return this; | ||||
|   } | ||||
| 
 | ||||
|   findClosestCue(seekTime: number): CuePointType | undefined { | ||||
| @ -170,4 +264,19 @@ export class CuesSystem extends StandardComponentSystem< | ||||
|       ? before | ||||
|       : after; | ||||
|   } | ||||
| 
 | ||||
|   getCueTrackPositions (cuePoint: CuePointType, track?: number): CueTrackPositionsType { | ||||
|     let cueTrackPositions: CueTrackPositionsType | undefined; | ||||
|     if (track! >= 0) { | ||||
|       cueTrackPositions = cuePoint.CueTrackPositions.find(c => c.CueTrack === track); | ||||
|     } | ||||
|    if (!cueTrackPositions) { | ||||
|      cueTrackPositions =  maxBy(cuePoint.CueTrackPositions, c => c.CueClusterPosition)!; | ||||
|    } | ||||
|    return cueTrackPositions; | ||||
|   } | ||||
| 
 | ||||
|   get prepared (): boolean { | ||||
|     return this.cues.length > 0; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -26,8 +26,9 @@ import { | ||||
|   withLatestFrom, | ||||
| } from 'rxjs'; | ||||
| import { createRangedStream } from '@/fetch'; | ||||
| import { EbmlSegment, Cluster, SEEK_ID_KAX_CUES, CuesSystem } from './model'; | ||||
| import { SegmentSystem, SEEK_ID_KAX_CUES, type CueSystem } from './model'; | ||||
| import { isTagIdPos } from './util'; | ||||
| import type { ClusterType } from "./schema"; | ||||
| 
 | ||||
| export function createRangedEbmlStream( | ||||
|   url: string, | ||||
| @ -124,12 +125,14 @@ export function createEbmlController(src: string) { | ||||
| 
 | ||||
|       const segments$ = segmentStart$.pipe( | ||||
|         map((startTag) => { | ||||
|           const segment = new EbmlSegment(startTag); | ||||
|           const segment = new SegmentSystem(startTag); | ||||
|           const clusterSystem = segment.cluster; | ||||
|           const seekSystem = segment.seek; | ||||
| 
 | ||||
|           const continuousReusedCluster$ = ebml$.pipe( | ||||
|             filter(isTagIdPos(EbmlTagIdEnum.Cluster, EbmlTagPosition.End)), | ||||
|             filter((s) => s.id === EbmlTagIdEnum.Cluster), | ||||
|             map(Cluster.fromTag.bind(Cluster)) | ||||
|             map(clusterSystem.addClusterWithTag.bind(clusterSystem)) | ||||
|           ); | ||||
| 
 | ||||
|           const segmentEnd$ = ebml$.pipe( | ||||
| @ -154,33 +157,27 @@ export function createEbmlController(src: string) { | ||||
|           ); | ||||
| 
 | ||||
|           const withMeta$ = meta$.pipe( | ||||
|             reduce((segment, meta) => { | ||||
|               segment.scanMeta(meta); | ||||
|               return segment; | ||||
|             }, segment), | ||||
|             map((segment) => { | ||||
|               segment.markMetaEnd(); | ||||
|               return segment; | ||||
|             }), | ||||
|             reduce((segment, meta) => segment.scanHead(meta), segment), | ||||
|             map(segment.completeHeads.bind(segment)), | ||||
|             take(1), | ||||
|             shareReplay(1) | ||||
|           ); | ||||
| 
 | ||||
|           const withRemoteCues$ = withMeta$.pipe( | ||||
|             switchMap((s) => { | ||||
|               if (s.cuesNode) { | ||||
|               const cueSystem = s.cue; | ||||
|               const seekSystem = s.seek; | ||||
|               if (cueSystem.prepared) { | ||||
|                 return EMPTY; | ||||
|               } | ||||
|               const cuesStartOffset = | ||||
|                 s.dataOffset + | ||||
|                 (s.findSeekPositionBySeekId(SEEK_ID_KAX_CUES) ?? Number.NaN); | ||||
|               if (cuesStartOffset >= 0) { | ||||
|                 return createRangedEbmlStream(src, cuesStartOffset).pipe( | ||||
|               const remoteCuesTagStartOffset = seekSystem.seekOffsetBySeekId(SEEK_ID_KAX_CUES); | ||||
|               if (remoteCuesTagStartOffset! >= 0) { | ||||
|                 return createRangedEbmlStream(src, remoteCuesTagStartOffset).pipe( | ||||
|                   switchMap((req) => req.ebml$), | ||||
|                   filter(isTagIdPos(EbmlTagIdEnum.Cues, EbmlTagPosition.End)), | ||||
|                   withLatestFrom(withMeta$), | ||||
|                   map(([cues, withMeta]) => { | ||||
|                     withMeta.cuesNode = cues; | ||||
|                     withMeta.cue.prepareCuesWithTag(cues); | ||||
|                     return withMeta; | ||||
|                   }) | ||||
|                 ); | ||||
| @ -192,12 +189,7 @@ export function createEbmlController(src: string) { | ||||
|           ); | ||||
| 
 | ||||
|           const withLocalCues$ = withMeta$.pipe( | ||||
|             switchMap((s) => { | ||||
|               if (s.cuesNode) { | ||||
|                 return of(s); | ||||
|               } | ||||
|               return EMPTY; | ||||
|             }), | ||||
|             switchMap((s) => s.cue.prepared ? of(s) : EMPTY), | ||||
|             shareReplay(1) | ||||
|           ); | ||||
| 
 | ||||
| @ -210,7 +202,7 @@ export function createEbmlController(src: string) { | ||||
|             switchMap((empty) => (empty ? withMeta$ : EMPTY)) | ||||
|           ); | ||||
| 
 | ||||
|           const seekWithoutCues = (seekTime: number): Observable<Cluster> => { | ||||
|           const seekWithoutCues = (seekTime: number): Observable<ClusterType> => { | ||||
|             const cluster$ = continuousReusedCluster$.pipe( | ||||
|               isEmpty(), | ||||
|               switchMap((empty) => { | ||||
| @ -223,7 +215,7 @@ export function createEbmlController(src: string) { | ||||
|                       filter( | ||||
|                         isTagIdPos(EbmlTagIdEnum.Cluster, EbmlTagPosition.End) | ||||
|                       ), | ||||
|                       map(Cluster.fromTag.bind(Cluster)) | ||||
|                       map((tag) => clusterSystem.addClusterWithTag(tag)) | ||||
|                     ) | ||||
|                   : continuousReusedCluster$; | ||||
|               }) | ||||
| @ -236,23 +228,23 @@ export function createEbmlController(src: string) { | ||||
|               scan( | ||||
|                 (prev, curr) => | ||||
|                   [prev?.[1], curr] as [ | ||||
|                     Cluster | undefined, | ||||
|                     Cluster | undefined, | ||||
|                     ClusterType | undefined, | ||||
|                     ClusterType | undefined, | ||||
|                   ], | ||||
|                 [undefined, undefined] as [ | ||||
|                   Cluster | undefined, | ||||
|                   Cluster | undefined, | ||||
|                   ClusterType | undefined, | ||||
|                   ClusterType | undefined, | ||||
|                 ] | ||||
|               ), | ||||
|               filter((c) => c[1]?.timestamp! > seekTime), | ||||
|               filter((c) => c[1]?.Timestamp! > seekTime), | ||||
|               map((c) => c[0] ?? c[1]!) | ||||
|             ); | ||||
|           }; | ||||
| 
 | ||||
|           const seekWithCues = ( | ||||
|             cues: CuesSystem, | ||||
|             cues: CueSystem, | ||||
|             seekTime: number | ||||
|           ): Observable<Cluster> => { | ||||
|           ): Observable<ClusterType> => { | ||||
|             if (seekTime === 0) { | ||||
|               return seekWithoutCues(seekTime); | ||||
|             } | ||||
| @ -265,29 +257,29 @@ export function createEbmlController(src: string) { | ||||
| 
 | ||||
|             return createRangedEbmlStream( | ||||
|               src, | ||||
|               cuePoint.position + segment.dataOffset | ||||
|               seekSystem.offsetFromSeekDataPosition(cues.getCueTrackPositions(cuePoint).CueClusterPosition) | ||||
|             ).pipe( | ||||
|               switchMap((req) => req.ebml$), | ||||
|               filter(isTagIdPos(EbmlTagIdEnum.Cluster, EbmlTagPosition.End)), | ||||
|               map(Cluster.fromTag.bind(Cluster)) | ||||
|               map(clusterSystem.addClusterWithTag.bind(clusterSystem)) | ||||
|             ); | ||||
|           }; | ||||
| 
 | ||||
|           const seek = (seekTime: number): Observable<Cluster> => { | ||||
|           const seek = (seekTime: number): Observable<ClusterType> => { | ||||
|             if (seekTime === 0) { | ||||
|               const subscripton = merge(withCues$, withoutCues$).subscribe(); | ||||
|               const subscription = merge(withCues$, withoutCues$).subscribe(); | ||||
| 
 | ||||
|               // if seekTime equals to 0 at start, reuse the initialize stream
 | ||||
|               return seekWithoutCues(seekTime).pipe( | ||||
|                 finalize(() => { | ||||
|                   subscripton.unsubscribe(); | ||||
|                   subscription.unsubscribe(); | ||||
|                 }) | ||||
|               ); | ||||
|             } | ||||
|             return merge( | ||||
|               withCues$.pipe( | ||||
|                 switchMap((s) => | ||||
|                   seekWithCues(CuesSystem.fromTag(s.cuesNode!), seekTime) | ||||
|                   seekWithCues(s.cue, seekTime) | ||||
|                 ) | ||||
|               ), | ||||
|               withoutCues$.pipe(switchMap((_) => seekWithoutCues(seekTime))) | ||||
|  | ||||
| @ -33,7 +33,7 @@ export const SeekSchema = type({ | ||||
| export type SeekType = typeof SeekSchema.infer; | ||||
| 
 | ||||
| export const SeekHeadSchema = type({ | ||||
|   Seek: SeekSchema.array(), | ||||
|   Seek: SeekSchema.array().atLeastLength(1), | ||||
| }); | ||||
| 
 | ||||
| export type SeekHeadType = typeof SeekHeadSchema.infer; | ||||
| @ -79,7 +79,7 @@ export const BlockMoreSchema = type({ | ||||
| export type BlockMoreType = typeof BlockMoreSchema.infer; | ||||
| 
 | ||||
| export const BlockAdditionsSchema = type({ | ||||
|   BlockMore: BlockMoreSchema.array(), | ||||
|   BlockMore: BlockMoreSchema.array().atLeastLength(1), | ||||
| }); | ||||
| 
 | ||||
| export type BlockAdditionsType = typeof BlockAdditionsSchema.infer; | ||||
| @ -198,12 +198,9 @@ export enum MatrixCoefficientsRestrictionEnum { | ||||
|   CHROMA_DERIVED_CONSTANT_LUMINANCE = 13, | ||||
|   // ITU-R BT.2100-0
 | ||||
|   ITU_R_BT_2100_0 = 14, | ||||
| } | ||||
| export const MatrixCoefficientsRestriction = type( | ||||
|   '0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14' | ||||
| ); | ||||
| export type MatrixCoefficientsRestrictionType = | ||||
|   typeof MatrixCoefficientsRestriction.infer; | ||||
| }; | ||||
| export const MatrixCoefficientsRestriction = type('0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14'); | ||||
| export type MatrixCoefficientsRestrictionType = typeof MatrixCoefficientsRestriction.infer; | ||||
| 
 | ||||
| export enum ChromaSitingHorzRestrictionEnum { | ||||
|   // unspecified
 | ||||
| @ -212,10 +209,9 @@ export enum ChromaSitingHorzRestrictionEnum { | ||||
|   LEFT_COLLOCATED = 1, | ||||
|   // half
 | ||||
|   HALF = 2, | ||||
| } | ||||
| }; | ||||
| export const ChromaSitingHorzRestriction = type('0 | 1 | 2'); | ||||
| export type ChromaSitingHorzRestrictionType = | ||||
|   typeof ChromaSitingHorzRestriction.infer; | ||||
| export type ChromaSitingHorzRestrictionType = typeof ChromaSitingHorzRestriction.infer; | ||||
| 
 | ||||
| export enum ChromaSitingVertRestrictionEnum { | ||||
|   // unspecified
 | ||||
| @ -224,10 +220,9 @@ export enum ChromaSitingVertRestrictionEnum { | ||||
|   TOP_COLLOCATED = 1, | ||||
|   // half
 | ||||
|   HALF = 2, | ||||
| } | ||||
| }; | ||||
| export const ChromaSitingVertRestriction = type('0 | 1 | 2'); | ||||
| export type ChromaSitingVertRestrictionType = | ||||
|   typeof ChromaSitingVertRestriction.infer; | ||||
| export type ChromaSitingVertRestrictionType = typeof ChromaSitingVertRestriction.infer; | ||||
| 
 | ||||
| export enum RangeRestrictionEnum { | ||||
|   // unspecified
 | ||||
| @ -238,7 +233,7 @@ export enum RangeRestrictionEnum { | ||||
|   FULL_RANGE_NO_CLIPPING = 2, | ||||
|   // defined by MatrixCoefficients / TransferCharacteristics
 | ||||
|   DEFINED_BY_MATRIX_COEFFICIENTS_TRANSFER_CHARACTERISTICS = 3, | ||||
| } | ||||
| }; | ||||
| export const RangeRestriction = type('0 | 1 | 2 | 3'); | ||||
| export type RangeRestrictionType = typeof RangeRestriction.infer; | ||||
| 
 | ||||
| @ -281,12 +276,9 @@ export enum TransferCharacteristicsRestrictionEnum { | ||||
|   SMPTE_ST_428_1 = 17, | ||||
|   // ARIB STD-B67 (HLG)
 | ||||
|   ARIB_STD_B67_HLG = 18, | ||||
| } | ||||
| export const TransferCharacteristicsRestriction = type( | ||||
|   '0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18' | ||||
| ); | ||||
| export type TransferCharacteristicsRestrictionType = | ||||
|   typeof TransferCharacteristicsRestriction.infer; | ||||
| }; | ||||
| export const TransferCharacteristicsRestriction = type('0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18'); | ||||
| export type TransferCharacteristicsRestrictionType = typeof TransferCharacteristicsRestriction.infer; | ||||
| 
 | ||||
| export enum PrimariesRestrictionEnum { | ||||
|   // reserved
 | ||||
| @ -317,10 +309,8 @@ export enum PrimariesRestrictionEnum { | ||||
|   SMPTE_EG_432_2 = 12, | ||||
|   // EBU Tech. 3213-E - JEDEC P22 phosphors
 | ||||
|   EBU_TECH_3213_E_JEDEC_P22_PHOSPHORS = 22, | ||||
| } | ||||
| export const PrimariesRestriction = type( | ||||
|   '0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 22' | ||||
| ); | ||||
| }; | ||||
| export const PrimariesRestriction = type('0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 22'); | ||||
| export type PrimariesRestrictionType = typeof PrimariesRestriction.infer; | ||||
| 
 | ||||
| export const ColourSchema = type({ | ||||
| @ -351,10 +341,9 @@ export enum ProjectionTypeRestrictionEnum { | ||||
|   CUBEMAP = 2, | ||||
|   // mesh
 | ||||
|   MESH = 3, | ||||
| } | ||||
| }; | ||||
| export const ProjectionTypeRestriction = type('0 | 1 | 2 | 3'); | ||||
| export type ProjectionTypeRestrictionType = | ||||
|   typeof ProjectionTypeRestriction.infer; | ||||
| export type ProjectionTypeRestrictionType = typeof ProjectionTypeRestriction.infer; | ||||
| 
 | ||||
| export const ProjectionSchema = type({ | ||||
|   ProjectionType: ProjectionTypeRestriction.default(0), | ||||
| @ -373,10 +362,9 @@ export enum FlagInterlacedRestrictionEnum { | ||||
|   INTERLACED = 1, | ||||
|   // progressive
 | ||||
|   PROGRESSIVE = 2, | ||||
| } | ||||
| }; | ||||
| export const FlagInterlacedRestriction = type('0 | 1 | 2'); | ||||
| export type FlagInterlacedRestrictionType = | ||||
|   typeof FlagInterlacedRestriction.infer; | ||||
| export type FlagInterlacedRestrictionType = typeof FlagInterlacedRestriction.infer; | ||||
| 
 | ||||
| export enum FieldOrderRestrictionEnum { | ||||
|   // progressive
 | ||||
| @ -391,7 +379,7 @@ export enum FieldOrderRestrictionEnum { | ||||
|   TFF_INTERLEAVED = 9, | ||||
|   // bff (interleaved)
 | ||||
|   BFF_INTERLEAVED = 14, | ||||
| } | ||||
| }; | ||||
| export const FieldOrderRestriction = type('0 | 1 | 2 | 6 | 9 | 14'); | ||||
| export type FieldOrderRestrictionType = typeof FieldOrderRestriction.infer; | ||||
| 
 | ||||
| @ -426,10 +414,8 @@ export enum StereoModeRestrictionEnum { | ||||
|   BOTH_EYES_LACED_IN_ONE_BLOCK_LEFT_EYE_IS_FIRST = 13, | ||||
|   // both eyes laced in one Block (right eye is first)
 | ||||
|   BOTH_EYES_LACED_IN_ONE_BLOCK_RIGHT_EYE_IS_FIRST = 14, | ||||
| } | ||||
| export const StereoModeRestriction = type( | ||||
|   '0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14' | ||||
| ); | ||||
| }; | ||||
| export const StereoModeRestriction = type('0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14'); | ||||
| export type StereoModeRestrictionType = typeof StereoModeRestriction.infer; | ||||
| 
 | ||||
| export enum AlphaModeRestrictionEnum { | ||||
| @ -437,7 +423,7 @@ export enum AlphaModeRestrictionEnum { | ||||
|   NONE = 0, | ||||
|   // present
 | ||||
|   PRESENT = 1, | ||||
| } | ||||
| }; | ||||
| export const AlphaModeRestriction = type('0 | 1'); | ||||
| export type AlphaModeRestrictionType = typeof AlphaModeRestriction.infer; | ||||
| 
 | ||||
| @ -450,10 +436,9 @@ export enum OldStereoModeRestrictionEnum { | ||||
|   LEFT_EYE = 2, | ||||
|   // both eyes
 | ||||
|   BOTH_EYES = 3, | ||||
| } | ||||
| }; | ||||
| export const OldStereoModeRestriction = type('0 | 1 | 2 | 3'); | ||||
| export type OldStereoModeRestrictionType = | ||||
|   typeof OldStereoModeRestriction.infer; | ||||
| export type OldStereoModeRestrictionType = typeof OldStereoModeRestriction.infer; | ||||
| 
 | ||||
| export enum DisplayUnitRestrictionEnum { | ||||
|   // pixels
 | ||||
| @ -466,7 +451,7 @@ export enum DisplayUnitRestrictionEnum { | ||||
|   DISPLAY_ASPECT_RATIO = 3, | ||||
|   // unknown
 | ||||
|   UNKNOWN = 4, | ||||
| } | ||||
| }; | ||||
| export const DisplayUnitRestriction = type('0 | 1 | 2 | 3 | 4'); | ||||
| export type DisplayUnitRestrictionType = typeof DisplayUnitRestriction.infer; | ||||
| 
 | ||||
| @ -477,10 +462,9 @@ export enum AspectRatioTypeRestrictionEnum { | ||||
|   KEEP_ASPECT_RATIO = 1, | ||||
|   // fixed
 | ||||
|   FIXED = 2, | ||||
| } | ||||
| }; | ||||
| export const AspectRatioTypeRestriction = type('0 | 1 | 2'); | ||||
| export type AspectRatioTypeRestrictionType = | ||||
|   typeof AspectRatioTypeRestriction.infer; | ||||
| export type AspectRatioTypeRestrictionType = typeof AspectRatioTypeRestriction.infer; | ||||
| 
 | ||||
| export const VideoSchema = type({ | ||||
|   FlagInterlaced: FlagInterlacedRestriction.default(0), | ||||
| @ -534,10 +518,8 @@ export enum EmphasisRestrictionEnum { | ||||
|   PHONO_LONDON = 15, | ||||
|   // Phono NARTB
 | ||||
|   PHONO_NARTB = 16, | ||||
| } | ||||
| export const EmphasisRestriction = type( | ||||
|   '0 | 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | 16' | ||||
| ); | ||||
| }; | ||||
| export const EmphasisRestriction = type('0 | 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | 16'); | ||||
| export type EmphasisRestrictionType = typeof EmphasisRestriction.infer; | ||||
| 
 | ||||
| export const AudioSchema = type({ | ||||
| @ -558,10 +540,9 @@ export enum TrackPlaneTypeRestrictionEnum { | ||||
|   RIGHT_EYE = 1, | ||||
|   // background
 | ||||
|   BACKGROUND = 2, | ||||
| } | ||||
| }; | ||||
| export const TrackPlaneTypeRestriction = type('0 | 1 | 2'); | ||||
| export type TrackPlaneTypeRestrictionType = | ||||
|   typeof TrackPlaneTypeRestriction.infer; | ||||
| export type TrackPlaneTypeRestrictionType = typeof TrackPlaneTypeRestriction.infer; | ||||
| 
 | ||||
| export const TrackPlaneSchema = type({ | ||||
|   TrackPlaneUID: type.number, | ||||
| @ -571,13 +552,13 @@ export const TrackPlaneSchema = type({ | ||||
| export type TrackPlaneType = typeof TrackPlaneSchema.infer; | ||||
| 
 | ||||
| export const TrackCombinePlanesSchema = type({ | ||||
|   TrackPlane: TrackPlaneSchema.array(), | ||||
|   TrackPlane: TrackPlaneSchema.array().atLeastLength(1), | ||||
| }); | ||||
| 
 | ||||
| export type TrackCombinePlanesType = typeof TrackCombinePlanesSchema.infer; | ||||
| 
 | ||||
| export const TrackJoinBlocksSchema = type({ | ||||
|   TrackJoinUID: type.number.array(), | ||||
|   TrackJoinUID: type.number.array().atLeastLength(1), | ||||
| }); | ||||
| 
 | ||||
| export type TrackJoinBlocksType = typeof TrackJoinBlocksSchema.infer; | ||||
| @ -598,10 +579,9 @@ export enum ContentCompAlgoRestrictionEnum { | ||||
|   LZO1X = 2, | ||||
|   // Header Stripping
 | ||||
|   HEADER_STRIPPING = 3, | ||||
| } | ||||
| }; | ||||
| export const ContentCompAlgoRestriction = type('0 | 1 | 2 | 3'); | ||||
| export type ContentCompAlgoRestrictionType = | ||||
|   typeof ContentCompAlgoRestriction.infer; | ||||
| export type ContentCompAlgoRestrictionType = typeof ContentCompAlgoRestriction.infer; | ||||
| 
 | ||||
| export const ContentCompressionSchema = type({ | ||||
|   ContentCompAlgo: ContentCompAlgoRestriction.default(0), | ||||
| @ -615,17 +595,15 @@ export enum AESSettingsCipherModeRestrictionEnum { | ||||
|   AES_CTR = 1, | ||||
|   // AES-CBC
 | ||||
|   AES_CBC = 2, | ||||
| } | ||||
| }; | ||||
| export const AESSettingsCipherModeRestriction = type('1 | 2'); | ||||
| export type AESSettingsCipherModeRestrictionType = | ||||
|   typeof AESSettingsCipherModeRestriction.infer; | ||||
| export type AESSettingsCipherModeRestrictionType = typeof AESSettingsCipherModeRestriction.infer; | ||||
| 
 | ||||
| export const ContentEncAESSettingsSchema = type({ | ||||
|   AESSettingsCipherMode: AESSettingsCipherModeRestriction, | ||||
| }); | ||||
| 
 | ||||
| export type ContentEncAESSettingsType = | ||||
|   typeof ContentEncAESSettingsSchema.infer; | ||||
| export type ContentEncAESSettingsType = typeof ContentEncAESSettingsSchema.infer; | ||||
| 
 | ||||
| export enum ContentEncAlgoRestrictionEnum { | ||||
|   // Not encrypted
 | ||||
| @ -640,20 +618,18 @@ export enum ContentEncAlgoRestrictionEnum { | ||||
|   BLOWFISH = 4, | ||||
|   // AES
 | ||||
|   AES = 5, | ||||
| } | ||||
| }; | ||||
| export const ContentEncAlgoRestriction = type('0 | 1 | 2 | 3 | 4 | 5'); | ||||
| export type ContentEncAlgoRestrictionType = | ||||
|   typeof ContentEncAlgoRestriction.infer; | ||||
| export type ContentEncAlgoRestrictionType = typeof ContentEncAlgoRestriction.infer; | ||||
| 
 | ||||
| export enum ContentSigAlgoRestrictionEnum { | ||||
|   // Not signed
 | ||||
|   NOT_SIGNED = 0, | ||||
|   // RSA
 | ||||
|   RSA = 1, | ||||
| } | ||||
| }; | ||||
| export const ContentSigAlgoRestriction = type('0 | 1'); | ||||
| export type ContentSigAlgoRestrictionType = | ||||
|   typeof ContentSigAlgoRestriction.infer; | ||||
| export type ContentSigAlgoRestrictionType = typeof ContentSigAlgoRestriction.infer; | ||||
| 
 | ||||
| export enum ContentSigHashAlgoRestrictionEnum { | ||||
|   // Not signed
 | ||||
| @ -662,10 +638,9 @@ export enum ContentSigHashAlgoRestrictionEnum { | ||||
|   SHA1_160 = 1, | ||||
|   // MD5
 | ||||
|   MD5 = 2, | ||||
| } | ||||
| }; | ||||
| export const ContentSigHashAlgoRestriction = type('0 | 1 | 2'); | ||||
| export type ContentSigHashAlgoRestrictionType = | ||||
|   typeof ContentSigHashAlgoRestriction.infer; | ||||
| export type ContentSigHashAlgoRestrictionType = typeof ContentSigHashAlgoRestriction.infer; | ||||
| 
 | ||||
| export const ContentEncryptionSchema = type({ | ||||
|   ContentEncAlgo: ContentEncAlgoRestriction.default(0), | ||||
| @ -686,20 +661,18 @@ export enum ContentEncodingScopeRestrictionEnum { | ||||
|   PRIVATE = 2, | ||||
|   // Next
 | ||||
|   NEXT = 4, | ||||
| } | ||||
| }; | ||||
| export const ContentEncodingScopeRestriction = type('1 | 2 | 4'); | ||||
| export type ContentEncodingScopeRestrictionType = | ||||
|   typeof ContentEncodingScopeRestriction.infer; | ||||
| export type ContentEncodingScopeRestrictionType = typeof ContentEncodingScopeRestriction.infer; | ||||
| 
 | ||||
| export enum ContentEncodingTypeRestrictionEnum { | ||||
|   // Compression
 | ||||
|   COMPRESSION = 0, | ||||
|   // Encryption
 | ||||
|   ENCRYPTION = 1, | ||||
| } | ||||
| }; | ||||
| export const ContentEncodingTypeRestriction = type('0 | 1'); | ||||
| export type ContentEncodingTypeRestrictionType = | ||||
|   typeof ContentEncodingTypeRestriction.infer; | ||||
| export type ContentEncodingTypeRestrictionType = typeof ContentEncodingTypeRestriction.infer; | ||||
| 
 | ||||
| export const ContentEncodingSchema = type({ | ||||
|   ContentEncodingOrder: type.number.default(0), | ||||
| @ -712,7 +685,7 @@ export const ContentEncodingSchema = type({ | ||||
| export type ContentEncodingType = typeof ContentEncodingSchema.infer; | ||||
| 
 | ||||
| export const ContentEncodingsSchema = type({ | ||||
|   ContentEncoding: ContentEncodingSchema.array(), | ||||
|   ContentEncoding: ContentEncodingSchema.array().atLeastLength(1), | ||||
| }); | ||||
| 
 | ||||
| export type ContentEncodingsType = typeof ContentEncodingsSchema.infer; | ||||
| @ -734,7 +707,7 @@ export enum TrackTypeRestrictionEnum { | ||||
|   CONTROL = 32, | ||||
|   // metadata
 | ||||
|   METADATA = 33, | ||||
| } | ||||
| }; | ||||
| export const TrackTypeRestriction = type('1 | 2 | 3 | 16 | 17 | 18 | 32 | 33'); | ||||
| export type TrackTypeRestrictionType = typeof TrackTypeRestriction.infer; | ||||
| 
 | ||||
| @ -760,7 +733,7 @@ export const TrackEntrySchema = type({ | ||||
|   MaxBlockAdditionID: type.number.default(0), | ||||
|   BlockAdditionMapping: BlockAdditionMappingSchema.array().optional(), | ||||
|   Name: type.string.optional(), | ||||
|   Language: type.string.default('eng'), | ||||
|   Language: type.string.default("eng"), | ||||
|   LanguageBCP47: type.string.optional(), | ||||
|   CodecID: type.string, | ||||
|   CodecPrivate: BinarySchema.optional(), | ||||
| @ -788,7 +761,7 @@ export const TrackEntrySchema = type({ | ||||
| export type TrackEntryType = typeof TrackEntrySchema.infer; | ||||
| 
 | ||||
| export const TracksSchema = type({ | ||||
|   TrackEntry: TrackEntrySchema.array(), | ||||
|   TrackEntry: TrackEntrySchema.array().atLeastLength(1), | ||||
| }); | ||||
| 
 | ||||
| export type TracksType = typeof TracksSchema.infer; | ||||
| @ -816,13 +789,13 @@ export type CueTrackPositionsType = typeof CueTrackPositionsSchema.infer; | ||||
| 
 | ||||
| export const CuePointSchema = type({ | ||||
|   CueTime: type.number, | ||||
|   CueTrackPositions: CueTrackPositionsSchema.array(), | ||||
|   CueTrackPositions: CueTrackPositionsSchema.array().atLeastLength(1), | ||||
| }); | ||||
| 
 | ||||
| export type CuePointType = typeof CuePointSchema.infer; | ||||
| 
 | ||||
| export const CuesSchema = type({ | ||||
|   CuePoint: CuePointSchema.array(), | ||||
|   CuePoint: CuePointSchema.array().atLeastLength(1), | ||||
| }); | ||||
| 
 | ||||
| export type CuesType = typeof CuesSchema.infer; | ||||
| @ -841,7 +814,7 @@ export const AttachedFileSchema = type({ | ||||
| export type AttachedFileType = typeof AttachedFileSchema.infer; | ||||
| 
 | ||||
| export const AttachmentsSchema = type({ | ||||
|   AttachedFile: AttachedFileSchema.array(), | ||||
|   AttachedFile: AttachedFileSchema.array().atLeastLength(1), | ||||
| }); | ||||
| 
 | ||||
| export type AttachmentsType = typeof AttachmentsSchema.infer; | ||||
| @ -859,38 +832,39 @@ export const EditionEntrySchema = type({ | ||||
|   EditionFlagDefault: type.number.default(0), | ||||
|   EditionFlagOrdered: type.number.default(0), | ||||
|   EditionDisplay: EditionDisplaySchema.array().optional(), | ||||
| 
 | ||||
| }); | ||||
| 
 | ||||
| export type EditionEntryType = typeof EditionEntrySchema.infer; | ||||
| 
 | ||||
| export const ChaptersSchema = type({ | ||||
|   EditionEntry: EditionEntrySchema.array(), | ||||
|   EditionEntry: EditionEntrySchema.array().atLeastLength(1), | ||||
| }); | ||||
| 
 | ||||
| export type ChaptersType = typeof ChaptersSchema.infer; | ||||
| 
 | ||||
| export const TagTrackUIDSchema = match({ | ||||
|   'number[]': (v) => (v.length > 0 ? v : [0]), | ||||
|   undefined: () => [0], | ||||
|   default: 'assert', | ||||
|   "number[]": v => v.length > 0 ? v : [0], | ||||
|   "undefined": () => [0], | ||||
|   default: "assert" | ||||
| }); | ||||
| 
 | ||||
| export const TagEditionUIDSchema = match({ | ||||
|   'number[]': (v) => (v.length > 0 ? v : [0]), | ||||
|   undefined: () => [0], | ||||
|   default: 'assert', | ||||
|   "number[]": v => v.length > 0 ? v : [0], | ||||
|   "undefined": () => [0], | ||||
|   default: "assert" | ||||
| }); | ||||
| 
 | ||||
| export const TagChapterUIDSchema = match({ | ||||
|   'number[]': (v) => (v.length > 0 ? v : [0]), | ||||
|   undefined: () => [0], | ||||
|   default: 'assert', | ||||
|   "number[]": v => v.length > 0 ? v : [0], | ||||
|   "undefined": () => [0], | ||||
|   default: "assert" | ||||
| }); | ||||
| 
 | ||||
| export const TagAttachmentUIDSchema = match({ | ||||
|   'number[]': (v) => (v.length > 0 ? v : [0]), | ||||
|   undefined: () => [0], | ||||
|   default: 'assert', | ||||
|   "number[]": v => v.length > 0 ? v : [0], | ||||
|   "undefined": () => [0], | ||||
|   default: "assert" | ||||
| }); | ||||
| 
 | ||||
| export enum TargetTypeValueRestrictionEnum { | ||||
| @ -908,60 +882,55 @@ export enum TargetTypeValueRestrictionEnum { | ||||
|   EDITION_ISSUE_VOLUME_OPUS_SEASON_SEQUEL = 60, | ||||
|   // COLLECTION
 | ||||
|   COLLECTION = 70, | ||||
| } | ||||
| export const TargetTypeValueRestriction = type( | ||||
|   '10 | 20 | 30 | 40 | 50 | 60 | 70' | ||||
| ); | ||||
| export type TargetTypeValueRestrictionType = | ||||
|   typeof TargetTypeValueRestriction.infer; | ||||
| }; | ||||
| export const TargetTypeValueRestriction = type('10 | 20 | 30 | 40 | 50 | 60 | 70'); | ||||
| export type TargetTypeValueRestrictionType = typeof TargetTypeValueRestriction.infer; | ||||
| 
 | ||||
| export enum TargetTypeRestrictionEnum { | ||||
|   // TargetTypeValue 70
 | ||||
|   COLLECTION = 'COLLECTION', | ||||
|   COLLECTION = "COLLECTION", | ||||
|   // TargetTypeValue 60
 | ||||
|   EDITION = 'EDITION', | ||||
|   EDITION = "EDITION", | ||||
|   // TargetTypeValue 60
 | ||||
|   ISSUE = 'ISSUE', | ||||
|   ISSUE = "ISSUE", | ||||
|   // TargetTypeValue 60
 | ||||
|   VOLUME = 'VOLUME', | ||||
|   VOLUME = "VOLUME", | ||||
|   // TargetTypeValue 60
 | ||||
|   OPUS = 'OPUS', | ||||
|   OPUS = "OPUS", | ||||
|   // TargetTypeValue 60
 | ||||
|   SEASON = 'SEASON', | ||||
|   SEASON = "SEASON", | ||||
|   // TargetTypeValue 60
 | ||||
|   SEQUEL = 'SEQUEL', | ||||
|   SEQUEL = "SEQUEL", | ||||
|   // TargetTypeValue 50
 | ||||
|   ALBUM = 'ALBUM', | ||||
|   ALBUM = "ALBUM", | ||||
|   // TargetTypeValue 50
 | ||||
|   OPERA = 'OPERA', | ||||
|   OPERA = "OPERA", | ||||
|   // TargetTypeValue 50
 | ||||
|   CONCERT = 'CONCERT', | ||||
|   CONCERT = "CONCERT", | ||||
|   // TargetTypeValue 50
 | ||||
|   MOVIE = 'MOVIE', | ||||
|   MOVIE = "MOVIE", | ||||
|   // TargetTypeValue 50
 | ||||
|   EPISODE = 'EPISODE', | ||||
|   EPISODE = "EPISODE", | ||||
|   // TargetTypeValue 40
 | ||||
|   PART = 'PART', | ||||
|   PART = "PART", | ||||
|   // TargetTypeValue 40
 | ||||
|   SESSION = 'SESSION', | ||||
|   SESSION = "SESSION", | ||||
|   // TargetTypeValue 30
 | ||||
|   TRACK = 'TRACK', | ||||
|   TRACK = "TRACK", | ||||
|   // TargetTypeValue 30
 | ||||
|   SONG = 'SONG', | ||||
|   SONG = "SONG", | ||||
|   // TargetTypeValue 30
 | ||||
|   CHAPTER = 'CHAPTER', | ||||
|   CHAPTER = "CHAPTER", | ||||
|   // TargetTypeValue 20
 | ||||
|   SUBTRACK = 'SUBTRACK', | ||||
|   SUBTRACK = "SUBTRACK", | ||||
|   // TargetTypeValue 20
 | ||||
|   MOVEMENT = 'MOVEMENT', | ||||
|   MOVEMENT = "MOVEMENT", | ||||
|   // TargetTypeValue 20
 | ||||
|   SCENE = 'SCENE', | ||||
|   SCENE = "SCENE", | ||||
|   // TargetTypeValue 10
 | ||||
|   SHOT = 'SHOT', | ||||
| } | ||||
| export const TargetTypeRestriction = type( | ||||
|   '"COLLECTION" | "EDITION" | "ISSUE" | "VOLUME" | "OPUS" | "SEASON" | "SEQUEL" | "ALBUM" | "OPERA" | "CONCERT" | "MOVIE" | "EPISODE" | "PART" | "SESSION" | "TRACK" | "SONG" | "CHAPTER" | "SUBTRACK" | "MOVEMENT" | "SCENE" | "SHOT"' | ||||
| ); | ||||
|   SHOT = "SHOT", | ||||
| }; | ||||
| export const TargetTypeRestriction = type('"COLLECTION" | "EDITION" | "ISSUE" | "VOLUME" | "OPUS" | "SEASON" | "SEQUEL" | "ALBUM" | "OPERA" | "CONCERT" | "MOVIE" | "EPISODE" | "PART" | "SESSION" | "TRACK" | "SONG" | "CHAPTER" | "SUBTRACK" | "MOVEMENT" | "SCENE" | "SHOT"'); | ||||
| export type TargetTypeRestrictionType = typeof TargetTypeRestriction.infer; | ||||
| 
 | ||||
| export const TargetsSchema = type({ | ||||
| @ -977,12 +946,13 @@ export type TargetsType = typeof TargetsSchema.infer; | ||||
| 
 | ||||
| export const TagSchema = type({ | ||||
|   Targets: TargetsSchema, | ||||
| 
 | ||||
| }); | ||||
| 
 | ||||
| export type TagType = typeof TagSchema.infer; | ||||
| 
 | ||||
| export const TagsSchema = type({ | ||||
|   Tag: TagSchema.array(), | ||||
|   Tag: TagSchema.array().atLeastLength(1), | ||||
| }); | ||||
| 
 | ||||
| export type TagsType = typeof TagsSchema.infer; | ||||
| @ -1037,5 +1007,5 @@ export const IdMultiSet = new Set([ | ||||
|   EbmlTagIdEnum.Tag, | ||||
|   EbmlTagIdEnum.SeekHead, | ||||
|   EbmlTagIdEnum.Cluster, | ||||
|   EbmlTagIdEnum.Tags, | ||||
| ]); | ||||
|   EbmlTagIdEnum.Tags | ||||
| ]) | ||||
| @ -2,11 +2,7 @@ import type { Type } from 'arktype'; | ||||
| import { EbmlElementType, EbmlTagIdEnum, type EbmlTagType } from 'konoebml'; | ||||
| import { IdMultiSet } from './schema'; | ||||
| 
 | ||||
| export type InferType<T> = T extends Type<infer U> ? U : never; | ||||
| 
 | ||||
| export const SEEK_ID_KAX_INFO = new Uint8Array([0x15, 0x49, 0xa9, 0x66]); | ||||
| export const SEEK_ID_KAX_TRACKS = new Uint8Array([0x16, 0x54, 0xae, 0x6b]); | ||||
| export const SEEK_ID_KAX_CUES = new Uint8Array([0x1c, 0x53, 0xbb, 0x6b]); | ||||
| export type InferType<T extends Type<any>> = T['infer']; | ||||
| 
 | ||||
| export type PredicateIdExtract<T, K> = Extract<T, { id: K }>; | ||||
| 
 | ||||
| @ -31,13 +27,13 @@ export function isTagPos< | ||||
|     pos === '*' || pos === tag.position; | ||||
| } | ||||
| 
 | ||||
| export function convertEbmlTagToModelShape(tag: EbmlTagType) { | ||||
| export function convertEbmlTagToComponent (tag: EbmlTagType) { | ||||
|   if (tag.type === EbmlElementType.Master) { | ||||
|     const obj: Record<string, any> = {}; | ||||
|     const children = tag.children; | ||||
|     for (const c of children) { | ||||
|       const name = EbmlTagIdEnum[c.id]; | ||||
|       const converted = convertEbmlTagToModelShape(c); | ||||
|       const converted = convertEbmlTagToComponent(c); | ||||
|       if (IdMultiSet.has(c.id)) { | ||||
|         if (obj[name]) { | ||||
|           obj[name].push(converted); | ||||
| @ -48,6 +44,7 @@ export function convertEbmlTagToModelShape(tag: EbmlTagType) { | ||||
|         obj[name] = converted; | ||||
|       } | ||||
|     } | ||||
|     return obj; | ||||
|   } | ||||
|   if (tag.id === EbmlTagIdEnum.SimpleBlock || tag.id === EbmlTagIdEnum.Block) { | ||||
|     return tag; | ||||
|  | ||||
| @ -390,6 +390,9 @@ function generateMkvSchemaHierarchy(elements_: EbmlElementType[]) { | ||||
|           : meta.primitive(v.name); | ||||
|         if (v.maxOccurs !== 1) { | ||||
|           expr = `${expr}.array()`; | ||||
|           if (v.maxOccurs !== 1 && v.minOccurs === 1 && !v.default) { | ||||
|             expr = `${expr}.atLeastLength(1)` | ||||
|           } | ||||
|           idMulti.add(v.name); | ||||
|         } | ||||
|         if (v.default) { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user