Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@
},
"license": "MIT",
"dependencies": {
"iconv-lite": "0.6.2",
"tmp": "^0.2.1"
"iconv-lite": "0.6.2"
},
"devDependencies": {
"@istanbuljs/nyc-config-typescript": "^1.0.2",
Expand All @@ -58,7 +57,6 @@
"@types/mocha": "^10.0.1",
"@types/node": "^18.11.10",
"@types/source-map-support": "^0.5.6",
"@types/tmp": "^0.2.3",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"chai": "^4.3.7",
Expand Down
26 changes: 2 additions & 24 deletions src/api/create.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,11 @@
import { WriteTags } from "../types/Tags"
import { isFunction } from "../util"
import { createId3Tag } from "../id3-tag"

/**
* Callback used to return a buffer with the created ID Tag.
*
* @public
*/
export type CreateCallback =
(data: Buffer) => void

/**
* Creates a buffer containing an ID3 Tag and returns it.
*
* @public
*/
export function create(tags: WriteTags): Buffer

/**
* Creates a buffer containing an ID3 Tag and returns it via the callback.
*
* @public
*/
export function create(tags: WriteTags, callback: CreateCallback): void

export function create(tags: WriteTags, callback?: CreateCallback) {
const id3Data = createId3Tag(tags)
if (isFunction(callback)) {
return callback(id3Data)
}
return id3Data
export function create(tags: WriteTags): Buffer {
return createId3Tag(tags)
}
47 changes: 20 additions & 27 deletions src/api/promises.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Tags, TagIdentifiers, WriteTags } from '../types/Tags'
import { Options } from '../types/Options'
import { create } from "./create"
import { read, ReadCallback } from "./read"
import { ReadCallback } from "../types/read"
import { read, } from "./read"
import { removeTags } from "./remove"
import { update } from "./update"
import { write, WriteCallback, WriteFileCallback } from "./write"
import { write } from "./write"

type Settle<T> = {
(error: NodeJS.ErrnoException | Error, result: null): void
Expand All @@ -14,7 +14,7 @@ type Settle<T> = {
function makePromise<T>(callback: (settle: Settle<T>) => void) {
return new Promise<T>((resolve, reject) => {
callback((error, result) => {
if(error) {
if (error) {
reject(error)
} else {
// result can't be null here according the Settle callable
Expand All @@ -33,36 +33,29 @@ function makePromise<T>(callback: (settle: Settle<T>) => void) {
* @public
*/
export const Promises = {
create: (tags: WriteTags) =>
makePromise((settle: Settle<Buffer>) =>
create(tags, result => settle(null, result)),
write: (tags: WriteTags, filepath: string) =>
makePromise<void>(settle => write(
tags,
filepath,
(error) => error ? settle(error, null) : settle(null)
)),
update: (tags: WriteTags, filepath: string, options?: Options) =>
makePromise<void>((settle) => update(
tags,
filepath,
options ?? {},
(error) => error ? settle(error, null) : settle(null)
)
),
write: (tags: WriteTags, filebuffer: string | Buffer) =>
makePromise<Buffer|null>((callback: WriteCallback | WriteFileCallback) =>
write(tags, filebuffer, callback)
),
update: (tags: WriteTags, filebuffer: string | Buffer, options?: Options) =>
makePromise<Buffer>((callback: WriteCallback | WriteFileCallback) =>
update(tags, filebuffer, options ?? {}, callback)
),
read: (file: string | Buffer, options?: Options) =>
read: (filepath: string, options?: Options) =>
makePromise<Tags | TagIdentifiers>((callback: ReadCallback) =>
read(file, options ?? {}, callback)
read(filepath, options ?? {}, callback)
),
removeTags: (filepath: string) =>
makePromise((settle: Settle<void>) =>
makePromise<void>((settle) =>
removeTags(
filepath,
(error) => error ? settle(error, null) : settle(null)
)
)
} as const

/**
* Asynchronous API for files and buffers operations using promises.
*
* @public
* @deprecated Consider using `Promises` instead as `Promise` creates conflict
* with the Javascript native promise.
*/
export { Promises as Promise }
145 changes: 100 additions & 45 deletions src/api/read.ts
Original file line number Diff line number Diff line change
@@ -1,65 +1,49 @@
import * as fs from 'fs'
import { getTagsFromId3Tag } from '../id3-tag'
import { isFunction, isString } from '../util'
import { Tags, TagIdentifiers } from '../types/Tags'
import { Options } from '../types/Options'
import { getId3TagDataFromFileAsync, getId3TagDataFromFileSync } from '../file-read'
import {
getId3TagDataFromFileAsync,
getId3TagDataFromFileSync
} from '../file-read'
import { FileReadOptions, ReadCallback } from '../types/read'

/**
* Callback signature for successful asynchronous read operation.
*
* @param tags - `TagsIdentifiers` if the `rawOnly` option was true otherwise
* `Tags`
* @public
*/
export type ReadSuccessCallback =
(error: null, tags: Tags | TagIdentifiers) => void

/**
* Callback signatures for failing asynchronous read operation.
*
* Reads ID3-Tags from a buffer.
* @deprecated Use `readFromBuffer` instead.
* @public
*/
export type ReadErrorCallback =
(error: NodeJS.ErrnoException | Error, tags: null) => void
export function read(buffer: Buffer, options?: Options): Tags

/**
* Callback signatures for asynchronous read operation.
*
* @public
*/
export type ReadCallback =
ReadSuccessCallback & ReadErrorCallback

/**
* Reads ID3-Tags synchronously from passed buffer/filepath.
*
* Reads ID3-Tags synchronously from a file.
* @deprecated Use `readFromFileSync` instead.
* @public
*/
export function read(filebuffer: string | Buffer, options?: Options): Tags
export function read(filepath: string, options?: FileReadOptions): Tags

/**
* Reads ID3-Tags asynchronously from passed buffer/filepath.
*
* Reads ID3-Tags asynchronously from passed filepath.
* @deprecated Use `readFromFile` instead.
* @public
*/
export function read(filebuffer: string | Buffer, callback: ReadCallback): void
export function read(filebuffer: string, callback: ReadCallback): void

/**
* Reads ID3-Tags asynchronously from passed buffer/filepath.
*
* Reads ID3-Tags asynchronously from passed filepath.
* @deprecated Use `readFromFile` instead.
* @public
*/
export function read(
filebuffer: string | Buffer, options: Options, callback: ReadCallback
filebuffer: string, options: FileReadOptions, callback: ReadCallback
): void

export function read(
filebuffer: string | Buffer,
optionsOrCallback?: Options | ReadCallback,
optionsOrCallback?: FileReadOptions | ReadCallback,
callback?: ReadCallback
): Tags | TagIdentifiers | void {
const options: Options =
const options: FileReadOptions =
(isFunction(optionsOrCallback) ? {} : optionsOrCallback) ?? {}
callback =
isFunction(optionsOrCallback) ? optionsOrCallback : callback
Expand All @@ -70,27 +54,98 @@ export function read(
return readSync(filebuffer, options)
}

function readSync(filebuffer: string | Buffer, options: Options) {
function readSync(filebuffer: string | Buffer, options: FileReadOptions) {
if (isString(filebuffer)) {
filebuffer = getId3TagDataFromFileSync(filebuffer) ?? Buffer.alloc(0)
filebuffer = getId3TagDataFromFileSync(filebuffer, options)[0] ?? Buffer.alloc(0)
}
return getTagsFromId3Tag(filebuffer, options)
}

function readAsync(
filebuffer: string | Buffer,
options: Options,
options: FileReadOptions,
callback: ReadCallback
) {
if (isString(filebuffer)) {
getId3TagDataFromFileAsync(filebuffer, (error, data) => {
if(error) {
callback(error, null)
} else {
callback(null, getTagsFromId3Tag(data ?? Buffer.alloc(0), options))
}
})
getId3TagDataFromFileAsync(filebuffer, options).then(
(buffers) => callback(
null, decodeTagBuffers(buffers, options)
),
(error) => callback(error, null)
)
} else {
callback(null, getTagsFromId3Tag(filebuffer, options))
}
}

// New API

/**
* Reads ID3-Tags from a buffer.
*
* @public
*/
export function readFromBuffer(
buffer: Buffer,
options: Options = {}
): Tags | TagIdentifiers {
return getTagsFromId3Tag(buffer, options)
}

/**
* Reads ID3-Tags synchronously from a file.
*
* @public
*/
export function readFromFileSync(
filepath: string,
options: FileReadOptions = {}
): Tags | TagIdentifiers {
const buffers = getId3TagDataFromFileSync(filepath, options)
return decodeTagBuffers(buffers, options)
}

/**
* Reads ID3-Tags asynchronously from a file.
*
* @public
*/
export function readFromFile(
filepath: string,
callback: ReadCallback
): void

/**
* Reads ID3-Tags asynchronously from a file.
*
* @public
*/
export function readFromFile(
filepath: string,
options: FileReadOptions,
callback: ReadCallback
): void

export function readFromFile(
filepath: string,
optionsOrCallback?: FileReadOptions | ReadCallback,
maybeCallback: ReadCallback = () => { /* */ }
): void {
const options: FileReadOptions =
(isFunction(optionsOrCallback) ? {} : optionsOrCallback) ?? {}
const callback =
isFunction(optionsOrCallback) ? optionsOrCallback : maybeCallback

getId3TagDataFromFileAsync(filepath, options).then(
(buffers) => callback(
null, decodeTagBuffers(buffers, options)
),
(error) => callback(error, null)
)
}

// For now, just take the first one
function decodeTagBuffers(buffers: Buffer[], options: Options) {
const firstBuffer = buffers[0] ?? Buffer.alloc(0)
return getTagsFromId3Tag(firstBuffer, options)
}
Loading