UNPKG

taglib-wasm

Version:

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

216 lines (215 loc) 7.15 kB
import { PICTURE_TYPE_VALUES } from "./types.js"; import { applyPictures, getCoverArt, readPictures, replacePictureByType, setCoverArt } from "./simple.js"; import { readFileData } from "./utils/file.js"; import { writeFileData } from "./utils/write.js"; async function exportCoverArt(audioPath, imagePath) { const coverData = await getCoverArt(audioPath); if (!coverData) { throw new Error(`No cover art found in: ${audioPath}`); } await writeFileData(imagePath, coverData); } async function exportPictureByType(audioPath, imagePath, type) { const pictures = await readPictures(audioPath); const typeValue = typeof type === "string" ? PICTURE_TYPE_VALUES[type] : type; const picture = pictures.find((pic) => pic.type === typeValue); if (!picture) { throw new Error(`No picture of type ${type} found in: ${audioPath}`); } await writeFileData(imagePath, picture.data); } const PICTURE_TYPE_NAMES = { [PICTURE_TYPE_VALUES.FrontCover]: "front-cover", [PICTURE_TYPE_VALUES.BackCover]: "back-cover", [PICTURE_TYPE_VALUES.LeafletPage]: "leaflet", [PICTURE_TYPE_VALUES.Media]: "media", [PICTURE_TYPE_VALUES.LeadArtist]: "lead-artist", [PICTURE_TYPE_VALUES.Artist]: "artist", [PICTURE_TYPE_VALUES.Conductor]: "conductor", [PICTURE_TYPE_VALUES.Band]: "band", [PICTURE_TYPE_VALUES.Composer]: "composer", [PICTURE_TYPE_VALUES.Lyricist]: "lyricist", [PICTURE_TYPE_VALUES.RecordingLocation]: "recording-location", [PICTURE_TYPE_VALUES.DuringRecording]: "during-recording", [PICTURE_TYPE_VALUES.DuringPerformance]: "during-performance", [PICTURE_TYPE_VALUES.MovieScreenCapture]: "screen-capture", [PICTURE_TYPE_VALUES.ColouredFish]: "fish", [PICTURE_TYPE_VALUES.Illustration]: "illustration", [PICTURE_TYPE_VALUES.BandLogo]: "band-logo", [PICTURE_TYPE_VALUES.PublisherLogo]: "publisher-logo" }; function generatePictureFilename(picture, index) { const typeName = PICTURE_TYPE_NAMES[picture.type] ?? "other"; const ext = picture.mimeType.split("/")[1] ?? "jpg"; return `${typeName}-${index + 1}.${ext}`; } async function exportAllPictures(audioPath, outputDir, options = {}) { const pictures = await readPictures(audioPath); const exportedPaths = []; const dir = outputDir.endsWith("/") ? outputDir : outputDir + "/"; for (let i = 0; i < pictures.length; i++) { const picture = pictures[i]; const filename = options.nameFormat ? options.nameFormat(picture, i) : generatePictureFilename(picture, i); const fullPath = dir + filename; await writeFileData(fullPath, picture.data); exportedPaths.push(fullPath); } return exportedPaths; } async function importCoverArt(audioPath, imagePath, options = {}) { const imageData = await readFileData(imagePath); let mimeType = options.mimeType; if (!mimeType) { const ext = imagePath.split(".").pop()?.toLowerCase(); const mimeTypes = { "jpg": "image/jpeg", "jpeg": "image/jpeg", "png": "image/png", "gif": "image/gif", "webp": "image/webp", "bmp": "image/bmp" }; mimeType = mimeTypes[ext ?? ""] ?? "image/jpeg"; } const modifiedBuffer = await setCoverArt(audioPath, imageData, mimeType); await writeFileData(audioPath, modifiedBuffer); } async function importPictureWithType(audioPath, imagePath, type, options = {}) { const imageData = await readFileData(imagePath); let mimeType = options.mimeType; if (!mimeType) { const ext = imagePath.split(".").pop()?.toLowerCase(); const mimeTypes = { "jpg": "image/jpeg", "jpeg": "image/jpeg", "png": "image/png", "gif": "image/gif", "webp": "image/webp", "bmp": "image/bmp" }; mimeType = mimeTypes[ext ?? ""] ?? "image/jpeg"; } const picture = { mimeType, data: imageData, type: typeof type === "string" ? PICTURE_TYPE_VALUES[type] : type, description: options.description }; const modifiedBuffer = await replacePictureByType(audioPath, picture); await writeFileData(audioPath, modifiedBuffer); } async function loadPictureFromFile(imagePath, type = "FrontCover", options = {}) { const data = await readFileData(imagePath); let mimeType = options.mimeType; if (!mimeType) { const ext = imagePath.split(".").pop()?.toLowerCase(); const mimeTypes = { "jpg": "image/jpeg", "jpeg": "image/jpeg", "png": "image/png", "gif": "image/gif", "webp": "image/webp", "bmp": "image/bmp" }; mimeType = mimeTypes[ext ?? ""] ?? "image/jpeg"; } return { mimeType, data, type: typeof type === "string" ? PICTURE_TYPE_VALUES[type] : type, description: options.description ?? imagePath.split("/").pop() }; } async function savePictureToFile(picture, imagePath) { await writeFileData(imagePath, picture.data); } async function copyCoverArt(sourcePath, targetPath, options = {}) { if (options.copyAll) { const pictures = await readPictures(sourcePath); if (pictures.length === 0) { throw new Error(`No pictures found in: ${sourcePath}`); } const modifiedBuffer = await applyPictures(targetPath, pictures); await writeFileData(targetPath, modifiedBuffer); } else { const coverData = await getCoverArt(sourcePath); if (!coverData) { throw new Error(`No cover art found in: ${sourcePath}`); } const pictures = await readPictures(sourcePath); const coverPicture = pictures.find( (p) => p.type === PICTURE_TYPE_VALUES.FrontCover ) ?? pictures[0]; const modifiedBuffer = await setCoverArt( targetPath, coverData, coverPicture.mimeType ); await writeFileData(targetPath, modifiedBuffer); } } async function fileExists(path) { try { const data = await readFileData(path); return data.length > 0; } catch { return false; } } async function findCoverFile(dir, names, extensions) { for (const name of names) { for (const ext of extensions) { const path = `${dir}${name}.${ext}`; if (await fileExists(path)) { return path; } } } return void 0; } async function findCoverArtFiles(audioPath) { const dir = audioPath.substring(0, audioPath.lastIndexOf("/") + 1); const extensions = ["jpg", "jpeg", "png", "gif", "webp"]; const found = {}; const frontPath = await findCoverFile( dir, ["cover", "front", "Cover", "Front"], extensions ); if (frontPath) found.front = frontPath; const folderPath = await findCoverFile( dir, ["folder", "Folder"], extensions ); if (folderPath) found.folder = folderPath; const otherNames = ["album", "artwork", "Album", "Artwork"]; for (const name of otherNames) { const path = await findCoverFile(dir, [name], extensions); if (path) found[name.toLowerCase()] = path; } const backPath = await findCoverFile( dir, ["back", "Back", "back-cover", "Back-Cover"], extensions ); if (backPath) found.back = backPath; return found; } export { copyCoverArt, exportAllPictures, exportCoverArt, exportPictureByType, findCoverArtFiles, importCoverArt, importPictureWithType, loadPictureFromFile, savePictureToFile };