UNPKG

taglib-wasm

Version:

TagLib for TypeScript platforms: Deno, Node.js, Bun, Electron, browsers, and Cloudflare Workers

262 lines (261 loc) 6.65 kB
import { PictureType } from "./types.js"; import { FileOperationError, InvalidFormatError, MetadataError } from "./errors.js"; import { writeFileData } from "./utils/write.js"; let cachedTagLib = null; async function getTagLib() { if (!cachedTagLib) { const { TagLib } = await import("./taglib.js"); cachedTagLib = await TagLib.initialize(); } return cachedTagLib; } async function readTags(file) { const taglib = await getTagLib(); const audioFile = await taglib.open(file); try { if (!audioFile.isValid()) { throw new InvalidFormatError( "File may be corrupted or in an unsupported format" ); } return audioFile.tag(); } finally { audioFile.dispose(); } } async function applyTags(file, tags, options) { const taglib = await getTagLib(); const audioFile = await taglib.open(file); try { if (!audioFile.isValid()) { throw new InvalidFormatError( "File may be corrupted or in an unsupported format" ); } const tag = audioFile.tag(); if (tags.title !== void 0) tag.setTitle(tags.title); if (tags.artist !== void 0) tag.setArtist(tags.artist); if (tags.album !== void 0) tag.setAlbum(tags.album); if (tags.comment !== void 0) tag.setComment(tags.comment); if (tags.genre !== void 0) tag.setGenre(tags.genre); if (tags.year !== void 0) tag.setYear(tags.year); if (tags.track !== void 0) tag.setTrack(tags.track); if (!audioFile.save()) { throw new FileOperationError( "save", "Failed to save metadata changes. The file may be read-only or corrupted." ); } return audioFile.getFileBuffer(); } finally { audioFile.dispose(); } } async function updateTags(file, tags, options) { if (typeof file !== "string") { throw new Error("updateTags requires a file path string to save changes"); } const modifiedBuffer = await applyTags(file, tags, options); await writeFileData(file, modifiedBuffer); } async function readProperties(file) { const taglib = await getTagLib(); const audioFile = await taglib.open(file); try { if (!audioFile.isValid()) { throw new InvalidFormatError( "File may be corrupted or in an unsupported format" ); } const props = audioFile.audioProperties(); if (!props) { throw new MetadataError( "read", "File may not contain valid audio data", "audioProperties" ); } return props; } finally { audioFile.dispose(); } } const Title = "title"; const Artist = "artist"; const Album = "album"; const Comment = "comment"; const Genre = "genre"; const Year = "year"; const Track = "track"; const AlbumArtist = "albumartist"; const Composer = "composer"; const DiscNumber = "discnumber"; async function isValidAudioFile(file) { try { const taglib = await getTagLib(); const audioFile = await taglib.open(file); const valid = audioFile.isValid(); audioFile.dispose(); return valid; } catch { return false; } } async function getFormat(file) { const taglib = await getTagLib(); const audioFile = await taglib.open(file); try { if (!audioFile.isValid()) { return void 0; } return audioFile.getFormat(); } finally { audioFile.dispose(); } } async function clearTags(file) { return applyTags(file, { title: "", artist: "", album: "", comment: "", genre: "", year: 0, track: 0 }); } async function readPictures(file) { const taglib = await getTagLib(); const audioFile = await taglib.open(file); try { if (!audioFile.isValid()) { throw new InvalidFormatError( "File may be corrupted or in an unsupported format" ); } return audioFile.getPictures(); } finally { audioFile.dispose(); } } async function applyPictures(file, pictures) { const taglib = await getTagLib(); const audioFile = await taglib.open(file); try { if (!audioFile.isValid()) { throw new InvalidFormatError( "File may be corrupted or in an unsupported format" ); } audioFile.setPictures(pictures); if (!audioFile.save()) { throw new FileOperationError( "save", "Failed to save picture changes. The file may be read-only or corrupted." ); } return audioFile.getFileBuffer(); } finally { audioFile.dispose(); } } async function addPicture(file, picture) { const taglib = await getTagLib(); const audioFile = await taglib.open(file); try { if (!audioFile.isValid()) { throw new InvalidFormatError( "File may be corrupted or in an unsupported format" ); } audioFile.addPicture(picture); if (!audioFile.save()) { throw new FileOperationError( "save", "Failed to save picture changes. The file may be read-only or corrupted." ); } return audioFile.getFileBuffer(); } finally { audioFile.dispose(); } } async function clearPictures(file) { return applyPictures(file, []); } async function getCoverArt(file) { const pictures = await readPictures(file); if (pictures.length === 0) { return null; } const frontCover = pictures.find( (pic) => pic.type === PictureType.FrontCover ); if (frontCover) { return frontCover.data; } return pictures[0].data; } async function setCoverArt(file, imageData, mimeType) { const picture = { mimeType, data: imageData, type: PictureType.FrontCover, description: "Front Cover" }; return applyPictures(file, [picture]); } function findPictureByType(pictures, type) { return pictures.find((pic) => pic.type === type) || null; } async function replacePictureByType(file, newPicture) { const pictures = await readPictures(file); const filteredPictures = pictures.filter( (pic) => pic.type !== newPicture.type ); filteredPictures.push(newPicture); return applyPictures(file, filteredPictures); } async function getPictureMetadata(file) { const pictures = await readPictures(file); return pictures.map((pic) => ({ type: pic.type, mimeType: pic.mimeType, description: pic.description, size: pic.data.length })); } import { PictureType as PictureType2 } from "./types.js"; export { Album, AlbumArtist, Artist, Comment, Composer, DiscNumber, Genre, PictureType2 as PictureType, Title, Track, Year, addPicture, applyPictures, applyTags, clearPictures, clearTags, findPictureByType, getCoverArt, getFormat, getPictureMetadata, isValidAudioFile, readPictures, readProperties, readTags, replacePictureByType, setCoverArt, updateTags };