Skip to content

Repository files navigation

.sng is a simple and generic binary container format that groups a list of files and metadata into a single file. The file format specification can be found here: https://github.com/mdsitton/SngFileFormat

Works in a browser context and Node.js v17.0.0 and later.

Testing

Before running tests, you need the following:

  • Locally clone the repository
  • Install NodeJS >= v24.6.0
  • Run npm i

To run tests, use:

$ npx tsx ./test.ts

Note: running this will print usage information. Add command line arguments to this to specify testing parameters.

API

/** * A class that reads and parses a .sng `Uint8Array` stream and emits * events when the different components of the stream have been parsed. */classSngStream{constructor(/** * A `ReadableStream` for the binary contents of the .sng file. */sngStream: ReadableStream<Uint8Array>,config?: SngStreamConfig,){}/** * Starts processing the provided .sng stream. Event listeners should be attached before calling this. */start(): void/** * Registers `listener` to be called once when the .sng header has been parsed. * The `SngHeader` object is passed to `listener`. * * This event is emitted before any `file` events are emitted. */on(event: 'header',listener: (header: SngHeader)=>void): void/** * Registers `listener` to be called when each file in .sng has started to parse. * The `fileName` is passed to `listener`, along with a `ReadableStream` * for the (unmasked) binary contents of the file. * * If `nextFile` is `null`, there are no more files to read. * Otherwise, `nextFile` must be called to emit the next file event. * * Cancelling `fileStream` will cancel the source stream. */on(event: 'file',listener: (fileName: string,fileStream: ReadableStream<Uint8Array>,nextFile: (()=>void)|null)=>void): void/** * Registers `listener` to be called once if an error occurs during the stream. * * The source stream is canceled and the error is passed to the listener. * It will usually by type `Error`. ((error instanceof Error) === true) * * This can either happen when `sngStream` emits an `error` event, or * if the .sng's header failed to parse. */on(event: 'error',listener: (error: unknown)=>void): void}interfaceSngStreamConfig{/** * The .sng format doesn't list a `song.ini` file in the `fileMeta`; that information is stored in `metadata`. * * Set this to true for `SngStream` to generate and emit a `song.ini` file in the `file` or `files` events. * * Default: `false`. */generateSongIni: boolean}interfaceSngHeader{fileIdentifier: stringversion: numberxorMask: Uint8Arraymetadata: {[key: string]: string}fileMeta: {filename: stringcontentsLen: bigintcontentsIndex: bigint}[]}

Parse .sng Stream Node.js Example

import{createReadStream,createWriteStream}from'fs'import{SngStream}from'parse-sng'import{Readable}from'stream'import{mkdir}from'fs/promises'import{join,parse}from'path'constsngStream=newSngStream(Readable.toWeb(createReadStream('C:/dev/test.sng'))asany,{generateSongIni: true},)sngStream.on('header',header=>{console.log('Header:',header)})sngStream.on('file',async(fileName,fileStream,nextFile)=>{console.log(`Starting to read file ${fileName}`)constreader=fileStream.getReader()awaitmkdir(join('C:/dev/output',parse(fileName).dir),{recursive: true})constwriteStream=createWriteStream(join('C:/dev/output',fileName))while(true){const{ done, value }=awaitreader.read()if(done){break}writeStream.write(value)}writeStream.close()console.log(`Finished reading file ${fileName}`)if(nextFile){nextFile()}else{console.log('test.sng has been fully parsed')}})sngStream.on('error',error=>{if(errorinstanceofError){console.log('Error: ',error.name,error.message)}else{console.log(error)}})sngStream.start()

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages