UNPKG

jamp3

Version:

mp3, id3v1, id3v2 - reader & writer

116 lines (106 loc) 3.36 kB
import {ID3v1Reader} from './id3v1.reader'; import {ID3v1Writer} from './id3v1.writer'; import {IID3V1} from './id3v1.types'; import {Readable} from 'stream'; import fse from 'fs-extra'; import {ITagID} from '../..'; import {updateFile} from '../common/update-file'; import {FileWriterStream} from '../common/stream-writer-file'; /** * Class for * - reading ID3v1 * - writing ID3v1 * - removing ID3v1 * * Basic usage example: * * ```ts * [[include:snippet_id3v1-read.ts]] * ``` */ export class ID3v1 { /** * Reads a filename & returns ID3v1 tag as Object * @param filename the file to read * @return a object returning i3v1 tag if found */ async read(filename: string): Promise<IID3V1.Tag | undefined> { const reader = new ID3v1Reader(); return await reader.read(filename); } /** * Reads a stream & returns ID3v1 tag as Object * @param stream the stream to read (NodeJS.stream.Readable) * @return a object returning i3v1 tag if found */ async readStream(stream: Readable): Promise<IID3V1.Tag | undefined> { const reader = new ID3v1Reader(); return await reader.readStream(stream); } /** * Removes ID3v1 Tag from a file with given options * @param filename the file to read * @param options remove options * @return true if tag has been found and removed */ async remove(filename: string, options: IID3V1.RemoveOptions): Promise<boolean> { const stat = await fse.stat(filename); let removed = false; await updateFile(filename, {id3v1: true}, !!options.keepBackup, () => true, async (layout, fileWriter): Promise<void> => { let finish = stat.size; for (const t of layout.tags) { if (t.id === ITagID.ID3v1) { removed = true; if (finish > t.start) { finish = t.start; } } } await fileWriter.copyRange(filename, 0, finish); }); return removed; } /** * Writes ID3v1 Tag from an ID3v1 object with given options * @param filename the file to write * @param tag the ID3v1 object to write * @param version the ID3v1.v version to write * @param options write options */ async write(filename: string, tag: IID3V1.ID3v1Tag, version: number, options: IID3V1.WriteOptions): Promise<void> { const exists = await fse.pathExists(filename); if (!exists) { await this.writeTag(filename, tag, version); } else { await this.replaceTag(filename, tag, version, !!options.keepBackup); } } private async writeTag(filename: string, tag: IID3V1.ID3v1Tag, version: number): Promise<void> { const stream = new FileWriterStream(); await stream.open(filename); const writer = new ID3v1Writer(); try { await writer.write(stream, tag, version); } catch (e: any) { await stream.close(); return Promise.reject(e); } await stream.close(); } private async replaceTag(filename: string, tag: IID3V1.ID3v1Tag, version: number, keepBackup: boolean): Promise<void> { const stat = await fse.stat(filename); await updateFile(filename, {id3v1: true}, keepBackup, () => true, async (layout, fileWriter): Promise<void> => { let finish = stat.size; for (const t of layout.tags) { if (t.id === ITagID.ID3v1) { if (finish > t.start) { finish = t.start; } } } await fileWriter.copyRange(filename, 0, finish); const writer = new ID3v1Writer(); await writer.write(fileWriter, tag, version); }); } }