From f41399cf1eb88444e90fd108f06cc4d289bfe956 Mon Sep 17 00:00:00 2001 From: ianshade Date: Fri, 6 Oct 2023 10:03:24 +0200 Subject: [PATCH] refactor: extract more deserializers --- src/deserializers.ts | 164 -------------------- src/deserializers/deserializeClipInfo.ts | 46 ++++++ src/deserializers/deserializeInfo.ts | 17 ++ src/deserializers/deserializeInfoChannel.ts | 43 +++++ src/deserializers/deserializeInfoLayer.ts | 8 + src/deserializers/deserializeVersion.ts | 31 ++++ src/deserializers/index.ts | 26 ++++ src/lib.ts | 8 + 8 files changed, 179 insertions(+), 164 deletions(-) delete mode 100755 src/deserializers.ts create mode 100644 src/deserializers/deserializeClipInfo.ts create mode 100644 src/deserializers/deserializeInfo.ts create mode 100644 src/deserializers/deserializeInfoChannel.ts create mode 100644 src/deserializers/deserializeInfoLayer.ts create mode 100644 src/deserializers/deserializeVersion.ts create mode 100644 src/deserializers/index.ts diff --git a/src/deserializers.ts b/src/deserializers.ts deleted file mode 100755 index 8f5209e8..00000000 --- a/src/deserializers.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { CReturnType, Commands } from './commands' -import { deserializeXML } from './deserializers/deserializeXML' -import { deserializeInfoConfig } from './deserializers/deserializeInfoConfig' -import { Version } from './enums' -import { ClipInfo, InfoChannelEntry, InfoEntry, InfoLayerEntry } from './parameters' - -function deserializeClipInfo(line: string): ClipInfo | undefined { - const groups = line.match(/"([\s\S]*)" +(MOVIE|STILL|AUDIO) +([\s\S]*)/i) - - if (!groups) { - return undefined - } - const data = groups[3].split(' ') - - let datetime = 0 - { - // Handle datetime on the form "20230609071314" - const m = `${data[1]}`.match(/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/) - if (m) { - const d = new Date( - parseInt(m[1], 10), - parseInt(m[2], 10) - 1, - parseInt(m[3], 10), - parseInt(m[4], 10), - parseInt(m[5], 10), - parseInt(m[6], 10) - ) - // is valid? - if (d.getTime() > 0) datetime = d.getTime() - } - } - - let framerate = 0 - { - // Handle framerate on the form "1/25" - const m = `${data[3]}`.match(/(\d+)\/(\d+)/) - if (m) { - framerate = parseInt(m[2], 10) - } - } - - return { - clip: groups[1], - type: groups[2] as 'MOVIE' | 'STILL' | 'AUDIO', - size: parseInt(data[0], 10), - datetime, - frames: parseInt(data[2]) || 0, - framerate, - } -} - -const deserializeInfo = (line: string): InfoEntry | undefined => { - // 1 720p5000 PLAYING - - const info = line.match(/(?\d) (?\d+(?p|i)(?\d+))(?.*)/i) - if (info && info.groups) { - return { - channel: parseInt(info.groups.ChannelNo, 10), - format: parseInt(info.groups.Format, 10), - channelRate: parseInt(info.groups.Channelrate || '', 10) / 100, - frameRate: parseInt(info.groups.Channelrate || '', 10) / 100, // note - under 2.3 the 50i channels should use 50p calculations - interlaced: info.groups.Interlaced === 'i', - status: info.groups.Status.trim(), - } - } - return undefined -} -function ensureArray(v: T | T[]): T[] { - return Array.isArray(v) ? v : [v] -} -const deserializeInfoChannel = async (line: string): Promise => { - if (!line.startsWith(' parseInt(v, 10)), - }, - }, - - layers: compact( - Object.entries(ensureArray(mixerStage.layer)[0]).map(([layerName, layer0]) => { - const m = layerName.match(/layer_(\d+)/) - if (!m) return undefined - - const layer = ensureArray(layer0 as any)[0] - return { - layer: parseInt(m[1], 10), - // perhaps parse these later: - background: ensureArray(layer.background)[0], - foreground: ensureArray(layer.foreground)[0], - } - }) - ), - }, - } - - return data -} -const deserializeInfoLayer = async (line: string): Promise => { - // Is this actually correct? - // The data seems to be equal to info channel in 2.3.2 - return deserializeInfoChannel(line) -} -const deserializeVersion = ( - line: string -): { - version: Version - fullVersion: string -} => { - let version = Version.Unsupported - const v = line.split('.') - const major = Number(v[0]) - const minor = Number(v[1]) - - if (major <= 2) { - if (minor === 1) { - version = Version.v21x - } else if (minor === 2) { - version = Version.v22x - } else if (minor >= 3) { - // just parse anything newer as v2.3 as it's most likely closest - version = Version.v23x - } - } else { - version = Version.v23x - } - - return { - version, - fullVersion: line, - } -} - -function compact(array: (T | undefined)[]): T[] { - return array.filter((item) => item !== undefined) as T[] -} -export type Deserializer = (data: string[]) => Promise> -/** Just a type guard to ensure that the inner function returns a value as defined in AllInternalCommands */ -function deserializer(fcn: Deserializer): Deserializer { - return fcn -} - -export const deserializers = { - [Commands.Cls]: deserializer(async (data: string[]) => compact(data.map(deserializeClipInfo))), - [Commands.Cinf]: deserializer(async (data: string[]) => deserializeClipInfo(data[0])), - [Commands.Version]: deserializer(async (data: string[]) => deserializeVersion(data[0])), - [Commands.Info]: deserializer(async (data: string[]) => compact(data.map(deserializeInfo))), - [Commands.InfoChannel]: deserializer(async (data: string[]) => - deserializeInfoChannel(data[0]) - ), - [Commands.InfoLayer]: deserializer(async (data: string[]) => deserializeInfoLayer(data[0])), - [Commands.InfoConfig]: deserializer(async (data: string[]) => deserializeInfoConfig(data[0])), -} diff --git a/src/deserializers/deserializeClipInfo.ts b/src/deserializers/deserializeClipInfo.ts new file mode 100644 index 00000000..a92764e0 --- /dev/null +++ b/src/deserializers/deserializeClipInfo.ts @@ -0,0 +1,46 @@ +import { ClipInfo } from '../parameters' + +export function deserializeClipInfo(line: string): ClipInfo | undefined { + const groups = line.match(/"([\s\S]*)" +(MOVIE|STILL|AUDIO) +([\s\S]*)/i) + + if (!groups) { + return undefined + } + const data = groups[3].split(' ') + + let datetime = 0 + { + // Handle datetime on the form "20230609071314" + const m = `${data[1]}`.match(/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/) + if (m) { + const d = new Date( + parseInt(m[1], 10), + parseInt(m[2], 10) - 1, + parseInt(m[3], 10), + parseInt(m[4], 10), + parseInt(m[5], 10), + parseInt(m[6], 10) + ) + // is valid? + if (d.getTime() > 0) datetime = d.getTime() + } + } + + let framerate = 0 + { + // Handle framerate on the form "1/25" + const m = `${data[3]}`.match(/(\d+)\/(\d+)/) + if (m) { + framerate = parseInt(m[2], 10) + } + } + + return { + clip: groups[1], + type: groups[2] as 'MOVIE' | 'STILL' | 'AUDIO', + size: parseInt(data[0], 10), + datetime, + frames: parseInt(data[2]) || 0, + framerate, + } +} diff --git a/src/deserializers/deserializeInfo.ts b/src/deserializers/deserializeInfo.ts new file mode 100644 index 00000000..b549b921 --- /dev/null +++ b/src/deserializers/deserializeInfo.ts @@ -0,0 +1,17 @@ +import { InfoEntry } from '../parameters' + +export const deserializeInfo = (line: string): InfoEntry | undefined => { + // 1 720p5000 PLAYING + const info = line.match(/(?\d) (?\d+(?p|i)(?\d+))(?.*)/i) + if (info && info.groups) { + return { + channel: parseInt(info.groups.ChannelNo, 10), + format: parseInt(info.groups.Format, 10), + channelRate: parseInt(info.groups.Channelrate || '', 10) / 100, + frameRate: parseInt(info.groups.Channelrate || '', 10) / 100, + interlaced: info.groups.Interlaced === 'i', + status: info.groups.Status.trim(), + } + } + return undefined +} diff --git a/src/deserializers/deserializeInfoChannel.ts b/src/deserializers/deserializeInfoChannel.ts new file mode 100644 index 00000000..ebf5f500 --- /dev/null +++ b/src/deserializers/deserializeInfoChannel.ts @@ -0,0 +1,43 @@ +import { deserializeXML } from './deserializeXML' +import { InfoChannelEntry } from '../parameters' +import { ensureArray, compact } from '../lib' + +export const deserializeInfoChannel = async (line: string): Promise => { + if (!line.startsWith(' parseInt(v, 10)), + }, + }, + + layers: compact( + Object.entries(ensureArray(mixerStage.layer)[0]).map(([layerName, layer0]) => { + const m = layerName.match(/layer_(\d+)/) + if (!m) return undefined + + const layer = ensureArray(layer0 as any)[0] + return { + layer: parseInt(m[1], 10), + // perhaps parse these later: + background: ensureArray(layer.background)[0], + foreground: ensureArray(layer.foreground)[0], + } + }) + ), + }, + } + + return data +} diff --git a/src/deserializers/deserializeInfoLayer.ts b/src/deserializers/deserializeInfoLayer.ts new file mode 100644 index 00000000..dc1a568e --- /dev/null +++ b/src/deserializers/deserializeInfoLayer.ts @@ -0,0 +1,8 @@ +import { InfoLayerEntry } from '../parameters' +import { deserializeInfoChannel } from './deserializeInfoChannel' + +export const deserializeInfoLayer = async (line: string): Promise => { + // Is this actually correct? + // The data seems to be equal to info channel in 2.3.2 + return deserializeInfoChannel(line) +} diff --git a/src/deserializers/deserializeVersion.ts b/src/deserializers/deserializeVersion.ts new file mode 100644 index 00000000..a26fe7e4 --- /dev/null +++ b/src/deserializers/deserializeVersion.ts @@ -0,0 +1,31 @@ +import { Version } from '../enums' + +export const deserializeVersion = ( + line: string +): { + version: Version + fullVersion: string +} => { + let version = Version.Unsupported + const v = line.split('.') + const major = Number(v[0]) + const minor = Number(v[1]) + + if (major <= 2) { + if (minor === 1) { + version = Version.v21x + } else if (minor === 2) { + version = Version.v22x + } else if (minor >= 3) { + // just parse anything newer as v2.3 as it's most likely closest + version = Version.v23x + } + } else { + version = Version.v23x + } + + return { + version, + fullVersion: line, + } +} diff --git a/src/deserializers/index.ts b/src/deserializers/index.ts new file mode 100644 index 00000000..8d8ae497 --- /dev/null +++ b/src/deserializers/index.ts @@ -0,0 +1,26 @@ +import { CReturnType, Commands } from '../commands' +import { deserializeInfoConfig } from './deserializeInfoConfig' +import { deserializeInfoChannel } from './deserializeInfoChannel' +import { deserializeInfoLayer } from './deserializeInfoLayer' +import { deserializeInfo } from './deserializeInfo' +import { deserializeClipInfo } from './deserializeClipInfo' +import { deserializeVersion } from './deserializeVersion' +import { compact } from '../lib' + +export type Deserializer = (data: string[]) => Promise> +/** Just a type guard to ensure that the inner function returns a value as defined in AllInternalCommands */ +function deserializer(fcn: Deserializer): Deserializer { + return fcn +} + +export const deserializers = { + [Commands.Cls]: deserializer(async (data: string[]) => compact(data.map(deserializeClipInfo))), + [Commands.Cinf]: deserializer(async (data: string[]) => deserializeClipInfo(data[0])), + [Commands.Version]: deserializer(async (data: string[]) => deserializeVersion(data[0])), + [Commands.Info]: deserializer(async (data: string[]) => compact(data.map(deserializeInfo))), + [Commands.InfoChannel]: deserializer(async (data: string[]) => + deserializeInfoChannel(data[0]) + ), + [Commands.InfoLayer]: deserializer(async (data: string[]) => deserializeInfoLayer(data[0])), + [Commands.InfoConfig]: deserializer(async (data: string[]) => deserializeInfoConfig(data[0])), +} diff --git a/src/lib.ts b/src/lib.ts index 14abde17..16172466 100644 --- a/src/lib.ts +++ b/src/lib.ts @@ -1,3 +1,11 @@ export function literal(o: T): T { return o } + +export function ensureArray(v: T | T[]): T[] { + return Array.isArray(v) ? v : [v] +} + +export function compact(array: (T | undefined)[]): T[] { + return array.filter((item) => item !== undefined) as T[] +}