You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, defaultTitle = "Mp3 Lyric Extractor", primaryColor = "#1db954", bgColor = "#121212", textColor = "#ffffff") {
// Determine the original image source for default album art
const defaultCoverSrc = originalImg ? originalImg.src : '';
// Create main container
const container = document.createElement('div');
container.style.display = "flex";
container.style.flexDirection = "row";
container.style.width = "100%";
container.style.maxWidth = "800px";
container.style.height = "500px";
container.style.backgroundColor = bgColor;
container.style.color = textColor;
container.style.borderRadius = "12px";
container.style.overflow = "hidden";
container.style.boxShadow = "0 10px 30px rgba(0,0,0,0.5)";
container.style.fontFamily = "'Segoe UI', Roboto, Helvetica, Arial, sans-serif";
container.style.boxSizing = "border-box";
// Left panel for Cover Art and File Upload
const leftPanel = document.createElement('div');
leftPanel.style.width = "40%";
leftPanel.style.padding = "30px";
leftPanel.style.display = "flex";
leftPanel.style.flexDirection = "column";
leftPanel.style.alignItems = "center";
leftPanel.style.justifyContent = "center";
leftPanel.style.backgroundColor = "rgba(255,255,255,0.05)";
leftPanel.style.borderRight = "1px solid rgba(255,255,255,0.1)";
leftPanel.style.boxSizing = "border-box";
// Album Art Preview
const coverArt = document.createElement('img');
coverArt.src = defaultCoverSrc;
coverArt.style.width = "100%";
coverArt.style.aspectRatio = "1 / 1";
coverArt.style.objectFit = "cover";
coverArt.style.borderRadius = "8px";
coverArt.style.boxShadow = "0 4px 15px rgba(0,0,0,0.6)";
coverArt.style.backgroundColor = "#282828";
coverArt.style.marginBottom = "25px";
// Track Title display
const trackLabel = document.createElement('div');
trackLabel.textContent = "Unknown Track";
trackLabel.style.fontWeight = "bold";
trackLabel.style.fontSize = "18px";
trackLabel.style.marginBottom = "5px";
trackLabel.style.textAlign = "center";
trackLabel.style.width = "100%";
trackLabel.style.whiteSpace = "nowrap";
trackLabel.style.overflow = "hidden";
trackLabel.style.textOverflow = "ellipsis";
// Artist display
const artistLabel = document.createElement('div');
artistLabel.textContent = "Unknown Artist";
artistLabel.style.fontSize = "14px";
artistLabel.style.opacity = "0.7";
artistLabel.style.marginBottom = "25px";
artistLabel.style.textAlign = "center";
artistLabel.style.width = "100%";
artistLabel.style.whiteSpace = "nowrap";
artistLabel.style.overflow = "hidden";
artistLabel.style.textOverflow = "ellipsis";
// Upload Button Layout
const uploadLabel = document.createElement('label');
uploadLabel.textContent = "Select MP3 File";
uploadLabel.style.padding = "10px 20px";
uploadLabel.style.backgroundColor = primaryColor;
uploadLabel.style.color = "#fff";
uploadLabel.style.borderRadius = "20px";
uploadLabel.style.cursor = "pointer";
uploadLabel.style.fontWeight = "bold";
uploadLabel.style.fontSize = "14px";
uploadLabel.style.transition = "transform 0.2s, opacity 0.2s";
uploadLabel.onmouseover = () => { uploadLabel.style.opacity = "0.8"; uploadLabel.style.transform = "scale(1.05)"; };
uploadLabel.onmouseleave = () => { uploadLabel.style.opacity = "1"; uploadLabel.style.transform = "scale(1)"; };
const fileInput = document.createElement('input');
fileInput.type = "file";
fileInput.accept = "audio/mp3, audio/mpeg";
fileInput.style.display = "none";
uploadLabel.appendChild(fileInput);
leftPanel.appendChild(coverArt);
leftPanel.appendChild(trackLabel);
leftPanel.appendChild(artistLabel);
leftPanel.appendChild(uploadLabel);
// Right panel for Lyrics Display
const rightPanel = document.createElement('div');
rightPanel.style.width = "60%";
rightPanel.style.padding = "30px";
rightPanel.style.display = "flex";
rightPanel.style.flexDirection = "column";
rightPanel.style.boxSizing = "border-box";
const titleH2 = document.createElement('h2');
titleH2.textContent = defaultTitle;
titleH2.style.margin = "0 0 20px 0";
titleH2.style.fontSize = "22px";
titleH2.style.borderBottom = "1px solid rgba(255,255,255,0.1)";
titleH2.style.paddingBottom = "10px";
const lyricsContainer = document.createElement('div');
lyricsContainer.textContent = "Please select an MP3 file to extract its embedded ID3 song lyrics...";
lyricsContainer.style.flexGrow = "1";
lyricsContainer.style.overflowY = "auto";
lyricsContainer.style.whiteSpace = "pre-wrap";
lyricsContainer.style.lineHeight = "1.6";
lyricsContainer.style.fontSize = "15px";
lyricsContainer.style.opacity = "0.9";
lyricsContainer.style.paddingRight = "10px";
// Custom scrollbar styling for lyrics container
lyricsContainer.style.scrollbarWidth = "thin";
lyricsContainer.style.scrollbarColor = `${primaryColor} transparent`;
rightPanel.appendChild(titleH2);
rightPanel.appendChild(lyricsContainer);
container.appendChild(leftPanel);
container.appendChild(rightPanel);
// Function to dynamically load jsmediatags for ID3 extraction
function loadJsMediaTags() {
if (window.jsmediatags) return Promise.resolve(window.jsmediatags);
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = "https://cdnjs.cloudflare.com/ajax/libs/jsmediatags/3.9.5/jsmediatags.min.js";
script.onload = () => resolve(window.jsmediatags);
script.onerror = () => reject(new Error("Failed to load jsmediatags library."));
document.head.appendChild(script);
});
}
// Handle MP3 File Processing
fileInput.addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file) return;
lyricsContainer.textContent = "Loading and analyzing MP3 tags...";
try {
const jsmediatags = await loadJsMediaTags();
jsmediatags.read(file, {
onSuccess: function(tag) {
const tags = tag.tags;
// Update Title & Artist
trackLabel.textContent = tags.title || file.name.replace(/\.[^/.]+$/, "");
artistLabel.textContent = tags.artist || "Unknown Artist";
// Update Lyrics
let extractedLyrics = "";
if (tags.lyrics) {
extractedLyrics = tags.lyrics.lyrics || tags.lyrics;
} else if (tags.USLT) {
extractedLyrics = tags.USLT.text || tags.USLT;
} else if (tags.SYLT) {
extractedLyrics = "[Synchronized lyrics detected. Text extraction may be limited.]\n\n" + JSON.stringify(tags.SYLT, null, 2);
} else if (tags.TXXX) {
// Check custom text tags
let txxx = Array.isArray(tags.TXXX) ? tags.TXXX : [tags.TXXX];
for(let t of txxx) {
if(t.description && t.description.toLowerCase().includes("lyrics")) {
extractedLyrics = t.data;
break;
}
}
}
if (!extractedLyrics || typeof extractedLyrics !== 'string') {
lyricsContainer.textContent = "No embedded lyrics found in the ID3 tags of this MP3 file.\n\nNote: Many audio files do not have lyrics saved locally inside their tags.";
} else {
lyricsContainer.textContent = extractedLyrics.trim();
}
// Update Cover Art if present
if (tags.picture) {
let base64String = "";
const data = tags.picture.data;
for (let i = 0; i < data.length; i++) {
base64String += String.fromCharCode(data[i]);
}
const base64Url = "data:" + tags.picture.format + ";base64," + window.btoa(base64String);
coverArt.src = base64Url;
} else {
// Re-use original image if no internal cover art found
coverArt.src = defaultCoverSrc;
}
},
onError: function(error) {
lyricsContainer.textContent = "Error reading MP3 tags:\n" + (error.info || "Unknown structure error.");
console.error("jsmediatags error:", error);
}
});
} catch (err) {
lyricsContainer.textContent = "There was an error initializing the ID3 extractor.\n" + err.message;
}
});
// Handle responsiveness purely with element properties
const ro = new ResizeObserver(entries => {
for (let entry of entries) {
if (entry.contentRect.width < 600) {
container.style.flexDirection = "column";
container.style.height = "auto";
leftPanel.style.width = "100%";
leftPanel.style.borderRight = "none";
leftPanel.style.borderBottom = "1px solid rgba(255,255,255,0.1)";
rightPanel.style.width = "100%";
rightPanel.style.height = "400px"; // Provide fixed scrolling height inside column flow
} else {
container.style.flexDirection = "row";
container.style.height = "500px";
leftPanel.style.width = "40%";
leftPanel.style.borderRight = "1px solid rgba(255,255,255,0.1)";
leftPanel.style.borderBottom = "none";
rightPanel.style.width = "60%";
rightPanel.style.height = "auto";
}
}
});
// Slight delay to allow dom mounting so observer functions
setTimeout(() => ro.observe(container), 0);
return container;
}
Apply Changes