NCNB
Cover Art + Tags
No upload · no re-encoding · local processing

Artwork in.
Audio untouched.

See what is already embedded, save it, replace it, or apply one cover to a whole album. MP3 and FLAC audio bytes are left alone.

Drop MP3 or FLAC files here

Add a whole album at once. JPEG, PNG and WebP artwork can come along too.

Files stay on this device. The page rewrites metadata only.

Artwork

Need different artwork?
Opens a normal Discogs search for this album. Nothing is sent there until you click.
Search Discogs ↗

Album & track info

Optional
Changing cover art does not require changing these fields. Unedited metadata is preserved.
Edit track titles, artists and numbers
Full metadata inspector
Shows every ID3 frame or FLAC metadata item this page found. Frames the editor does not expose remain intact.
safeName(art.name||('cover.'+(art.mime==='image/png'?'png':art.mime==='image/webp'?'webp':'jpg')))}`,blob:art.blob});const g=group();await downloadZip(entries,`${safeName(g.albumArtist?g.albumArtist+' - '+g.album:g.album)}.zip`)});$('.artout',box)?.addEventListener('click',()=>downloadBlob(art.blob,art.name||'cover.jpg'));box.scrollIntoView({behavior:'smooth',block:'start'})} function downloadBlob(blob,name){const url=URL.createObjectURL(blob),a=document.createElement('a');a.href=url;a.download=name;document.body.appendChild(a);a.click();a.remove();setTimeout(()=>URL.revokeObjectURL(url),30000)} const crcTable=(()=>{const t=new Uint32Array(256);for(let n=0;n<256;n++){let c=n;for(let k=0;k<8;k++)c=(c&1)?0xedb88320^(c>>>1):c>>>1;t[n]=c>>>0}return t})();function crc32(u8){let c=0xffffffff;for(const b of u8)c=crcTable[(c^b)&255]^(c>>>8);return(c^0xffffffff)>>>0}function u16le(n){const a=new Uint8Array(2);new DataView(a.buffer).setUint16(0,n,true);return a}function u32le(n){const a=new Uint8Array(4);new DataView(a.buffer).setUint32(0,n>>>0,true);return a}function dosDateTime(d=new Date()){return{time:(d.getHours()<<11)|(d.getMinutes()<<5)|(d.getSeconds()>>1),date:((d.getFullYear()-1980)<<9)|((d.getMonth()+1)<<5)|d.getDate()}} async function downloadZip(entries,filename){setStatus('Packaging files for one download…');const locals=[],centrals=[];let offset=0;for(const ent of entries){const data=new Uint8Array(await ent.blob.arrayBuffer()),name=enc.encode(ent.name.replace(/\\/g,'/')),crc=crc32(data),dt=dosDateTime(),local=[u32le(0x04034b50),u16le(20),u16le(0x0800),u16le(0),u16le(dt.time),u16le(dt.date),u32le(crc),u32le(data.length),u32le(data.length),u16le(name.length),u16le(0),name,data];locals.push(...local);const localLen=local.reduce((s,p)=>s+p.byteLength,0);centrals.push(u32le(0x02014b50),u16le(20),u16le(20),u16le(0x0800),u16le(0),u16le(dt.time),u16le(dt.date),u32le(crc),u32le(data.length),u32le(data.length),u16le(name.length),u16le(0),u16le(0),u16le(0),u16le(0),u32le(0),u32le(offset),name);offset+=localLen}const centralSize=centrals.reduce((s,p)=>s+p.byteLength,0),end=[u32le(0x06054b50),u16le(0),u16le(0),u16le(entries.length),u16le(entries.length),u32le(centralSize),u32le(offset),u16le(0)],blob=new Blob([...locals,...centrals,...end],{type:'application/zip'});downloadBlob(blob,filename);setStatus('Album package ready.')}