Skip to content

Commit

Permalink
Merge branch 'release/v6.0.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
benrr101 committed Dec 13, 2024
2 parents 8e14ef4 + be9ad5e commit 6816096
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 97 deletions.
90 changes: 90 additions & 0 deletions docs/classes/Id3v2FrameFactory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
[node-taglib-sharp](../README.md) / [Exports](../modules.md) / Id3v2FrameFactory

# Class: Id3v2FrameFactory

Performs the necessary operations to determine and create the correct child classes of
Frame for a given raw ID3v2 frame.
By default, this will only load frames contained in the library. To add additional frames to the
process, register a frame creator with [addFrameCreator](Id3v2FrameFactory.md#addframecreator).

## Table of contents

### Constructors

- [constructor](Id3v2FrameFactory.md#constructor)

### Methods

- [addFrameCreator](Id3v2FrameFactory.md#addframecreator)
- [clearFrameCreators](Id3v2FrameFactory.md#clearframecreators)
- [createFrame](Id3v2FrameFactory.md#createframe)

## Constructors

### constructor

**new Id3v2FrameFactory**()

## Methods

### addFrameCreator

`Static` **addFrameCreator**(`creator`): `void`

Adds a custom frame creator to try before using standard frame creation methods.
Frame creators are used before standard methods so custom checking can be used and new
formats can be added. They are executed in reverse order in which they are added.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `creator` | [`Id3v2FrameCreator`](../modules.md#id3v2framecreator) | Frame creator function * data: ByteVector Raw ID3v2 frame * offset: number Offset in data at which the frame data begins (should be int) * header: Id3v2FrameHeader Header for the frame contained in data * version: number ID3v2 version the raw frame data is stored in (should be byte) * returns Frame if method was able to match the frame, falsy otherwise |

#### Returns

`void`

___

### clearFrameCreators

`Static` **clearFrameCreators**(): `void`

Removes all custom frame creators

#### Returns

`void`

___

### createFrame

`Static` **createFrame**(`data`, `file`, `offset`, `version`, `alreadyUnsynced`): `Object`

Creates a Frame object by reading it from raw ID3v2 frame data.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `data` | [`ByteVector`](ByteVector.md) | Raw ID3v2 frame |
| `file` | [`File`](File.md) | File to read the frame from if `data` is falsy |
| `offset` | `number` | Index into `file` or in `data` if truthy, at which the frame begins. After reading, the offset where the next frame can be read is returned in the `offset` property of the returned object |
| `version` | `number` | ID3v2 version the frame is encoded with. Must be unsigned 8-bit int |
| `alreadyUnsynced` | `boolean` | Whether or not the entire tag has already been unsynchronized |

#### Returns

`Object`

Undefined is returned if there are no more frames to read.
Object is returned if a frame was found. Object has the following properties:
* frame: Frame that was read
* offset: updated offset where the next frame starts

| Name | Type |
| :------ | :------ |
| `frame` | [`Id3v2Frame`](Id3v2Frame.md) |
| `offset` | `number` |
21 changes: 1 addition & 20 deletions docs/modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
- [Id3v2EventTimeCodeFrame](classes/Id3v2EventTimeCodeFrame.md)
- [Id3v2ExtendedHeader](classes/Id3v2ExtendedHeader.md)
- [Id3v2Frame](classes/Id3v2Frame.md)
- [Id3v2FrameFactory](classes/Id3v2FrameFactory.md)
- [Id3v2FrameHeader](classes/Id3v2FrameHeader.md)
- [Id3v2FrameIdentifier](classes/Id3v2FrameIdentifier.md)
- [Id3v2MusicCdIdentifierFrame](classes/Id3v2MusicCdIdentifierFrame.md)
Expand Down Expand Up @@ -187,7 +188,6 @@

### Variables

- [Id3v2FrameFactory](modules.md#id3v2framefactory)
- [Id3v2FrameIdentifiers](modules.md#id3v2frameidentifiers)

## References
Expand Down Expand Up @@ -312,25 +312,6 @@ Generated [IOggCodec](interfaces/IOggCodec.md) is returned if a codec could be

## Variables

### Id3v2FrameFactory

**Id3v2FrameFactory**: `Object`

Performs the necessary operations to determine and create the correct child classes of
Frame for a given raw ID3v2 frame.
By default, this will only load frames contained in the library. To add additional frames to the
process, register a frame creator with addFrameCreator.

#### Type declaration

| Name | Type |
| :------ | :------ |
| `addFrameCreator` | (`creator`: [`Id3v2FrameCreator`](modules.md#id3v2framecreator)) => `void` |
| `clearFrameCreators` | () => `void` |
| `createFrame` | (`data`: [`ByteVector`](classes/ByteVector.md), `file`: [`File`](classes/File.md), `offset`: `number`, `version`: `number`, `alreadyUnsynced`: `boolean`) => { `frame`: [`Id3v2Frame`](classes/Id3v2Frame.md) ; `offset`: `number` } |

___

### Id3v2FrameIdentifiers

`Const` **Id3v2FrameIdentifiers**: `Object`
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "node-taglib-sharp",
"description": "Read and write audio/video/picture tags using a similar interface to TagLib#",
"version": "6.0.0",
"version": "6.0.1",
"license": "LGPL-2.1-or-later",
"author": "Ben Russell <[email protected]> (https://github.com/benrr101)",
"repository": "github:benrr101/node-taglib-sharp",
Expand Down
28 changes: 15 additions & 13 deletions src/id3v2/frames/frameFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,17 @@ import {Guards, NumberUtils} from "../../utils";
*/
export type FrameCreator = (data: ByteVector, offset: number, header: Id3v2FrameHeader, version: number) => Frame;

let customFrameCreators: FrameCreator[] = [];

/**
* Performs the necessary operations to determine and create the correct child classes of
* {@link Frame} for a given raw ID3v2 frame.
* By default, this will only load frames contained in the library. To add additional frames to the
* process, register a frame creator with {@link addFrameCreator}.
*/
export default {
export class Id3v2FrameFactory {


private static readonly CUSTOM_FRAME_CREATORS: FrameCreator[] = [];

/**
* Adds a custom frame creator to try before using standard frame creation methods.
* Frame creators are used before standard methods so custom checking can be used and new
Expand All @@ -50,17 +52,17 @@ export default {
* * version: number ID3v2 version the raw frame data is stored in (should be byte)
* * returns Frame if method was able to match the frame, falsy otherwise
*/
addFrameCreator: (creator: FrameCreator): void => {
public static addFrameCreator(creator: FrameCreator): void {
Guards.truthy(creator, "creator");
customFrameCreators.unshift(creator);
},
this.CUSTOM_FRAME_CREATORS.unshift(creator);
}

/**
* Removes all custom frame creators
*/
clearFrameCreators: (): void => {
customFrameCreators = [];
},
public static clearFrameCreators(): void {
this.CUSTOM_FRAME_CREATORS.length = 0;
}

/**
* Creates a {@link Frame} object by reading it from raw ID3v2 frame data.
Expand All @@ -78,13 +80,13 @@ export default {
* * offset: updated offset where the next frame starts
*/
// @TODO: Split into fromFile and fromData
createFrame: (
public static createFrame(
data: ByteVector,
file: File,
offset: number,
version: number,
alreadyUnsynced: boolean
): {frame: Frame, offset: number} => {
): {frame: Frame, offset: number} {
Guards.uint(offset, "offset");
Guards.byte(version, "version");

Expand Down Expand Up @@ -132,7 +134,7 @@ export default {

try {
// Try to find a custom creator
for (const creator of customFrameCreators) {
for (const creator of this.CUSTOM_FRAME_CREATORS) {
// @TODO: If we're reading from a file, data will only ever contain the header
const frame = creator(data, position, header, version);
if (frame) {
Expand Down Expand Up @@ -243,4 +245,4 @@ export default {
};
}
}
};
}
52 changes: 33 additions & 19 deletions src/id3v2/id3v2Tag.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import AttachmentFrame from "./frames/attachmentFrame";
import CommentsFrame from "./frames/commentsFrame";
import FrameFactory from "./frames/frameFactory";
import Id3v2ExtendedHeader from "./id3v2ExtendedHeader";
import Id3v2TagFooter from "./id3v2TagFooter";
import Id3v2Settings from "./id3v2Settings";
Expand All @@ -11,6 +10,7 @@ import {ByteVector, StringType} from "../byteVector";
import {CorruptFileError, NotImplementedError, NotSupportedError} from "../errors";
import {File, ReadStyle} from "../file";
import {Frame, FrameClassType} from "./frames/frame";
import {Id3v2FrameFactory} from "./frames/frameFactory";
import {FrameIdentifier, FrameIdentifiers} from "./frameIdentifiers";
import {Id3v2FrameFlags} from "./frames/frameHeader";
import {Id3v2TagHeader, Id3v2TagHeaderFlags} from "./id3v2TagHeader";
Expand Down Expand Up @@ -1394,6 +1394,7 @@ export default class Id3v2Tag extends Tag {
let frameDataEndPosition = (data ? data.length : this._header.tagSize) + frameDataPosition;

// Check for the extended header
// @TODO: Replace with NumberUtils.hasFlags
if ((this._header.flags & Id3v2TagHeaderFlags.ExtendedHeader) !== 0) {
this._extendedHeader = Id3v2ExtendedHeader.fromData(data, this._header.majorVersion);

Expand All @@ -1405,28 +1406,41 @@ export default class Id3v2Tag extends Tag {

// Parse the frames
while (frameDataPosition < frameDataEndPosition) {
const frameRead = FrameFactory.createFrame(
data,
file,
frameDataPosition,
this._header.majorVersion,
fullTagUnsync
);
try {
const frameRead = Id3v2FrameFactory.createFrame(
data,
file,
frameDataPosition,
this._header.majorVersion,
fullTagUnsync
);

// If the frame factory returned undefined, that means we've hit the end of frames
if (!frameRead) {
break;
}

// If the frame factory returned undefined, that means we've hit the end of frames
if (!frameRead) {
break;
}
// We found a frame, deconstruct the read result
const frame = frameRead.frame;
frameDataPosition = frameRead.offset;

// Only add frames that contain data
if (!frame || frame.size === 0) {
continue;
}
this.addFrame(frame);
} catch (e: unknown) {
// If we fail at any point while trying to read the frames of the tag, we will have
// lost our place in the file and will have to give up reading the tag.
// Ok, technically we could use some heuristics to try to recover (eg, Foobar can
// do this), but it is a lot of effort for minimal reward.

// We found a frame, deconstruct the read result
const frame = frameRead.frame;
frameDataPosition = frameRead.offset;
// NOTE: It's important to not let this error propagate to the file level, else
// the user will not be able to recover the file.

// Only add frames that contain data
if (!frame || frame.size === 0) {
continue;
// this.markCorrupt(e); @TODO: Add corruption reasons.
break;
}
this.addFrame(frame);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ export {
FrameClassType as Id3v2FrameClassType
} from "./id3v2/frames/frame";
export {
default as Id3v2FrameFactory,
FrameCreator as Id3v2FrameCreator
FrameCreator as Id3v2FrameCreator,
Id3v2FrameFactory
} from "./id3v2/frames/frameFactory";
export {Id3v2FrameFlags, Id3v2FrameHeader} from "./id3v2/frames/frameHeader";
export {default as Id3v2MusicCdIdentifierFrame} from "./id3v2/frames/musicCdIdentifierFrame";
Expand Down
Loading

0 comments on commit 6816096

Please sign in to comment.