tagpilot-lib
v1.0.0
Published
A high-performance Node.js library for reading and writing audio metadata and cover art, built with Rust and NAPI-RS
Maintainers
Readme
tagpilot-lib
A high-performance Node.js library for reading and writing audio metadata and cover art, built with Rust and NAPI-RS.
Features
- 🚀 High Performance: Native Rust implementation for maximum speed
- 🎵 Audio Metadata: Read and write ID3 tags, MP3 metadata, and more
- 🖼️ Cover Art: Extract, embed, and manage album artwork
- 📦 Buffer Support: Work with audio data directly in memory
- 🔄 Async/Await: Promise-based API for modern JavaScript
- 🛡️ TypeScript: Full TypeScript support with type definitions
- 🌐 Cross Platform: Works on Windows, macOS, and Linux
Installation
npm install tagpilot-libQuick Start
const { readTags, writeTags, readCoverImage, writeCoverImage } = require('tagpilot-lib');
// Read audio metadata
const tags = await readTags('./music/song.mp3');
console.log(tags.title); // "Song Title"
console.log(tags.artist); // "Artist Name"
// Write audio metadata
await writeTags('./music/song.mp3', {
title: 'New Title',
artist: 'New Artist',
album: 'Album Name',
year: 2024,
genre: 'Rock',
track: 1,
trackTotal: 12
});
// Read cover image
const coverImage = await readCoverImage(audioBuffer);
if (coverImage) {
console.log('Cover image found:', coverImage.length, 'bytes');
}
// Write cover image
const imageBuffer = fs.readFileSync('./cover.jpg');
const modifiedAudio = await writeCoverImage(audioBuffer, imageBuffer);API Reference
Audio Tags
readTags(filePath: string): Promise<AudioTags>
Reads metadata from an audio file.
Parameters:
filePath(string): Path to the audio file
Returns: Promise
Example:
const tags = await readTags('./music/song.mp3');
console.log(tags);
// {
// title: "Song Title",
// artist: "Artist Name",
// album: "Album Name",
// year: 2024,
// genre: "Rock",
// track: 1,
// trackTotal: 12,
// albumArtist: "Album Artist",
// comment: "Comment",
// disc: 1,
// discTotal: 2
// }writeTags(filePath: string, tags: AudioTags): Promise<void>
Writes metadata to an audio file.
Parameters:
filePath(string): Path to the audio filetags(AudioTags): Metadata to write
Returns: Promise
Example:
await writeTags('./music/song.mp3', {
title: 'New Title',
artist: 'New Artist',
album: 'Album Name',
year: 2024,
genre: 'Rock',
track: 1,
trackTotal: 12,
albumArtist: 'Album Artist',
comment: 'My comment',
disc: 1,
discTotal: 2
});clearTags(filePath: string): Promise<void>
Clears all metadata from an audio file.
Parameters:
filePath(string): Path to the audio file
Returns: Promise
Example:
await clearTags('./music/song.mp3');Buffer Operations
readTagsFromBuffer(buffer: Buffer): Promise<AudioTags>
Reads metadata from an audio buffer.
Parameters:
buffer(Buffer): Audio data buffer
Returns: Promise
Example:
const audioBuffer = fs.readFileSync('./music/song.mp3');
const tags = await readTagsFromBuffer(audioBuffer);writeTagsToBuffer(buffer: Buffer, tags: AudioTags): Promise<Buffer>
Writes metadata to an audio buffer and returns the modified buffer.
Parameters:
buffer(Buffer): Audio data buffertags(AudioTags): Metadata to write
Returns: Promise
Example:
const audioBuffer = fs.readFileSync('./music/song.mp3');
const modifiedBuffer = await writeTagsToBuffer(audioBuffer, {
title: 'New Title',
artist: 'New Artist'
});
fs.writeFileSync('./music/modified-song.mp3', modifiedBuffer);Cover Art
readCoverImage(buffer: Buffer): Promise<Buffer | null>
Reads cover art from an audio buffer.
Parameters:
buffer(Buffer): Audio data buffer
Returns: Promise<Buffer | null>
Example:
const audioBuffer = fs.readFileSync('./music/song.mp3');
const coverImage = await readCoverImage(audioBuffer);
if (coverImage) {
fs.writeFileSync('./cover.jpg', coverImage);
}writeCoverImage(buffer: Buffer, imageData: Buffer): Promise<Buffer>
Writes cover art to an audio buffer and returns the modified buffer.
Parameters:
buffer(Buffer): Audio data bufferimageData(Buffer): Image data (JPEG, PNG, GIF, BMP, TIFF)
Returns: Promise
Example:
const audioBuffer = fs.readFileSync('./music/song.mp3');
const imageBuffer = fs.readFileSync('./cover.jpg');
const modifiedAudio = await writeCoverImage(audioBuffer, imageBuffer);
fs.writeFileSync('./music/song-with-cover.mp3', modifiedAudio);Types
AudioTags
interface AudioTags {
title?: string;
artist?: string;
album?: string;
year?: number;
genre?: string;
track?: number;
trackTotal?: number;
albumArtist?: string;
comment?: string;
disc?: number;
discTotal?: number;
}Examples
Basic Usage
const { readTags, writeTags } = require('tagpilot-lib');
async function updateSongMetadata() {
// Read existing metadata
const tags = await readTags('./music/song.mp3');
console.log('Current title:', tags.title);
// Update metadata
await writeTags('./music/song.mp3', {
...tags,
title: 'Updated Title',
year: 2024
});
console.log('Metadata updated successfully!');
}Cover Art Management
const { readCoverImage, writeCoverImage } = require('tagpilot-lib');
const fs = require('fs');
async function manageCoverArt() {
const audioBuffer = fs.readFileSync('./music/song.mp3');
// Read existing cover art
const existingCover = await readCoverImage(audioBuffer);
if (existingCover) {
console.log('Existing cover art found:', existingCover.length, 'bytes');
fs.writeFileSync('./existing-cover.jpg', existingCover);
}
// Add new cover art
const newCover = fs.readFileSync('./new-cover.jpg');
const modifiedAudio = await writeCoverImage(audioBuffer, newCover);
fs.writeFileSync('./music/song-with-new-cover.mp3', modifiedAudio);
}Batch Processing
const { readTags, writeTags } = require('tagpilot-lib');
const fs = require('fs');
const path = require('path');
async function batchUpdateMetadata() {
const musicDir = './music';
const files = fs.readdirSync(musicDir).filter(f => f.endsWith('.mp3'));
for (const file of files) {
const filePath = path.join(musicDir, file);
const tags = await readTags(filePath);
// Update all files with a common album name
await writeTags(filePath, {
...tags,
album: 'My Greatest Hits',
year: 2024
});
console.log(`Updated: ${file}`);
}
}Data URL Generation
const { readCoverImage } = require('tagpilot-lib');
const fs = require('fs');
function bufferToDataURL(buffer, mimeType = 'image/jpeg') {
const base64 = buffer.toString('base64');
return `data:${mimeType};base64,${base64}`;
}
async function getCoverAsDataURL() {
const audioBuffer = fs.readFileSync('./music/song.mp3');
const coverImage = await readCoverImage(audioBuffer);
if (coverImage) {
const dataURL = bufferToDataURL(coverImage, 'image/jpeg');
console.log('Cover art data URL:', dataURL.substring(0, 100) + '...');
return dataURL;
}
return null;
}Supported Formats
Audio Formats
- MP3 (ID3v1, ID3v2)
- FLAC
- M4A (MPEG-4 Audio)
- OGG (Vorbis)
- WAV
- WAVPACK
- AAC
- AIFF
- OPUS
- Speex
Image Formats
- JPEG
- PNG
- GIF
- BMP
- TIFF
Performance
tagpilot-lib is built with Rust and NAPI-RS for maximum performance:
- Fast: Native implementation with minimal overhead
- Memory Efficient: Direct buffer operations without temporary files
- Scalable: Handles large audio files efficiently
- Concurrent: Async operations for better throughput
Development
Prerequisites
- Node.js 16+
- Rust toolchain
- npm or yarn
Building from Source
git clone https://github.com/yortyrh/tagpilot-lib.git
cd tagpilot-lib
npm install
npm run buildRunning Tests
npm testRunning Examples
# Read tags example
node examples/read-tags-example.js ./music/song.mp3
# Write tags example
node examples/write-tags-example.js ./music/song.mp3
# Cover image example
node examples/cover-image-buffer-example.js ./music/song.mp3 ./cover.jpg
# Read cover image as data URL
node examples/read-cover-image-example.js ./music/song.mp3Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Run the test suite
- Submit a pull request
License
MIT License - see LICENSE file for details.
Changelog
v1.0.0
- Initial release
- Audio metadata reading and writing
- Cover art extraction and embedding
- Buffer-based operations
- TypeScript support
- Comprehensive examples
Support
- Issues: GitHub Issues
- Documentation: GitHub Wiki
- Discussions: GitHub Discussions
